changeset 22555:7d25264c246c v8.2.1826

patch 8.2.1826: Vim9: cannot use a {} block at script level Commit: https://github.com/vim/vim/commit/9becdf2b98e56d5eb193f3413d706ea433269216 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Oct 10 21:33:48 2020 +0200 patch 8.2.1826: Vim9: cannot use a {} block at script level Problem: Vim9: cannot use a {} block at script level. Solution: Recognize a {} block.
author Bram Moolenaar <Bram@vim.org>
date Sat, 10 Oct 2020 21:45:06 +0200
parents 0ecf643db435
children 1c91898919e5
files src/errors.h src/ex_cmdidxs.h src/ex_cmds.h src/ex_docmd.c src/ex_eval.c src/proto/ex_eval.pro src/structs.h src/testdir/test_vim9_script.vim src/version.c
diffstat 9 files changed, 76 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/errors.h
+++ b/src/errors.h
@@ -278,4 +278,6 @@ EXTERN char e_cannot_use_let_in_vim9_scr
 	INIT(= N_("E1126: Cannot use :let in Vim9 script"));
 EXTERN char e_missing_name_after_dot[]
 	INIT(= N_("E1127: Missing name after dot"));
+EXTERN char e_endblock_without_block[]
+	INIT(= N_("E1128: } without {"));
 #endif
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][
   /* z */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
 };
 
-static const int command_count = 571;
+static const int command_count = 573;
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1812,6 +1812,12 @@ EXCMD(CMD_rshift,	">",		ex_operators,
 EXCMD(CMD_at,		"@",		ex_at,
 	EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
 	ADDR_LINES),
+EXCMD(CMD_block,	"{{{{{{{{",	ex_block,  // not found normally
+	0,
+	ADDR_NONE),
+EXCMD(CMD_endblock,	"}",		ex_endblock,
+	EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+	ADDR_NONE),
 EXCMD(CMD_tilde,	"~",		ex_substitute,
 	EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
 	ADDR_LINES),
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3222,7 +3222,7 @@ find_ex_command(
 		*p == '('
 		    || (p == eap->cmd
 			? (
-			    // "{..." is an dict expression.
+			    // "{..." is a dict expression or block start.
 			    *eap->cmd == '{'
 			    // "'string'->func()" is an expression.
 			 || *eap->cmd == '\''
@@ -3234,6 +3234,12 @@ find_ex_command(
 			    // "varname->func()" is an expression.
 			: (*p == '-' && p[1] == '>')))
 	    {
+		if (*eap->cmd == '{' && ends_excmd(*skipwhite(eap->cmd + 1)))
+		{
+		    // "{" by itself is the start of a block.
+		    eap->cmdidx = CMD_block;
+		    return eap->cmd + 1;
+		}
 		eap->cmdidx = CMD_eval;
 		return eap->cmd;
 	    }
@@ -3355,7 +3361,7 @@ find_ex_command(
 	}
 
 	// check for non-alpha command
-	if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL)
+	if (p == eap->cmd && vim_strchr((char_u *)"@*!=><&~#}", *p) != NULL)
 	    ++p;
 	len = (int)(p - eap->cmd);
 	if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p'))
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -1002,7 +1002,7 @@ ex_endif(exarg_T *eap)
     did_endif = TRUE;
     if (cstack->cs_idx < 0
 	    || (cstack->cs_flags[cstack->cs_idx]
-					   & (CSF_WHILE | CSF_FOR | CSF_TRY)))
+				& (CSF_WHILE | CSF_FOR | CSF_TRY | CSF_BLOCK)))
 	eap->errmsg = _(e_endif_without_if);
     else
     {
@@ -1043,7 +1043,7 @@ ex_else(exarg_T *eap)
 
     if (cstack->cs_idx < 0
 	    || (cstack->cs_flags[cstack->cs_idx]
-					   & (CSF_WHILE | CSF_FOR | CSF_TRY)))
+				& (CSF_WHILE | CSF_FOR | CSF_TRY | CSF_BLOCK)))
     {
 	if (eap->cmdidx == CMD_else)
 	{
@@ -1375,6 +1375,37 @@ ex_endwhile(exarg_T *eap)
     }
 }
 
+/*
+ * "{" start of a block in Vim9 script
+ */
+    void
+ex_block(exarg_T *eap)
+{
+    cstack_T	*cstack = eap->cstack;
+
+    if (cstack->cs_idx == CSTACK_LEN - 1)
+	eap->errmsg = _("E579: block nesting too deep");
+    else
+    {
+	enter_block(cstack);
+	cstack->cs_flags[cstack->cs_idx] = CSF_BLOCK | CSF_ACTIVE | CSF_TRUE;
+    }
+}
+
+/*
+ * "}" end of a block in Vim9 script
+ */
+    void
+ex_endblock(exarg_T *eap)
+{
+    cstack_T	*cstack = eap->cstack;
+
+    if (cstack->cs_idx < 0
+	    || (cstack->cs_flags[cstack->cs_idx] & CSF_BLOCK) == 0)
+	eap->errmsg = _(e_endblock_without_block);
+    else
+	leave_block(cstack);
+}
 
 /*
  * ":throw expr"
--- a/src/proto/ex_eval.pro
+++ b/src/proto/ex_eval.pro
@@ -20,6 +20,8 @@ void ex_while(exarg_T *eap);
 void ex_continue(exarg_T *eap);
 void ex_break(exarg_T *eap);
 void ex_endwhile(exarg_T *eap);
+void ex_block(exarg_T *eap);
+void ex_endblock(exarg_T *eap);
 void ex_throw(exarg_T *eap);
 void do_throw(cstack_T *cstack);
 void ex_try(exarg_T *eap);
--- a/src/structs.h
+++ b/src/structs.h
@@ -907,6 +907,7 @@ typedef struct {
 # define CSF_ELSE	0x0004	// ":else" has been passed
 # define CSF_WHILE	0x0008	// is a ":while"
 # define CSF_FOR	0x0010	// is a ":for"
+# define CSF_BLOCK	0x0020	// is a "{" block
 
 # define CSF_TRY	0x0100	// is a ":try"
 # define CSF_FINALLY	0x0200	// ":finally" has been passed
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -2733,6 +2733,27 @@ def Test_script_var_scope()
       echo one
   END
   CheckScriptFailure(lines, 'E121:', 6)
+
+  lines =<< trim END
+      vim9script
+      {
+        var one = 'one'
+        assert_equal('one', one)
+      }
+      assert_false(exists('one'))
+      assert_false(exists('s:one'))
+  END
+  CheckScriptSuccess(lines)
+
+  lines =<< trim END
+      vim9script
+      {
+        var one = 'one'
+        echo one
+      }
+      echo one
+  END
+  CheckScriptFailure(lines, 'E121:', 6)
 enddef
 
 " Keep this last, it messes up highlighting.
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1826,
+/**/
     1825,
 /**/
     1824,