changeset 19473:b09afbebffee v8.2.0294

patch 8.2.0294: cannot use Ex command that is also a function name Commit: https://github.com/vim/vim/commit/5b1c8fe3d588ab450d4646a0088db4efda88200a Author: Bram Moolenaar <Bram@vim.org> Date: Fri Feb 21 18:42:43 2020 +0100 patch 8.2.0294: cannot use Ex command that is also a function name Problem: Cannot use Ex command that is also a function name. Solution: Recognize an Ex command by a colon prefix.
author Bram Moolenaar <Bram@vim.org>
date Fri, 21 Feb 2020 18:45:06 +0100
parents fa1ea6285f80
children 3e0b71dd3dc5
files runtime/doc/vim9.txt src/testdir/test_vim9_script.vim src/version.c src/vim9compile.c
diffstat 4 files changed, 74 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -1,4 +1,4 @@
-*vim9.txt*	For Vim version 8.2.  Last change: 2020 Feb 13
+*vim9.txt*	For Vim version 8.2.  Last change: 2020 Feb 21
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -140,6 +140,13 @@ identifier or can't be an Ex command.  I
 	"foobar"->Process()		" does NOT work
 	eval "foobar"->Process()	" works
 
+In case there is ambiguity between a function name and an Ex command, use ":"
+to make clear you want to use the Ex command.  For example, there is both the
+`:substitute` command and the `substitute()` function.  When the line starts
+with `substitute(` this will use the function, prepend a colon to use the
+command instead: >
+	:substitute(pattern(replacement(
+
 
 No curly braces expansion ~
 
@@ -175,6 +182,9 @@ White space is not allowed:
   	call Func(arg)	   " OK
   	call Func(
 	     \ arg)	   " OK
+  	call Func(
+	     \ arg	   " OK
+	     \ )
 
 
 Conditions and expressions ~
@@ -254,6 +264,12 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHI
 :enddef			End of a function defined with `:def`.
 
 
+If the script the function is defined in is Vim9 script, then script-local
+variables can be accessed without the "s:" prefix.  They must be defined
+before the function.  If the script the function is defined in is legacy
+script, then script-local variables must be accessed with the "s:" prefix.
+
+
 						*:disa* *:disassemble*
 :disa[ssemble] {func}	Show the instructions generated for {func}.
 			This is for debugging and testing.
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -570,5 +570,12 @@ def Test_delfunc()
   delete('XToDelFunc')
 enddef
 
+def Test_substitute_cmd()
+  new
+  setline(1, 'something')
+  :substitute(some(other(
+  assert_equal('otherthing', getline(1))
+enddef
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    294,
+/**/
     293,
 /**/
     292,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4739,6 +4739,8 @@ compile_def_function(ufunc_T *ufunc, int
      */
     for (;;)
     {
+	int	is_ex_command;
+
 	if (line != NULL && *line == '|')
 	    // the line continues after a '|'
 	    ++line;
@@ -4793,6 +4795,7 @@ compile_def_function(ufunc_T *ufunc, int
 	    line = compile_block(ea.cmd, &cctx);
 	    continue;
 	}
+	is_ex_command = *ea.cmd == ':';
 
 	/*
 	 * COMMAND MODIFIERS
@@ -4810,48 +4813,53 @@ compile_def_function(ufunc_T *ufunc, int
 	if (checkforcmd(&ea.cmd, "call", 3))
 	    ea.cmd = skipwhite(ea.cmd);
 
-	// Assuming the command starts with a variable or function name, find
-	// what follows.  Also "&opt = val", "$ENV = val" and "@r = val".
-	p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@')
-							 ? ea.cmd + 1 : ea.cmd;
-	p = to_name_end(p);
-	if (p > ea.cmd && *p != NUL)
+	if (!is_ex_command)
 	{
-	    int oplen;
-	    int heredoc;
-
-	    // "funcname(" is always a function call.
-	    // "varname[]" is an expression.
-	    // "varname->expr" is an expression.
-	    if (*p == '('
-		    || *p == '['
-		    || ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
-		    || (*p == '-' && p[1] == '>'))
+	    // Assuming the command starts with a variable or function name,
+	    // find what follows.  Also "&opt = val", "$ENV = val" and "@r =
+	    // val".
+	    p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@')
+							 ? ea.cmd + 1 : ea.cmd;
+	    p = to_name_end(p);
+	    if (p > ea.cmd && *p != NUL)
 	    {
-		// TODO
-	    }
-
-	    oplen = assignment_len(skipwhite(p), &heredoc);
-	    if (oplen > 0)
-	    {
-		// Recognize an assignment if we recognize the variable name:
-		// "g:var = expr"
-		// "var = expr"  where "var" is a local var name.
-		// "&opt = expr"
-		// "$ENV = expr"
-		// "@r = expr"
-		if (*ea.cmd == '&'
-			|| *ea.cmd == '$'
-			|| *ea.cmd == '@'
+		int oplen;
+		int heredoc;
+
+		// "funcname(" is always a function call.
+		// "varname[]" is an expression.
+		// "varname->expr" is an expression.
+		if (*p == '('
+			|| *p == '['
 			|| ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
-			|| lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
-			|| lookup_script(ea.cmd, p - ea.cmd) == OK
-			|| find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
+			|| (*p == '-' && p[1] == '>'))
+		{
+		    // TODO
+		}
+
+		oplen = assignment_len(skipwhite(p), &heredoc);
+		if (oplen > 0)
 		{
-		    line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
-		    if (line == NULL)
-			goto erret;
-		    continue;
+		    // Recognize an assignment if we recognize the variable
+		    // name:
+		    // "g:var = expr"
+		    // "var = expr"  where "var" is a local var name.
+		    // "&opt = expr"
+		    // "$ENV = expr"
+		    // "@r = expr"
+		    if (*ea.cmd == '&'
+			    || *ea.cmd == '$'
+			    || *ea.cmd == '@'
+			    || ((p - ea.cmd) > 2 && ea.cmd[1] == ':')
+			    || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0
+			    || lookup_script(ea.cmd, p - ea.cmd) == OK
+			    || find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL)
+		    {
+			line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
+			if (line == NULL)
+			    goto erret;
+			continue;
+		    }
 		}
 	    }
 	}
@@ -4860,7 +4868,8 @@ compile_def_function(ufunc_T *ufunc, int
 	 * COMMAND after range
 	 */
 	ea.cmd = skip_range(ea.cmd, NULL);
-	p = find_ex_command(&ea, NULL, lookup_local, &cctx);
+	p = find_ex_command(&ea, NULL, is_ex_command ? NULL : lookup_local,
+									&cctx);
 
 	if (p == ea.cmd && ea.cmdidx != CMD_SIZE)
 	{