forked from aniani/vim
patch 8.2.2209: Vim9: return type of => lambda not parsed
Problem: Vim9: return type of => lambda not parsed. Solution: Parse and use the return type.
This commit is contained in:
parent
4aab88d919
commit
9e68c32563
@ -868,7 +868,9 @@ get_lval(
|
|||||||
char_u *tp = skipwhite(p + 1);
|
char_u *tp = skipwhite(p + 1);
|
||||||
|
|
||||||
// parse the type after the name
|
// parse the type after the name
|
||||||
lp->ll_type = parse_type(&tp, &si->sn_type_list);
|
lp->ll_type = parse_type(&tp, &si->sn_type_list, !quiet);
|
||||||
|
if (lp->ll_type == NULL && !quiet)
|
||||||
|
return NULL;
|
||||||
lp->ll_name_end = tp;
|
lp->ll_name_end = tp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ void arg_type_mismatch(type_T *expected, type_T *actual, int argidx);
|
|||||||
int check_type(type_T *expected, type_T *actual, int give_msg, int argidx);
|
int check_type(type_T *expected, type_T *actual, int give_msg, int argidx);
|
||||||
int check_arg_type(type_T *expected, type_T *actual, int argidx);
|
int check_arg_type(type_T *expected, type_T *actual, int argidx);
|
||||||
char_u *skip_type(char_u *start, int optional);
|
char_u *skip_type(char_u *start, int optional);
|
||||||
type_T *parse_type(char_u **arg, garray_T *type_gap);
|
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
|
||||||
void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap);
|
void common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap);
|
||||||
type_T *get_member_type_from_stack(type_T **stack_top, int count, int skip, garray_T *type_gap);
|
type_T *get_member_type_from_stack(type_T **stack_top, int count, int skip, garray_T *type_gap);
|
||||||
char *vartype_name(vartype_T type);
|
char *vartype_name(vartype_T type);
|
||||||
|
@ -1951,7 +1951,7 @@ def Test_expr7_new_lambda()
|
|||||||
assert_equal([1, 3, 5], res)
|
assert_equal([1, 3, 5], res)
|
||||||
|
|
||||||
# Lambda returning a dict
|
# Lambda returning a dict
|
||||||
var Lmb = () => {key: 42}
|
var Lmb = () => ({key: 42})
|
||||||
assert_equal({key: 42}, Lmb())
|
assert_equal({key: 42}, Lmb())
|
||||||
END
|
END
|
||||||
CheckDefSuccess(lines)
|
CheckDefSuccess(lines)
|
||||||
@ -1960,11 +1960,16 @@ def Test_expr7_new_lambda()
|
|||||||
CheckDefFailure(["var Ref = (a)=> a + 1"], 'E1001:')
|
CheckDefFailure(["var Ref = (a)=> a + 1"], 'E1001:')
|
||||||
CheckDefFailure(["var Ref = (a) =>a + 1"], 'E1001:')
|
CheckDefFailure(["var Ref = (a) =>a + 1"], 'E1001:')
|
||||||
|
|
||||||
|
CheckDefSuccess(["var Ref: func(number): string = (a: number): string => 'x'"])
|
||||||
|
CheckDefSuccess(["var Ref: func(number): any = (a: number): any => 'x'"])
|
||||||
|
CheckDefFailure(["var Ref: func(number): number = (a: number): string => 'x'"], 'E1012:')
|
||||||
|
CheckDefFailure(["var Ref: func(number): string = (a: number): string => 99"], 'E1012:')
|
||||||
|
|
||||||
CheckDefFailure(["filter([1, 2], (k,v) => 1)"], 'E1069:', 1)
|
CheckDefFailure(["filter([1, 2], (k,v) => 1)"], 'E1069:', 1)
|
||||||
# error is in first line of the lambda
|
# error is in first line of the lambda
|
||||||
CheckDefFailure(["var L = (a) -> a + b"], 'E1001:', 1)
|
CheckDefFailure(["var L = (a) -> a + b"], 'E1001:', 1)
|
||||||
|
|
||||||
# TODO: lambda after -> doesn't work yet
|
# TODO: ->(lambda)() doesn't work yet
|
||||||
# assert_equal('xxxyyy', 'xxx'->((a, b) => a .. b)('yyy'))
|
# assert_equal('xxxyyy', 'xxx'->((a, b) => a .. b)('yyy'))
|
||||||
|
|
||||||
# CheckDefExecFailure(["var s = 'asdf'->{a -> a}('x')"],
|
# CheckDefExecFailure(["var s = 'asdf'->{a -> a}('x')"],
|
||||||
@ -1973,9 +1978,9 @@ def Test_expr7_new_lambda()
|
|||||||
# 'E1106: 2 arguments too many')
|
# 'E1106: 2 arguments too many')
|
||||||
# CheckDefFailure(["echo 'asdf'->{a -> a}(x)"], 'E1001:', 1)
|
# CheckDefFailure(["echo 'asdf'->{a -> a}(x)"], 'E1001:', 1)
|
||||||
|
|
||||||
CheckDefSuccess(['var Fx = (a) => {k1: 0,', ' k2: 1}'])
|
CheckDefSuccess(['var Fx = (a) => ({k1: 0,', ' k2: 1})'])
|
||||||
CheckDefFailure(['var Fx = (a) => {k1: 0', ' k2: 1}'], 'E722:', 2)
|
CheckDefFailure(['var Fx = (a) => ({k1: 0', ' k2: 1})'], 'E722:', 2)
|
||||||
CheckDefFailure(['var Fx = (a) => {k1: 0,', ' k2 1}'], 'E720:', 2)
|
CheckDefFailure(['var Fx = (a) => ({k1: 0,', ' k2 1})'], 'E720:', 2)
|
||||||
|
|
||||||
CheckDefSuccess(['var Fx = (a) => [0,', ' 1]'])
|
CheckDefSuccess(['var Fx = (a) => [0,', ' 1]'])
|
||||||
CheckDefFailure(['var Fx = (a) => [0', ' 1]'], 'E696:', 2)
|
CheckDefFailure(['var Fx = (a) => [0', ' 1]'], 'E696:', 2)
|
||||||
|
@ -349,7 +349,7 @@ parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs)
|
|||||||
// will get the type from the default value
|
// will get the type from the default value
|
||||||
type = &t_unknown;
|
type = &t_unknown;
|
||||||
else
|
else
|
||||||
type = parse_type(&p, &fp->uf_type_list);
|
type = parse_type(&p, &fp->uf_type_list, TRUE);
|
||||||
if (type == NULL)
|
if (type == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
fp->uf_arg_types[i] = type;
|
fp->uf_arg_types[i] = type;
|
||||||
@ -369,7 +369,7 @@ parse_argument_types(ufunc_T *fp, garray_T *argtypes, int varargs)
|
|||||||
// todo: get type from default value
|
// todo: get type from default value
|
||||||
fp->uf_va_type = &t_any;
|
fp->uf_va_type = &t_any;
|
||||||
else
|
else
|
||||||
fp->uf_va_type = parse_type(&p, &fp->uf_type_list);
|
fp->uf_va_type = parse_type(&p, &fp->uf_type_list, TRUE);
|
||||||
if (fp->uf_va_type == NULL)
|
if (fp->uf_va_type == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -460,17 +460,22 @@ register_cfunc(cfunc_T cb, cfunc_free_T cb_free, void *state)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip over "->" or "=>" after the arguments of a lambda.
|
* Skip over "->" or "=>" after the arguments of a lambda.
|
||||||
|
* If ": type" is found make "ret_type" point to "type".
|
||||||
* Return NULL if no valid arrow found.
|
* Return NULL if no valid arrow found.
|
||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
skip_arrow(char_u *start, int equal_arrow)
|
skip_arrow(char_u *start, int equal_arrow, char_u **ret_type)
|
||||||
{
|
{
|
||||||
char_u *s = start;
|
char_u *s = start;
|
||||||
|
|
||||||
if (equal_arrow)
|
if (equal_arrow)
|
||||||
{
|
{
|
||||||
if (*s == ':')
|
if (*s == ':')
|
||||||
s = skip_type(skipwhite(s + 1), TRUE);
|
{
|
||||||
|
s = skipwhite(s + 1);
|
||||||
|
*ret_type = s;
|
||||||
|
s = skip_type(s, TRUE);
|
||||||
|
}
|
||||||
s = skipwhite(s);
|
s = skipwhite(s);
|
||||||
if (*s != '=')
|
if (*s != '=')
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -503,6 +508,7 @@ get_lambda_tv(
|
|||||||
ufunc_T *fp = NULL;
|
ufunc_T *fp = NULL;
|
||||||
partial_T *pt = NULL;
|
partial_T *pt = NULL;
|
||||||
int varargs;
|
int varargs;
|
||||||
|
char_u *ret_type = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
char_u *s;
|
char_u *s;
|
||||||
char_u *start, *end;
|
char_u *start, *end;
|
||||||
@ -517,19 +523,20 @@ get_lambda_tv(
|
|||||||
ga_init(&newargs);
|
ga_init(&newargs);
|
||||||
ga_init(&newlines);
|
ga_init(&newlines);
|
||||||
|
|
||||||
// First, check if this is a lambda expression. "->" or "=>" must exist.
|
// First, check if this is really a lambda expression. "->" or "=>" must
|
||||||
|
// be found after the arguments.
|
||||||
s = skipwhite(*arg + 1);
|
s = skipwhite(*arg + 1);
|
||||||
ret = get_function_args(&s, equal_arrow ? ')' : '-', NULL,
|
ret = get_function_args(&s, equal_arrow ? ')' : '-', NULL,
|
||||||
types_optional ? &argtypes : NULL, types_optional,
|
types_optional ? &argtypes : NULL, types_optional,
|
||||||
NULL, NULL, TRUE, NULL, NULL);
|
NULL, NULL, TRUE, NULL, NULL);
|
||||||
if (ret == FAIL || skip_arrow(s, equal_arrow) == NULL)
|
if (ret == FAIL || skip_arrow(s, equal_arrow, &ret_type) == NULL)
|
||||||
{
|
{
|
||||||
if (types_optional)
|
if (types_optional)
|
||||||
ga_clear_strings(&argtypes);
|
ga_clear_strings(&argtypes);
|
||||||
return NOTDONE;
|
return NOTDONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the arguments again.
|
// Parse the arguments for real.
|
||||||
if (evaluate)
|
if (evaluate)
|
||||||
pnewargs = &newargs;
|
pnewargs = &newargs;
|
||||||
else
|
else
|
||||||
@ -538,7 +545,8 @@ get_lambda_tv(
|
|||||||
ret = get_function_args(arg, equal_arrow ? ')' : '-', pnewargs,
|
ret = get_function_args(arg, equal_arrow ? ')' : '-', pnewargs,
|
||||||
types_optional ? &argtypes : NULL, types_optional,
|
types_optional ? &argtypes : NULL, types_optional,
|
||||||
&varargs, NULL, FALSE, NULL, NULL);
|
&varargs, NULL, FALSE, NULL, NULL);
|
||||||
if (ret == FAIL || (*arg = skip_arrow(*arg, equal_arrow)) == NULL)
|
if (ret == FAIL
|
||||||
|
|| (*arg = skip_arrow(*arg, equal_arrow, &ret_type)) == NULL)
|
||||||
{
|
{
|
||||||
if (types_optional)
|
if (types_optional)
|
||||||
ga_clear_strings(&argtypes);
|
ga_clear_strings(&argtypes);
|
||||||
@ -551,11 +559,11 @@ get_lambda_tv(
|
|||||||
|
|
||||||
*arg = skipwhite_and_linebreak(*arg, evalarg);
|
*arg = skipwhite_and_linebreak(*arg, evalarg);
|
||||||
|
|
||||||
// Only recognize "{" as the start of a function body when followed by
|
// Recognize "{" as the start of a function body.
|
||||||
// white space, "{key: val}" is a dict.
|
if (equal_arrow && **arg == '{')
|
||||||
if (equal_arrow && **arg == '{' && IS_WHITE_OR_NUL((*arg)[1]))
|
|
||||||
{
|
{
|
||||||
// TODO: process the function body upto the "}".
|
// TODO: process the function body upto the "}".
|
||||||
|
// Return type is required then.
|
||||||
emsg("Lambda function body not supported yet");
|
emsg("Lambda function body not supported yet");
|
||||||
goto errret;
|
goto errret;
|
||||||
}
|
}
|
||||||
@ -619,9 +627,18 @@ get_lambda_tv(
|
|||||||
hash_add(&func_hashtab, UF2HIKEY(fp));
|
hash_add(&func_hashtab, UF2HIKEY(fp));
|
||||||
fp->uf_args = newargs;
|
fp->uf_args = newargs;
|
||||||
ga_init(&fp->uf_def_args);
|
ga_init(&fp->uf_def_args);
|
||||||
if (types_optional
|
if (types_optional)
|
||||||
&& parse_argument_types(fp, &argtypes, FALSE) == FAIL)
|
{
|
||||||
goto errret;
|
if (parse_argument_types(fp, &argtypes, FALSE) == FAIL)
|
||||||
|
goto errret;
|
||||||
|
if (ret_type != NULL)
|
||||||
|
{
|
||||||
|
fp->uf_ret_type = parse_type(&ret_type,
|
||||||
|
&fp->uf_type_list, TRUE);
|
||||||
|
if (fp->uf_ret_type == NULL)
|
||||||
|
goto errret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fp->uf_lines = newlines;
|
fp->uf_lines = newlines;
|
||||||
if (current_funccal != NULL && eval_lavars)
|
if (current_funccal != NULL && eval_lavars)
|
||||||
@ -3752,7 +3769,7 @@ define_function(exarg_T *eap, char_u *name_arg)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = ret_type;
|
p = ret_type;
|
||||||
fp->uf_ret_type = parse_type(&p, &fp->uf_type_list);
|
fp->uf_ret_type = parse_type(&p, &fp->uf_type_list, TRUE);
|
||||||
}
|
}
|
||||||
SOURCING_LNUM = lnum_save;
|
SOURCING_LNUM = lnum_save;
|
||||||
}
|
}
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2209,
|
||||||
/**/
|
/**/
|
||||||
2208,
|
2208,
|
||||||
/**/
|
/**/
|
||||||
|
@ -4118,11 +4118,9 @@ compile_expr7t(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
// Recognize <type>
|
// Recognize <type>
|
||||||
if (**arg == '<' && eval_isnamec1((*arg)[1]))
|
if (**arg == '<' && eval_isnamec1((*arg)[1]))
|
||||||
{
|
{
|
||||||
int called_emsg_before = called_emsg;
|
|
||||||
|
|
||||||
++*arg;
|
++*arg;
|
||||||
want_type = parse_type(arg, cctx->ctx_type_list);
|
want_type = parse_type(arg, cctx->ctx_type_list, TRUE);
|
||||||
if (called_emsg != called_emsg_before)
|
if (want_type == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
if (**arg != '>')
|
if (**arg != '>')
|
||||||
@ -4809,7 +4807,7 @@ compile_expr0(char_u **arg, cctx_T *cctx)
|
|||||||
* compile "return [expr]"
|
* compile "return [expr]"
|
||||||
*/
|
*/
|
||||||
static char_u *
|
static char_u *
|
||||||
compile_return(char_u *arg, int set_return_type, cctx_T *cctx)
|
compile_return(char_u *arg, int check_return_type, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
char_u *p = arg;
|
char_u *p = arg;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
@ -4824,8 +4822,10 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx)
|
|||||||
if (cctx->ctx_skip != SKIP_YES)
|
if (cctx->ctx_skip != SKIP_YES)
|
||||||
{
|
{
|
||||||
stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
if (set_return_type)
|
if (check_return_type && cctx->ctx_ufunc->uf_ret_type == NULL)
|
||||||
|
{
|
||||||
cctx->ctx_ufunc->uf_ret_type = stack_type;
|
cctx->ctx_ufunc->uf_ret_type = stack_type;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (cctx->ctx_ufunc->uf_ret_type->tt_type == VAR_VOID
|
if (cctx->ctx_ufunc->uf_ret_type->tt_type == VAR_VOID
|
||||||
@ -4843,7 +4843,7 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// "set_return_type" cannot be TRUE, only used for a lambda which
|
// "check_return_type" cannot be TRUE, only used for a lambda which
|
||||||
// always has an argument.
|
// always has an argument.
|
||||||
if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID
|
if (cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_VOID
|
||||||
&& cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_UNKNOWN)
|
&& cctx->ctx_ufunc->uf_ret_type->tt_type != VAR_UNKNOWN)
|
||||||
@ -5636,7 +5636,9 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
p = skipwhite(var_end + 1);
|
p = skipwhite(var_end + 1);
|
||||||
type = parse_type(&p, cctx->ctx_type_list);
|
type = parse_type(&p, cctx->ctx_type_list, TRUE);
|
||||||
|
if (type == NULL)
|
||||||
|
goto theend;
|
||||||
has_type = TRUE;
|
has_type = TRUE;
|
||||||
}
|
}
|
||||||
else if (lvar != NULL)
|
else if (lvar != NULL)
|
||||||
@ -7417,15 +7419,16 @@ add_def_function(ufunc_T *ufunc)
|
|||||||
* After ex_function() has collected all the function lines: parse and compile
|
* After ex_function() has collected all the function lines: parse and compile
|
||||||
* the lines into instructions.
|
* the lines into instructions.
|
||||||
* Adds the function to "def_functions".
|
* Adds the function to "def_functions".
|
||||||
* When "set_return_type" is set then set ufunc->uf_ret_type to the type of the
|
* When "check_return_type" is set then set ufunc->uf_ret_type to the type of
|
||||||
* return statement (used for lambda).
|
* the return statement (used for lambda). When uf_ret_type is already set
|
||||||
|
* then check that it matches.
|
||||||
* "outer_cctx" is set for a nested function.
|
* "outer_cctx" is set for a nested function.
|
||||||
* This can be used recursively through compile_lambda(), which may reallocate
|
* This can be used recursively through compile_lambda(), which may reallocate
|
||||||
* "def_functions".
|
* "def_functions".
|
||||||
* Returns OK or FAIL.
|
* Returns OK or FAIL.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx)
|
||||||
{
|
{
|
||||||
char_u *line = NULL;
|
char_u *line = NULL;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
@ -7797,7 +7800,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
|||||||
goto erret;
|
goto erret;
|
||||||
|
|
||||||
case CMD_return:
|
case CMD_return:
|
||||||
line = compile_return(p, set_return_type, &cctx);
|
line = compile_return(p, check_return_type, &cctx);
|
||||||
cctx.ctx_had_return = TRUE;
|
cctx.ctx_had_return = TRUE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -511,7 +511,6 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
|||||||
char_u *name;
|
char_u *name;
|
||||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
type_T *type;
|
type_T *type;
|
||||||
int called_emsg_before = called_emsg;
|
|
||||||
typval_T init_tv;
|
typval_T init_tv;
|
||||||
|
|
||||||
if (eap->cmdidx == CMD_final || eap->cmdidx == CMD_const)
|
if (eap->cmdidx == CMD_final || eap->cmdidx == CMD_const)
|
||||||
@ -548,8 +547,8 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
|||||||
|
|
||||||
// parse type
|
// parse type
|
||||||
p = skipwhite(p + 1);
|
p = skipwhite(p + 1);
|
||||||
type = parse_type(&p, &si->sn_type_list);
|
type = parse_type(&p, &si->sn_type_list, TRUE);
|
||||||
if (called_emsg != called_emsg_before)
|
if (type == NULL)
|
||||||
{
|
{
|
||||||
vim_free(name);
|
vim_free(name);
|
||||||
return p;
|
return p;
|
||||||
|
@ -596,28 +596,38 @@ skip_type(char_u *start, int optional)
|
|||||||
* Returns NULL in case of failure.
|
* Returns NULL in case of failure.
|
||||||
*/
|
*/
|
||||||
static type_T *
|
static type_T *
|
||||||
parse_type_member(char_u **arg, type_T *type, garray_T *type_gap)
|
parse_type_member(
|
||||||
|
char_u **arg,
|
||||||
|
type_T *type,
|
||||||
|
garray_T *type_gap,
|
||||||
|
int give_error)
|
||||||
{
|
{
|
||||||
type_T *member_type;
|
type_T *member_type;
|
||||||
int prev_called_emsg = called_emsg;
|
int prev_called_emsg = called_emsg;
|
||||||
|
|
||||||
if (**arg != '<')
|
if (**arg != '<')
|
||||||
{
|
{
|
||||||
if (*skipwhite(*arg) == '<')
|
if (give_error)
|
||||||
semsg(_(e_no_white_space_allowed_before_str), "<");
|
{
|
||||||
else
|
if (*skipwhite(*arg) == '<')
|
||||||
emsg(_(e_missing_type));
|
semsg(_(e_no_white_space_allowed_before_str), "<");
|
||||||
return type;
|
else
|
||||||
|
emsg(_(e_missing_type));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
|
|
||||||
member_type = parse_type(arg, type_gap);
|
member_type = parse_type(arg, type_gap, give_error);
|
||||||
|
if (member_type == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
if (**arg != '>' && called_emsg == prev_called_emsg)
|
if (**arg != '>' && called_emsg == prev_called_emsg)
|
||||||
{
|
{
|
||||||
emsg(_(e_missing_gt_after_type));
|
if (give_error)
|
||||||
return type;
|
emsg(_(e_missing_gt_after_type));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
++*arg;
|
++*arg;
|
||||||
|
|
||||||
@ -628,10 +638,11 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_gap)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a type at "arg" and advance over it.
|
* Parse a type at "arg" and advance over it.
|
||||||
* Return &t_any for failure.
|
* When "give_error" is TRUE give error messages, otherwise be quiet.
|
||||||
|
* Return NULL for failure.
|
||||||
*/
|
*/
|
||||||
type_T *
|
type_T *
|
||||||
parse_type(char_u **arg, garray_T *type_gap)
|
parse_type(char_u **arg, garray_T *type_gap, int give_error)
|
||||||
{
|
{
|
||||||
char_u *p = *arg;
|
char_u *p = *arg;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -673,7 +684,8 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
if (len == 4 && STRNCMP(*arg, "dict", len) == 0)
|
if (len == 4 && STRNCMP(*arg, "dict", len) == 0)
|
||||||
{
|
{
|
||||||
*arg += len;
|
*arg += len;
|
||||||
return parse_type_member(arg, &t_dict_any, type_gap);
|
return parse_type_member(arg, &t_dict_any,
|
||||||
|
type_gap, give_error);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -683,8 +695,9 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
*arg += len;
|
*arg += len;
|
||||||
return &t_float;
|
return &t_float;
|
||||||
#else
|
#else
|
||||||
emsg(_(e_this_vim_is_not_compiled_with_float_support));
|
if (give_error)
|
||||||
return &t_any;
|
emsg(_(e_this_vim_is_not_compiled_with_float_support));
|
||||||
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (len == 4 && STRNCMP(*arg, "func", len) == 0)
|
if (len == 4 && STRNCMP(*arg, "func", len) == 0)
|
||||||
@ -721,11 +734,15 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
}
|
}
|
||||||
else if (first_optional != -1)
|
else if (first_optional != -1)
|
||||||
{
|
{
|
||||||
emsg(_(e_mandatory_argument_after_optional_argument));
|
if (give_error)
|
||||||
return &t_any;
|
emsg(_(e_mandatory_argument_after_optional_argument));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_type[argcount++] = parse_type(&p, type_gap);
|
type = parse_type(&p, type_gap, give_error);
|
||||||
|
if (type == NULL)
|
||||||
|
return NULL;
|
||||||
|
arg_type[argcount++] = type;
|
||||||
|
|
||||||
// Nothing comes after "...{type}".
|
// Nothing comes after "...{type}".
|
||||||
if (flags & TTFLAG_VARARGS)
|
if (flags & TTFLAG_VARARGS)
|
||||||
@ -733,31 +750,35 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
|
|
||||||
if (*p != ',' && *skipwhite(p) == ',')
|
if (*p != ',' && *skipwhite(p) == ',')
|
||||||
{
|
{
|
||||||
semsg(_(e_no_white_space_allowed_before_str), ",");
|
if (give_error)
|
||||||
return &t_any;
|
semsg(_(e_no_white_space_allowed_before_str), ",");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
{
|
{
|
||||||
++p;
|
++p;
|
||||||
if (!VIM_ISWHITE(*p))
|
if (!VIM_ISWHITE(*p))
|
||||||
{
|
{
|
||||||
semsg(_(e_white_space_required_after_str), ",");
|
if (give_error)
|
||||||
return &t_any;
|
semsg(_(e_white_space_required_after_str), ",");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
if (argcount == MAX_FUNC_ARGS)
|
if (argcount == MAX_FUNC_ARGS)
|
||||||
{
|
{
|
||||||
emsg(_(e_too_many_argument_types));
|
if (give_error)
|
||||||
return &t_any;
|
emsg(_(e_too_many_argument_types));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
if (*p != ')')
|
if (*p != ')')
|
||||||
{
|
{
|
||||||
emsg(_(e_missing_close));
|
if (give_error)
|
||||||
return &t_any;
|
emsg(_(e_missing_close));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
*arg = p + 1;
|
*arg = p + 1;
|
||||||
}
|
}
|
||||||
@ -765,10 +786,12 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
{
|
{
|
||||||
// parse return type
|
// parse return type
|
||||||
++*arg;
|
++*arg;
|
||||||
if (!VIM_ISWHITE(**arg))
|
if (!VIM_ISWHITE(**arg) && give_error)
|
||||||
semsg(_(e_white_space_required_after_str), ":");
|
semsg(_(e_white_space_required_after_str), ":");
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
ret_type = parse_type(arg, type_gap);
|
ret_type = parse_type(arg, type_gap, give_error);
|
||||||
|
if (ret_type == NULL)
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
if (flags == 0 && first_optional == -1 && argcount <= 0)
|
if (flags == 0 && first_optional == -1 && argcount <= 0)
|
||||||
type = get_func_type(ret_type, argcount, type_gap);
|
type = get_func_type(ret_type, argcount, type_gap);
|
||||||
@ -783,7 +806,7 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
? argcount : first_optional;
|
? argcount : first_optional;
|
||||||
if (func_type_add_arg_types(type, argcount,
|
if (func_type_add_arg_types(type, argcount,
|
||||||
type_gap) == FAIL)
|
type_gap) == FAIL)
|
||||||
return &t_any;
|
return NULL;
|
||||||
mch_memmove(type->tt_args, arg_type,
|
mch_memmove(type->tt_args, arg_type,
|
||||||
sizeof(type_T *) * argcount);
|
sizeof(type_T *) * argcount);
|
||||||
}
|
}
|
||||||
@ -802,7 +825,8 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
if (len == 4 && STRNCMP(*arg, "list", len) == 0)
|
if (len == 4 && STRNCMP(*arg, "list", len) == 0)
|
||||||
{
|
{
|
||||||
*arg += len;
|
*arg += len;
|
||||||
return parse_type_member(arg, &t_list_any, type_gap);
|
return parse_type_member(arg, &t_list_any,
|
||||||
|
type_gap, give_error);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
@ -828,8 +852,9 @@ parse_type(char_u **arg, garray_T *type_gap)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
semsg(_(e_type_not_recognized_str), *arg);
|
if (give_error)
|
||||||
return &t_any;
|
semsg(_(e_type_not_recognized_str), *arg);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1016,9 +1041,12 @@ vartype_name(vartype_T type)
|
|||||||
char *
|
char *
|
||||||
type_name(type_T *type, char **tofree)
|
type_name(type_T *type, char **tofree)
|
||||||
{
|
{
|
||||||
char *name = vartype_name(type->tt_type);
|
char *name;
|
||||||
|
|
||||||
*tofree = NULL;
|
*tofree = NULL;
|
||||||
|
if (type == NULL)
|
||||||
|
return "[unknown]";
|
||||||
|
name = vartype_name(type->tt_type);
|
||||||
if (type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
|
if (type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
|
||||||
{
|
{
|
||||||
char *member_free;
|
char *member_free;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user