Mirror of the Vim source from https://github.com/vim/vim
Revisión | df0548b649c12d6fafa758974f105332c45848e8 (tree) |
---|---|
Tiempo | 2020-12-02 00:45:04 |
Autor | Bram Moolenaar <Bram@vim....> |
Commiter | Bram Moolenaar |
patch 8.2.2073: Vim9: for with unpack only works for local variables
Commit: https://github.com/vim/vim/commit/4b8a065145bb53762b869cd6b8e55b7ad7341761
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Dec 1 16:30:44 2020 +0100
@@ -1863,22 +1863,49 @@ | ||
1863 | 1863 | enddef |
1864 | 1864 | |
1865 | 1865 | def Test_for_loop_unpack() |
1866 | - var result = [] | |
1867 | - for [v1, v2] in [[1, 2], [3, 4]] | |
1868 | - result->add(v1) | |
1869 | - result->add(v2) | |
1870 | - endfor | |
1871 | - assert_equal([1, 2, 3, 4], result) | |
1872 | - | |
1873 | - result = [] | |
1874 | - for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]] | |
1875 | - result->add(v1) | |
1876 | - result->add(v2) | |
1877 | - result->add(v3) | |
1878 | - endfor | |
1879 | - assert_equal([1, 2, [], 3, 4, [5, 6]], result) | |
1880 | - | |
1881 | 1866 | var lines =<< trim END |
1867 | + var result = [] | |
1868 | + for [v1, v2] in [[1, 2], [3, 4]] | |
1869 | + result->add(v1) | |
1870 | + result->add(v2) | |
1871 | + endfor | |
1872 | + assert_equal([1, 2, 3, 4], result) | |
1873 | + | |
1874 | + result = [] | |
1875 | + for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]] | |
1876 | + result->add(v1) | |
1877 | + result->add(v2) | |
1878 | + result->add(v3) | |
1879 | + endfor | |
1880 | + assert_equal([1, 2, [], 3, 4, [5, 6]], result) | |
1881 | + | |
1882 | + result = [] | |
1883 | + for [&ts, &sw] in [[1, 2], [3, 4]] | |
1884 | + result->add(&ts) | |
1885 | + result->add(&sw) | |
1886 | + endfor | |
1887 | + assert_equal([1, 2, 3, 4], result) | |
1888 | + | |
1889 | + var slist: list<string> | |
1890 | + for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']] | |
1891 | + slist->add($LOOPVAR) | |
1892 | + slist->add(@r) | |
1893 | + slist->add(v:errmsg) | |
1894 | + endfor | |
1895 | + assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist) | |
1896 | + | |
1897 | + slist = [] | |
1898 | + for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']] | |
1899 | + slist->add(g:globalvar) | |
1900 | + slist->add(b:bufvar) | |
1901 | + slist->add(w:winvar) | |
1902 | + slist->add(t:tabvar) | |
1903 | + endfor | |
1904 | + assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist) | |
1905 | + END | |
1906 | + CheckDefAndScriptSuccess(lines) | |
1907 | + | |
1908 | + lines =<< trim END | |
1882 | 1909 | for [v1, v2] in [[1, 2, 3], [3, 4]] |
1883 | 1910 | echo v1 v2 |
1884 | 1911 | endfor |
@@ -751,6 +751,8 @@ | ||
751 | 751 | static int included_patches[] = |
752 | 752 | { /* Add new patch number below this line */ |
753 | 753 | /**/ |
754 | + 2073, | |
755 | +/**/ | |
754 | 756 | 2072, |
755 | 757 | /**/ |
756 | 758 | 2071, |
@@ -5066,6 +5066,184 @@ | ||
5066 | 5066 | } |
5067 | 5067 | |
5068 | 5068 | /* |
5069 | + * For one assignment figure out the type of destination. Return it in "dest". | |
5070 | + * When not recognized "dest" is not set. | |
5071 | + * For an option "opt_flags" is set. | |
5072 | + * For a v:var "vimvaridx" is set. | |
5073 | + * "type" is set to the destination type if known, unchanted otherwise. | |
5074 | + * Return FAIL if an error message was given. | |
5075 | + */ | |
5076 | + static int | |
5077 | +get_var_dest( | |
5078 | + char_u *name, | |
5079 | + assign_dest_T *dest, | |
5080 | + int cmdidx, | |
5081 | + int *opt_flags, | |
5082 | + int *vimvaridx, | |
5083 | + type_T **type, | |
5084 | + cctx_T *cctx) | |
5085 | +{ | |
5086 | + char_u *p; | |
5087 | + | |
5088 | + if (*name == '&') | |
5089 | + { | |
5090 | + int cc; | |
5091 | + long numval; | |
5092 | + int opt_type; | |
5093 | + | |
5094 | + *dest = dest_option; | |
5095 | + if (cmdidx == CMD_final || cmdidx == CMD_const) | |
5096 | + { | |
5097 | + emsg(_(e_const_option)); | |
5098 | + return FAIL; | |
5099 | + } | |
5100 | + p = name; | |
5101 | + p = find_option_end(&p, opt_flags); | |
5102 | + if (p == NULL) | |
5103 | + { | |
5104 | + // cannot happen? | |
5105 | + emsg(_(e_letunexp)); | |
5106 | + return FAIL; | |
5107 | + } | |
5108 | + cc = *p; | |
5109 | + *p = NUL; | |
5110 | + opt_type = get_option_value(skip_option_env_lead(name), | |
5111 | + &numval, NULL, *opt_flags); | |
5112 | + *p = cc; | |
5113 | + if (opt_type == -3) | |
5114 | + { | |
5115 | + semsg(_(e_unknown_option), name); | |
5116 | + return FAIL; | |
5117 | + } | |
5118 | + if (opt_type == -2 || opt_type == 0) | |
5119 | + *type = &t_string; | |
5120 | + else | |
5121 | + *type = &t_number; // both number and boolean option | |
5122 | + } | |
5123 | + else if (*name == '$') | |
5124 | + { | |
5125 | + *dest = dest_env; | |
5126 | + *type = &t_string; | |
5127 | + } | |
5128 | + else if (*name == '@') | |
5129 | + { | |
5130 | + if (!valid_yank_reg(name[1], FALSE) || name[1] == '.') | |
5131 | + { | |
5132 | + emsg_invreg(name[1]); | |
5133 | + return FAIL; | |
5134 | + } | |
5135 | + *dest = dest_reg; | |
5136 | + *type = &t_string; | |
5137 | + } | |
5138 | + else if (STRNCMP(name, "g:", 2) == 0) | |
5139 | + { | |
5140 | + *dest = dest_global; | |
5141 | + } | |
5142 | + else if (STRNCMP(name, "b:", 2) == 0) | |
5143 | + { | |
5144 | + *dest = dest_buffer; | |
5145 | + } | |
5146 | + else if (STRNCMP(name, "w:", 2) == 0) | |
5147 | + { | |
5148 | + *dest = dest_window; | |
5149 | + } | |
5150 | + else if (STRNCMP(name, "t:", 2) == 0) | |
5151 | + { | |
5152 | + *dest = dest_tab; | |
5153 | + } | |
5154 | + else if (STRNCMP(name, "v:", 2) == 0) | |
5155 | + { | |
5156 | + typval_T *vtv; | |
5157 | + int di_flags; | |
5158 | + | |
5159 | + *vimvaridx = find_vim_var(name + 2, &di_flags); | |
5160 | + if (*vimvaridx < 0) | |
5161 | + { | |
5162 | + semsg(_(e_variable_not_found_str), name); | |
5163 | + return FAIL; | |
5164 | + } | |
5165 | + // We use the current value of "sandbox" here, is that OK? | |
5166 | + if (var_check_ro(di_flags, name, FALSE)) | |
5167 | + return FAIL; | |
5168 | + *dest = dest_vimvar; | |
5169 | + vtv = get_vim_var_tv(*vimvaridx); | |
5170 | + *type = typval2type_vimvar(vtv, cctx->ctx_type_list); | |
5171 | + } | |
5172 | + return OK; | |
5173 | +} | |
5174 | + | |
5175 | +/* | |
5176 | + * Generate a STORE instruction for "dest", not being "dest_local". | |
5177 | + * Return FAIL when out of memory. | |
5178 | + */ | |
5179 | + static int | |
5180 | +generate_store_var( | |
5181 | + cctx_T *cctx, | |
5182 | + assign_dest_T dest, | |
5183 | + int opt_flags, | |
5184 | + int vimvaridx, | |
5185 | + int scriptvar_idx, | |
5186 | + int scriptvar_sid, | |
5187 | + type_T *type, | |
5188 | + char_u *name) | |
5189 | +{ | |
5190 | + switch (dest) | |
5191 | + { | |
5192 | + case dest_option: | |
5193 | + return generate_STOREOPT(cctx, skip_option_env_lead(name), | |
5194 | + opt_flags); | |
5195 | + case dest_global: | |
5196 | + // include g: with the name, easier to execute that way | |
5197 | + return generate_STORE(cctx, ISN_STOREG, 0, name); | |
5198 | + case dest_buffer: | |
5199 | + // include b: with the name, easier to execute that way | |
5200 | + return generate_STORE(cctx, ISN_STOREB, 0, name); | |
5201 | + case dest_window: | |
5202 | + // include w: with the name, easier to execute that way | |
5203 | + return generate_STORE(cctx, ISN_STOREW, 0, name); | |
5204 | + case dest_tab: | |
5205 | + // include t: with the name, easier to execute that way | |
5206 | + return generate_STORE(cctx, ISN_STORET, 0, name); | |
5207 | + case dest_env: | |
5208 | + return generate_STORE(cctx, ISN_STOREENV, 0, name + 1); | |
5209 | + case dest_reg: | |
5210 | + return generate_STORE(cctx, ISN_STOREREG, name[1], NULL); | |
5211 | + case dest_vimvar: | |
5212 | + return generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL); | |
5213 | + case dest_script: | |
5214 | + if (scriptvar_idx < 0) | |
5215 | + { | |
5216 | + char_u *name_s = name; | |
5217 | + int r; | |
5218 | + | |
5219 | + // Include s: in the name for store_var() | |
5220 | + if (name[1] != ':') | |
5221 | + { | |
5222 | + int len = (int)STRLEN(name) + 3; | |
5223 | + | |
5224 | + name_s = alloc(len); | |
5225 | + if (name_s == NULL) | |
5226 | + name_s = name; | |
5227 | + else | |
5228 | + vim_snprintf((char *)name_s, len, "s:%s", name); | |
5229 | + } | |
5230 | + r = generate_OLDSCRIPT(cctx, ISN_STORES, name_s, | |
5231 | + scriptvar_sid, type); | |
5232 | + if (name_s != name) | |
5233 | + vim_free(name_s); | |
5234 | + return r; | |
5235 | + } | |
5236 | + return generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT, | |
5237 | + scriptvar_sid, scriptvar_idx, type); | |
5238 | + case dest_local: | |
5239 | + case dest_expr: | |
5240 | + // cannot happen | |
5241 | + break; | |
5242 | + } | |
5243 | + return FAIL; | |
5244 | +} | |
5245 | + | |
5246 | +/* | |
5069 | 5247 | * Compile declaration and assignment: |
5070 | 5248 | * "let name" |
5071 | 5249 | * "var name = expr" |
@@ -5205,12 +5383,12 @@ | ||
5205 | 5383 | var_start = arg; |
5206 | 5384 | for (var_idx = 0; var_idx == 0 || var_idx < var_count; var_idx++) |
5207 | 5385 | { |
5208 | - char_u *var_end = skip_var_one(var_start, FALSE); | |
5386 | + char_u *var_end; | |
5387 | + char_u *dest_end; | |
5209 | 5388 | size_t varlen; |
5210 | 5389 | int new_local = FALSE; |
5211 | - int opt_type; | |
5390 | + assign_dest_T dest = dest_local; | |
5212 | 5391 | int opt_flags = 0; |
5213 | - assign_dest_T dest = dest_local; | |
5214 | 5392 | int vimvaridx = -1; |
5215 | 5393 | lvar_T *lvar = NULL; |
5216 | 5394 | lvar_T arg_lvar; |
@@ -5218,22 +5396,27 @@ | ||
5218 | 5396 | int has_index = FALSE; |
5219 | 5397 | int instr_count = -1; |
5220 | 5398 | |
5399 | + // "dest_end" is the end of the destination, including "[expr]" or | |
5400 | + // ".name". | |
5401 | + // "var_end" is the end of the variable/option/etc. name. | |
5402 | + dest_end = skip_var_one(var_start, FALSE); | |
5221 | 5403 | if (*var_start == '@') |
5222 | - p = var_start + 2; | |
5404 | + var_end = var_start + 2; | |
5223 | 5405 | else |
5224 | 5406 | { |
5225 | 5407 | // skip over the leading "&", "&l:", "&g:" and "$" |
5226 | - p = skip_option_env_lead(var_start); | |
5227 | - p = to_name_end(p, TRUE); | |
5228 | - } | |
5229 | - | |
5230 | - // "a: type" is declaring variable "a" with a type, not "a:". | |
5408 | + var_end = skip_option_env_lead(var_start); | |
5409 | + var_end = to_name_end(var_end, TRUE); | |
5410 | + } | |
5411 | + | |
5412 | + // "a: type" is declaring variable "a" with a type, not dict "a:". | |
5413 | + if (is_decl && dest_end == var_start + 2 && dest_end[-1] == ':') | |
5414 | + --dest_end; | |
5231 | 5415 | if (is_decl && var_end == var_start + 2 && var_end[-1] == ':') |
5232 | 5416 | --var_end; |
5233 | - if (is_decl && p == var_start + 2 && p[-1] == ':') | |
5234 | - --p; | |
5235 | - | |
5236 | - varlen = p - var_start; | |
5417 | + | |
5418 | + // compute the length of the destination without "[expr]" or ".name" | |
5419 | + varlen = var_end - var_start; | |
5237 | 5420 | vim_free(name); |
5238 | 5421 | name = vim_strnsave(var_start, varlen); |
5239 | 5422 | if (name == NULL) |
@@ -5245,101 +5428,19 @@ | ||
5245 | 5428 | { |
5246 | 5429 | int declare_error = FALSE; |
5247 | 5430 | |
5248 | - if (*var_start == '&') | |
5249 | - { | |
5250 | - int cc; | |
5251 | - long numval; | |
5252 | - | |
5253 | - dest = dest_option; | |
5254 | - if (cmdidx == CMD_final || cmdidx == CMD_const) | |
5255 | - { | |
5256 | - emsg(_(e_const_option)); | |
5257 | - goto theend; | |
5258 | - } | |
5259 | - declare_error = is_decl; | |
5260 | - p = var_start; | |
5261 | - p = find_option_end(&p, &opt_flags); | |
5262 | - if (p == NULL) | |
5263 | - { | |
5264 | - // cannot happen? | |
5265 | - emsg(_(e_letunexp)); | |
5266 | - goto theend; | |
5267 | - } | |
5268 | - cc = *p; | |
5269 | - *p = NUL; | |
5270 | - opt_type = get_option_value(skip_option_env_lead(var_start), | |
5271 | - &numval, NULL, opt_flags); | |
5272 | - *p = cc; | |
5273 | - if (opt_type == -3) | |
5274 | - { | |
5275 | - semsg(_(e_unknown_option), var_start); | |
5276 | - goto theend; | |
5277 | - } | |
5278 | - if (opt_type == -2 || opt_type == 0) | |
5279 | - type = &t_string; | |
5280 | - else | |
5281 | - type = &t_number; // both number and boolean option | |
5282 | - } | |
5283 | - else if (*var_start == '$') | |
5284 | - { | |
5285 | - dest = dest_env; | |
5286 | - type = &t_string; | |
5287 | - declare_error = is_decl; | |
5288 | - } | |
5289 | - else if (*var_start == '@') | |
5431 | + if (get_var_dest(name, &dest, cmdidx, &opt_flags, | |
5432 | + &vimvaridx, &type, cctx) == FAIL) | |
5433 | + goto theend; | |
5434 | + if (dest != dest_local) | |
5290 | 5435 | { |
5291 | - if (!valid_yank_reg(var_start[1], FALSE) || var_start[1] == '.') | |
5292 | - { | |
5293 | - emsg_invreg(var_start[1]); | |
5294 | - goto theend; | |
5295 | - } | |
5296 | - dest = dest_reg; | |
5297 | - type = &t_string; | |
5298 | - declare_error = is_decl; | |
5299 | - } | |
5300 | - else if (varlen > 1 && STRNCMP(var_start, "g:", 2) == 0) | |
5301 | - { | |
5302 | - dest = dest_global; | |
5303 | - declare_error = is_decl; | |
5304 | - } | |
5305 | - else if (varlen > 1 && STRNCMP(var_start, "b:", 2) == 0) | |
5306 | - { | |
5307 | - dest = dest_buffer; | |
5308 | - declare_error = is_decl; | |
5309 | - } | |
5310 | - else if (varlen > 1 && STRNCMP(var_start, "w:", 2) == 0) | |
5311 | - { | |
5312 | - dest = dest_window; | |
5313 | - declare_error = is_decl; | |
5314 | - } | |
5315 | - else if (varlen > 1 && STRNCMP(var_start, "t:", 2) == 0) | |
5316 | - { | |
5317 | - dest = dest_tab; | |
5318 | - declare_error = is_decl; | |
5319 | - } | |
5320 | - else if (varlen > 1 && STRNCMP(var_start, "v:", 2) == 0) | |
5321 | - { | |
5322 | - typval_T *vtv; | |
5323 | - int di_flags; | |
5324 | - | |
5325 | - vimvaridx = find_vim_var(name + 2, &di_flags); | |
5326 | - if (vimvaridx < 0) | |
5327 | - { | |
5328 | - semsg(_(e_variable_not_found_str), var_start); | |
5329 | - goto theend; | |
5330 | - } | |
5331 | - // We use the current value of "sandbox" here, is that OK? | |
5332 | - if (var_check_ro(di_flags, name, FALSE)) | |
5333 | - goto theend; | |
5334 | - dest = dest_vimvar; | |
5335 | - vtv = get_vim_var_tv(vimvaridx); | |
5336 | - type = typval2type_vimvar(vtv, cctx->ctx_type_list); | |
5436 | + // Specific kind of variable recognized. | |
5337 | 5437 | declare_error = is_decl; |
5338 | 5438 | } |
5339 | 5439 | else |
5340 | 5440 | { |
5341 | 5441 | int idx; |
5342 | 5442 | |
5443 | + // No specific kind of variable recognized, just a name. | |
5343 | 5444 | for (idx = 0; reserved[idx] != NULL; ++idx) |
5344 | 5445 | if (STRCMP(reserved[idx], name) == 0) |
5345 | 5446 | { |
@@ -5450,19 +5551,19 @@ | ||
5450 | 5551 | |
5451 | 5552 | // handle "a:name" as a name, not index "name" on "a" |
5452 | 5553 | if (varlen > 1 || var_start[varlen] != ':') |
5453 | - p = var_end; | |
5554 | + var_end = dest_end; | |
5454 | 5555 | |
5455 | 5556 | if (dest != dest_option) |
5456 | 5557 | { |
5457 | - if (is_decl && *p == ':') | |
5558 | + if (is_decl && *var_end == ':') | |
5458 | 5559 | { |
5459 | 5560 | // parse optional type: "let var: type = expr" |
5460 | - if (!VIM_ISWHITE(p[1])) | |
5561 | + if (!VIM_ISWHITE(var_end[1])) | |
5461 | 5562 | { |
5462 | 5563 | semsg(_(e_white_space_required_after_str), ":"); |
5463 | 5564 | goto theend; |
5464 | 5565 | } |
5465 | - p = skipwhite(p + 1); | |
5566 | + p = skipwhite(var_end + 1); | |
5466 | 5567 | type = parse_type(&p, cctx->ctx_type_list); |
5467 | 5568 | has_type = TRUE; |
5468 | 5569 | } |
@@ -5499,7 +5600,7 @@ | ||
5499 | 5600 | } |
5500 | 5601 | |
5501 | 5602 | member_type = type; |
5502 | - if (var_end > var_start + varlen) | |
5603 | + if (dest_end > var_start + varlen) | |
5503 | 5604 | { |
5504 | 5605 | // Something follows after the variable: "var[idx]" or "var.key". |
5505 | 5606 | // TODO: should we also handle "->func()" here? |
@@ -5856,12 +5957,12 @@ | ||
5856 | 5957 | if (type->tt_type == VAR_LIST) |
5857 | 5958 | { |
5858 | 5959 | if (generate_instr_drop(cctx, ISN_STORELIST, 3) == FAIL) |
5859 | - return FAIL; | |
5960 | + goto theend; | |
5860 | 5961 | } |
5861 | 5962 | else if (type->tt_type == VAR_DICT) |
5862 | 5963 | { |
5863 | 5964 | if (generate_instr_drop(cctx, ISN_STOREDICT, 3) == FAIL) |
5864 | - return FAIL; | |
5965 | + goto theend; | |
5865 | 5966 | } |
5866 | 5967 | else |
5867 | 5968 | { |
@@ -5876,100 +5977,40 @@ | ||
5876 | 5977 | // ":const var": lock the value, but not referenced variables |
5877 | 5978 | generate_LOCKCONST(cctx); |
5878 | 5979 | |
5879 | - switch (dest) | |
5980 | + if (dest != dest_local) | |
5880 | 5981 | { |
5881 | - case dest_option: | |
5882 | - generate_STOREOPT(cctx, skip_option_env_lead(name), | |
5883 | - opt_flags); | |
5884 | - break; | |
5885 | - case dest_global: | |
5886 | - // include g: with the name, easier to execute that way | |
5887 | - generate_STORE(cctx, ISN_STOREG, 0, name); | |
5888 | - break; | |
5889 | - case dest_buffer: | |
5890 | - // include b: with the name, easier to execute that way | |
5891 | - generate_STORE(cctx, ISN_STOREB, 0, name); | |
5892 | - break; | |
5893 | - case dest_window: | |
5894 | - // include w: with the name, easier to execute that way | |
5895 | - generate_STORE(cctx, ISN_STOREW, 0, name); | |
5896 | - break; | |
5897 | - case dest_tab: | |
5898 | - // include t: with the name, easier to execute that way | |
5899 | - generate_STORE(cctx, ISN_STORET, 0, name); | |
5900 | - break; | |
5901 | - case dest_env: | |
5902 | - generate_STORE(cctx, ISN_STOREENV, 0, name + 1); | |
5903 | - break; | |
5904 | - case dest_reg: | |
5905 | - generate_STORE(cctx, ISN_STOREREG, name[1], NULL); | |
5906 | - break; | |
5907 | - case dest_vimvar: | |
5908 | - generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL); | |
5909 | - break; | |
5910 | - case dest_script: | |
5911 | - { | |
5912 | - if (scriptvar_idx < 0) | |
5913 | - { | |
5914 | - char_u *name_s = name; | |
5915 | - | |
5916 | - // Include s: in the name for store_var() | |
5917 | - if (name[1] != ':') | |
5918 | - { | |
5919 | - int len = (int)STRLEN(name) + 3; | |
5920 | - | |
5921 | - name_s = alloc(len); | |
5922 | - if (name_s == NULL) | |
5923 | - name_s = name; | |
5924 | - else | |
5925 | - vim_snprintf((char *)name_s, len, | |
5926 | - "s:%s", name); | |
5927 | - } | |
5928 | - generate_OLDSCRIPT(cctx, ISN_STORES, name_s, | |
5929 | - scriptvar_sid, type); | |
5930 | - if (name_s != name) | |
5931 | - vim_free(name_s); | |
5932 | - } | |
5933 | - else | |
5934 | - generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT, | |
5935 | - scriptvar_sid, scriptvar_idx, type); | |
5936 | - } | |
5937 | - break; | |
5938 | - case dest_local: | |
5939 | - if (lvar != NULL) | |
5940 | - { | |
5941 | - isn_T *isn = ((isn_T *)instr->ga_data) | |
5942 | - + instr->ga_len - 1; | |
5943 | - | |
5944 | - // optimization: turn "var = 123" from ISN_PUSHNR + | |
5945 | - // ISN_STORE into ISN_STORENR | |
5946 | - if (!lvar->lv_from_outer | |
5947 | - && instr->ga_len == instr_count + 1 | |
5948 | - && isn->isn_type == ISN_PUSHNR) | |
5949 | - { | |
5950 | - varnumber_T val = isn->isn_arg.number; | |
5951 | - | |
5952 | - isn->isn_type = ISN_STORENR; | |
5953 | - isn->isn_arg.storenr.stnr_idx = lvar->lv_idx; | |
5954 | - isn->isn_arg.storenr.stnr_val = val; | |
5955 | - if (stack->ga_len > 0) | |
5956 | - --stack->ga_len; | |
5957 | - } | |
5958 | - else if (lvar->lv_from_outer) | |
5959 | - generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, | |
5960 | - NULL); | |
5961 | - else | |
5962 | - generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); | |
5963 | - } | |
5964 | - break; | |
5965 | - case dest_expr: | |
5966 | - // cannot happen | |
5967 | - break; | |
5982 | + if (generate_store_var(cctx, dest, opt_flags, vimvaridx, | |
5983 | + scriptvar_idx, scriptvar_sid, type, name) == FAIL) | |
5984 | + goto theend; | |
5985 | + } | |
5986 | + else if (lvar != NULL) | |
5987 | + { | |
5988 | + isn_T *isn = ((isn_T *)instr->ga_data) | |
5989 | + + instr->ga_len - 1; | |
5990 | + | |
5991 | + // optimization: turn "var = 123" from ISN_PUSHNR + | |
5992 | + // ISN_STORE into ISN_STORENR | |
5993 | + if (!lvar->lv_from_outer | |
5994 | + && instr->ga_len == instr_count + 1 | |
5995 | + && isn->isn_type == ISN_PUSHNR) | |
5996 | + { | |
5997 | + varnumber_T val = isn->isn_arg.number; | |
5998 | + | |
5999 | + isn->isn_type = ISN_STORENR; | |
6000 | + isn->isn_arg.storenr.stnr_idx = lvar->lv_idx; | |
6001 | + isn->isn_arg.storenr.stnr_val = val; | |
6002 | + if (stack->ga_len > 0) | |
6003 | + --stack->ga_len; | |
6004 | + } | |
6005 | + else if (lvar->lv_from_outer) | |
6006 | + generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, NULL); | |
6007 | + else | |
6008 | + generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); | |
5968 | 6009 | } |
5969 | 6010 | } |
5970 | 6011 | |
5971 | 6012 | if (var_idx + 1 < var_count) |
5972 | - var_start = skipwhite(var_end + 1); | |
6013 | + var_start = skipwhite(dest_end + 1); | |
5973 | 6014 | } |
5974 | 6015 | |
5975 | 6016 | // for "[var, var] = expr" drop the "expr" value |
@@ -6443,6 +6484,7 @@ | ||
6443 | 6484 | { |
6444 | 6485 | char_u *arg; |
6445 | 6486 | char_u *arg_end; |
6487 | + char_u *name = NULL; | |
6446 | 6488 | char_u *p; |
6447 | 6489 | int var_count = 0; |
6448 | 6490 | int semicolon = FALSE; |
@@ -6538,41 +6580,62 @@ | ||
6538 | 6580 | |
6539 | 6581 | for (idx = 0; idx < var_count; ++idx) |
6540 | 6582 | { |
6541 | - // TODO: use skip_var_one, also assign to @r, $VAR, etc. | |
6542 | - p = arg; | |
6543 | - while (eval_isnamec(*p)) | |
6544 | - ++p; | |
6583 | + assign_dest_T dest = dest_local; | |
6584 | + int opt_flags = 0; | |
6585 | + int vimvaridx = -1; | |
6586 | + type_T *type = &t_any; | |
6587 | + | |
6588 | + p = skip_var_one(arg, FALSE); | |
6545 | 6589 | varlen = p - arg; |
6546 | - var_lvar = lookup_local(arg, varlen, cctx); | |
6547 | - if (var_lvar != NULL) | |
6548 | - { | |
6549 | - semsg(_(e_variable_already_declared), arg); | |
6550 | - drop_scope(cctx); | |
6551 | - return NULL; | |
6552 | - } | |
6553 | - | |
6554 | - // Reserve a variable to store "var". | |
6555 | - // TODO: check for type | |
6556 | - var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any); | |
6557 | - if (var_lvar == NULL) | |
6558 | - { | |
6559 | - // out of memory or used as an argument | |
6560 | - drop_scope(cctx); | |
6561 | - return NULL; | |
6562 | - } | |
6563 | - | |
6564 | - if (semicolon && idx == var_count - 1) | |
6565 | - var_lvar->lv_type = vartype; | |
6590 | + name = vim_strnsave(arg, varlen); | |
6591 | + if (name == NULL) | |
6592 | + goto failed; | |
6593 | + | |
6594 | + // TODO: script var not supported? | |
6595 | + if (get_var_dest(name, &dest, CMD_for, &opt_flags, | |
6596 | + &vimvaridx, &type, cctx) == FAIL) | |
6597 | + goto failed; | |
6598 | + if (dest != dest_local) | |
6599 | + { | |
6600 | + if (generate_store_var(cctx, dest, opt_flags, vimvaridx, | |
6601 | + 0, 0, type, name) == FAIL) | |
6602 | + goto failed; | |
6603 | + } | |
6566 | 6604 | else |
6567 | - var_lvar->lv_type = item_type; | |
6568 | - generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); | |
6605 | + { | |
6606 | + var_lvar = lookup_local(arg, varlen, cctx); | |
6607 | + if (var_lvar != NULL) | |
6608 | + { | |
6609 | + semsg(_(e_variable_already_declared), arg); | |
6610 | + goto failed; | |
6611 | + } | |
6612 | + | |
6613 | + // Reserve a variable to store "var". | |
6614 | + // TODO: check for type | |
6615 | + var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any); | |
6616 | + if (var_lvar == NULL) | |
6617 | + // out of memory or used as an argument | |
6618 | + goto failed; | |
6619 | + | |
6620 | + if (semicolon && idx == var_count - 1) | |
6621 | + var_lvar->lv_type = vartype; | |
6622 | + else | |
6623 | + var_lvar->lv_type = item_type; | |
6624 | + generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); | |
6625 | + } | |
6569 | 6626 | |
6570 | 6627 | if (*p == ',' || *p == ';') |
6571 | 6628 | ++p; |
6572 | 6629 | arg = skipwhite(p); |
6630 | + vim_free(name); | |
6573 | 6631 | } |
6574 | 6632 | |
6575 | 6633 | return arg_end; |
6634 | + | |
6635 | +failed: | |
6636 | + vim_free(name); | |
6637 | + drop_scope(cctx); | |
6638 | + return NULL; | |
6576 | 6639 | } |
6577 | 6640 | |
6578 | 6641 | /* |