forked from aniani/vim
patch 8.2.0508: Vim9: func and partial types not done yet
Problem: Vim9: func and partial types not done yet Solution: Fill in details about func declaration, drop a separate partial declaration.
This commit is contained in:
parent
5259275347
commit
d77a8525d5
@ -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
|
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
|
the function follows in the next lines, until the
|
||||||
matching `:enddef`.
|
matching `:enddef`.
|
||||||
|
|
||||||
When {return-type} is omitted the function is not
|
When {return-type} is omitted or is "void" the
|
||||||
expected to return anything.
|
function is not expected to return anything.
|
||||||
|
|
||||||
{arguments} is a sequence of zero or more argument
|
{arguments} is a sequence of zero or more argument
|
||||||
declarations. There are three forms:
|
declarations. There are three forms:
|
||||||
@ -296,29 +296,40 @@ The following builtin types are supported:
|
|||||||
float
|
float
|
||||||
string
|
string
|
||||||
blob
|
blob
|
||||||
list<type>
|
list<{type}>
|
||||||
dict<type>
|
dict<{type}>
|
||||||
(a: type, b: type): type
|
|
||||||
job
|
job
|
||||||
channel
|
channel
|
||||||
func
|
func
|
||||||
partial
|
func({type}, ...)
|
||||||
|
func({type}, ...): {type}
|
||||||
|
|
||||||
Not supported yet:
|
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:
|
These types can be used in declarations, but no value will have this type:
|
||||||
type|type
|
{type}|{type}
|
||||||
void
|
void
|
||||||
any
|
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
|
efficient implementation is used that avoids allocating lot of small pieces of
|
||||||
memory.
|
memory.
|
||||||
|
|
||||||
A function defined with `:def` must declare the return type. If there is no
|
A partial and function can be declared in more or less specific ways:
|
||||||
type then the function doesn't return anything. "void" is used in type
|
func any kind of function reference, no type
|
||||||
declarations.
|
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`: >
|
Custom types can be defined with `:type`: >
|
||||||
:type MyList list<string>
|
:type MyList list<string>
|
||||||
|
@ -336,11 +336,6 @@ ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
|||||||
return &t_func_any;
|
return &t_func_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
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)
|
ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_channel;
|
return &t_channel;
|
||||||
@ -564,7 +559,7 @@ static funcentry_T global_functions[] =
|
|||||||
{"foldtext", 0, 0, 0, ret_string, f_foldtext},
|
{"foldtext", 0, 0, 0, ret_string, f_foldtext},
|
||||||
{"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
|
{"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
|
||||||
{"foreground", 0, 0, 0, ret_void, f_foreground},
|
{"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},
|
{"function", 1, 3, FEARG_1, ret_f_function, f_function},
|
||||||
{"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
|
{"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
|
||||||
{"get", 2, 3, FEARG_1, ret_any, f_get},
|
{"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_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_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_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_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_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},
|
{"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)
|
if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
|
||||||
return &t_func_any;
|
return &t_func_any;
|
||||||
return &t_partial_void;
|
return &t_func_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -379,36 +379,39 @@ EXTERN sctx_T current_sctx INIT4(0, 0, 0, 0);
|
|||||||
|
|
||||||
|
|
||||||
// Commonly used types.
|
// Commonly used types.
|
||||||
EXTERN type_T t_any INIT4(VAR_UNKNOWN, 0, NULL, NULL);
|
EXTERN type_T t_any INIT5(VAR_UNKNOWN, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_void INIT4(VAR_VOID, 0, NULL, NULL);
|
EXTERN type_T t_void INIT5(VAR_VOID, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_bool INIT4(VAR_BOOL, 0, NULL, NULL);
|
EXTERN type_T t_bool INIT5(VAR_BOOL, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_special INIT4(VAR_SPECIAL, 0, NULL, NULL);
|
EXTERN type_T t_special INIT5(VAR_SPECIAL, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_number INIT4(VAR_NUMBER, 0, NULL, NULL);
|
EXTERN type_T t_number INIT5(VAR_NUMBER, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_float INIT4(VAR_FLOAT, 0, NULL, NULL);
|
EXTERN type_T t_float INIT5(VAR_FLOAT, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_string INIT4(VAR_STRING, 0, NULL, NULL);
|
EXTERN type_T t_string INIT5(VAR_STRING, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_blob INIT4(VAR_BLOB, 0, NULL, NULL);
|
EXTERN type_T t_blob INIT5(VAR_BLOB, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_job INIT4(VAR_JOB, 0, NULL, NULL);
|
EXTERN type_T t_job INIT5(VAR_JOB, 0, 0, NULL, NULL);
|
||||||
EXTERN type_T t_channel INIT4(VAR_CHANNEL, 0, NULL, NULL);
|
EXTERN type_T t_channel INIT5(VAR_CHANNEL, 0, 0, NULL, NULL);
|
||||||
|
|
||||||
EXTERN type_T t_func_void INIT4(VAR_FUNC, -1, &t_void, NULL);
|
EXTERN type_T t_func_void INIT5(VAR_FUNC, -1, 0, &t_void, NULL);
|
||||||
EXTERN type_T t_func_any INIT4(VAR_FUNC, -1, &t_any, 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_partial_void INIT4(VAR_PARTIAL, -1, &t_void, NULL);
|
EXTERN type_T t_list_any INIT5(VAR_LIST, 0, 0, &t_any, NULL);
|
||||||
EXTERN type_T t_partial_any INIT4(VAR_PARTIAL, -1, &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_any INIT4(VAR_LIST, 0, &t_any, NULL);
|
EXTERN type_T t_list_bool INIT5(VAR_LIST, 0, 0, &t_bool, NULL);
|
||||||
EXTERN type_T t_dict_any INIT4(VAR_DICT, 0, &t_any, NULL);
|
EXTERN type_T t_list_number INIT5(VAR_LIST, 0, 0, &t_number, NULL);
|
||||||
EXTERN type_T t_list_empty INIT4(VAR_LIST, 0, &t_void, NULL);
|
EXTERN type_T t_list_string INIT5(VAR_LIST, 0, 0, &t_string, NULL);
|
||||||
EXTERN type_T t_dict_empty INIT4(VAR_DICT, 0, &t_void, NULL);
|
EXTERN type_T t_list_dict_any INIT5(VAR_LIST, 0, 0, &t_dict_any, NULL);
|
||||||
|
|
||||||
EXTERN type_T t_list_bool INIT4(VAR_LIST, 0, &t_bool, NULL);
|
EXTERN type_T t_dict_bool INIT5(VAR_DICT, 0, 0, &t_bool, NULL);
|
||||||
EXTERN type_T t_list_number INIT4(VAR_LIST, 0, &t_number, NULL);
|
EXTERN type_T t_dict_number INIT5(VAR_DICT, 0, 0, &t_number, NULL);
|
||||||
EXTERN type_T t_list_string INIT4(VAR_LIST, 0, &t_string, NULL);
|
EXTERN type_T t_dict_string INIT5(VAR_DICT, 0, 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);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1342,10 +1342,14 @@ typedef struct type_S type_T;
|
|||||||
struct type_S {
|
struct type_S {
|
||||||
vartype_T tt_type;
|
vartype_T tt_type;
|
||||||
short tt_argcount; // for func, partial, -1 for unknown
|
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_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.
|
* Structure to hold an internal variable without a name.
|
||||||
*/
|
*/
|
||||||
|
@ -362,8 +362,7 @@ enddef
|
|||||||
def WithFunc()
|
def WithFunc()
|
||||||
let funky1: func
|
let funky1: func
|
||||||
let funky2: func = function("len")
|
let funky2: func = function("len")
|
||||||
let party1: partial
|
let party2: func = funcref("UserFunc")
|
||||||
let party2: partial = funcref("UserFunc")
|
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_disassemble_function()
|
def Test_disassemble_function()
|
||||||
@ -376,15 +375,12 @@ def Test_disassemble_function()
|
|||||||
\ .. '2 PUSHS "len".*'
|
\ .. '2 PUSHS "len".*'
|
||||||
\ .. '3 BCALL function(argc 1).*'
|
\ .. '3 BCALL function(argc 1).*'
|
||||||
\ .. '4 STORE $1.*'
|
\ .. '4 STORE $1.*'
|
||||||
\ .. 'let party1: partial.*'
|
\ .. 'let party2: func = funcref("UserFunc").*'
|
||||||
\ .. '5 PUSHPARTIAL "\[none]".*'
|
\ .. '\d PUSHS "UserFunc".*'
|
||||||
\ .. '6 STORE $2.*'
|
\ .. '\d BCALL funcref(argc 1).*'
|
||||||
\ .. 'let party2: partial = funcref("UserFunc").*'
|
\ .. '\d STORE $2.*'
|
||||||
\ .. '7 PUSHS "UserFunc".*'
|
\ .. '\d PUSHNR 0.*'
|
||||||
\ .. '8 BCALL funcref(argc 1).*'
|
\ .. '\d RETURN.*'
|
||||||
\ .. '9 STORE $3.*'
|
|
||||||
\ .. '10 PUSHNR 0.*'
|
|
||||||
\ .. '11 RETURN.*'
|
|
||||||
\, instr)
|
\, instr)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
@ -753,10 +749,10 @@ def Test_disassemble_compare()
|
|||||||
\ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
|
\ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
|
||||||
\ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
|
\ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
|
||||||
\
|
\
|
||||||
\ ['{->33} == {->44}', 'COMPAREPARTIAL =='],
|
\ ['{->33} == {->44}', 'COMPAREFUNC =='],
|
||||||
\ ['{->33} != {->44}', 'COMPAREPARTIAL !='],
|
\ ['{->33} != {->44}', 'COMPAREFUNC !='],
|
||||||
\ ['{->33} is {->44}', 'COMPAREPARTIAL is'],
|
\ ['{->33} is {->44}', 'COMPAREFUNC is'],
|
||||||
\ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'],
|
\ ['{->33} isnot {->44}', 'COMPAREFUNC isnot'],
|
||||||
\
|
\
|
||||||
\ ['77 == g:xx', 'COMPAREANY =='],
|
\ ['77 == g:xx', 'COMPAREANY =='],
|
||||||
\ ['77 != g:xx', 'COMPAREANY !='],
|
\ ['77 != g:xx', 'COMPAREANY !='],
|
||||||
|
@ -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 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: 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: 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
|
endfunc
|
||||||
|
|
||||||
" test addition, subtraction, concatenation
|
" test addition, subtraction, concatenation
|
||||||
|
@ -68,8 +68,7 @@ def Test_assignment()
|
|||||||
endif
|
endif
|
||||||
let funky1: func
|
let funky1: func
|
||||||
let funky2: func = function('len')
|
let funky2: func = function('len')
|
||||||
let party1: partial
|
let party2: func = funcref('Test_syntax')
|
||||||
let party2: partial = funcref('Test_syntax')
|
|
||||||
|
|
||||||
" type becomes list<any>
|
" type becomes list<any>
|
||||||
let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
|
let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
|
||||||
@ -157,9 +156,6 @@ def Test_assignment()
|
|||||||
let thefunc: func
|
let thefunc: func
|
||||||
assert_equal(test_null_function(), thefunc)
|
assert_equal(test_null_function(), thefunc)
|
||||||
|
|
||||||
let thepartial: partial
|
|
||||||
assert_equal(test_null_partial(), thepartial)
|
|
||||||
|
|
||||||
let thelist: list<any>
|
let thelist: list<any>
|
||||||
assert_equal([], thelist)
|
assert_equal([], thelist)
|
||||||
|
|
||||||
@ -213,7 +209,7 @@ func Test_assignment_failure()
|
|||||||
call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:')
|
call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:')
|
||||||
call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number but got void')
|
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:')
|
call CheckDefFailure(['let var: dict<number'], 'E1009:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
@ -738,6 +738,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 */
|
||||||
|
/**/
|
||||||
|
508,
|
||||||
/**/
|
/**/
|
||||||
507,
|
507,
|
||||||
/**/
|
/**/
|
||||||
|
@ -224,7 +224,7 @@ check_defined(char_u *p, int len, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
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;
|
type_T *type;
|
||||||
|
|
||||||
@ -241,17 +241,19 @@ get_list_type(type_T *member_type, garray_T *type_list)
|
|||||||
return &t_list_string;
|
return &t_list_string;
|
||||||
|
|
||||||
// Not a common type, create a new entry.
|
// 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;
|
return &t_any;
|
||||||
type = ((type_T *)type_list->ga_data) + type_list->ga_len;
|
type = ((type_T *)type_gap->ga_data) + type_gap->ga_len;
|
||||||
++type_list->ga_len;
|
++type_gap->ga_len;
|
||||||
type->tt_type = VAR_LIST;
|
type->tt_type = VAR_LIST;
|
||||||
type->tt_member = member_type;
|
type->tt_member = member_type;
|
||||||
|
type->tt_argcount = 0;
|
||||||
|
type->tt_args = NULL;
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
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;
|
type_T *type;
|
||||||
|
|
||||||
@ -268,12 +270,68 @@ get_dict_type(type_T *member_type, garray_T *type_list)
|
|||||||
return &t_dict_string;
|
return &t_dict_string;
|
||||||
|
|
||||||
// Not a common type, create a new entry.
|
// 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;
|
return &t_any;
|
||||||
type = ((type_T *)type_list->ga_data) + type_list->ga_len;
|
type = ((type_T *)type_gap->ga_data) + type_gap->ga_len;
|
||||||
++type_list->ga_len;
|
++type_gap->ga_len;
|
||||||
type->tt_type = VAR_DICT;
|
type->tt_type = VAR_DICT;
|
||||||
type->tt_member = member_type;
|
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;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,8 +832,7 @@ generate_PUSHPARTIAL(cctx_T *cctx, partial_T *part)
|
|||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL,
|
if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, &t_func_any)) == NULL)
|
||||||
&t_partial_any)) == NULL)
|
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.partial = part;
|
isn->isn_arg.partial = part;
|
||||||
|
|
||||||
@ -942,7 +999,6 @@ generate_NEWLIST(cctx_T *cctx, int count)
|
|||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
garray_T *type_list = cctx->ctx_type_list;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
type_T *member;
|
type_T *member;
|
||||||
|
|
||||||
@ -960,7 +1016,7 @@ generate_NEWLIST(cctx_T *cctx, int count)
|
|||||||
member = ((type_T **)stack->ga_data)[stack->ga_len];
|
member = ((type_T **)stack->ga_data)[stack->ga_len];
|
||||||
else
|
else
|
||||||
member = &t_void;
|
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
|
// add the list type to the type stack
|
||||||
if (ga_grow(stack, 1) == FAIL)
|
if (ga_grow(stack, 1) == FAIL)
|
||||||
@ -979,7 +1035,6 @@ generate_NEWDICT(cctx_T *cctx, int count)
|
|||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
garray_T *type_list = cctx->ctx_type_list;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
type_T *member;
|
type_T *member;
|
||||||
|
|
||||||
@ -997,7 +1052,7 @@ generate_NEWDICT(cctx_T *cctx, int count)
|
|||||||
member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
|
member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
|
||||||
else
|
else
|
||||||
member = &t_void;
|
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
|
// add the dict type to the type stack
|
||||||
if (ga_grow(stack, 1) == FAIL)
|
if (ga_grow(stack, 1) == FAIL)
|
||||||
@ -1024,7 +1079,7 @@ generate_FUNCREF(cctx_T *cctx, int dfunc_idx)
|
|||||||
|
|
||||||
if (ga_grow(stack, 1) == FAIL)
|
if (ga_grow(stack, 1) == FAIL)
|
||||||
return 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
|
// TODO: argument and return types
|
||||||
++stack->ga_len;
|
++stack->ga_len;
|
||||||
|
|
||||||
@ -1298,6 +1353,8 @@ generate_EXEC(cctx_T *cctx, char_u *line)
|
|||||||
|
|
||||||
static char e_white_both[] =
|
static char e_white_both[] =
|
||||||
N_("E1004: white space required before and after '%s'");
|
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.
|
* 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.
|
* 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.
|
* Returns NULL in case of failure.
|
||||||
*/
|
*/
|
||||||
static type_T *
|
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;
|
type_T *member_type;
|
||||||
int prev_called_emsg = called_emsg;
|
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 (**arg != '<')
|
||||||
{
|
{
|
||||||
if (*skipwhite(*arg) == '<')
|
if (*skipwhite(*arg) == '<')
|
||||||
emsg(_("E1007: No white space allowed before <"));
|
semsg(_(e_no_white_before), "<");
|
||||||
else
|
else
|
||||||
emsg(_("E1008: Missing <type>"));
|
emsg(_("E1008: Missing <type>"));
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
*arg = skipwhite(*arg + 1);
|
*arg = skipwhite(*arg + 1);
|
||||||
|
|
||||||
member_type = parse_type(arg, type_list);
|
member_type = parse_type(arg, type_gap);
|
||||||
|
|
||||||
*arg = skipwhite(*arg);
|
*arg = skipwhite(*arg);
|
||||||
if (**arg != '>' && called_emsg == prev_called_emsg)
|
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;
|
++*arg;
|
||||||
|
|
||||||
if (type->tt_type == VAR_LIST)
|
if (type->tt_type == VAR_LIST)
|
||||||
return get_list_type(member_type, type_list);
|
return get_list_type(member_type, type_gap);
|
||||||
return get_dict_type(member_type, type_list);
|
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.
|
* Return &t_any for failure.
|
||||||
*/
|
*/
|
||||||
type_T *
|
type_T *
|
||||||
parse_type(char_u **arg, garray_T *type_list)
|
parse_type(char_u **arg, garray_T *type_gap)
|
||||||
{
|
{
|
||||||
char_u *p = *arg;
|
char_u *p = *arg;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -1466,7 +1523,7 @@ parse_type(char_u **arg, garray_T *type_list)
|
|||||||
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_list);
|
return parse_type_member(arg, &t_dict_any, type_gap);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -1482,9 +1539,85 @@ parse_type(char_u **arg, garray_T *type_list)
|
|||||||
}
|
}
|
||||||
if (len == 4 && STRNCMP(*arg, "func", len) == 0)
|
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;
|
*arg += len;
|
||||||
// TODO: arguments and return type
|
if (**arg == '(')
|
||||||
return &t_func_any;
|
{
|
||||||
|
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;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
@ -1498,7 +1631,7 @@ parse_type(char_u **arg, garray_T *type_list)
|
|||||||
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_list);
|
return parse_type_member(arg, &t_list_any, type_gap);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
@ -1508,14 +1641,6 @@ parse_type(char_u **arg, garray_T *type_list)
|
|||||||
return &t_number;
|
return &t_number;
|
||||||
}
|
}
|
||||||
break;
|
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':
|
case 's':
|
||||||
if (len == 6 && STRNCMP(*arg, "string", len) == 0)
|
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.
|
* "type2" and "dest" may be the same.
|
||||||
*/
|
*/
|
||||||
static void
|
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))
|
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;
|
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)
|
if (type1->tt_type == VAR_LIST)
|
||||||
*dest = get_list_type(common, type_list);
|
*dest = get_list_type(common, type_gap);
|
||||||
else
|
else
|
||||||
*dest = get_dict_type(common, type_list);
|
*dest = get_dict_type(common, type_gap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO: VAR_FUNC and VAR_PARTIAL
|
// TODO: VAR_FUNC and VAR_PARTIAL
|
||||||
@ -1962,14 +2087,14 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
|
|||||||
|
|
||||||
if (*p != ',' && *skipwhite(p) == ',')
|
if (*p != ',' && *skipwhite(p) == ',')
|
||||||
{
|
{
|
||||||
emsg(_("E1068: No white space allowed before ,"));
|
semsg(_(e_no_white_before), ",");
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
}
|
}
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
{
|
{
|
||||||
++p;
|
++p;
|
||||||
if (!VIM_ISWHITE(*p))
|
if (!VIM_ISWHITE(*p))
|
||||||
emsg(_("E1069: white space required after ,"));
|
semsg(_(e_white_after), ",");
|
||||||
}
|
}
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user