diff src/eval.c @ 9686:8c2553beff0f v7.4.2119

commit https://github.com/vim/vim/commit/1e96d9bf98f9ab84d5af7f98d6a961d91b17364f Author: Bram Moolenaar <Bram@vim.org> Date: Fri Jul 29 22:15:09 2016 +0200 patch 7.4.2119 Problem: Closures are not supported. Solution: Capture variables in lambdas from the outer scope. (Yasuhiro Matsumoto, Ken Takata)
author Christian Brabandt <cb@256bit.org>
date Fri, 29 Jul 2016 22:30:08 +0200
parents fd9727ae3c49
children 2ea935bdd1a1
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -237,8 +237,8 @@ static int get_env_tv(char_u **arg, typv
 
 static int get_env_len(char_u **arg);
 static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
+static void check_vars(char_u *name, int len);
 static typval_T *alloc_string_tv(char_u *string);
-static hashtab_T *find_var_ht(char_u *name, char_u **varname);
 static void delete_var(hashtab_T *ht, hashitem_T *hi);
 static void list_one_var(dictitem_T *v, char_u *prefix, int *first);
 static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first);
@@ -4332,6 +4332,9 @@ eval7(
 	    {
 		partial_T *partial;
 
+		if (!evaluate)
+		    check_vars(s, len);
+
 		/* If "s" is the name of a variable of type VAR_FUNC
 		 * use its contents. */
 		s = deref_func_name(s, &len, &partial, !evaluate);
@@ -4363,7 +4366,10 @@ eval7(
 	    else if (evaluate)
 		ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE);
 	    else
+	    {
+		check_vars(s, len);
 		ret = OK;
+	    }
 	}
 	vim_free(alias);
     }
@@ -5540,6 +5546,10 @@ set_ref_in_item(
 	    }
 	}
     }
+    else if (tv->v_type == VAR_FUNC)
+    {
+	abort = set_ref_in_func(tv->vval.v_string, copyID);
+    }
     else if (tv->v_type == VAR_PARTIAL)
     {
 	partial_T	*pt = tv->vval.v_partial;
@@ -5549,6 +5559,8 @@ set_ref_in_item(
 	 */
 	if (pt != NULL)
 	{
+	    abort = set_ref_in_func(pt->pt_name, copyID);
+
 	    if (pt->pt_dict != NULL)
 	    {
 		typval_T dtv;
@@ -6791,6 +6803,34 @@ get_var_tv(
 }
 
 /*
+ * Check if variable "name[len]" is a local variable or an argument.
+ * If so, "*eval_lavars_used" is set to TRUE.
+ */
+    static void
+check_vars(char_u *name, int len)
+{
+    int		cc;
+    char_u	*varname;
+    hashtab_T	*ht;
+
+    if (eval_lavars_used == NULL)
+	return;
+
+    /* truncate the name, so that we can use strcmp() */
+    cc = name[len];
+    name[len] = NUL;
+
+    ht = find_var_ht(name, &varname);
+    if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
+    {
+	if (find_var(name, NULL, TRUE) != NULL)
+	    *eval_lavars_used = TRUE;
+    }
+
+    name[len] = cc;
+}
+
+/*
  * Handle expr[expr], expr[expr:expr] subscript and .name lookup.
  * Also handle function call with Funcref variable: func(expr)
  * Can all be combined: dict.func(expr)[idx]['func'](expr)
@@ -7274,13 +7314,20 @@ find_var(char_u *name, hashtab_T **htp, 
 {
     char_u	*varname;
     hashtab_T	*ht;
+    dictitem_T	*ret = NULL;
 
     ht = find_var_ht(name, &varname);
     if (htp != NULL)
 	*htp = ht;
     if (ht == NULL)
 	return NULL;
-    return find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
+    ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
+    if (ret != NULL)
+	return ret;
+
+    /* Search in parent scope for lambda */
+    return find_var_in_scoped_ht(name, varname ? &varname : NULL,
+		no_autoload || htp != NULL);
 }
 
 /*
@@ -7341,7 +7388,7 @@ find_var_in_ht(
  * Return NULL if the name is not valid.
  * Set "varname" to the start of name without ':'.
  */
-    static hashtab_T *
+    hashtab_T *
 find_var_ht(char_u *name, char_u **varname)
 {
     hashitem_T	*hi;
@@ -7617,6 +7664,10 @@ set_var(
     }
     v = find_var_in_ht(ht, 0, varname, TRUE);
 
+    /* Search in parent scope which is possible to reference from lambda */
+    if (v == NULL)
+	v = find_var_in_scoped_ht(name, varname ? &varname : NULL, TRUE);
+
     if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
 				      && var_check_func_name(name, v == NULL))
 	return;