Mercurial > vim
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 |