Patch 8.2.1824
Problem: Vim9: variables at the script level escape their scope.
Solution: When leaving a scope remove variables declared in it.
Files: src/structs.h, src/ex_eval.c, src/evalvars.c,
src/proto/evalvars.pro, src/testdir/test_vim9_script.vim
*** ../vim-8.2.1823/src/structs.h 2020-10-10 14:12:58.024646147 +0200
--- src/structs.h 2020-10-10 17:27:40.236527958 +0200
***************
*** 889,894 ****
--- 889,896 ----
} cs_pend;
void *cs_forinfo[CSTACK_LEN]; // info used by ":for"
int cs_line[CSTACK_LEN]; // line nr of ":while"/":for"
line
+ int cs_script_var_len[CSTACK_LEN]; // value of
sn_var_vals.ga_len
+ // when entering the block
int cs_idx; // current entry, or -1 if none
int cs_looplevel; // nr of nested ":while"s and
":for"s
int cs_trylevel; // nr of nested ":try"s
*** ../vim-8.2.1823/src/ex_eval.c 2020-09-10 19:25:01.612194701 +0200
--- src/ex_eval.c 2020-10-10 18:27:24.558010168 +0200
***************
*** 906,911 ****
--- 906,953 ----
}
/*
+ * Start a new scope/block. Caller should have checked that cs_idx is not
+ * exceeding CSTACK_LEN.
+ */
+ static void
+ enter_block(cstack_T *cstack)
+ {
+ ++cstack->cs_idx;
+ if (in_vim9script())
+ cstack->cs_script_var_len[cstack->cs_idx] =
+ SCRIPT_ITEM(current_sctx.sc_sid)->sn_var_vals.ga_len;
+ }
+
+ static void
+ leave_block(cstack_T *cstack)
+ {
+ int i;
+
+ if (in_vim9script())
+ {
+ scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
+
+ for (i = cstack->cs_script_var_len[cstack->cs_idx];
+ i < si->sn_var_vals.ga_len; ++i)
+ {
+ svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + i;
+ hashtab_T *ht = get_script_local_ht();
+ hashitem_T *hi;
+
+ if (ht != NULL)
+ {
+ // Remove a variable declared inside the block, if it still
+ // exists.
+ hi = hash_find(ht, sv->sv_name);
+ if (!HASHITEM_EMPTY(hi))
+ delete_var(ht, hi);
+ }
+ }
+ }
+ --cstack->cs_idx;
+ }
+
+ /*
* ":if".
*/
void
***************
*** 920,931 ****
eap->errmsg = _("E579: :if nesting too deep");
else
{
! ++cstack->cs_idx;
cstack->cs_flags[cstack->cs_idx] = 0;
/*
! * Don't do something after an error, interrupt, or throw, or when there
! * is a surrounding conditional and it was not active.
*/
skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
&& !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
--- 962,973 ----
eap->errmsg = _("E579: :if nesting too deep");
else
{
! enter_block(cstack);
cstack->cs_flags[cstack->cs_idx] = 0;
/*
! * Don't do something after an error, interrupt, or throw, or when
! * there is a surrounding conditional and it was not active.
*/
skip = did_emsg || got_int || did_throw || (cstack->cs_idx > 0
&& !(cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE));
***************
*** 949,957 ****
void
ex_endif(exarg_T *eap)
{
did_endif = TRUE;
! if (eap->cstack->cs_idx < 0
! || (eap->cstack->cs_flags[eap->cstack->cs_idx]
& (CSF_WHILE | CSF_FOR | CSF_TRY)))
eap->errmsg = _(e_endif_without_if);
else
--- 991,1001 ----
void
ex_endif(exarg_T *eap)
{
+ cstack_T *cstack = eap->cstack;
+
did_endif = TRUE;
! if (cstack->cs_idx < 0
! || (cstack->cs_flags[cstack->cs_idx]
& (CSF_WHILE | CSF_FOR | CSF_TRY)))
eap->errmsg = _(e_endif_without_if);
else
***************
*** 965,975 ****
* Doing this here prevents an exception for a parsing error being
* discarded by throwing the interrupt exception later on.
*/
! if (!(eap->cstack->cs_flags[eap->cstack->cs_idx] & CSF_TRUE)
&& dbg_check_skipped(eap))
! (void)do_intthrow(eap->cstack);
! --eap->cstack->cs_idx;
}
}
--- 1009,1019 ----
* Doing this here prevents an exception for a parsing error being
* discarded by throwing the interrupt exception later on.
*/
! if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE)
&& dbg_check_skipped(eap))
! (void)do_intthrow(cstack);
! leave_block(cstack);
}
}
***************
*** 1086,1092 ****
*/
if ((cstack->cs_lflags & CSL_HAD_LOOP) == 0)
{
! ++cstack->cs_idx;
++cstack->cs_looplevel;
cstack->cs_line[cstack->cs_idx] = -1;
}
--- 1130,1136 ----
*/
if ((cstack->cs_lflags & CSL_HAD_LOOP) == 0)
{
! enter_block(cstack);
++cstack->cs_looplevel;
cstack->cs_line[cstack->cs_idx] = -1;
}
***************
*** 1450,1456 ****
eap->errmsg = _("E601: :try nesting too deep");
else
{
! ++cstack->cs_idx;
++cstack->cs_trylevel;
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
--- 1494,1500 ----
eap->errmsg = _("E601: :try nesting too deep");
else
{
! enter_block(cstack);
++cstack->cs_trylevel;
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
cstack->cs_pending[cstack->cs_idx] = CSTP_NONE;
***************
*** 1923,1929 ****
*/
(void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE);
! --cstack->cs_idx;
--cstack->cs_trylevel;
if (!skip)
--- 1967,1973 ----
*/
(void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, TRUE);
! leave_block(cstack);
--cstack->cs_trylevel;
if (!skip)
***************
*** 2303,2309 ****
--*cond_level;
if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR)
free_for_info(cstack->cs_forinfo[cstack->cs_idx]);
! --cstack->cs_idx;
}
}
--- 2347,2353 ----
--*cond_level;
if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR)
free_for_info(cstack->cs_forinfo[cstack->cs_idx]);
! leave_block(cstack);
}
}
*** ../vim-8.2.1823/src/evalvars.c 2020-10-08 21:30:35.969526619 +0200
--- src/evalvars.c 2020-10-10 18:27:40.229968758 +0200
***************
*** 174,180 ****
static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, int flags,
char_u *endchars, char_u *op);
static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep,
void *cookie);
static int do_lock_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep,
void *cookie);
- static void delete_var(hashtab_T *ht, hashitem_T *hi);
static void list_one_var(dictitem_T *v, char *prefix, int *first);
static void list_one_var_a(char *prefix, char_u *name, int type, char_u
*string, int *first);
--- 174,179 ----
***************
*** 2890,2896 ****
* Delete a variable from hashtab "ht" at item "hi".
* Clear the variable value and free the dictitem.
*/
! static void
delete_var(hashtab_T *ht, hashitem_T *hi)
{
dictitem_T *di = HI2DI(hi);
--- 2889,2895 ----
* Delete a variable from hashtab "ht" at item "hi".
* Clear the variable value and free the dictitem.
*/
! void
delete_var(hashtab_T *ht, hashitem_T *hi)
{
dictitem_T *di = HI2DI(hi);
*** ../vim-8.2.1823/src/proto/evalvars.pro 2020-10-08 21:16:38.643643838
+0200
--- src/proto/evalvars.pro 2020-10-10 18:27:29.069998249 +0200
***************
*** 67,72 ****
--- 67,73 ----
void unref_var_dict(dict_T *dict);
void vars_clear(hashtab_T *ht);
void vars_clear_ext(hashtab_T *ht, int free_val);
+ void delete_var(hashtab_T *ht, hashitem_T *hi);
void set_var(char_u *name, typval_T *tv, int copy);
void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy,
int flags);
int var_check_ro(int flags, char_u *name, int use_gettext);
*** ../vim-8.2.1823/src/testdir/test_vim9_script.vim 2020-10-08
21:16:38.643643838 +0200
--- src/testdir/test_vim9_script.vim 2020-10-10 18:39:33.084055199 +0200
***************
*** 2685,2690 ****
--- 2685,2740 ----
delete('Xdidcmd')
enddef
+ def Test_script_var_scope()
+ var lines =<< trim END
+ vim9script
+ if true
+ if true
+ var one = 'one'
+ echo one
+ endif
+ echo one
+ endif
+ END
+ CheckScriptFailure(lines, 'E121:', 7)
+
+ lines =<< trim END
+ vim9script
+ if true
+ if false
+ var one = 'one'
+ echo one
+ else
+ var one = 'one'
+ echo one
+ endif
+ echo one
+ endif
+ END
+ CheckScriptFailure(lines, 'E121:', 10)
+
+ lines =<< trim END
+ vim9script
+ while true
+ var one = 'one'
+ echo one
+ break
+ endwhile
+ echo one
+ END
+ CheckScriptFailure(lines, 'E121:', 7)
+
+ lines =<< trim END
+ vim9script
+ for i in range(1)
+ var one = 'one'
+ echo one
+ endfor
+ echo one
+ END
+ CheckScriptFailure(lines, 'E121:', 6)
+ enddef
+
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new
*** ../vim-8.2.1823/src/version.c 2020-10-10 16:45:20.711469191 +0200
--- src/version.c 2020-10-10 18:42:26.595601471 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 1824,
/**/
--
Be thankful to be in a traffic jam, because it means you own a car.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202010101707.09AH7fdm3772636%40masaka.moolenaar.net.