To: vim_dev@googlegroups.com Subject: Patch 8.2.0223 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0223 Problem: Some instructions not yet tested. Solution: Disassemble more instructions. Move tests to a new file. Compile call to s:function(). Files: src/testdir/test_vim9_script.vim, src/testdir/Make_all.mak, src/testdir/test_vim9_disassemble.vim, src/vim9compile.c, src/userfunc.c, src/proto/userfunc.pro, src/vim.h *** ../vim-8.2.0222/src/testdir/test_vim9_script.vim 2020-02-06 17:51:31.306336443 +0100 --- src/testdir/test_vim9_script.vim 2020-02-06 18:36:52.595282394 +0100 *************** *** 489,703 **** assert_notmatch('JUMP', instr) enddef - func NotCompiled() - echo "not" - endfunc - - let s:scriptvar = 4 - let g:globalvar = 'g' - - def s:ScriptFuncLoad(arg: string) - let local = 1 - buffers - echo arg - echo local - echo v:version - echo s:scriptvar - echo g:globalvar - echo &tabstop - echo $ENVVAR - echo @z - enddef - - def Test_disassembleLoad() - assert_fails('disass NoFunc', 'E1061:') - assert_fails('disass NotCompiled', 'E1062:') - - let res = execute('disass s:ScriptFuncLoad') - assert_match('\d*_ScriptFuncLoad.*' - \ .. 'buffers.*' - \ .. ' EXEC \+buffers.*' - \ .. ' LOAD arg\[-1\].*' - \ .. ' LOAD $0.*' - \ .. ' LOADV v:version.*' - \ .. ' LOADS s:scriptvar from .*test_vim9_script.vim.*' - \ .. ' LOADG g:globalvar.*' - \ .. ' LOADENV $ENVVAR.*' - \ .. ' LOADREG @z.*' - \, res) - enddef - - def s:ScriptFuncPush() - let localbool = true - let localspec = v:none - let localblob = 0z1234 - if has('float') - let localfloat = 1.234 - endif - enddef - - def Test_disassemblePush() - let res = execute('disass s:ScriptFuncPush') - assert_match('\d*_ScriptFuncPush.*' - \ .. 'localbool = true.*' - \ .. ' PUSH v:true.*' - \ .. 'localspec = v:none.*' - \ .. ' PUSH v:none.*' - \ .. 'localblob = 0z1234.*' - \ .. ' PUSHBLOB 0z1234.*' - \, res) - if has('float') - assert_match('\d*_ScriptFuncPush.*' - \ .. 'localfloat = 1.234.*' - \ .. ' PUSHF 1.234.*' - \, res) - endif - enddef - - def s:ScriptFuncStore() - let localnr = 1 - localnr = 2 - let localstr = 'abc' - localstr = 'xyz' - v:char = 'abc' - s:scriptvar = 'sv' - g:globalvar = 'gv' - &tabstop = 8 - $ENVVAR = 'ev' - @z = 'rv' - enddef - - def Test_disassembleStore() - let res = execute('disass s:ScriptFuncStore') - assert_match('\d*_ScriptFuncStore.*' - \ .. 'localnr = 2.*' - \ .. ' STORE 2 in $0.*' - \ .. 'localstr = ''xyz''.*' - \ .. ' STORE $1.*' - \ .. 'v:char = ''abc''.*' - \ .. 'STOREV v:char.*' - \ .. 's:scriptvar = ''sv''.*' - \ .. ' STORES s:scriptvar in .*test_vim9_script.vim.*' - \ .. 'g:globalvar = ''gv''.*' - \ .. ' STOREG g:globalvar.*' - \ .. '&tabstop = 8.*' - \ .. ' STOREOPT &tabstop.*' - \ .. '$ENVVAR = ''ev''.*' - \ .. ' STOREENV $ENVVAR.*' - \ .. '@z = ''rv''.*' - \ .. ' STOREREG @z.*' - \, res) - enddef - - def s:ScriptFuncTry() - try - echo 'yes' - catch /fail/ - echo 'no' - finally - echo 'end' - endtry - enddef - - def Test_disassembleTry() - let res = execute('disass s:ScriptFuncTry') - assert_match('\d*_ScriptFuncTry.*' - \ .. 'try.*' - \ .. 'TRY catch -> \d\+, finally -> \d\+.*' - \ .. 'catch /fail/.*' - \ .. ' JUMP -> \d\+.*' - \ .. ' PUSH v:exception.*' - \ .. ' PUSHS "fail".*' - \ .. ' COMPARESTRING =\~.*' - \ .. ' JUMP_IF_FALSE -> \d\+.*' - \ .. ' CATCH.*' - \ .. 'finally.*' - \ .. ' PUSHS "end".*' - \ .. 'endtry.*' - \ .. ' ENDTRY.*' - \, res) - enddef - - def s:ScriptFuncNew() - let ll = [1, "two", 333] - let dd = #{one: 1, two: "val"} - enddef - - def Test_disassembleNew() - let res = execute('disass s:ScriptFuncNew') - assert_match('\d*_ScriptFuncNew.*' - \ .. 'let ll = \[1, "two", 333].*' - \ .. 'PUSHNR 1.*' - \ .. 'PUSHS "two".*' - \ .. 'PUSHNR 333.*' - \ .. 'NEWLIST size 3.*' - \ .. 'let dd = #{one: 1, two: "val"}.*' - \ .. 'PUSHS "one".*' - \ .. 'PUSHNR 1.*' - \ .. 'PUSHS "two".*' - \ .. 'PUSHS "val".*' - \ .. 'NEWDICT size 2.*' - \, res) - enddef - - def FuncWithArg(arg) - echo arg - enddef - - func UserFunc() - echo 'nothing' - endfunc - - func UserFuncWithArg(arg) - echo a:arg - endfunc - - def s:ScriptFuncCall(): string - changenr() - char2nr("abc") - Test_disassembleNew() - FuncWithArg(343) - UserFunc() - UserFuncWithArg("foo") - let FuncRef = function("UserFunc") - FuncRef() - let FuncRefWithArg = function("UserFuncWithArg") - FuncRefWithArg("bar") - return "yes" - enddef - - def Test_disassembleCall() - let res = execute('disass s:ScriptFuncCall') - assert_match('\d*_ScriptFuncCall.*' - \ .. 'changenr().*' - \ .. ' BCALL changenr(argc 0).*' - \ .. 'char2nr("abc").*' - \ .. ' PUSHS "abc".*' - \ .. ' BCALL char2nr(argc 1).*' - \ .. 'Test_disassembleNew().*' - \ .. ' DCALL Test_disassembleNew(argc 0).*' - \ .. 'FuncWithArg(343).*' - \ .. ' PUSHNR 343.*' - \ .. ' DCALL FuncWithArg(argc 1).*' - \ .. 'UserFunc().*' - \ .. ' UCALL UserFunc(argc 0).*' - \ .. 'UserFuncWithArg("foo").*' - \ .. ' PUSHS "foo".*' - \ .. ' UCALL UserFuncWithArg(argc 1).*' - \ .. 'let FuncRef = function("UserFunc").*' - \ .. 'FuncRef().*' - \ .. ' LOAD $\d.*' - \ .. ' PCALL (argc 0).*' - \ .. 'let FuncRefWithArg = function("UserFuncWithArg").*' - \ .. 'FuncRefWithArg("bar").*' - \ .. ' PUSHS "bar".*' - \ .. ' LOAD $\d.*' - \ .. ' PCALL (argc 1).*' - \ .. 'return "yes".*' - \ .. ' PUSHS "yes".*' - \ .. ' RETURN.*' - \, res) - enddef - " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker --- 489,493 ---- *** ../vim-8.2.0222/src/testdir/Make_all.mak 2020-01-28 21:53:24.039964573 +0100 --- src/testdir/Make_all.mak 2020-02-06 18:38:47.010836096 +0100 *************** *** 268,273 **** --- 268,274 ---- test_utf8 \ test_utf8_comparisons \ test_vartabs \ + test_vim9_disassemble \ test_vim9_expr \ test_vim9_script \ test_viminfo \ *************** *** 470,475 **** --- 471,477 ---- test_user_func.res \ test_usercommands.res \ test_vartabs.res \ + test_vim9_disassemble.res \ test_vim9_expr.res \ test_vim9_script.res \ test_viminfo.res \ *** ../vim-8.2.0222/src/testdir/test_vim9_disassemble.vim 2020-02-06 19:24:19.456463654 +0100 --- src/testdir/test_vim9_disassemble.vim 2020-02-06 19:23:57.984545879 +0100 *************** *** 0 **** --- 1,220 ---- + " Test the :disassemble command, and compilation as a side effect + + func NotCompiled() + echo "not" + endfunc + + let s:scriptvar = 4 + let g:globalvar = 'g' + + def s:ScriptFuncLoad(arg: string) + let local = 1 + buffers + echo arg + echo local + echo v:version + echo s:scriptvar + echo g:globalvar + echo &tabstop + echo $ENVVAR + echo @z + enddef + + def Test_disassembleLoad() + assert_fails('disass NoFunc', 'E1061:') + assert_fails('disass NotCompiled', 'E1062:') + + let res = execute('disass s:ScriptFuncLoad') + assert_match('\d*_ScriptFuncLoad.*' + \ .. 'buffers.*' + \ .. ' EXEC \+buffers.*' + \ .. ' LOAD arg\[-1\].*' + \ .. ' LOAD $0.*' + \ .. ' LOADV v:version.*' + \ .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' + \ .. ' LOADG g:globalvar.*' + \ .. ' LOADENV $ENVVAR.*' + \ .. ' LOADREG @z.*' + \, res) + enddef + + def s:ScriptFuncPush() + let localbool = true + let localspec = v:none + let localblob = 0z1234 + if has('float') + let localfloat = 1.234 + endif + enddef + + def Test_disassemblePush() + let res = execute('disass s:ScriptFuncPush') + assert_match('\d*_ScriptFuncPush.*' + \ .. 'localbool = true.*' + \ .. ' PUSH v:true.*' + \ .. 'localspec = v:none.*' + \ .. ' PUSH v:none.*' + \ .. 'localblob = 0z1234.*' + \ .. ' PUSHBLOB 0z1234.*' + \, res) + if has('float') + assert_match('\d*_ScriptFuncPush.*' + \ .. 'localfloat = 1.234.*' + \ .. ' PUSHF 1.234.*' + \, res) + endif + enddef + + def s:ScriptFuncStore() + let localnr = 1 + localnr = 2 + let localstr = 'abc' + localstr = 'xyz' + v:char = 'abc' + s:scriptvar = 'sv' + g:globalvar = 'gv' + &tabstop = 8 + $ENVVAR = 'ev' + @z = 'rv' + enddef + + def Test_disassembleStore() + let res = execute('disass s:ScriptFuncStore') + assert_match('\d*_ScriptFuncStore.*' + \ .. 'localnr = 2.*' + \ .. ' STORE 2 in $0.*' + \ .. 'localstr = ''xyz''.*' + \ .. ' STORE $1.*' + \ .. 'v:char = ''abc''.*' + \ .. 'STOREV v:char.*' + \ .. 's:scriptvar = ''sv''.*' + \ .. ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' + \ .. 'g:globalvar = ''gv''.*' + \ .. ' STOREG g:globalvar.*' + \ .. '&tabstop = 8.*' + \ .. ' STOREOPT &tabstop.*' + \ .. '$ENVVAR = ''ev''.*' + \ .. ' STOREENV $ENVVAR.*' + \ .. '@z = ''rv''.*' + \ .. ' STOREREG @z.*' + \, res) + enddef + + def s:ScriptFuncTry() + try + echo 'yes' + catch /fail/ + echo 'no' + finally + echo 'end' + endtry + enddef + + def Test_disassembleTry() + let res = execute('disass s:ScriptFuncTry') + assert_match('\d*_ScriptFuncTry.*' + \ .. 'try.*' + \ .. 'TRY catch -> \d\+, finally -> \d\+.*' + \ .. 'catch /fail/.*' + \ .. ' JUMP -> \d\+.*' + \ .. ' PUSH v:exception.*' + \ .. ' PUSHS "fail".*' + \ .. ' COMPARESTRING =\~.*' + \ .. ' JUMP_IF_FALSE -> \d\+.*' + \ .. ' CATCH.*' + \ .. 'finally.*' + \ .. ' PUSHS "end".*' + \ .. 'endtry.*' + \ .. ' ENDTRY.*' + \, res) + enddef + + def s:ScriptFuncNew() + let ll = [1, "two", 333] + let dd = #{one: 1, two: "val"} + enddef + + def Test_disassembleNew() + let res = execute('disass s:ScriptFuncNew') + assert_match('\d*_ScriptFuncNew.*' + \ .. 'let ll = \[1, "two", 333].*' + \ .. 'PUSHNR 1.*' + \ .. 'PUSHS "two".*' + \ .. 'PUSHNR 333.*' + \ .. 'NEWLIST size 3.*' + \ .. 'let dd = #{one: 1, two: "val"}.*' + \ .. 'PUSHS "one".*' + \ .. 'PUSHNR 1.*' + \ .. 'PUSHS "two".*' + \ .. 'PUSHS "val".*' + \ .. 'NEWDICT size 2.*' + \, res) + enddef + + def FuncWithArg(arg) + echo arg + enddef + + func UserFunc() + echo 'nothing' + endfunc + + func UserFuncWithArg(arg) + echo a:arg + endfunc + + def s:ScriptFuncCall(): string + changenr() + char2nr("abc") + Test_disassembleNew() + FuncWithArg(343) + ScriptFuncNew() + s:ScriptFuncNew() + UserFunc() + UserFuncWithArg("foo") + let FuncRef = function("UserFunc") + FuncRef() + let FuncRefWithArg = function("UserFuncWithArg") + FuncRefWithArg("bar") + return "yes" + enddef + + def Test_disassembleCall() + let res = execute('disass s:ScriptFuncCall') + assert_match('\d\+_ScriptFuncCall.*' + \ .. 'changenr().*' + \ .. ' BCALL changenr(argc 0).*' + \ .. 'char2nr("abc").*' + \ .. ' PUSHS "abc".*' + \ .. ' BCALL char2nr(argc 1).*' + \ .. 'Test_disassembleNew().*' + \ .. ' DCALL Test_disassembleNew(argc 0).*' + \ .. 'FuncWithArg(343).*' + \ .. ' PUSHNR 343.*' + \ .. ' DCALL FuncWithArg(argc 1).*' + \ .. 'ScriptFuncNew().*' + \ .. ' DCALL \d\+_ScriptFuncNew(argc 0).*' + \ .. 's:ScriptFuncNew().*' + \ .. ' DCALL \d\+_ScriptFuncNew(argc 0).*' + \ .. 'UserFunc().*' + \ .. ' UCALL UserFunc(argc 0).*' + \ .. 'UserFuncWithArg("foo").*' + \ .. ' PUSHS "foo".*' + \ .. ' UCALL UserFuncWithArg(argc 1).*' + \ .. 'let FuncRef = function("UserFunc").*' + \ .. 'FuncRef().*' + \ .. ' LOAD $\d.*' + \ .. ' PCALL (argc 0).*' + \ .. 'let FuncRefWithArg = function("UserFuncWithArg").*' + \ .. 'FuncRefWithArg("bar").*' + \ .. ' PUSHS "bar".*' + \ .. ' LOAD $\d.*' + \ .. ' PCALL (argc 1).*' + \ .. 'return "yes".*' + \ .. ' PUSHS "yes".*' + \ .. ' RETURN.*' + \, res) + enddef + + + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker *** ../vim-8.2.0222/src/vim9compile.c 2020-02-06 17:51:31.306336443 +0100 --- src/vim9compile.c 2020-02-06 19:19:41.025526497 +0100 *************** *** 1686,1734 **** char_u *p; int argcount = argcount_init; char_u namebuf[100]; ufunc_T *ufunc; if (varlen >= sizeof(namebuf)) { semsg(_("E1011: name too long: %s"), name); return FAIL; } ! vim_strncpy(namebuf, name, varlen); *arg = skipwhite(*arg + varlen + 1); if (compile_arguments(arg, cctx, &argcount) == FAIL) ! return FAIL; ! if (ASCII_ISLOWER(*name)) { int idx; // builtin function ! idx = find_internal_func(namebuf); if (idx >= 0) ! return generate_BCALL(cctx, idx, argcount); semsg(_(e_unknownfunc), namebuf); } - // User defined function or variable must start with upper case. - if (!ASCII_ISUPPER(*name)) - { - semsg(_("E1012: Invalid function name: %s"), namebuf); - return FAIL; - } - // If we can find the function by name generate the right call. ! ufunc = find_func(namebuf, cctx); if (ufunc != NULL) ! return generate_CALL(cctx, ufunc, argcount); // If the name is a variable, load it and use PCALL. p = namebuf; if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) ! return generate_PCALL(cctx, argcount, FALSE); // The function may be defined only later. Need to figure out at runtime. ! return generate_UCALL(cctx, namebuf, argcount); } // like NAMESPACE_CHAR but with 'a' and 'l'. --- 1686,1745 ---- char_u *p; int argcount = argcount_init; char_u namebuf[100]; + char_u fname_buf[FLEN_FIXED + 1]; + char_u *tofree = NULL; + int error = FCERR_NONE; ufunc_T *ufunc; + int res = FAIL; if (varlen >= sizeof(namebuf)) { semsg(_("E1011: name too long: %s"), name); return FAIL; } ! vim_strncpy(namebuf, *arg, varlen); ! name = fname_trans_sid(namebuf, fname_buf, &tofree, &error); *arg = skipwhite(*arg + varlen + 1); if (compile_arguments(arg, cctx, &argcount) == FAIL) ! goto theend; ! if (ASCII_ISLOWER(*name) && name[1] != ':') { int idx; // builtin function ! idx = find_internal_func(name); if (idx >= 0) ! { ! res = generate_BCALL(cctx, idx, argcount); ! goto theend; ! } semsg(_(e_unknownfunc), namebuf); } // If we can find the function by name generate the right call. ! ufunc = find_func(name, cctx); if (ufunc != NULL) ! { ! res = generate_CALL(cctx, ufunc, argcount); ! goto theend; ! } // If the name is a variable, load it and use PCALL. p = namebuf; if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) ! { ! res = generate_PCALL(cctx, argcount, FALSE); ! goto theend; ! } // The function may be defined only later. Need to figure out at runtime. ! res = generate_UCALL(cctx, name, argcount); ! ! theend: ! vim_free(tofree); ! return res; } // like NAMESPACE_CHAR but with 'a' and 'l'. *** ../vim-8.2.0222/src/userfunc.c 2020-02-06 17:51:31.306336443 +0100 --- src/userfunc.c 2020-02-06 19:15:08.234558758 +0100 *************** *** 573,580 **** return ret; } - #define FLEN_FIXED 40 - /* * Return TRUE if "p" starts with "" or "s:". * Only works if eval_fname_script() returned non-zero for "p"! --- 573,578 ---- *************** *** 591,597 **** * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory * (slow). */ ! static char_u * fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) { int llen; --- 589,595 ---- * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory * (slow). */ ! char_u * fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) { int llen; *** ../vim-8.2.0222/src/proto/userfunc.pro 2020-01-26 15:52:33.023833239 +0100 --- src/proto/userfunc.pro 2020-02-06 19:16:58.658142270 +0100 *************** *** 6,11 **** --- 6,12 ---- char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe); + char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); ufunc_T *find_func(char_u *name, cctx_T *cctx); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); *************** *** 26,32 **** int function_exists(char_u *name, int no_deref); char_u *get_expanded_name(char_u *name, int check); char_u *get_user_func_name(expand_T *xp, int idx); - void clean_script_functions(int sid); void ex_delfunction(exarg_T *eap); void func_unref(char_u *name); void func_ptr_unref(ufunc_T *fp); --- 27,32 ---- *** ../vim-8.2.0222/src/vim.h 2020-01-26 22:43:27.484098902 +0100 --- src/vim.h 2020-02-06 19:16:09.830326727 +0100 *************** *** 2574,2579 **** --- 2574,2582 ---- #define FCERR_DELETED 7 #define FCERR_NOTMETHOD 8 // function cannot be used as a method + // fixed buffer length for fname_trans_sid() + #define FLEN_FIXED 40 + // flags for find_name_end() #define FNE_INCL_BR 1 // include [] in name #define FNE_CHECK_START 2 // check name starts with valid character *** ../vim-8.2.0222/src/version.c 2020-02-06 17:51:31.306336443 +0100 --- src/version.c 2020-02-06 18:38:12.370971292 +0100 *************** *** 744,745 **** --- 744,747 ---- { /* Add new patch number below this line */ + /**/ + 223, /**/ -- He who laughs last, thinks slowest. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///