Mercurial > vim
comparison src/ex_docmd.c @ 21526:a7afee13873d v8.2.1313
patch 8.2.1313: Vim9 script: cannot assign to environment variable
Commit: https://github.com/vim/vim/commit/b5ed266037dea49024e00c4e1f9c89f3a9ebaa60
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Jul 28 22:38:37 2020 +0200
patch 8.2.1313: Vim9 script: cannot assign to environment variable
Problem: Vim9 script: cannot assign to environment variable.
Solution: Recognize environment variable assignment. (closes https://github.com/vim/vim/issues/6548)
Also options and registers.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 28 Jul 2020 22:45:03 +0200 |
parents | 0b448762ebbd |
children | 6c67c86a202a |
comparison
equal
deleted
inserted
replaced
21525:8c78fe47b321 | 21526:a7afee13873d |
---|---|
1708 int save_reg_executing = reg_executing; | 1708 int save_reg_executing = reg_executing; |
1709 int ni; // set when Not Implemented | 1709 int ni; // set when Not Implemented |
1710 char_u *cmd; | 1710 char_u *cmd; |
1711 int starts_with_colon = FALSE; | 1711 int starts_with_colon = FALSE; |
1712 #ifdef FEAT_EVAL | 1712 #ifdef FEAT_EVAL |
1713 int starts_with_quote; | 1713 int may_have_range; |
1714 int vim9script = in_vim9script(); | 1714 int vim9script = in_vim9script(); |
1715 #endif | 1715 #endif |
1716 | 1716 |
1717 CLEAR_FIELD(ea); | 1717 CLEAR_FIELD(ea); |
1718 ea.line1 = 1; | 1718 ea.line1 = 1; |
1771 * | 1771 * |
1772 * We need the command to know what kind of range it uses. | 1772 * We need the command to know what kind of range it uses. |
1773 */ | 1773 */ |
1774 cmd = ea.cmd; | 1774 cmd = ea.cmd; |
1775 #ifdef FEAT_EVAL | 1775 #ifdef FEAT_EVAL |
1776 starts_with_quote = vim9script && !starts_with_colon && *ea.cmd == '\''; | 1776 // In Vim9 script a colon is required before the range. |
1777 if (!starts_with_quote) | 1777 may_have_range = !vim9script || starts_with_colon; |
1778 if (may_have_range) | |
1778 #endif | 1779 #endif |
1779 ea.cmd = skip_range(ea.cmd, NULL); | 1780 ea.cmd = skip_range(ea.cmd, NULL); |
1780 if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) | 1781 if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) |
1781 ea.cmd = skipwhite(ea.cmd + 1); | 1782 ea.cmd = skipwhite(ea.cmd + 1); |
1782 | 1783 |
1783 #ifdef FEAT_EVAL | 1784 #ifdef FEAT_EVAL |
1784 if (vim9script && !starts_with_colon) | 1785 if (vim9script && !starts_with_colon) |
1785 { | 1786 { |
1786 if (ea.cmd > cmd) | 1787 if (ea.cmd == cmd + 1 && *cmd == '$') |
1788 // should be "$VAR = val" | |
1789 --ea.cmd; | |
1790 else if (ea.cmd > cmd) | |
1787 { | 1791 { |
1788 emsg(_(e_colon_required)); | 1792 emsg(_(e_colon_required)); |
1789 goto doend; | 1793 goto doend; |
1790 } | 1794 } |
1791 p = find_ex_command(&ea, NULL, lookup_scriptvar, NULL); | 1795 p = find_ex_command(&ea, NULL, lookup_scriptvar, NULL); |
1874 #endif | 1878 #endif |
1875 } | 1879 } |
1876 | 1880 |
1877 ea.cmd = cmd; | 1881 ea.cmd = cmd; |
1878 #ifdef FEAT_EVAL | 1882 #ifdef FEAT_EVAL |
1879 if (!starts_with_quote) | 1883 if (may_have_range) |
1880 #endif | 1884 #endif |
1881 if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL) | 1885 if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL) |
1882 goto doend; | 1886 goto doend; |
1883 | 1887 |
1884 /* | 1888 /* |
3265 /* | 3269 /* |
3266 * Recognize a Vim9 script function/method call and assignment: | 3270 * Recognize a Vim9 script function/method call and assignment: |
3267 * "lvar = value", "lvar(arg)", "[1, 2 3]->Func()" | 3271 * "lvar = value", "lvar(arg)", "[1, 2 3]->Func()" |
3268 */ | 3272 */ |
3269 p = eap->cmd; | 3273 p = eap->cmd; |
3270 if (lookup != NULL && (vim_strchr((char_u *)"{('[", *p) != NULL | 3274 if (lookup != NULL) |
3271 || ((p = to_name_const_end(eap->cmd)) > eap->cmd | 3275 { |
3272 && *p != NUL))) | 3276 // Skip over first char for "&opt = val", "$ENV = val" and "@r = val". |
3273 { | 3277 char_u *pskip = (*eap->cmd == '&' || *eap->cmd == '$' |
3274 int oplen; | 3278 || *eap->cmd == '@') ? eap->cmd + 1 : eap->cmd; |
3275 int heredoc; | 3279 |
3276 | 3280 if (vim_strchr((char_u *)"{('[", *p) != NULL |
3277 if ( | 3281 || ((p = to_name_const_end(pskip)) > eap->cmd && *p != NUL)) |
3278 // "(..." is an expression. | 3282 { |
3279 // "funcname(" is always a function call. | 3283 int oplen; |
3280 *p == '(' | 3284 int heredoc; |
3281 || (p == eap->cmd | 3285 |
3282 ? ( | 3286 if ( |
3283 // "{..." is an dict expression. | 3287 // "(..." is an expression. |
3284 *eap->cmd == '{' | 3288 // "funcname(" is always a function call. |
3285 // "'string'->func()" is an expression. | 3289 *p == '(' |
3286 || *eap->cmd == '\'' | 3290 || (p == eap->cmd |
3287 // "g:varname" is an expression. | 3291 ? ( |
3288 || eap->cmd[1] == ':' | 3292 // "{..." is an dict expression. |
3289 ) | 3293 *eap->cmd == '{' |
3290 : ( | 3294 // "'string'->func()" is an expression. |
3291 // "varname[]" is an expression. | 3295 || *eap->cmd == '\'' |
3292 *p == '[' | 3296 // "g:varname" is an expression. |
3293 // "varname->func()" is an expression. | 3297 || eap->cmd[1] == ':' |
3294 || (*p == '-' && p[1] == '>') | 3298 ) |
3295 // "varname.expr" is an expression. | 3299 : ( |
3296 || (*p == '.' && ASCII_ISALPHA(p[1])) | 3300 // "varname[]" is an expression. |
3297 ))) | 3301 *p == '[' |
3298 { | 3302 // "varname->func()" is an expression. |
3299 eap->cmdidx = CMD_eval; | 3303 || (*p == '-' && p[1] == '>') |
3300 return eap->cmd; | 3304 // "varname.expr" is an expression. |
3301 } | 3305 || (*p == '.' && ASCII_ISALPHA(p[1])) |
3302 | 3306 ))) |
3303 // "[...]->Method()" is a list expression, but "[a, b] = Func()" is | |
3304 // an assignment. | |
3305 // If there is no line break inside the "[...]" then "p" is advanced to | |
3306 // after the "]" by to_name_const_end(): check if a "=" follows. | |
3307 // If "[...]" has a line break "p" still points at the "[" and it can't | |
3308 // be an assignment. | |
3309 if (*eap->cmd == '[') | |
3310 { | |
3311 p = to_name_const_end(eap->cmd); | |
3312 if (p == eap->cmd || *skipwhite(p) != '=') | |
3313 { | 3307 { |
3314 eap->cmdidx = CMD_eval; | 3308 eap->cmdidx = CMD_eval; |
3315 return eap->cmd; | 3309 return eap->cmd; |
3316 } | 3310 } |
3317 if (p > eap->cmd && *skipwhite(p) == '=') | 3311 |
3312 // "[...]->Method()" is a list expression, but "[a, b] = Func()" is | |
3313 // an assignment. | |
3314 // If there is no line break inside the "[...]" then "p" is | |
3315 // advanced to after the "]" by to_name_const_end(): check if a "=" | |
3316 // follows. | |
3317 // If "[...]" has a line break "p" still points at the "[" and it | |
3318 // can't be an assignment. | |
3319 if (*eap->cmd == '[') | |
3318 { | 3320 { |
3319 eap->cmdidx = CMD_let; | 3321 p = to_name_const_end(eap->cmd); |
3322 if (p == eap->cmd || *skipwhite(p) != '=') | |
3323 { | |
3324 eap->cmdidx = CMD_eval; | |
3325 return eap->cmd; | |
3326 } | |
3327 if (p > eap->cmd && *skipwhite(p) == '=') | |
3328 { | |
3329 eap->cmdidx = CMD_let; | |
3330 return eap->cmd; | |
3331 } | |
3332 } | |
3333 | |
3334 // Recognize an assignment if we recognize the variable name: | |
3335 // "g:var = expr" | |
3336 // "var = expr" where "var" is a local var name. | |
3337 oplen = assignment_len(skipwhite(p), &heredoc); | |
3338 if (oplen > 0) | |
3339 { | |
3340 if (((p - eap->cmd) > 2 && eap->cmd[1] == ':') | |
3341 || *eap->cmd == '&' | |
3342 || *eap->cmd == '$' | |
3343 || *eap->cmd == '@' | |
3344 || lookup(eap->cmd, p - eap->cmd, cctx) != NULL) | |
3345 { | |
3346 eap->cmdidx = CMD_let; | |
3347 return eap->cmd; | |
3348 } | |
3349 } | |
3350 | |
3351 // Recognize using a type for a w:, b:, t: or g: variable: | |
3352 // "w:varname: number = 123". | |
3353 if (eap->cmd[1] == ':' && *p == ':') | |
3354 { | |
3355 eap->cmdidx = CMD_eval; | |
3320 return eap->cmd; | 3356 return eap->cmd; |
3321 } | 3357 } |
3322 } | |
3323 | |
3324 // Recognize an assignment if we recognize the variable name: | |
3325 // "g:var = expr" | |
3326 // "var = expr" where "var" is a local var name. | |
3327 oplen = assignment_len(skipwhite(p), &heredoc); | |
3328 if (oplen > 0) | |
3329 { | |
3330 if (((p - eap->cmd) > 2 && eap->cmd[1] == ':') | |
3331 || lookup(eap->cmd, p - eap->cmd, cctx) != NULL) | |
3332 { | |
3333 eap->cmdidx = CMD_let; | |
3334 return eap->cmd; | |
3335 } | |
3336 } | |
3337 | |
3338 // Recognize using a type for a w:, b:, t: or g: variable: | |
3339 // "w:varname: number = 123". | |
3340 if (eap->cmd[1] == ':' && *p == ':') | |
3341 { | |
3342 eap->cmdidx = CMD_eval; | |
3343 return eap->cmd; | |
3344 } | 3358 } |
3345 } | 3359 } |
3346 #endif | 3360 #endif |
3347 | 3361 |
3348 /* | 3362 /* |