Mercurial > vim
comparison src/ex_eval.c @ 22551:86a115a80262 v8.2.1824
patch 8.2.1824: Vim9: variables at the script level escape their scope
Commit: https://github.com/vim/vim/commit/fcdc5d83fbfd7ddce634769ea902e58c87f27f20
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Oct 10 19:07:09 2020 +0200
patch 8.2.1824: Vim9: variables at the script level escape their scope
Problem: Vim9: variables at the script level escape their scope.
Solution: When leaving a scope remove variables declared in it.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 10 Oct 2020 19:15:04 +0200 |
parents | a607f02fd17a |
children | 3ed3bed38e0f |
comparison
equal
deleted
inserted
replaced
22550:d61c22faf4be | 22551:86a115a80262 |
---|---|
904 | 904 |
905 clear_evalarg(&evalarg, eap); | 905 clear_evalarg(&evalarg, eap); |
906 } | 906 } |
907 | 907 |
908 /* | 908 /* |
909 * Start a new scope/block. Caller should have checked that cs_idx is not | |
910 * exceeding CSTACK_LEN. | |
911 */ | |
912 static void | |
913 enter_block(cstack_T *cstack) | |
914 { | |
915 ++cstack->cs_idx; | |
916 if (in_vim9script()) | |
917 cstack->cs_script_var_len[cstack->cs_idx] = | |
918 SCRIPT_ITEM(current_sctx.sc_sid)->sn_var_vals.ga_len; | |
919 } | |
920 | |
921 static void | |
922 leave_block(cstack_T *cstack) | |
923 { | |
924 int i; | |
925 | |
926 if (in_vim9script()) | |
927 { | |
928 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); | |
929 | |
930 for (i = cstack->cs_script_var_len[cstack->cs_idx]; | |
931 i < si->sn_var_vals.ga_len; ++i) | |
932 { | |
933 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + i; | |
934 hashtab_T *ht = get_script_local_ht(); | |
935 hashitem_T *hi; | |
936 | |
937 if (ht != NULL) | |
938 { | |
939 // Remove a variable declared inside the block, if it still | |
940 // exists. | |
941 hi = hash_find(ht, sv->sv_name); | |
942 if (!HASHITEM_EMPTY(hi)) | |
943 delete_var(ht, hi); | |
944 } | |
945 } | |
946 } | |
947 --cstack->cs_idx; | |
948 } | |
949 | |
950 /* | |
909 * ":if". | 951 * ":if". |
910 */ | 952 */ |
911 void | 953 void |
912 ex_if(exarg_T *eap) | 954 ex_if(exarg_T *eap) |
913 { | 955 { |
918 | 960 |
919 if (cstack->cs_idx == CSTACK_LEN - 1) | 961 if (cstack->cs_idx == CSTACK_LEN - 1) |
920 eap->errmsg = _("E579: :if nesting too deep"); | 962 eap->errmsg = _("E579: :if nesting too deep"); |
921 else | 963 else |
922 { | 964 { |
923 ++cstack->cs_idx; | 965 enter_block(cstack); |
924 cstack->cs_flags[cstack->cs_idx] = 0; | 966 cstack->cs_flags[cstack->cs_idx] = 0; |
925 | 967 |
926 /* | 968 /* |
927 * Don't do something after an error, interrupt, or throw, or when there | 969 * Don't do something after an error, interrupt, or throw, or when |
928 * is a surrounding conditional and it was not active. | 970 * there is a surrounding conditional and it was not active. |
929 */ | 971 */ |
930 skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0 | 972 skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0 |
931 && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)); | 973 && !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)); |
932 | 974 |
933 result = eval_to_bool(eap->arg, &error, eap, skip); | 975 result = eval_to_bool(eap->arg, &error, eap, skip); |
947 * ":endif". | 989 * ":endif". |
948 */ | 990 */ |
949 void | 991 void |
950 ex_endif(exarg_T *eap) | 992 ex_endif(exarg_T *eap) |
951 { | 993 { |
994 cstack_T *cstack = eap->cstack; | |
995 | |
952 did_endif = TRUE; | 996 did_endif = TRUE; |
953 if (eap->cstack->cs_idx < 0 | 997 if (cstack->cs_idx < 0 |
954 || (eap->cstack->cs_flags[eap->cstack->cs_idx] | 998 || (cstack->cs_flags[cstack->cs_idx] |
955 & (CSF_WHILE | CSF_FOR | CSF_TRY))) | 999 & (CSF_WHILE | CSF_FOR | CSF_TRY))) |
956 eap->errmsg = _(e_endif_without_if); | 1000 eap->errmsg = _(e_endif_without_if); |
957 else | 1001 else |
958 { | 1002 { |
959 /* | 1003 /* |
963 * Handle a ">quit" debug command as if an interrupt had occurred before | 1007 * Handle a ">quit" debug command as if an interrupt had occurred before |
964 * the ":endif". That is, throw an interrupt exception if appropriate. | 1008 * the ":endif". That is, throw an interrupt exception if appropriate. |
965 * Doing this here prevents an exception for a parsing error being | 1009 * Doing this here prevents an exception for a parsing error being |
966 * discarded by throwing the interrupt exception later on. | 1010 * discarded by throwing the interrupt exception later on. |
967 */ | 1011 */ |
968 if (!(eap->cstack->cs_flags[eap->cstack->cs_idx] & CSF_TRUE) | 1012 if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE) |
969 && dbg_check_skipped(eap)) | 1013 && dbg_check_skipped(eap)) |
970 (void)do_intthrow(eap->cstack); | 1014 (void)do_intthrow(cstack); |
971 | 1015 |
972 --eap->cstack->cs_idx; | 1016 leave_block(cstack); |
973 } | 1017 } |
974 } | 1018 } |
975 | 1019 |
976 /* | 1020 /* |
977 * ":else" and ":elseif". | 1021 * ":else" and ":elseif". |
1084 * ":endwhile" or ":endfor". When not set, need to initialise this | 1128 * ":endwhile" or ":endfor". When not set, need to initialise this |
1085 * cstack entry. | 1129 * cstack entry. |
1086 */ | 1130 */ |
1087 if ((cstack->cs_lflags & CSL_HAD_LOOP) == 0) | 1131 if ((cstack->cs_lflags & CSL_HAD_LOOP) == 0) |
1088 { | 1132 { |
1089 ++cstack->cs_idx; | 1133 enter_block(cstack); |
1090 ++cstack->cs_looplevel; | 1134 ++cstack->cs_looplevel; |
1091 cstack->cs_line[cstack->cs_idx] = -1; | 1135 cstack->cs_line[cstack->cs_idx] = -1; |
1092 } | 1136 } |
1093 cstack->cs_flags[cstack->cs_idx] = | 1137 cstack->cs_flags[cstack->cs_idx] = |
1094 eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR; | 1138 eap->cmdidx == CMD_while ? CSF_WHILE : CSF_FOR; |
1448 | 1492 |
1449 if (cstack->cs_idx == CSTACK_LEN - 1) | 1493 if (cstack->cs_idx == CSTACK_LEN - 1) |
1450 eap->errmsg = _("E601: :try nesting too deep"); | 1494 eap->errmsg = _("E601: :try nesting too deep"); |
1451 else | 1495 else |
1452 { | 1496 { |
1453 ++cstack->cs_idx; | 1497 enter_block(cstack); |
1454 ++cstack->cs_trylevel; | 1498 ++cstack->cs_trylevel; |
1455 cstack->cs_flags[cstack->cs_idx] = CSF_TRY; | 1499 cstack->cs_flags[cstack->cs_idx] = CSF_TRY; |
1456 cstack->cs_pending[cstack->cs_idx] = CSTP_NONE; | 1500 cstack->cs_pending[cstack->cs_idx] = CSTP_NONE; |
1457 | 1501 |
1458 /* | 1502 /* |
1921 * after errors except when this ":endtry" is not within a ":try". | 1965 * after errors except when this ":endtry" is not within a ":try". |
1922 * Restore "emsg_silent" if it has been reset by this try conditional. | 1966 * Restore "emsg_silent" if it has been reset by this try conditional. |
1923 */ | 1967 */ |
1924 (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE); | 1968 (void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE); |
1925 | 1969 |
1926 --cstack->cs_idx; | 1970 leave_block(cstack); |
1927 --cstack->cs_trylevel; | 1971 --cstack->cs_trylevel; |
1928 | 1972 |
1929 if (!skip) | 1973 if (!skip) |
1930 { | 1974 { |
1931 report_resume_pending(pending, | 1975 report_resume_pending(pending, |
2301 { | 2345 { |
2302 if (cstack->cs_flags[cstack->cs_idx] & cond_type) | 2346 if (cstack->cs_flags[cstack->cs_idx] & cond_type) |
2303 --*cond_level; | 2347 --*cond_level; |
2304 if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR) | 2348 if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR) |
2305 free_for_info(cstack->cs_forinfo[cstack->cs_idx]); | 2349 free_for_info(cstack->cs_forinfo[cstack->cs_idx]); |
2306 --cstack->cs_idx; | 2350 leave_block(cstack); |
2307 } | 2351 } |
2308 } | 2352 } |
2309 | 2353 |
2310 /* | 2354 /* |
2311 * ":endfunction" when not after a ":function" | 2355 * ":endfunction" when not after a ":function" |