Patch 8.2.1824

3 views
Skip to first unread message

Bram Moolenaar

unread,
Oct 10, 2020, 1:07:51 PM10/10/20
to vim...@googlegroups.com

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 -- Br...@Moolenaar.net -- 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 ///
Reply all
Reply to author
Forward
0 new messages