comparison src/vim9compile.c @ 23537:7f0fc2ab90e3 v8.2.2311

patch 8.2.2311: Vim9: cannot assign to variable that shadows command modifier Commit: https://github.com/vim/vim/commit/17126b13969c3b91516a8e9ff80fb6a1f6924d40 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Jan 7 22:03:02 2021 +0100 patch 8.2.2311: Vim9: cannot assign to variable that shadows command modifier Problem: Vim9: cannot assign to a variable that shadows a command modifier. Solution: Check for assignment after possible command modifier. (closes #7632)
author Bram Moolenaar <Bram@vim.org>
date Thu, 07 Jan 2021 22:15:05 +0100
parents f39a18a42aed
children f90e429453fd
comparison
equal deleted inserted replaced
23536:708e07fe1fb4 23537:7f0fc2ab90e3
6215 vim_free(lhs.lhs_name); 6215 vim_free(lhs.lhs_name);
6216 return ret; 6216 return ret;
6217 } 6217 }
6218 6218
6219 /* 6219 /*
6220 * Check for an assignment at "eap->cmd", compile it if found.
6221 * Return NOTDONE if there is none, FAIL for failure, OK if done.
6222 */
6223 static int
6224 may_compile_assignment(exarg_T *eap, char_u **line, cctx_T *cctx)
6225 {
6226 char_u *pskip;
6227 char_u *p;
6228
6229 // Assuming the command starts with a variable or function name,
6230 // find what follows.
6231 // Skip over "var.member", "var[idx]" and the like.
6232 // Also "&opt = val", "$ENV = val" and "@r = val".
6233 pskip = (*eap->cmd == '&' || *eap->cmd == '$' || *eap->cmd == '@')
6234 ? eap->cmd + 1 : eap->cmd;
6235 p = to_name_end(pskip, TRUE);
6236 if (p > eap->cmd && *p != NUL)
6237 {
6238 char_u *var_end;
6239 int oplen;
6240 int heredoc;
6241
6242 if (eap->cmd[0] == '@')
6243 var_end = eap->cmd + 2;
6244 else
6245 var_end = find_name_end(pskip, NULL, NULL,
6246 FNE_CHECK_START | FNE_INCL_BR);
6247 oplen = assignment_len(skipwhite(var_end), &heredoc);
6248 if (oplen > 0)
6249 {
6250 size_t len = p - eap->cmd;
6251
6252 // Recognize an assignment if we recognize the variable
6253 // name:
6254 // "g:var = expr"
6255 // "local = expr" where "local" is a local var.
6256 // "script = expr" where "script" is a script-local var.
6257 // "import = expr" where "import" is an imported var
6258 // "&opt = expr"
6259 // "$ENV = expr"
6260 // "@r = expr"
6261 if (*eap->cmd == '&'
6262 || *eap->cmd == '$'
6263 || *eap->cmd == '@'
6264 || ((len) > 2 && eap->cmd[1] == ':')
6265 || lookup_local(eap->cmd, len, NULL, cctx) == OK
6266 || arg_exists(eap->cmd, len, NULL, NULL, NULL, cctx) == OK
6267 || script_var_exists(eap->cmd, len, FALSE, cctx) == OK
6268 || find_imported(eap->cmd, len, cctx) != NULL)
6269 {
6270 *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);
6271 if (*line == NULL || *line == eap->cmd)
6272 return FAIL;
6273 return OK;
6274 }
6275 }
6276 }
6277
6278 if (*eap->cmd == '[')
6279 {
6280 // [var, var] = expr
6281 *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx);
6282 if (*line == NULL)
6283 return FAIL;
6284 if (*line != eap->cmd)
6285 return OK;
6286 }
6287 return NOTDONE;
6288 }
6289
6290 /*
6220 * Check if "name" can be "unlet". 6291 * Check if "name" can be "unlet".
6221 */ 6292 */
6222 int 6293 int
6223 check_vim9_unlet(char_u *name) 6294 check_vim9_unlet(char_u *name)
6224 { 6295 {
7836 ea.cmd = skipwhite(ea.cmd); 7907 ea.cmd = skipwhite(ea.cmd);
7837 } 7908 }
7838 7909
7839 if (!starts_with_colon) 7910 if (!starts_with_colon)
7840 { 7911 {
7841 char_u *pskip; 7912 int assign;
7842 7913
7843 // Assuming the command starts with a variable or function name, 7914 // Check for assignment after command modifiers.
7844 // find what follows. 7915 assign = may_compile_assignment(&ea, &line, &cctx);
7845 // Skip over "var.member", "var[idx]" and the like. 7916 if (assign == OK)
7846 // Also "&opt = val", "$ENV = val" and "@r = val". 7917 goto nextline;
7847 pskip = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@') 7918 if (assign == FAIL)
7848 ? ea.cmd + 1 : ea.cmd; 7919 goto erret;
7849 p = to_name_end(pskip, TRUE);
7850 if (p > ea.cmd && *p != NUL)
7851 {
7852 char_u *var_end;
7853 int oplen;
7854 int heredoc;
7855
7856 if (ea.cmd[0] == '@')
7857 var_end = ea.cmd + 2;
7858 else
7859 var_end = find_name_end(pskip, NULL, NULL,
7860 FNE_CHECK_START | FNE_INCL_BR);
7861 oplen = assignment_len(skipwhite(var_end), &heredoc);
7862 if (oplen > 0)
7863 {
7864 size_t len = p - ea.cmd;
7865
7866 // Recognize an assignment if we recognize the variable
7867 // name:
7868 // "g:var = expr"
7869 // "local = expr" where "local" is a local var.
7870 // "script = expr" where "script" is a script-local var.
7871 // "import = expr" where "import" is an imported var
7872 // "&opt = expr"
7873 // "$ENV = expr"
7874 // "@r = expr"
7875 if (*ea.cmd == '&'
7876 || *ea.cmd == '$'
7877 || *ea.cmd == '@'
7878 || ((len) > 2 && ea.cmd[1] == ':')
7879 || lookup_local(ea.cmd, len, NULL, &cctx) == OK
7880 || arg_exists(ea.cmd, len, NULL, NULL,
7881 NULL, &cctx) == OK
7882 || script_var_exists(ea.cmd, len,
7883 FALSE, &cctx) == OK
7884 || find_imported(ea.cmd, len, &cctx) != NULL)
7885 {
7886 line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
7887 if (line == NULL || line == ea.cmd)
7888 goto erret;
7889 goto nextline;
7890 }
7891 }
7892 }
7893
7894 if (*ea.cmd == '[')
7895 {
7896 // [var, var] = expr
7897 line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
7898 if (line == NULL)
7899 goto erret;
7900 if (line != ea.cmd)
7901 goto nextline;
7902 }
7903 } 7920 }
7904 7921
7905 /* 7922 /*
7906 * COMMAND after range 7923 * COMMAND after range
7907 * 'text'->func() should not be confused with 'a mark 7924 * 'text'->func() should not be confused with 'a mark