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 /*