From cccb21df3b4c6fe0aaa99743c418aa973aeebad0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 04:10:59 +0200 Subject: Merging upstream version 2:9.1.0374. Signed-off-by: Daniel Baumann --- src/eval.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 131 insertions(+), 33 deletions(-) (limited to 'src/eval.c') diff --git a/src/eval.c b/src/eval.c index 69b8374..51ee604 100644 --- a/src/eval.c +++ b/src/eval.c @@ -549,6 +549,7 @@ skip_expr_concatenate( ((char_u **)gap->ga_data)[gap->ga_len - 1]; ((char_u **)gap->ga_data)[gap->ga_len - 1] = NULL; ga_clear_strings(gap); + ga_clear(freegap); } else { @@ -574,16 +575,16 @@ skip_expr_concatenate( /* * Convert "tv" to a string. - * When "convert" is TRUE convert a List into a sequence of lines. + * When "join_list" is TRUE convert a List into a sequence of lines. * Returns an allocated string (NULL when out of memory). */ char_u * -typval2string(typval_T *tv, int convert) +typval2string(typval_T *tv, int join_list) { garray_T ga; char_u *retval; - if (convert && tv->v_type == VAR_LIST) + if (join_list && tv->v_type == VAR_LIST) { ga_init2(&ga, sizeof(char), 80); if (tv->vval.v_list != NULL) @@ -595,6 +596,16 @@ typval2string(typval_T *tv, int convert) ga_append(&ga, NUL); retval = (char_u *)ga.ga_data; } + else if (tv->v_type == VAR_LIST || tv->v_type == VAR_DICT) + { + char_u *tofree; + char_u numbuf[NUMBUFLEN]; + + retval = tv2string(tv, &tofree, numbuf, 0); + // Make a copy if we have a value but it's not in allocated memory. + if (retval != NULL && tofree == NULL) + retval = vim_strsave(retval); + } else retval = vim_strsave(tv_get_string(tv)); return retval; @@ -603,13 +614,13 @@ typval2string(typval_T *tv, int convert) /* * Top level evaluation function, returning a string. Does not handle line * breaks. - * When "convert" is TRUE convert a List into a sequence of lines. + * When "join_list" is TRUE convert a List into a sequence of lines. * Return pointer to allocated memory, or NULL for failure. */ char_u * eval_to_string_eap( char_u *arg, - int convert, + int join_list, exarg_T *eap, int use_simple_function) { @@ -627,7 +638,7 @@ eval_to_string_eap( retval = NULL; else { - retval = typval2string(&tv, convert); + retval = typval2string(&tv, join_list); clear_tv(&tv); } clear_evalarg(&evalarg, NULL); @@ -638,10 +649,10 @@ eval_to_string_eap( char_u * eval_to_string( char_u *arg, - int convert, + int join_list, int use_simple_function) { - return eval_to_string_eap(arg, convert, NULL, use_simple_function); + return eval_to_string_eap(arg, join_list, NULL, use_simple_function); } /* @@ -1119,7 +1130,18 @@ get_lval_check_access( if (*p == '[' || *p == '.') break; if ((flags & GLV_READ_ONLY) == 0) - msg = e_variable_is_not_writable_str; + { + if (IS_ENUM(cl)) + { + if (om->ocm_type->tt_type == VAR_OBJECT) + semsg(_(e_enumvalue_str_cannot_be_modified), + cl->class_name, om->ocm_name); + else + msg = e_variable_is_not_writable_str; + } + else + msg = e_variable_is_not_writable_str; + } break; case VIM_ACCESS_ALL: break; @@ -1134,6 +1156,91 @@ get_lval_check_access( return OK; } +/* + * Get lval information for a variable imported from script "imp_sid". On + * success, updates "lp" with the variable name, type, script ID and typval. + * The variable name starts at or after "p". + * If "rettv" is not NULL it points to the value to be assigned. This used to + * match the rhs and lhs types. + * Returns a pointer to the character after the variable name if the imported + * variable is valid and writable. + * Returns NULL if the variable is not exported or typval is not found or the + * rhs type doesn't match the lhs type or the variable is not writable. + */ + static char_u * +get_lval_imported( + lval_T *lp, + typval_T *rettv, + scid_T imp_sid, + char_u *p, + dictitem_T **dip, + int fne_flags, + int vim9script) +{ + ufunc_T *ufunc; + type_T *type = NULL; + int cc; + int rc = FAIL; + + p = skipwhite(p); + + import_check_sourced_sid(&imp_sid); + lp->ll_sid = imp_sid; + lp->ll_name = p; + p = find_name_end(lp->ll_name, NULL, NULL, fne_flags); + lp->ll_name_end = p; + + // check the item is exported + cc = *p; + *p = NUL; + if (find_exported(imp_sid, lp->ll_name, &ufunc, &type, NULL, NULL, + TRUE) == -1) + goto failed; + + if (vim9script && type != NULL) + { + where_T where = WHERE_INIT; + + // In a vim9 script, do type check and make sure the variable is + // writable. + if (check_typval_type(type, rettv, where) == FAIL) + goto failed; + } + + // Get the typval for the exported item + hashtab_T *ht = &SCRIPT_VARS(imp_sid); + if (ht == NULL) + goto failed; + + dictitem_T *di = find_var_in_ht(ht, 0, lp->ll_name, TRUE); + if (di == NULL) + // script is autoloaded. So variable will be found later + goto success; + + *dip = di; + + // Check whether the variable is writable. + svar_T *sv = find_typval_in_script(&di->di_tv, imp_sid, FALSE); + if (sv != NULL && sv->sv_const != 0) + { + semsg(_(e_cannot_change_readonly_variable_str), lp->ll_name); + goto failed; + } + + // check whether variable is locked + if (value_check_lock(di->di_tv.v_lock, lp->ll_name, FALSE)) + goto failed; + + lp->ll_tv = &di->di_tv; + +success: + rc = OK; + +failed: + *p = cc; + return rc == OK ? p : NULL; +} + /* * Get an lval: variable, Dict item or List item that can be assigned a value * to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]", @@ -1166,7 +1273,7 @@ get_lval( char_u *p; char_u *expr_start, *expr_end; int cc; - dictitem_T *v; + dictitem_T *v = NULL; typval_T var1; typval_T var2; int empty1 = FALSE; @@ -1300,28 +1407,13 @@ get_lval( if (*p == '.') { imported_T *import = find_imported(lp->ll_name, p - lp->ll_name, TRUE); - if (import != NULL) { - ufunc_T *ufunc; - type_T *type; - - import_check_sourced_sid(&import->imp_sid); - lp->ll_sid = import->imp_sid; - lp->ll_name = skipwhite(p + 1); - p = find_name_end(lp->ll_name, NULL, NULL, fne_flags); - lp->ll_name_end = p; - - // check the item is exported - cc = *p; - *p = NUL; - if (find_exported(import->imp_sid, lp->ll_name, &ufunc, &type, - NULL, NULL, TRUE) == -1) - { - *p = cc; + p++; // skip '.' + p = get_lval_imported(lp, rettv, import->imp_sid, p, &v, + fne_flags, vim9script); + if (p == NULL) return NULL; - } - *p = cc; } } @@ -1341,7 +1433,7 @@ get_lval( lp->ll_tv = lval_root->lr_tv; v = NULL; } - else + else if (lp->ll_tv == NULL) { cc = *p; *p = NUL; @@ -6310,9 +6402,15 @@ echo_string_core( case VAR_CLASS: { class_T *cl = tv->vval.v_class; - size_t len = 6 + (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1; + char *s = "class"; + if (IS_INTERFACE(cl)) + s = "interface"; + else if (IS_ENUM(cl)) + s = "enum"; + size_t len = STRLEN(s) + 1 + + (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1; r = *tofree = alloc(len); - vim_snprintf((char *)r, len, "class %s", + vim_snprintf((char *)r, len, "%s %s", s, cl == NULL ? "[unknown]" : (char *)cl->class_name); } break; @@ -6806,7 +6904,7 @@ find_name_end( int br_nest = 0; char_u *p; int len; - int allow_curly = (flags & FNE_ALLOW_CURLY) || !in_vim9script(); + int allow_curly = !in_vim9script(); if (expr_start != NULL) { -- cgit v1.2.3