Commits

ZyX_I  committed 04a1041

Scope variables fix applied to python interface

  • Participants
  • Parent commits e92f6b1
  • Branches fix-scope-dicts-python

Comments (0)

Files changed (7)

 static void set_var __ARGS((char_u *name, typval_T *varp, int copy));
 static int var_check_ro __ARGS((int flags, char_u *name));
 static int var_check_fixed __ARGS((int flags, char_u *name));
-static int var_check_func_name __ARGS((char_u *name, int new_var));
-static int valid_varname __ARGS((char_u *varname));
 static int tv_check_lock __ARGS((int lock, char_u *name));
 static int item_copy __ARGS((typval_T *from, typval_T *to, int deep, int copyID));
 static char_u *find_option_end __ARGS((char_u **arg, int *opt_flags));
 		}
 		wrong = (lp->ll_dict->dv_scope == VAR_DEF_SCOPE
 			       && rettv->v_type == VAR_FUNC
-			       && var_check_func_name(key, lp->ll_di == NULL))
-			|| !valid_varname(key);
+			       && var_check_func_name(key, lp->ll_di == NULL, TRUE))
+			|| !valid_varname(key, TRUE);
 		if (len != -1)
 		    key[len] = prevval;
 		if (wrong)
 		        if (d1->dv_scope == VAR_DEF_SCOPE
 				&& HI2DI(hi2)->di_tv.v_type == VAR_FUNC
 				&& var_check_func_name(hi2->hi_key,
-								 di1 == NULL))
+								 di1 == NULL,
+								 TRUE))
 			    break;
-			if (!valid_varname(hi2->hi_key))
+			if (!valid_varname(hi2->hi_key, TRUE))
 			    break;
 		    }
 		    if (di1 == NULL)
     }
     v = find_var_in_ht(ht, varname, TRUE);
 
-    if (tv->v_type == VAR_FUNC && var_check_func_name(name, v == NULL))
+    if (tv->v_type == VAR_FUNC && var_check_func_name(name, v == NULL, TRUE))
 	return;
 
     if (v != NULL)
 	}
 
 	/* Make sure the variable name is valid. */
-	if (!valid_varname(varname))
+	if (!valid_varname(varname, TRUE))
 	    return;
 
 	v = (dictitem_T *)alloc((unsigned)(sizeof(dictitem_T)
 
 /*
  * Check if a funcref is assigned to a valid variable name.
- * Return TRUE and give an error if not.
- */
-    static int
-var_check_func_name(name, new_var)
-    char_u *name;    /* points to start of variable name */
-    int    new_var;  /* TRUE when creating the variable */
+ * Return TRUE if not. Give an error unless echo_error is set to FALSE.
+ */
+    int
+var_check_func_name(name, new_var, echo_error)
+    char_u *name;      /* points to start of variable name */
+    int    new_var;    /* TRUE when creating the variable */
+    int    echo_error; /* TRUE if it is needed to echo vim error */
 {
     if (!(vim_strchr((char_u *)"wbs", name[0]) != NULL && name[1] == ':')
 	    && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
 						     ? name[2] : name[0]))
     {
-	EMSG2(_("E704: Funcref variable name must start with a capital: %s"),
-									name);
+	if (echo_error)
+	    EMSG2(_("E704: Funcref variable name must start with a capital: %s"),
+									    name);
 	return TRUE;
     }
     /* Don't allow hiding a function.  When "v" is not NULL we might be
      * below. */
     if (new_var && function_exists(name))
     {
-	EMSG2(_("E705: Variable name conflicts with existing function: %s"),
-								    name);
+	if (echo_error)
+	    EMSG2(_("E705: Variable name conflicts with existing function: %s"),
+									name);
 	return TRUE;
     }
     return FALSE;
 
 /*
  * Check if a variable name is valid.
- * Return FALSE and give an error if not.
- */
-    static int
-valid_varname(varname)
+ * Return FALSE if not. Also give an error in this case unless echo_error is set 
+ * to false.
+ */
+    int
+valid_varname(varname, echo_error)
     char_u *varname;
+    int    echo_error;
 {
     char_u *p;
 
 	if (!eval_isnamec1(*p) && (p == varname || !VIM_ISDIGIT(*p))
 						   && *p != AUTOLOAD_CHAR)
 	{
-	    EMSG2(_(e_illvar), varname);
+	    /* When using this function from python don’t throw vim error, throw 
+	     * a python exception instead */
+	    if (echo_error)
+		EMSG2(_(e_illvar), varname);
 	    return FALSE;
 	}
     return TRUE;

File src/if_py_both.h

     if (ConvertFromPyObject(valObject, &tv) == -1)
 	return -1;
 
+    if (d->dv_scope != 0)
+    {
+	if (d->dv_scope == VAR_DEF_SCOPE
+		&& tv.v_type == VAR_FUNC
+		&& var_check_func_name(key, di == NULL, FALSE))
+	{
+	    PyErr_SetString(PyExc_ValueError, _("cannot assing function reference to this variable"));
+	    return -1;
+	}
+	if(!valid_varname(key, FALSE))
+	{
+	    PyErr_SetString(PyExc_ValueError, _("invalid variable name"));
+	    return -1;
+	}
+    }
+
     if (di == NULL)
     {
 	di = dictitem_alloc(key);

File src/proto/eval.pro

 void ex_oldfiles __ARGS((exarg_T *eap));
 int modify_fname __ARGS((char_u *src, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen));
 char_u *do_string_sub __ARGS((char_u *str, char_u *pat, char_u *sub, char_u *flags));
+int valid_varname __ARGS((char_u *varname, int echo_error));
+int var_check_func_name __ARGS((char_u *name, int new_var, int echo_error));
 /* vim: set ft=c : */

File src/testdir/test86.in

 :$put =string(l)
 :unlockvar! l
 :"
+:" Invalid assignments to scope dictionary
+:call map(keys(l:), 'remove(l:, v:val)')
+:py g, l = (vim.bindeval(s+':') for s in 'gl')
+:py g['max']=vim.bindeval('function("min")')
+:$put =max([1, 3])
+:py l['1']=''
+:$put =string(keys(l:))
+:"
 :" Function calls
 :function New(...)
 :return ['NewStart']+a:000+['NewEnd']

File src/testdir/test86.ok

 [0, 1, 'g', 2, 3]
 ['h']
 [0, 1, 2, 3]
+3
+[]
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']

File src/testdir/test87.in

 :$put =string(l)
 :unlockvar! l
 :"
+:" Invalid assignments to scope dictionary
+:call map(keys(l:), 'remove(l:, v:val)')
+:py3 g, l = (vim.bindeval(s+':') for s in 'gl')
+:py3 g['max']=vim.bindeval('function("min")')
+:$put =max([1, 3])
+:py3 l['1']=''
+:$put =string(keys(l:))
+:"
 :" Function calls
 :function New(...)
 :return ['NewStart']+a:000+['NewEnd']

File src/testdir/test87.ok

 [0, 1, 'g', 2, 3]
 ['h']
 [0, 1, 2, 3]
+3
+[]
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd']
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}]
 [function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New']