mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	vim-patch:8.2.0918: duplicate code for evaluating expression argument
Problem:    Duplicate code for evaluating expression argument.
Solution:   Merge the code and make the use more flexible.
a9c0104947
			
			
This commit is contained in:
		| @@ -766,6 +766,15 @@ static int eval1_emsg(char_u **arg, typval_T *rettv, bool evaluate) | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| /// @return whether a typval is a valid expression to pass to eval_expr_typval() | ||||
| /// or eval_expr_to_bool().  An empty string returns false; | ||||
| bool eval_expr_valid_arg(const typval_T *const tv) | ||||
|   FUNC_ATTR_NONNULL_ALL FUNC_ATTR_CONST | ||||
| { | ||||
|   return tv->v_type != VAR_UNKNOWN | ||||
|          && (tv->v_type != VAR_STRING || (tv->vval.v_string != NULL && *tv->vval.v_string != NUL)); | ||||
| } | ||||
|  | ||||
| int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv) | ||||
|   FUNC_ATTR_NONNULL_ARG(1, 2, 4) | ||||
| { | ||||
| @@ -3381,67 +3390,6 @@ static int eval_func(char_u **const arg, char_u *const name, const int name_len, | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| /// Process a function argument that can be a string expression or a function | ||||
| /// reference. | ||||
| /// "tv" must remain valid until calling evalarg_clean()! | ||||
| /// @return false when the argument is invalid. | ||||
| bool evalarg_get(typval_T *const tv, evalarg_T *const eva) | ||||
|   FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   if (tv->v_type == VAR_STRING || tv->v_type == VAR_NUMBER || tv->v_type == VAR_BOOL | ||||
|       || tv->v_type == VAR_SPECIAL) { | ||||
|     char numbuf[NUMBUFLEN]; | ||||
|     eva->eva_string = tv_get_string_buf(tv, numbuf); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   return callback_from_typval(&eva->eva_callback, tv); | ||||
| } | ||||
|  | ||||
| /// @return whether "eva" has a valid expression or callback. | ||||
| bool evalarg_valid(const evalarg_T *const eva) | ||||
|   FUNC_ATTR_NONNULL_ALL FUNC_ATTR_CONST | ||||
| { | ||||
|   return eva->eva_string != NULL || eva->eva_callback.type != kCallbackNone; | ||||
| } | ||||
|  | ||||
| /// Invoke the expression or callback "eva" and return the result in "tv". | ||||
| /// @return false if something failed | ||||
| bool evalarg_call(evalarg_T *const eva, typval_T *const tv) | ||||
|   FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   if (eva->eva_string != NULL) { | ||||
|     return eval0((char_u *)eva->eva_string, tv, NULL, true); | ||||
|   } | ||||
|  | ||||
|   typval_T argv[1]; | ||||
|   argv[0].v_type = VAR_UNKNOWN; | ||||
|   return callback_call(&eva->eva_callback, 0, argv, tv); | ||||
| } | ||||
|  | ||||
| /// Like evalarg_call(), but just return true or false. | ||||
| /// Sets "error" to true if evaluation failed. | ||||
| bool evalarg_call_bool(evalarg_T *const eva, bool *const error) | ||||
|   FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   typval_T tv; | ||||
|   if (!evalarg_call(eva, &tv)) { | ||||
|     *error = true; | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   const bool r = tv_get_number(&tv); | ||||
|   tv_clear(&tv); | ||||
|   *error = false; | ||||
|   return r; | ||||
| } | ||||
|  | ||||
| void evalarg_clean(evalarg_T *const eva) | ||||
|   FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   callback_free(&eva->eva_callback); | ||||
| } | ||||
|  | ||||
| // TODO(ZyX-I): move to eval/expressions | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -272,22 +272,6 @@ typedef int (*ex_unletlock_callback)(lval_T *, char_u *, exarg_T *, int); | ||||
| // Used for checking if local variables or arguments used in a lambda. | ||||
| extern bool *eval_lavars_used; | ||||
|  | ||||
| /// Function argument that can be a string, funcref or partial. | ||||
| /// - declare:  evalarg_T name; | ||||
| /// - init:     name = EVALARG_INIT; | ||||
| /// - set:      evalarg_get(&argvars[3], &name); | ||||
| /// - use:      if (evalarg_valid(&name)) res = evalarg_call(&name); | ||||
| /// - cleanup:  evalarg_clean(&name); | ||||
| typedef struct { | ||||
|   const char *eva_string; | ||||
|   Callback eva_callback; | ||||
| } evalarg_T; | ||||
|  | ||||
| #define EVALARG_INIT (evalarg_T) { \ | ||||
|   .eva_string = NULL, \ | ||||
|   .eva_callback = CALLBACK_NONE, \ | ||||
| } | ||||
|  | ||||
| #ifdef INCLUDE_GENERATED_DECLARATIONS | ||||
| # include "eval.h.generated.h" | ||||
| #endif | ||||
|   | ||||
| @@ -8237,7 +8237,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) | ||||
|   int options = SEARCH_KEEP; | ||||
|   int subpatnum; | ||||
|   searchit_arg_T sia; | ||||
|   evalarg_T skip = EVALARG_INIT; | ||||
|   bool use_skip = false; | ||||
|  | ||||
|   const char *const pat = tv_get_string(&argvars[0]); | ||||
|   dir = get_search_arg(&argvars[1], flagsp);  // May set p_ws. | ||||
| @@ -8266,9 +8266,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) | ||||
|       if (time_limit < 0) { | ||||
|         goto theend; | ||||
|       } | ||||
|       if (argvars[4].v_type != VAR_UNKNOWN && !evalarg_get(&argvars[4], &skip)) { | ||||
|         goto theend; | ||||
|       } | ||||
|       use_skip = eval_expr_valid_arg(&argvars[4]); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -8303,19 +8301,19 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) | ||||
|       subpatnum = FAIL; | ||||
|     } | ||||
|  | ||||
|     if (subpatnum == FAIL || !evalarg_valid(&skip)) { | ||||
|     if (subpatnum == FAIL || !use_skip) { | ||||
|       // didn't find it or no skip argument | ||||
|       break; | ||||
|     } | ||||
|     firstpos = pos; | ||||
|  | ||||
|     // If the skip pattern matches, ignore this match. | ||||
|     // If the skip expression matches, ignore this match. | ||||
|     { | ||||
|       bool err; | ||||
|       const pos_T save_pos = curwin->w_cursor; | ||||
|  | ||||
|       curwin->w_cursor = pos; | ||||
|       const bool do_skip = evalarg_call_bool(&skip, &err); | ||||
|       bool err = false; | ||||
|       const bool do_skip = eval_expr_to_bool(&argvars[4], &err); | ||||
|       curwin->w_cursor = save_pos; | ||||
|       if (err) { | ||||
|         // Evaluating {skip} caused an error, break here. | ||||
| @@ -8356,7 +8354,6 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) | ||||
|   } | ||||
| theend: | ||||
|   p_ws = save_p_ws; | ||||
|   evalarg_clean(&skip); | ||||
|  | ||||
|   return retval; | ||||
| } | ||||
| @@ -8788,13 +8785,9 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos) | ||||
|       || argvars[4].v_type == VAR_UNKNOWN) { | ||||
|     skip = NULL; | ||||
|   } else { | ||||
|     // Type is checked later. | ||||
|     skip = &argvars[4]; | ||||
|     if (skip->v_type != VAR_FUNC | ||||
|         && skip->v_type != VAR_PARTIAL | ||||
|         && skip->v_type != VAR_STRING) { | ||||
|       semsg(_(e_invarg2), tv_get_string(&argvars[4])); | ||||
|       goto theend;  // Type error. | ||||
|     } | ||||
|  | ||||
|     if (argvars[5].v_type != VAR_UNKNOWN) { | ||||
|       lnum_stop = tv_get_number_chk(&argvars[5], NULL); | ||||
|       if (lnum_stop < 0) { | ||||
| @@ -8905,10 +8898,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir | ||||
|   } | ||||
|  | ||||
|   if (skip != NULL) { | ||||
|     // Empty string means to not use the skip expression. | ||||
|     if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) { | ||||
|       use_skip = skip->vval.v_string != NULL && *skip->vval.v_string != NUL; | ||||
|     } | ||||
|     use_skip = eval_expr_valid_arg(skip); | ||||
|   } | ||||
|  | ||||
|   save_cursor = curwin->w_cursor; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sean Dewar
					Sean Dewar