mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.1071: Vim9: no line break allowed inside a lambda
Problem: Vim9: no line break allowed inside a lambda.
Solution: Handle line break inside a lambda in Vim9 script.
e40fbc2ca9
Omit skip_expr_concatenate(). Apply the change to skip_expr() instead.
Omit eval_ga: Vim9 script only.
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
parent
89ff05b258
commit
d927128fcc
@ -847,12 +847,24 @@ char *eval_to_string_skip(char *arg, exarg_T *eap, const bool skip)
|
|||||||
/// Skip over an expression at "*pp".
|
/// Skip over an expression at "*pp".
|
||||||
///
|
///
|
||||||
/// @return FAIL for an error, OK otherwise.
|
/// @return FAIL for an error, OK otherwise.
|
||||||
int skip_expr(char **pp)
|
int skip_expr(char **pp, evalarg_T *const evalarg)
|
||||||
{
|
{
|
||||||
typval_T rettv;
|
const int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags;
|
||||||
|
|
||||||
|
// Don't evaluate the expression.
|
||||||
|
if (evalarg != NULL) {
|
||||||
|
evalarg->eval_flags &= ~EVAL_EVALUATE;
|
||||||
|
}
|
||||||
|
|
||||||
*pp = skipwhite(*pp);
|
*pp = skipwhite(*pp);
|
||||||
return eval1(pp, &rettv, NULL);
|
typval_T rettv;
|
||||||
|
int res = eval1(pp, &rettv, NULL);
|
||||||
|
|
||||||
|
if (evalarg != NULL) {
|
||||||
|
evalarg->eval_flags = save_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Top level evaluation function, returning a string.
|
/// Top level evaluation function, returning a string.
|
||||||
@ -2236,9 +2248,6 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
|
|||||||
const int called_emsg_before = called_emsg;
|
const int called_emsg_before = called_emsg;
|
||||||
bool end_error = false;
|
bool end_error = false;
|
||||||
|
|
||||||
if (evalarg != NULL) {
|
|
||||||
evalarg->eval_tofree = NULL;
|
|
||||||
}
|
|
||||||
p = skipwhite(arg);
|
p = skipwhite(arg);
|
||||||
ret = eval1(&p, rettv, evalarg);
|
ret = eval1(&p, rettv, evalarg);
|
||||||
|
|
||||||
@ -2269,19 +2278,14 @@ int eval0(char *arg, typval_T *rettv, exarg_T *eap, evalarg_T *const evalarg)
|
|||||||
eap->nextcmd = check_nextcmd(p);
|
eap->nextcmd = check_nextcmd(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evalarg != NULL) {
|
if (evalarg != NULL && eap != NULL && evalarg->eval_tofree != NULL) {
|
||||||
if (eap != NULL) {
|
|
||||||
if (evalarg->eval_tofree != NULL) {
|
|
||||||
// We may need to keep the original command line, e.g. for
|
// We may need to keep the original command line, e.g. for
|
||||||
// ":let" it has the variable names. But we may also need the
|
// ":let" it has the variable names. But we may also need the
|
||||||
// new one, "nextcmd" points into it. Keep both.
|
// new one, "nextcmd" points into it. Keep both.
|
||||||
xfree(eap->cmdline_tofree);
|
xfree(eap->cmdline_tofree);
|
||||||
eap->cmdline_tofree = *eap->cmdlinep;
|
eap->cmdline_tofree = *eap->cmdlinep;
|
||||||
*eap->cmdlinep = evalarg->eval_tofree;
|
*eap->cmdlinep = evalarg->eval_tofree;
|
||||||
}
|
evalarg->eval_tofree = NULL;
|
||||||
} else {
|
|
||||||
xfree(evalarg->eval_tofree);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -2987,7 +2991,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
|
|||||||
// Lambda: {arg, arg -> expr}
|
// Lambda: {arg, arg -> expr}
|
||||||
// Dictionary: {'key': val, 'key': val}
|
// Dictionary: {'key': val, 'key': val}
|
||||||
case '{':
|
case '{':
|
||||||
ret = get_lambda_tv(arg, rettv, evaluate);
|
ret = get_lambda_tv(arg, rettv, evalarg);
|
||||||
if (ret == NOTDONE) {
|
if (ret == NOTDONE) {
|
||||||
ret = eval_dict(arg, rettv, evalarg, false);
|
ret = eval_dict(arg, rettv, evalarg, false);
|
||||||
}
|
}
|
||||||
@ -3062,7 +3066,7 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan
|
|||||||
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||||
// expr(expr), expr->name(expr)
|
// expr(expr), expr->name(expr)
|
||||||
if (ret == OK) {
|
if (ret == OK) {
|
||||||
ret = handle_subscript((const char **)arg, rettv, flags, true);
|
ret = handle_subscript((const char **)arg, rettv, evalarg, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply logical NOT and unary '-', from right to left, ignore '+'.
|
// Apply logical NOT and unary '-', from right to left, ignore '+'.
|
||||||
@ -3192,16 +3196,17 @@ static int call_func_rettv(char **const arg, typval_T *const rettv, const bool e
|
|||||||
/// @return FAIL or OK.
|
/// @return FAIL or OK.
|
||||||
///
|
///
|
||||||
/// @note "*arg" is advanced to after the ')'.
|
/// @note "*arg" is advanced to after the ')'.
|
||||||
static int eval_lambda(char **const arg, typval_T *const rettv, const bool evaluate,
|
static int eval_lambda(char **const arg, typval_T *const rettv, evalarg_T *const evalarg,
|
||||||
const bool verbose)
|
const bool verbose)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||||
{
|
{
|
||||||
|
const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
// Skip over the ->.
|
// Skip over the ->.
|
||||||
*arg += 2;
|
*arg += 2;
|
||||||
typval_T base = *rettv;
|
typval_T base = *rettv;
|
||||||
rettv->v_type = VAR_UNKNOWN;
|
rettv->v_type = VAR_UNKNOWN;
|
||||||
|
|
||||||
int ret = get_lambda_tv(arg, rettv, evaluate);
|
int ret = get_lambda_tv(arg, rettv, evalarg);
|
||||||
if (ret != OK) {
|
if (ret != OK) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
} else if (**arg != '(') {
|
} else if (**arg != '(') {
|
||||||
@ -3306,9 +3311,9 @@ static int eval_method(char **const arg, typval_T *const rettv, const bool evalu
|
|||||||
/// @param verbose give error messages
|
/// @param verbose give error messages
|
||||||
///
|
///
|
||||||
/// @returns FAIL or OK. "*arg" is advanced to after the ']'.
|
/// @returns FAIL or OK. "*arg" is advanced to after the ']'.
|
||||||
static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose)
|
static int eval_index(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool verbose)
|
||||||
{
|
{
|
||||||
const bool evaluate = flags & EVAL_EVALUATE;
|
const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
bool empty1 = false;
|
bool empty1 = false;
|
||||||
bool empty2 = false;
|
bool empty2 = false;
|
||||||
ptrdiff_t len = -1;
|
ptrdiff_t len = -1;
|
||||||
@ -3357,15 +3362,13 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose
|
|||||||
}
|
}
|
||||||
*arg = skipwhite(key + len);
|
*arg = skipwhite(key + len);
|
||||||
} else {
|
} else {
|
||||||
evalarg_T evalarg = { .eval_flags = flags };
|
|
||||||
|
|
||||||
// something[idx]
|
// something[idx]
|
||||||
//
|
//
|
||||||
// Get the (first) variable from inside the [].
|
// Get the (first) variable from inside the [].
|
||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
if (**arg == ':') {
|
if (**arg == ':') {
|
||||||
empty1 = true;
|
empty1 = true;
|
||||||
} else if (eval1(arg, &var1, &evalarg) == FAIL) { // Recursive!
|
} else if (eval1(arg, &var1, evalarg) == FAIL) { // Recursive!
|
||||||
return FAIL;
|
return FAIL;
|
||||||
} else if (evaluate && !tv_check_str(&var1)) {
|
} else if (evaluate && !tv_check_str(&var1)) {
|
||||||
// Not a number or string.
|
// Not a number or string.
|
||||||
@ -3379,7 +3382,7 @@ static int eval_index(char **arg, typval_T *rettv, const int flags, bool verbose
|
|||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
if (**arg == ']') {
|
if (**arg == ']') {
|
||||||
empty2 = true;
|
empty2 = true;
|
||||||
} else if (eval1(arg, &var2, &evalarg) == FAIL) { // Recursive!
|
} else if (eval1(arg, &var2, evalarg) == FAIL) { // Recursive!
|
||||||
if (!empty1) {
|
if (!empty1) {
|
||||||
tv_clear(&var1);
|
tv_clear(&var1);
|
||||||
}
|
}
|
||||||
@ -7007,9 +7010,10 @@ int check_luafunc_name(const char *const str, const bool paren)
|
|||||||
/// @param verbose give error messages
|
/// @param verbose give error messages
|
||||||
/// @param start_leader start of '!' and '-' prefixes
|
/// @param start_leader start of '!' and '-' prefixes
|
||||||
/// @param end_leaderp end of '!' and '-' prefixes
|
/// @param end_leaderp end of '!' and '-' prefixes
|
||||||
int handle_subscript(const char **const arg, typval_T *rettv, const int flags, bool verbose)
|
int handle_subscript(const char **const arg, typval_T *rettv, evalarg_T *const evalarg,
|
||||||
|
bool verbose)
|
||||||
{
|
{
|
||||||
const bool evaluate = flags & EVAL_EVALUATE;
|
const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
dict_T *selfdict = NULL;
|
dict_T *selfdict = NULL;
|
||||||
const char *lua_funcname = NULL;
|
const char *lua_funcname = NULL;
|
||||||
@ -7054,7 +7058,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, const int flags, b
|
|||||||
} else if (**arg == '-') {
|
} else if (**arg == '-') {
|
||||||
if ((*arg)[2] == '{') {
|
if ((*arg)[2] == '{') {
|
||||||
// expr->{lambda}()
|
// expr->{lambda}()
|
||||||
ret = eval_lambda((char **)arg, rettv, evaluate, verbose);
|
ret = eval_lambda((char **)arg, rettv, evalarg, verbose);
|
||||||
} else {
|
} else {
|
||||||
// expr->name()
|
// expr->name()
|
||||||
ret = eval_method((char **)arg, rettv, evaluate, verbose);
|
ret = eval_method((char **)arg, rettv, evaluate, verbose);
|
||||||
@ -7069,7 +7073,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, const int flags, b
|
|||||||
} else {
|
} else {
|
||||||
selfdict = NULL;
|
selfdict = NULL;
|
||||||
}
|
}
|
||||||
if (eval_index((char **)arg, rettv, flags, verbose) == FAIL) {
|
if (eval_index((char **)arg, rettv, evalarg, verbose) == FAIL) {
|
||||||
tv_clear(rettv);
|
tv_clear(rettv);
|
||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
}
|
}
|
||||||
|
@ -252,8 +252,9 @@ static void set_ufunc_name(ufunc_T *fp, char *name)
|
|||||||
/// Parse a lambda expression and get a Funcref from "*arg".
|
/// Parse a lambda expression and get a Funcref from "*arg".
|
||||||
///
|
///
|
||||||
/// @return OK or FAIL. Returns NOTDONE for dict or {expr}.
|
/// @return OK or FAIL. Returns NOTDONE for dict or {expr}.
|
||||||
int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
|
int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg)
|
||||||
{
|
{
|
||||||
|
const bool evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE);
|
||||||
garray_T newargs = GA_EMPTY_INIT_VALUE;
|
garray_T newargs = GA_EMPTY_INIT_VALUE;
|
||||||
garray_T *pnewargs;
|
garray_T *pnewargs;
|
||||||
ufunc_T *fp = NULL;
|
ufunc_T *fp = NULL;
|
||||||
@ -264,6 +265,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
|
|||||||
char *s, *e;
|
char *s, *e;
|
||||||
bool *old_eval_lavars = eval_lavars_used;
|
bool *old_eval_lavars = eval_lavars_used;
|
||||||
bool eval_lavars = false;
|
bool eval_lavars = false;
|
||||||
|
char *tofree = NULL;
|
||||||
|
|
||||||
// First, check if this is a lambda expression. "->" must exists.
|
// First, check if this is a lambda expression. "->" must exists.
|
||||||
ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
|
ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
|
||||||
@ -291,10 +293,16 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
|
|||||||
// Get the start and the end of the expression.
|
// Get the start and the end of the expression.
|
||||||
*arg = skipwhite((*arg) + 1);
|
*arg = skipwhite((*arg) + 1);
|
||||||
s = *arg;
|
s = *arg;
|
||||||
ret = skip_expr(arg);
|
ret = skip_expr(arg, evalarg);
|
||||||
if (ret == FAIL) {
|
if (ret == FAIL) {
|
||||||
goto errret;
|
goto errret;
|
||||||
}
|
}
|
||||||
|
if (evalarg != NULL) {
|
||||||
|
// avoid that the expression gets freed when another line break follows
|
||||||
|
tofree = evalarg->eval_tofree;
|
||||||
|
evalarg->eval_tofree = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
e = *arg;
|
e = *arg;
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
if (**arg != '}') {
|
if (**arg != '}') {
|
||||||
@ -359,12 +367,14 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
|
xfree(tofree);
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
errret:
|
errret:
|
||||||
ga_clear_strings(&newargs);
|
ga_clear_strings(&newargs);
|
||||||
xfree(fp);
|
xfree(fp);
|
||||||
xfree(pt);
|
xfree(pt);
|
||||||
|
xfree(tofree);
|
||||||
eval_lavars_used = old_eval_lavars;
|
eval_lavars_used = old_eval_lavars;
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -3075,8 +3085,7 @@ void ex_call(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle a function returning a Funcref, Dictionary or List.
|
// Handle a function returning a Funcref, Dictionary or List.
|
||||||
if (handle_subscript((const char **)&arg, &rettv, EVAL_EVALUATE, true)
|
if (handle_subscript((const char **)&arg, &rettv, &EVALARG_EVALUATE, true) == FAIL) {
|
||||||
== FAIL) {
|
|
||||||
failed = true;
|
failed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "nvim/eval.h"
|
||||||
#include "nvim/eval/typval.h"
|
#include "nvim/eval/typval.h"
|
||||||
#include "nvim/eval/typval_defs.h"
|
#include "nvim/eval/typval_defs.h"
|
||||||
#include "nvim/ex_cmds_defs.h"
|
#include "nvim/ex_cmds_defs.h"
|
||||||
|
@ -267,6 +267,7 @@ void ex_let(exarg_T *eap)
|
|||||||
if (eap->skip) {
|
if (eap->skip) {
|
||||||
emsg_skip--;
|
emsg_skip--;
|
||||||
}
|
}
|
||||||
|
xfree(evalarg.eval_tofree);
|
||||||
|
|
||||||
if (!eap->skip && eval_res != FAIL) {
|
if (!eap->skip && eval_res != FAIL) {
|
||||||
(void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
|
(void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, is_const, op);
|
||||||
@ -510,7 +511,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
|
|||||||
} else {
|
} else {
|
||||||
// handle d.key, l[idx], f(expr)
|
// handle d.key, l[idx], f(expr)
|
||||||
const char *const arg_subsc = arg;
|
const char *const arg_subsc = arg;
|
||||||
if (handle_subscript(&arg, &tv, EVAL_EVALUATE, true) == FAIL) {
|
if (handle_subscript(&arg, &tv, &EVALARG_EVALUATE, true) == FAIL) {
|
||||||
error = true;
|
error = true;
|
||||||
} else {
|
} else {
|
||||||
if (arg == arg_subsc && len == 2 && name[1] == ':') {
|
if (arg == arg_subsc && len == 2 && name[1] == ':') {
|
||||||
@ -1717,7 +1718,7 @@ bool var_exists(const char *var)
|
|||||||
n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
|
n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
|
||||||
if (n) {
|
if (n) {
|
||||||
// Handle d.key, l[idx], f(expr).
|
// Handle d.key, l[idx], f(expr).
|
||||||
n = handle_subscript(&var, &tv, EVAL_EVALUATE, false) == OK;
|
n = handle_subscript(&var, &tv, &EVALARG_EVALUATE, false) == OK;
|
||||||
if (n) {
|
if (n) {
|
||||||
tv_clear(&tv);
|
tv_clear(&tv);
|
||||||
}
|
}
|
||||||
|
@ -3751,7 +3751,7 @@ int expand_filename(exarg_T *eap, char **cmdlinep, char **errormsgp)
|
|||||||
// Skip over `=expr`, wildcards in it are not expanded.
|
// Skip over `=expr`, wildcards in it are not expanded.
|
||||||
if (p[0] == '`' && p[1] == '=') {
|
if (p[0] == '`' && p[1] == '=') {
|
||||||
p += 2;
|
p += 2;
|
||||||
(void)skip_expr(&p);
|
(void)skip_expr(&p, NULL);
|
||||||
if (*p == '`') {
|
if (*p == '`') {
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
@ -3970,7 +3970,7 @@ void separate_nextcmd(exarg_T *eap)
|
|||||||
} else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) {
|
} else if (p[0] == '`' && p[1] == '=' && (eap->argt & EX_XFILE)) {
|
||||||
// Skip over `=expr` when wildcards are expanded.
|
// Skip over `=expr` when wildcards are expanded.
|
||||||
p += 2;
|
p += 2;
|
||||||
(void)skip_expr(&p);
|
(void)skip_expr(&p, NULL);
|
||||||
if (*p == NUL) { // stop at NUL after CTRL-V
|
if (*p == NUL) { // stop at NUL after CTRL-V
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es
|
|||||||
if (src[0] == '`' && src[1] == '=') {
|
if (src[0] == '`' && src[1] == '=') {
|
||||||
var = src;
|
var = src;
|
||||||
src += 2;
|
src += 2;
|
||||||
(void)skip_expr(&src);
|
(void)skip_expr(&src, NULL);
|
||||||
if (*src == '`') {
|
if (*src == '`') {
|
||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user