diff src/userfunc.c @ 20279:49b50843e725 v8.2.0695

patch 8.2.0695: Vim9: cannot define a function inside a function Commit: https://github.com/vim/vim/commit/04b12697838b232b8b17c553ccc74cf1f1bdb81c Author: Bram Moolenaar <Bram@vim.org> Date: Mon May 4 23:24:44 2020 +0200 patch 8.2.0695: Vim9: cannot define a function inside a function Problem: Vim9: cannot define a function inside a function. Solution: Initial support for :def inside :def.
author Bram Moolenaar <Bram@vim.org>
date Mon, 04 May 2020 23:30:04 +0200
parents 683c2da4982b
children 7587d892c00c
line wrap: on
line diff
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -329,6 +329,19 @@ set_ufunc_name(ufunc_T *fp, char_u *name
 }
 
 /*
+ * Get a name for a lambda.  Returned in static memory.
+ */
+    char_u *
+get_lambda_name(void)
+{
+    static char_u   name[30];
+    static int	    lambda_no = 0;
+
+    sprintf((char*)name, "<lambda>%d", ++lambda_no);
+    return name;
+}
+
+/*
  * Parse a lambda expression and get a Funcref from "*arg".
  * Return OK or FAIL.  Returns NOTDONE for dict or {expr}.
  */
@@ -344,7 +357,6 @@ get_lambda_tv(char_u **arg, typval_T *re
     int		ret;
     char_u	*start = skipwhite(*arg + 1);
     char_u	*s, *e;
-    static int	lambda_no = 0;
     int		*old_eval_lavars = eval_lavars_used;
     int		eval_lavars = FALSE;
 
@@ -392,9 +404,7 @@ get_lambda_tv(char_u **arg, typval_T *re
     {
 	int	    len, flags = 0;
 	char_u	    *p;
-	char_u	    name[20];
-
-	sprintf((char*)name, "<lambda>%d", ++lambda_no);
+	char_u	    *name = get_lambda_name();
 
 	fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
 	if (fp == NULL)
@@ -2364,10 +2374,11 @@ untrans_function_name(char_u *name)
 }
 
 /*
- * ":function"
+ * ":function" also supporting nested ":def".
+ * Returns a pointer to the function or NULL if no function defined.
  */
-    void
-ex_function(exarg_T *eap)
+    ufunc_T *
+def_function(exarg_T *eap, char_u *name_arg, void *context)
 {
     char_u	*theline;
     char_u	*line_to_free = NULL;
@@ -2375,7 +2386,7 @@ ex_function(exarg_T *eap)
     int		c;
     int		saved_did_emsg;
     int		saved_wait_return = need_wait_return;
-    char_u	*name = NULL;
+    char_u	*name = name_arg;
     int		is_global = FALSE;
     char_u	*p;
     char_u	*arg;
@@ -2387,7 +2398,7 @@ ex_function(exarg_T *eap)
     int		varargs = FALSE;
     int		flags = 0;
     char_u	*ret_type = NULL;
-    ufunc_T	*fp;
+    ufunc_T	*fp = NULL;
     int		overwrite = FALSE;
     int		indent;
     int		nesting;
@@ -2429,7 +2440,7 @@ ex_function(exarg_T *eap)
 	    }
 	}
 	eap->nextcmd = check_nextcmd(eap->arg);
-	return;
+	return NULL;
     }
 
     /*
@@ -2469,7 +2480,7 @@ ex_function(exarg_T *eap)
 	if (*p == '/')
 	    ++p;
 	eap->nextcmd = check_nextcmd(p);
-	return;
+	return NULL;
     }
 
     ga_init(&newargs);
@@ -2493,25 +2504,34 @@ ex_function(exarg_T *eap)
      * g:func	    global function name, same as "func"
      */
     p = eap->arg;
-    name = trans_function_name(&p, &is_global, eap->skip,
-						 TFN_NO_AUTOLOAD, &fudi, NULL);
-    paren = (vim_strchr(p, '(') != NULL);
-    if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
+    if (name_arg != NULL)
+    {
+	// nested function, argument is (args).
+	paren = TRUE;
+	CLEAR_FIELD(fudi);
+    }
+    else
     {
-	/*
-	 * Return on an invalid expression in braces, unless the expression
-	 * evaluation has been cancelled due to an aborting error, an
-	 * interrupt, or an exception.
-	 */
-	if (!aborting())
+	name = trans_function_name(&p, &is_global, eap->skip,
+						 TFN_NO_AUTOLOAD, &fudi, NULL);
+	paren = (vim_strchr(p, '(') != NULL);
+	if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
 	{
-	    if (!eap->skip && fudi.fd_newkey != NULL)
-		semsg(_(e_dictkey), fudi.fd_newkey);
-	    vim_free(fudi.fd_newkey);
-	    return;
+	    /*
+	     * Return on an invalid expression in braces, unless the expression
+	     * evaluation has been cancelled due to an aborting error, an
+	     * interrupt, or an exception.
+	     */
+	    if (!aborting())
+	    {
+		if (!eap->skip && fudi.fd_newkey != NULL)
+		    semsg(_(e_dictkey), fudi.fd_newkey);
+		vim_free(fudi.fd_newkey);
+		return NULL;
+	    }
+	    else
+		eap->skip = TRUE;
 	}
-	else
-	    eap->skip = TRUE;
     }
 
     // An error in a function call during evaluation of an expression in magic
@@ -2596,7 +2616,7 @@ ex_function(exarg_T *eap)
 
     ga_init2(&newlines, (int)sizeof(char_u *), 3);
 
-    if (!eap->skip)
+    if (!eap->skip && name_arg == NULL)
     {
 	// Check the name of the function.  Unless it's a dictionary function
 	// (that we are overwriting).
@@ -3255,7 +3275,7 @@ ex_function(exarg_T *eap)
 
     // ":def Func()" needs to be compiled
     if (eap->cmdidx == CMD_def)
-	compile_def_function(fp, FALSE, NULL);
+	compile_def_function(fp, FALSE, context);
 
     goto ret_free;
 
@@ -3269,10 +3289,22 @@ ret_free:
     vim_free(skip_until);
     vim_free(line_to_free);
     vim_free(fudi.fd_newkey);
-    vim_free(name);
+    if (name != name_arg)
+	vim_free(name);
     vim_free(ret_type);
     did_emsg |= saved_did_emsg;
     need_wait_return |= saved_wait_return;
+
+    return fp;
+}
+
+/*
+ * ":function"
+ */
+    void
+ex_function(exarg_T *eap)
+{
+    def_function(eap, NULL, NULL);
 }
 
 /*