To: vim_dev@googlegroups.com Subject: Patch 8.2.0201 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0201 Problem: Cannot assign to an imported variable. Solution: Make it work. Files: src/evalvars.c, src/vim9compile.c, src/proto/vim9compile.pro, src/userfunc.c, src/testdir/test_vim9_script.vim *** ../vim-8.2.0200/src/evalvars.c 2020-02-02 22:24:00.624827188 +0100 --- src/evalvars.c 2020-02-02 23:01:32.498917653 +0100 *************** *** 2296,2302 **** if (tv == NULL && current_sctx.sc_version == SCRIPT_VERSION_VIM9) { ! imported_T *import = find_imported(name, NULL); // imported variable from another script if (import != NULL) --- 2296,2302 ---- if (tv == NULL && current_sctx.sc_version == SCRIPT_VERSION_VIM9) { ! imported_T *import = find_imported(name, 0, NULL); // imported variable from another script if (import != NULL) *************** *** 2472,2478 **** res = HASHITEM_EMPTY(hi) ? -1 : 1; // if not script-local, then perhaps imported ! if (res == -1 && find_imported(p, NULL) != NULL) res = 1; if (p != buffer) --- 2472,2478 ---- res = HASHITEM_EMPTY(hi) ? -1 : 1; // if not script-local, then perhaps imported ! if (res == -1 && find_imported(p, 0, NULL) != NULL) res = 1; if (p != buffer) *** ../vim-8.2.0200/src/vim9compile.c 2020-02-02 22:24:00.624827188 +0100 --- src/vim9compile.c 2020-02-03 20:50:05.549112994 +0100 *************** *** 1467,1473 **** * Find "name" in imported items of the current script/ */ imported_T * ! find_imported(char_u *name, cctx_T *cctx) { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); int idx; --- 1467,1473 ---- * Find "name" in imported items of the current script/ */ imported_T * ! find_imported(char_u *name, size_t len, cctx_T *cctx) { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); int idx; *************** *** 1478,1484 **** imported_T *import = ((imported_T *)cctx->ctx_imports.ga_data) + idx; ! if (STRCMP(name, import->imp_name) == 0) return import; } --- 1478,1486 ---- imported_T *import = ((imported_T *)cctx->ctx_imports.ga_data) + idx; ! if (len == 0 ? STRCMP(name, import->imp_name) == 0 ! : STRLEN(import->imp_name) == len ! && STRNCMP(name, import->imp_name, len) == 0) return import; } *************** *** 1486,1492 **** { imported_T *import = ((imported_T *)si->sn_imports.ga_data) + idx; ! if (STRCMP(name, import->imp_name) == 0) return import; } return NULL; --- 1488,1496 ---- { imported_T *import = ((imported_T *)si->sn_imports.ga_data) + idx; ! if (len == 0 ? STRCMP(name, import->imp_name) == 0 ! : STRLEN(import->imp_name) == len ! && STRNCMP(name, import->imp_name, len) == 0) return import; } return NULL; *************** *** 1517,1523 **** return OK; } ! import = find_imported(name, cctx); if (import != NULL) { // TODO: check this is a variable, not a function --- 1521,1527 ---- return OK; } ! import = find_imported(name, 0, cctx); if (import != NULL) { // TODO: check this is a variable, not a function *************** *** 3071,3076 **** --- 3075,3090 ---- [cctx->ctx_lnum]); } + typedef enum { + dest_local, + dest_option, + dest_env, + dest_global, + dest_vimvar, + dest_script, + dest_reg, + } assign_dest_T; + /* * compile "let var [= expr]", "const var = expr" and "var = expr" * "arg" points to "var". *************** *** 3086,3099 **** garray_T *instr = &cctx->ctx_instr; int idx = -1; char_u *op; - int option = FALSE; int opt_type; int opt_flags = 0; - int global = FALSE; - int env = FALSE; - int reg = FALSE; int vimvaridx = -1; - int script = FALSE; int oplen = 0; int heredoc = FALSE; type_T *type; --- 3100,3109 ---- garray_T *instr = &cctx->ctx_instr; int idx = -1; char_u *op; int opt_type; + assign_dest_T dest = dest_local; int opt_flags = 0; int vimvaridx = -1; int oplen = 0; int heredoc = FALSE; type_T *type; *************** *** 3125,3131 **** long numval; char_u *stringval = NULL; ! option = TRUE; if (cmdidx == CMD_const) { emsg(_(e_const_option)); --- 3135,3141 ---- long numval; char_u *stringval = NULL; ! dest = dest_option; if (cmdidx == CMD_const) { emsg(_(e_const_option)); *************** *** 3159,3165 **** } else if (*arg == '$') { ! env = TRUE; if (is_decl) { semsg(_("E1065: Cannot declare an environment variable: %s"), name); --- 3169,3175 ---- } else if (*arg == '$') { ! dest = dest_env; if (is_decl) { semsg(_("E1065: Cannot declare an environment variable: %s"), name); *************** *** 3173,3179 **** emsg_invreg(arg[1]); return FAIL; } ! reg = TRUE; if (is_decl) { semsg(_("E1066: Cannot declare a register: %s"), name); --- 3183,3189 ---- emsg_invreg(arg[1]); return FAIL; } ! dest = dest_reg; if (is_decl) { semsg(_("E1066: Cannot declare a register: %s"), name); *************** *** 3182,3188 **** } else if (STRNCMP(arg, "g:", 2) == 0) { ! global = TRUE; if (is_decl) { semsg(_("E1016: Cannot declare a global variable: %s"), name); --- 3192,3198 ---- } else if (STRNCMP(arg, "g:", 2) == 0) { ! dest = dest_global; if (is_decl) { semsg(_("E1016: Cannot declare a global variable: %s"), name); *************** *** 3197,3202 **** --- 3207,3213 ---- semsg(_(e_var_notfound), arg); goto theend; } + dest = dest_vimvar; if (is_decl) { semsg(_("E1064: Cannot declare a v: variable: %s"), name); *************** *** 3232,3240 **** } else if ((STRNCMP(arg, "s:", 2) == 0 ? lookup_script(arg + 2, varlen - 2) ! : lookup_script(arg, varlen)) == OK) { ! script = TRUE; if (is_decl) { semsg(_("E1054: Variable already declared in the script: %s"), --- 3243,3252 ---- } else if ((STRNCMP(arg, "s:", 2) == 0 ? lookup_script(arg + 2, varlen - 2) ! : lookup_script(arg, varlen)) == OK ! || find_imported(arg, varlen, cctx) != NULL) { ! dest = dest_script; if (is_decl) { semsg(_("E1054: Variable already declared in the script: %s"), *************** *** 3244,3250 **** } } ! if (!option) { if (is_decl && *p == ':') { --- 3256,3262 ---- } } ! if (dest != dest_option) { if (is_decl && *p == ':') { *************** *** 3279,3293 **** semsg(_(e_white_both), buf); } ! if (oplen == 3 && !heredoc && !global && type->tt_type != VAR_STRING ! && type->tt_type != VAR_UNKNOWN) { emsg("E1019: Can only concatenate to string"); goto theend; } // +=, /=, etc. require an existing variable ! if (idx < 0 && !global && !env && !reg && !option) { if (oplen > 1 && !heredoc) { --- 3291,3305 ---- semsg(_(e_white_both), buf); } ! if (oplen == 3 && !heredoc && dest != dest_global ! && type->tt_type != VAR_STRING && type->tt_type != VAR_UNKNOWN) { emsg("E1019: Can only concatenate to string"); goto theend; } // +=, /=, etc. require an existing variable ! if (idx < 0 && dest == dest_local) { if (oplen > 1 && !heredoc) { *************** *** 3328,3347 **** // for "+=", "*=", "..=" etc. first load the current value if (*op != '=') { ! if (option) ! // TODO: check the option exists ! generate_LOAD(cctx, ISN_LOADOPT, 0, name + 1, type); ! else if (global) ! generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type); ! else if (env) ! // Include $ in the name here ! generate_LOAD(cctx, ISN_LOADENV, 0, name, type); ! else if (reg) ! generate_LOAD(cctx, ISN_LOADREG, arg[1], NULL, &t_string); ! else if (vimvaridx >= 0) ! generate_LOADV(cctx, name + 2, TRUE); ! else ! generate_LOAD(cctx, ISN_LOAD, idx, NULL, type); } // compile the expression --- 3340,3371 ---- // for "+=", "*=", "..=" etc. first load the current value if (*op != '=') { ! switch (dest) ! { ! case dest_option: ! // TODO: check the option exists ! generate_LOAD(cctx, ISN_LOADOPT, 0, name + 1, type); ! break; ! case dest_global: ! generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type); ! break; ! case dest_script: ! compile_load_scriptvar(cctx, name); ! break; ! case dest_env: ! // Include $ in the name here ! generate_LOAD(cctx, ISN_LOADENV, 0, name, type); ! break; ! case dest_reg: ! generate_LOAD(cctx, ISN_LOADREG, arg[1], NULL, &t_string); ! break; ! case dest_vimvar: ! generate_LOADV(cctx, name + 2, TRUE); ! break; ! case dest_local: ! generate_LOAD(cctx, ISN_LOAD, idx, NULL, type); ! break; ! } } // compile the expression *************** *** 3377,3383 **** emsg(_("E1021: const requires a value")); goto theend; } ! else if (!has_type || option) { emsg(_("E1022: type or initialization required")); goto theend; --- 3401,3407 ---- emsg(_("E1021: const requires a value")); goto theend; } ! else if (!has_type || dest == dest_option) { emsg(_("E1022: type or initialization required")); goto theend; *************** *** 3427,3475 **** } } ! if (option) ! generate_STOREOPT(cctx, name + 1, opt_flags); ! else if (global) ! // include g: with the name, easier to execute that way ! generate_STORE(cctx, ISN_STOREG, 0, name); ! else if (env) ! generate_STORE(cctx, ISN_STOREENV, 0, name + 1); ! else if (reg) ! generate_STORE(cctx, ISN_STOREREG, name[1], NULL); ! else if (vimvaridx >= 0) ! generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL); ! else if (script) { ! char_u *rawname = name + (name[1] == ':' ? 2 : 0); ! idx = get_script_item_idx(current_sctx.sc_sid, rawname, TRUE); ! // TODO: specific type ! if (idx < 0) ! generate_OLDSCRIPT(cctx, ISN_STORES, rawname, ! current_sctx.sc_sid, &t_any); ! else ! generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT, ! current_sctx.sc_sid, idx, &t_any); ! } ! else ! { ! isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; ! // optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE into ! // ISN_STORENR ! if (instr->ga_len == instr_count + 1 && isn->isn_type == ISN_PUSHNR) ! { ! varnumber_T val = isn->isn_arg.number; ! garray_T *stack = &cctx->ctx_type_stack; ! isn->isn_type = ISN_STORENR; ! isn->isn_arg.storenr.str_idx = idx; ! isn->isn_arg.storenr.str_val = val; ! if (stack->ga_len > 0) ! --stack->ga_len; ! } ! else ! generate_STORE(cctx, ISN_STORE, idx, NULL); } ret = p; --- 3451,3518 ---- } } ! switch (dest) { ! case dest_option: ! generate_STOREOPT(cctx, name + 1, opt_flags); ! break; ! case dest_global: ! // include g: with the name, easier to execute that way ! generate_STORE(cctx, ISN_STOREG, 0, name); ! break; ! case dest_env: ! generate_STORE(cctx, ISN_STOREENV, 0, name + 1); ! break; ! case dest_reg: ! generate_STORE(cctx, ISN_STOREREG, name[1], NULL); ! break; ! case dest_vimvar: ! generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL); ! break; ! case dest_script: ! { ! char_u *rawname = name + (name[1] == ':' ? 2 : 0); ! imported_T *import = NULL; ! int sid = current_sctx.sc_sid; ! if (name[1] != ':') ! { ! import = find_imported(name, 0, cctx); ! if (import != NULL) ! sid = import->imp_sid; ! } ! idx = get_script_item_idx(sid, rawname, TRUE); ! // TODO: specific type ! if (idx < 0) ! generate_OLDSCRIPT(cctx, ISN_STORES, rawname, sid, &t_any); ! else ! generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT, ! sid, idx, &t_any); ! } ! break; ! case dest_local: ! { ! isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; ! // optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE ! // into ISN_STORENR ! if (instr->ga_len == instr_count + 1 ! && isn->isn_type == ISN_PUSHNR) ! { ! varnumber_T val = isn->isn_arg.number; ! garray_T *stack = &cctx->ctx_type_stack; ! ! isn->isn_type = ISN_STORENR; ! isn->isn_arg.storenr.str_idx = idx; ! isn->isn_arg.storenr.str_val = val; ! if (stack->ga_len > 0) ! --stack->ga_len; ! } ! else ! generate_STORE(cctx, ISN_STORE, idx, NULL); ! } ! break; } ret = p; *************** *** 4619,4625 **** // "funcname(" is always a function call. // "varname[]" is an expression. - // "g:varname" is an expression. // "varname->expr" is an expression. if (*p == '(' || *p == '[' --- 4662,4667 ---- *************** *** 4643,4649 **** || *ea.cmd == '@' || ((p - ea.cmd) > 2 && ea.cmd[1] == ':') || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0 ! || lookup_script(ea.cmd, p - ea.cmd) == OK) { line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx); if (line == NULL) --- 4685,4692 ---- || *ea.cmd == '@' || ((p - ea.cmd) > 2 && ea.cmd[1] == ':') || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0 ! || lookup_script(ea.cmd, p - ea.cmd) == OK ! || find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL) { line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx); if (line == NULL) *** ../vim-8.2.0200/src/proto/vim9compile.pro 2020-01-26 15:52:33.023833239 +0100 --- src/proto/vim9compile.pro 2020-02-02 23:01:55.478792829 +0100 *************** *** 4,10 **** char *vartype_name(vartype_T type); char *type_name(type_T *type, char **tofree); int get_script_item_idx(int sid, char_u *name, int check_writable); ! imported_T *find_imported(char_u *name, cctx_T *cctx); char_u *to_name_end(char_u *arg); char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); --- 4,10 ---- char *vartype_name(vartype_T type); char *type_name(type_T *type, char **tofree); int get_script_item_idx(int sid, char_u *name, int check_writable); ! imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); char_u *to_name_end(char_u *arg); char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); *** ../vim-8.2.0200/src/userfunc.c 2020-02-02 17:22:23.438043236 +0100 --- src/userfunc.c 2020-02-02 23:01:48.194832260 +0100 *************** *** 678,684 **** return func; // Find imported funcion before global one. ! imported = find_imported(name, cctx); if (imported != NULL && imported->imp_funcname != NULL) { hi = hash_find(&func_hashtab, imported->imp_funcname); --- 678,684 ---- return func; // Find imported funcion before global one. ! imported = find_imported(name, 0, cctx); if (imported != NULL && imported->imp_funcname != NULL) { hi = hash_find(&func_hashtab, imported->imp_funcname); *** ../vim-8.2.0200/src/testdir/test_vim9_script.vim 2020-02-02 22:24:00.624827188 +0100 --- src/testdir/test_vim9_script.vim 2020-02-03 20:35:45.627973293 +0100 *************** *** 320,328 **** \ 'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"', \ 'def UseExported()', \ ' g:imported_abs = exported', \ 'enddef', \ 'UseExported()', ! \ 'g:import_disassabled = execute("disass UseExported")', \ ] writefile(import_lines, 'Ximport_abs.vim') writefile(s:export_script_lines, 'Xexport_abs.vim') --- 320,330 ---- \ 'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"', \ 'def UseExported()', \ ' g:imported_abs = exported', + \ ' exported = 8888', + \ ' g:imported_after = exported', \ 'enddef', \ 'UseExported()', ! \ 'g:import_disassembled = execute("disass UseExported")', \ ] writefile(import_lines, 'Ximport_abs.vim') writefile(s:export_script_lines, 'Xexport_abs.vim') *************** *** 330,341 **** source Ximport_abs.vim assert_equal(9876, g:imported_abs) assert_match('\d\+_UseExported.*' \ .. 'g:imported_abs = exported.*' \ .. '0 LOADSCRIPT exported from .*Xexport_abs.vim.*' ! \ .. '1 STOREG g:imported_abs', g:import_disassabled) unlet g:imported_abs ! unlet g:import_disassabled delete('Ximport_abs.vim') delete('Xexport_abs.vim') --- 332,350 ---- source Ximport_abs.vim assert_equal(9876, g:imported_abs) + assert_equal(8888, g:imported_after) assert_match('\d\+_UseExported.*' \ .. 'g:imported_abs = exported.*' \ .. '0 LOADSCRIPT exported from .*Xexport_abs.vim.*' ! \ .. '1 STOREG g:imported_abs.*' ! \ .. 'exported = 8888.*' ! \ .. '3 STORESCRIPT exported in .*Xexport_abs.vim.*' ! \ .. 'g:imported_after = exported.*' ! \ .. '4 LOADSCRIPT exported from .*Xexport_abs.vim.*' ! \ .. '5 STOREG g:imported_after.*' ! \, g:import_disassembled) unlet g:imported_abs ! unlet g:import_disassembled delete('Ximport_abs.vim') delete('Xexport_abs.vim') *** ../vim-8.2.0200/src/version.c 2020-02-02 22:24:00.628827172 +0100 --- src/version.c 2020-02-03 20:50:32.225015557 +0100 *************** *** 744,745 **** --- 744,747 ---- { /* Add new patch number below this line */ + /**/ + 201, /**/ -- If Pacman had affected us as kids we'd be running around in dark rooms, munching pills and listening to repetitive music. -- Marcus Brigstocke /// 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 ///