diff options
-rw-r--r-- | runtime/doc/vim9.txt | 39 | ||||
-rw-r--r-- | src/evalfunc.c | 11 | ||||
-rw-r--r-- | src/globals.h | 63 | ||||
-rw-r--r-- | src/structs.h | 6 | ||||
-rw-r--r-- | src/testdir/test_vim9_disassemble.vim | 26 | ||||
-rw-r--r-- | src/testdir/test_vim9_expr.vim | 2 | ||||
-rw-r--r-- | src/testdir/test_vim9_script.vim | 8 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim9compile.c | 205 |
9 files changed, 247 insertions, 115 deletions
diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 9128b62e7..1c180708a 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 Mar 01 +*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -249,8 +249,8 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE the function follows in the next lines, until the matching `:enddef`. - When {return-type} is omitted the function is not - expected to return anything. + When {return-type} is omitted or is "void" the + function is not expected to return anything. {arguments} is a sequence of zero or more argument declarations. There are three forms: @@ -296,29 +296,40 @@ The following builtin types are supported: float string blob - list<type> - dict<type> - (a: type, b: type): type + list<{type}> + dict<{type}> job channel func - partial + func({type}, ...) + func({type}, ...): {type} Not supported yet: - tuple<a: type, b: type, ...> + tuple<a: {type}, b: {type}, ...> -These types can be used in declarations, but no variable will have this type: - type|type +These types can be used in declarations, but no value will have this type: + {type}|{type} void any -There is no array type, use list<type> instead. For a list constant an +There is no array type, use list<{type}> instead. For a list constant an efficient implementation is used that avoids allocating lot of small pieces of memory. -A function defined with `:def` must declare the return type. If there is no -type then the function doesn't return anything. "void" is used in type -declarations. +A partial and function can be declared in more or less specific ways: +func any kind of function reference, no type + checking +func: {type} any number and type of arguments with specific + return type +func({type} ...) function with argument types, does not return + a value +func({type} ...): {type} function with argument types and return type + +If the return type is "void" the function does not return a value. + +The reference can also be a |Partial|, in which case it stores extra arguments +and/or a dictionary, which are not visible to the caller. Since they are +called in the same way the declaration is the same. Custom types can be defined with `:type`: > :type MyList list<string> diff --git a/src/evalfunc.c b/src/evalfunc.c index 0db848cb3..f43ac082c 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -336,11 +336,6 @@ ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED) return &t_func_any; } static type_T * -ret_partial_any(int argcount UNUSED, type_T **argtypes UNUSED) -{ - return &t_partial_any; -} - static type_T * ret_channel(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_channel; @@ -564,7 +559,7 @@ static funcentry_T global_functions[] = {"foldtext", 0, 0, 0, ret_string, f_foldtext}, {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult}, {"foreground", 0, 0, 0, ret_void, f_foreground}, - {"funcref", 1, 3, FEARG_1, ret_partial_any, f_funcref}, + {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref}, {"function", 1, 3, FEARG_1, ret_f_function, f_function}, {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect}, {"get", 2, 3, FEARG_1, ret_any, f_get}, @@ -961,7 +956,7 @@ static funcentry_T global_functions[] = {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function}, {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)}, {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list}, - {"test_null_partial", 0, 0, 0, ret_partial_any, f_test_null_partial}, + {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial}, {"test_null_string", 0, 0, 0, ret_string, f_test_null_string}, {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set}, {"test_override", 2, 2, FEARG_2, ret_void, f_test_override}, @@ -2902,7 +2897,7 @@ ret_f_function(int argcount, type_T **argtypes UNUSED) { if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING) return &t_func_any; - return &t_partial_void; + return &t_func_void; } /* diff --git a/src/globals.h b/src/globals.h index ac48a793d..59f22d1af 100644 --- a/src/globals.h +++ b/src/globals.h @@ -379,36 +379,39 @@ EXTERN sctx_T current_sctx INIT4(0, 0, 0, 0); // Commonly used types. -EXTERN type_T t_any INIT4(VAR_UNKNOWN, 0, NULL, NULL); -EXTERN type_T t_void INIT4(VAR_VOID, 0, NULL, NULL); -EXTERN type_T t_bool INIT4(VAR_BOOL, 0, NULL, NULL); -EXTERN type_T t_special INIT4(VAR_SPECIAL, 0, NULL, NULL); -EXTERN type_T t_number INIT4(VAR_NUMBER, 0, NULL, NULL); -EXTERN type_T t_float INIT4(VAR_FLOAT, 0, NULL, NULL); -EXTERN type_T t_string INIT4(VAR_STRING, 0, NULL, NULL); -EXTERN type_T t_blob INIT4(VAR_BLOB, 0, NULL, NULL); -EXTERN type_T t_job INIT4(VAR_JOB, 0, NULL, NULL); -EXTERN type_T t_channel INIT4(VAR_CHANNEL, 0, NULL, NULL); - -EXTERN type_T t_func_void INIT4(VAR_FUNC, -1, &t_void, NULL); -EXTERN type_T t_func_any INIT4(VAR_FUNC, -1, &t_any, NULL); - -EXTERN type_T t_partial_void INIT4(VAR_PARTIAL, -1, &t_void, NULL); -EXTERN type_T t_partial_any INIT4(VAR_PARTIAL, -1, &t_any, NULL); - -EXTERN type_T t_list_any INIT4(VAR_LIST, 0, &t_any, NULL); -EXTERN type_T t_dict_any INIT4(VAR_DICT, 0, &t_any, NULL); -EXTERN type_T t_list_empty INIT4(VAR_LIST, 0, &t_void, NULL); -EXTERN type_T t_dict_empty INIT4(VAR_DICT, 0, &t_void, NULL); - -EXTERN type_T t_list_bool INIT4(VAR_LIST, 0, &t_bool, NULL); -EXTERN type_T t_list_number INIT4(VAR_LIST, 0, &t_number, NULL); -EXTERN type_T t_list_string INIT4(VAR_LIST, 0, &t_string, NULL); -EXTERN type_T t_list_dict_any INIT4(VAR_LIST, 0, &t_dict_any, NULL); - -EXTERN type_T t_dict_bool INIT4(VAR_DICT, 0, &t_bool, NULL); -EXTERN type_T t_dict_number INIT4(VAR_DICT, 0, &t_number, NULL); -EXTERN type_T t_dict_string INIT4(VAR_DICT, 0, &t_string, NULL); +EXTERN type_T t_any INIT5(VAR_UNKNOWN, 0, 0, NULL, NULL); +EXTERN type_T t_void INIT5(VAR_VOID, 0, 0, NULL, NULL); +EXTERN type_T t_bool INIT5(VAR_BOOL, 0, 0, NULL, NULL); +EXTERN type_T t_special INIT5(VAR_SPECIAL, 0, 0, NULL, NULL); +EXTERN type_T t_number INIT5(VAR_NUMBER, 0, 0, NULL, NULL); +EXTERN type_T t_float INIT5(VAR_FLOAT, 0, 0, NULL, NULL); +EXTERN type_T t_string INIT5(VAR_STRING, 0, 0, NULL, NULL); +EXTERN type_T t_blob INIT5(VAR_BLOB, 0, 0, NULL, NULL); +EXTERN type_T t_job INIT5(VAR_JOB, 0, 0, NULL, NULL); +EXTERN type_T t_channel INIT5(VAR_CHANNEL, 0, 0, NULL, NULL); + +EXTERN type_T t_func_void INIT5(VAR_FUNC, -1, 0, &t_void, NULL); +EXTERN type_T t_func_any INIT5(VAR_FUNC, -1, 0, &t_any, NULL); +EXTERN type_T t_func_number INIT5(VAR_FUNC, -1, 0, &t_number, NULL); +EXTERN type_T t_func_string INIT5(VAR_FUNC, -1, 0, &t_string, NULL); +EXTERN type_T t_func_0_void INIT5(VAR_FUNC, 0, 0, &t_void, NULL); +EXTERN type_T t_func_0_any INIT5(VAR_FUNC, 0, 0, &t_any, NULL); +EXTERN type_T t_func_0_number INIT5(VAR_FUNC, 0, 0, &t_number, NULL); +EXTERN type_T t_func_0_string INIT5(VAR_FUNC, 0, 0, &t_string, NULL); + +EXTERN type_T t_list_any INIT5(VAR_LIST, 0, 0, &t_any, NULL); +EXTERN type_T t_dict_any INIT5(VAR_DICT, 0, 0, &t_any, NULL); +EXTERN type_T t_list_empty INIT5(VAR_LIST, 0, 0, &t_void, NULL); +EXTERN type_T t_dict_empty INIT5(VAR_DICT, 0, 0, &t_void, NULL); + +EXTERN type_T t_list_bool INIT5(VAR_LIST, 0, 0, &t_bool, NULL); +EXTERN type_T t_list_number INIT5(VAR_LIST, 0, 0, &t_number, NULL); +EXTERN type_T t_list_string INIT5(VAR_LIST, 0, 0, &t_string, NULL); +EXTERN type_T t_list_dict_any INIT5(VAR_LIST, 0, 0, &t_dict_any, NULL); + +EXTERN type_T t_dict_bool INIT5(VAR_DICT, 0, 0, &t_bool, NULL); +EXTERN type_T t_dict_number INIT5(VAR_DICT, 0, 0, &t_number, NULL); +EXTERN type_T t_dict_string INIT5(VAR_DICT, 0, 0, &t_string, NULL); #endif diff --git a/src/structs.h b/src/structs.h index 9f3628e3c..efc74da17 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1342,10 +1342,14 @@ typedef struct type_S type_T; struct type_S { vartype_T tt_type; short tt_argcount; // for func, partial, -1 for unknown + short tt_flags; // TTFLAG_ values type_T *tt_member; // for list, dict, func return type - type_T *tt_args; // func arguments + type_T **tt_args; // func arguments, allocated }; +#define TTFLAG_VARARGS 1 // func args ends with "..." +#define TTFLAG_OPTARG 2 // func arg type with "?" + /* * Structure to hold an internal variable without a name. */ diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 36c098c7e..e71782b97 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -362,8 +362,7 @@ enddef def WithFunc() let funky1: func let funky2: func = function("len") - let party1: partial - let party2: partial = funcref("UserFunc") + let party2: func = funcref("UserFunc") enddef def Test_disassemble_function() @@ -376,15 +375,12 @@ def Test_disassemble_function() \ .. '2 PUSHS "len".*' \ .. '3 BCALL function(argc 1).*' \ .. '4 STORE $1.*' - \ .. 'let party1: partial.*' - \ .. '5 PUSHPARTIAL "\[none]".*' - \ .. '6 STORE $2.*' - \ .. 'let party2: partial = funcref("UserFunc").*' - \ .. '7 PUSHS "UserFunc".*' - \ .. '8 BCALL funcref(argc 1).*' - \ .. '9 STORE $3.*' - \ .. '10 PUSHNR 0.*' - \ .. '11 RETURN.*' + \ .. 'let party2: func = funcref("UserFunc").*' + \ .. '\d PUSHS "UserFunc".*' + \ .. '\d BCALL funcref(argc 1).*' + \ .. '\d STORE $2.*' + \ .. '\d PUSHNR 0.*' + \ .. '\d RETURN.*' \, instr) enddef @@ -753,10 +749,10 @@ def Test_disassemble_compare() \ ['#{a:1} is #{x:2}', 'COMPAREDICT is'], \ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'], \ - \ ['{->33} == {->44}', 'COMPAREPARTIAL =='], - \ ['{->33} != {->44}', 'COMPAREPARTIAL !='], - \ ['{->33} is {->44}', 'COMPAREPARTIAL is'], - \ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'], + \ ['{->33} == {->44}', 'COMPAREFUNC =='], + \ ['{->33} != {->44}', 'COMPAREFUNC !='], + \ ['{->33} is {->44}', 'COMPAREFUNC is'], + \ ['{->33} isnot {->44}', 'COMPAREFUNC isnot'], \ \ ['77 == g:xx', 'COMPAREANY =='], \ ['77 != g:xx', 'COMPAREANY !='], diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 8f27c6d84..d9c20acb1 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -461,7 +461,7 @@ func Test_expr4_fails() call CheckDefFailureMult(['let j: job', 'let chan: channel', 'let r = j == chan'], 'Cannot compare job with channel') call CheckDefFailureMult(['let j: job', 'let x: list<any>', 'let r = j == x'], 'Cannot compare job with list') call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 'Cannot compare job with func') - call CheckDefFailureMult(['let j: job', 'let x: partial', 'let r = j == x'], 'Cannot compare job with partial') + call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 'Cannot compare job with func') endfunc " test addition, subtraction, concatenation diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 518f60c62..cf12e85bb 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -68,8 +68,7 @@ def Test_assignment() endif let funky1: func let funky2: func = function('len') - let party1: partial - let party2: partial = funcref('Test_syntax') + let party2: func = funcref('Test_syntax') " type becomes list<any> let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] @@ -157,9 +156,6 @@ def Test_assignment() let thefunc: func assert_equal(test_null_function(), thefunc) - let thepartial: partial - assert_equal(test_null_partial(), thepartial) - let thelist: list<any> assert_equal([], thelist) @@ -213,7 +209,7 @@ func Test_assignment_failure() call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:') call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number but got void') - call CheckDefFailure(['let var: dict <number>'], 'E1007:') + call CheckDefFailure(['let var: dict <number>'], 'E1068:') call CheckDefFailure(['let var: dict<number'], 'E1009:') endfunc diff --git a/src/version.c b/src/version.c index 38ab53155..f0823995e 100644 --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 508, +/**/ 507, /**/ 506, diff --git a/src/vim9compile.c b/src/vim9compile.c index 3ce04a14a..b64f8efd5 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -224,7 +224,7 @@ check_defined(char_u *p, int len, cctx_T *cctx) } static type_T * -get_list_type(type_T *member_type, garray_T *type_list) +get_list_type(type_T *member_type, garray_T *type_gap) { type_T *type; @@ -241,17 +241,19 @@ get_list_type(type_T *member_type, garray_T *type_list) return &t_list_string; // Not a common type, create a new entry. - if (ga_grow(type_list, 1) == FAIL) + if (ga_grow(type_gap, 1) == FAIL) return &t_any; - type = ((type_T *)type_list->ga_data) + type_list->ga_len; - ++type_list->ga_len; + type = ((type_T *)type_gap->ga_data) + type_gap->ga_len; + ++type_gap->ga_len; type->tt_type = VAR_LIST; type->tt_member = member_type; + type->tt_argcount = 0; + type->tt_args = NULL; return type; } static type_T * -get_dict_type(type_T *member_type, garray_T *type_list) +get_dict_type(type_T *member_type, garray_T *type_gap) { type_T *type; @@ -268,12 +270,68 @@ get_dict_type(type_T *member_type, garray_T *type_list) return &t_dict_string; // Not a common type, create a new entry. - if (ga_grow(type_list, 1) == FAIL) + if (ga_grow(type_gap, 1) == FAIL) return &t_any; - type = ((type_T *)type_list->ga_data) + type_list->ga_len; - ++type_list->ga_len; + type = ((type_T *)type_gap->ga_data) + type_gap->ga_len; + ++type_gap->ga_len; type->tt_type = VAR_DICT; type->tt_member = member_type; + type->tt_argcount = 0; + type->tt_args = NULL; + return type; +} + +/* + * Get a function type, based on the return type "ret_type". + * If "argcount" is -1 or 0 a predefined type can be used. + * If "argcount" > 0 always create a new type, so that arguments can be added. + */ + static type_T * +get_func_type(type_T *ret_type, int argcount, garray_T *type_gap) +{ + type_T *type; + + // recognize commonly used types + if (argcount <= 0) + { + if (ret_type == &t_void) + { + if (argcount == 0) + return &t_func_0_void; + else + return &t_func_void; + } + if (ret_type == &t_any) + { + if (argcount == 0) + return &t_func_0_any; + else + return &t_func_any; + } + if (ret_type == &t_number) + { + if (argcount == 0) + return &t_func_0_number; + else + return &t_func_number; + } + if (ret_type == &t_string) + { + if (argcount == 0) + return &t_func_0_string; + else + return &t_func_string; + } + } + + // Not a common type or has arguments, create a new entry. + if (ga_grow(type_gap, 1) == FAIL) + return &t_any; + type = ((type_T *)type_gap->ga_data) + type_gap->ga_len; + ++type_gap->ga_len; + type->tt_type = VAR_FUNC; + type->tt_member = ret_type; + type->tt_args = NULL; return type; } @@ -774,8 +832,7 @@ generate_PUSHPARTIAL(cctx_T *cctx, partial_T *part) isn_T *isn; RETURN_OK_IF_SKIP(cctx); - if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, - &t_partial_any)) == NULL) + if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, &t_func_any)) == NULL) return FAIL; isn->isn_arg.partial = part; @@ -942,7 +999,6 @@ generate_NEWLIST(cctx_T *cctx, int count) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; - garray_T *type_list = cctx->ctx_type_list; type_T *type; type_T *member; @@ -960,7 +1016,7 @@ generate_NEWLIST(cctx_T *cctx, int count) member = ((type_T **)stack->ga_data)[stack->ga_len]; else member = &t_void; - type = get_list_type(member, type_list); + type = get_list_type(member, cctx->ctx_type_list); // add the list type to the type stack if (ga_grow(stack, 1) == FAIL) @@ -979,7 +1035,6 @@ generate_NEWDICT(cctx_T *cctx, int count) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; - garray_T *type_list = cctx->ctx_type_list; type_T *type; type_T *member; @@ -997,7 +1052,7 @@ generate_NEWDICT(cctx_T *cctx, int count) member = ((type_T **)stack->ga_data)[stack->ga_len + 1]; else member = &t_void; - type = get_dict_type(member, type_list); + type = get_dict_type(member, cctx->ctx_type_list); // add the dict type to the type stack if (ga_grow(stack, 1) == FAIL) @@ -1024,7 +1079,7 @@ generate_FUNCREF(cctx_T *cctx, int dfunc_idx) if (ga_grow(stack, 1) == FAIL) return FAIL; - ((type_T **)stack->ga_data)[stack->ga_len] = &t_partial_any; + ((type_T **)stack->ga_data)[stack->ga_len] = &t_func_any; // TODO: argument and return types ++stack->ga_len; @@ -1298,6 +1353,8 @@ generate_EXEC(cctx_T *cctx, char_u *line) static char e_white_both[] = N_("E1004: white space required before and after '%s'"); +static char e_white_after[] = N_("E1069: white space required after '%s'"); +static char e_no_white_before[] = N_("E1068: No white space allowed before '%s'"); /* * Reserve space for a local variable. @@ -1385,11 +1442,11 @@ skip_type(char_u *start) /* * Parse the member type: "<type>" and return "type" with the member set. - * Use "type_list" if a new type needs to be added. + * Use "type_gap" if a new type needs to be added. * Returns NULL in case of failure. */ static type_T * -parse_type_member(char_u **arg, type_T *type, garray_T *type_list) +parse_type_member(char_u **arg, type_T *type, garray_T *type_gap) { type_T *member_type; int prev_called_emsg = called_emsg; @@ -1397,14 +1454,14 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_list) if (**arg != '<') { if (*skipwhite(*arg) == '<') - emsg(_("E1007: No white space allowed before <")); + semsg(_(e_no_white_before), "<"); else emsg(_("E1008: Missing <type>")); return type; } *arg = skipwhite(*arg + 1); - member_type = parse_type(arg, type_list); + member_type = parse_type(arg, type_gap); *arg = skipwhite(*arg); if (**arg != '>' && called_emsg == prev_called_emsg) @@ -1415,8 +1472,8 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_list) ++*arg; if (type->tt_type == VAR_LIST) - return get_list_type(member_type, type_list); - return get_dict_type(member_type, type_list); + return get_list_type(member_type, type_gap); + return get_dict_type(member_type, type_gap); } /* @@ -1424,7 +1481,7 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_list) * Return &t_any for failure. */ type_T * -parse_type(char_u **arg, garray_T *type_list) +parse_type(char_u **arg, garray_T *type_gap) { char_u *p = *arg; size_t len; @@ -1466,7 +1523,7 @@ parse_type(char_u **arg, garray_T *type_list) if (len == 4 && STRNCMP(*arg, "dict", len) == 0) { *arg += len; - return parse_type_member(arg, &t_dict_any, type_list); + return parse_type_member(arg, &t_dict_any, type_gap); } break; case 'f': @@ -1482,9 +1539,85 @@ parse_type(char_u **arg, garray_T *type_list) } if (len == 4 && STRNCMP(*arg, "func", len) == 0) { + type_T *type; + type_T *ret_type = &t_void; + int argcount = -1; + int flags = 0; + type_T *arg_type[MAX_FUNC_ARGS + 1]; + + // func({type}, ...): {type} *arg += len; - // TODO: arguments and return type - return &t_func_any; + if (**arg == '(') + { + p = ++*arg; + argcount = 0; + while (*p != NUL && *p != ')') + { + if (STRNCMP(p, "...", 3) == 0) + { + flags |= TTFLAG_VARARGS; + break; + } + arg_type[argcount++] = parse_type(&p, type_gap); + + if (*p != ',' && *skipwhite(p) == ',') + { + semsg(_(e_no_white_before), ","); + return &t_any; + } + if (*p == ',') + { + ++p; + if (!VIM_ISWHITE(*p)) + semsg(_(e_white_after), ","); + } + p = skipwhite(p); + if (argcount == MAX_FUNC_ARGS) + { + emsg(_("E740: Too many argument types")); + return &t_any; + } + } + + p = skipwhite(p); + if (*p != ')') + { + emsg(_(e_missing_close)); + return &t_any; + } + *arg = p + 1; + } + if (**arg == ':') + { + // parse return type + ++*arg; + if (!VIM_ISWHITE(*p)) + semsg(_(e_white_after), ":"); + *arg = skipwhite(*arg); + ret_type = parse_type(arg, type_gap); + } + type = get_func_type(ret_type, flags == 0 ? argcount : 99, + type_gap); + if (flags != 0) + type->tt_flags = flags; + if (argcount > 0) + { + int type_ptr_cnt = (sizeof(type_T *) * argcount + + sizeof(type_T) - 1) / sizeof(type_T); + + type->tt_argcount = argcount; + // Get space from "type_gap" to avoid having to keep track + // of the pointer and freeing it. + ga_grow(type_gap, type_ptr_cnt); + if (ga_grow(type_gap, type_ptr_cnt) == FAIL) + return &t_any; + type->tt_args = + ((type_T **)type_gap->ga_data) + type_gap->ga_len; + type_gap->ga_len += type_ptr_cnt; + mch_memmove(type->tt_args, arg_type, + sizeof(type_T *) * argcount); + } + return type; } break; case 'j': @@ -1498,7 +1631,7 @@ parse_type(char_u **arg, garray_T *type_list) if (len == 4 && STRNCMP(*arg, "list", len) == 0) { *arg += len; - return parse_type_member(arg, &t_list_any, type_list); + return parse_type_member(arg, &t_list_any, type_gap); } break; case 'n': @@ -1508,14 +1641,6 @@ parse_type(char_u **arg, garray_T *type_list) return &t_number; } break; - case 'p': - if (len == 7 && STRNCMP(*arg, "partial", len) == 0) - { - *arg += len; - // TODO: arguments and return type - return &t_partial_any; - } - break; case 's': if (len == 6 && STRNCMP(*arg, "string", len) == 0) { @@ -1574,7 +1699,7 @@ equal_type(type_T *type1, type_T *type2) * "type2" and "dest" may be the same. */ static void -common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_list) +common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap) { if (equal_type(type1, type2)) { @@ -1588,11 +1713,11 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_list) { type_T *common; - common_type(type1->tt_member, type2->tt_member, &common, type_list); + common_type(type1->tt_member, type2->tt_member, &common, type_gap); if (type1->tt_type == VAR_LIST) - *dest = get_list_type(common, type_list); + *dest = get_list_type(common, type_gap); else - *dest = get_dict_type(common, type_list); + *dest = get_dict_type(common, type_gap); return; } // TODO: VAR_FUNC and VAR_PARTIAL @@ -1962,14 +2087,14 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount) if (*p != ',' && *skipwhite(p) == ',') { - emsg(_("E1068: No white space allowed before ,")); + semsg(_(e_no_white_before), ","); p = skipwhite(p); } if (*p == ',') { ++p; if (!VIM_ISWHITE(*p)) - emsg(_("E1069: white space required after ,")); + semsg(_(e_white_after), ","); } p = skipwhite(p); } |