diff src/vim9compile.c @ 21558:1c4d4aa22b37 v8.2.1329

patch 8.2.1329: Vim9: cannot define global function inside :def function Commit: https://github.com/vim/vim/commit/38ddf333f6b2806b0ea2dd052ee1cd50dd7f4525 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Jul 31 22:05:04 2020 +0200 patch 8.2.1329: Vim9: cannot define global function inside :def function Problem: Vim9: cannot define global function inside :def function. Solution: Assign to global variable instead of local. (closes https://github.com/vim/vim/issues/6584)
author Bram Moolenaar <Bram@vim.org>
date Fri, 31 Jul 2020 22:15:04 +0200
parents 4d3e983313dc
children 55aa283a0e5e
line wrap: on
line diff
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1523,6 +1523,27 @@ generate_FUNCREF(cctx_T *cctx, int dfunc
 }
 
 /*
+ * Generate an ISN_NEWFUNC instruction.
+ */
+    static int
+generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name)
+{
+    isn_T	*isn;
+    char_u	*name;
+
+    RETURN_OK_IF_SKIP(cctx);
+    name = vim_strsave(lambda_name);
+    if (name == NULL)
+	return FAIL;
+    if ((isn = generate_instr(cctx, ISN_NEWFUNC)) == NULL)
+	return FAIL;
+    isn->isn_arg.newfunc.nf_lambda = name;
+    isn->isn_arg.newfunc.nf_global = func_name;
+
+    return OK;
+}
+
+/*
  * Generate an ISN_JUMP instruction.
  */
     static int
@@ -4875,11 +4896,13 @@ exarg_getline(
     static char_u *
 compile_nested_function(exarg_T *eap, cctx_T *cctx)
 {
+    int		is_global = *eap->arg == 'g' && eap->arg[1] == ':';
     char_u	*name_start = eap->arg;
-    char_u	*name_end = to_name_end(eap->arg, FALSE);
+    char_u	*name_end = to_name_end(eap->arg, is_global);
     char_u	*name = get_lambda_name();
     lvar_T	*lvar;
     ufunc_T	*ufunc;
+    int		r;
 
     eap->arg = name_end;
     eap->getline = exarg_getline;
@@ -4894,16 +4917,28 @@ compile_nested_function(exarg_T *eap, cc
 	    && compile_def_function(ufunc, TRUE, cctx) == FAIL)
 	return NULL;
 
-    // Define a local variable for the function reference.
-    lvar = reserve_local(cctx, name_start, name_end - name_start,
+    if (is_global)
+    {
+	char_u *func_name = vim_strnsave(name_start + 2,
+						    name_end - name_start - 2);
+
+	if (func_name == NULL)
+	    r = FAIL;
+	else
+	    r = generate_NEWFUNC(cctx, name, func_name);
+    }
+    else
+    {
+	// Define a local variable for the function reference.
+	lvar = reserve_local(cctx, name_start, name_end - name_start,
 						    TRUE, ufunc->uf_func_type);
-
-    if (generate_FUNCREF(cctx, ufunc->uf_dfunc_idx) == FAIL
-	    || generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL) == FAIL)
-	return NULL;
+	if (generate_FUNCREF(cctx, ufunc->uf_dfunc_idx) == FAIL)
+	    return NULL;
+	r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
+    }
 
     // TODO: warning for trailing text?
-    return (char_u *)"";
+    return r == FAIL ? NULL : (char_u *)"";
 }
 
 /*
@@ -7641,6 +7676,11 @@ delete_instr(isn_T *isn)
 	    }
 	    break;
 
+	case ISN_NEWFUNC:
+	    vim_free(isn->isn_arg.newfunc.nf_lambda);
+	    vim_free(isn->isn_arg.newfunc.nf_global);
+	    break;
+
 	case ISN_2BOOL:
 	case ISN_2STRING:
 	case ISN_ADDBLOB: