mirror of
https://github.com/zoriya/vim.git
synced 2025-12-20 14:15:18 +00:00
patch 8.2.3996: Vim9: type checking lacks information about declared type
Problem: Vim9: type checking for list and dict lacks information about
declared type.
Solution: Add dv_decl_type and lv_decl_type. Refactor the type stack to
store two types in each entry.
This commit is contained in:
@@ -109,6 +109,8 @@ dict_free_contents(dict_T *d)
|
|||||||
hashtab_free_contents(&d->dv_hashtab);
|
hashtab_free_contents(&d->dv_hashtab);
|
||||||
free_type(d->dv_type);
|
free_type(d->dv_type);
|
||||||
d->dv_type = NULL;
|
d->dv_type = NULL;
|
||||||
|
free_type(d->dv_decl_type);
|
||||||
|
d->dv_decl_type = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1354,8 +1356,7 @@ dict_filter_map(
|
|||||||
if (filtermap == FILTERMAP_MAP)
|
if (filtermap == FILTERMAP_MAP)
|
||||||
{
|
{
|
||||||
if (argtype != NULL && check_typval_arg_type(
|
if (argtype != NULL && check_typval_arg_type(
|
||||||
argtype->tt_member, &newtv,
|
argtype->tt_member, &newtv, func_name, 0) == FAIL)
|
||||||
func_name, 0) == FAIL)
|
|
||||||
{
|
{
|
||||||
clear_tv(&newtv);
|
clear_tv(&newtv);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -807,12 +807,6 @@ f_getbufline(typval_T *argvars, typval_T *rettv)
|
|||||||
get_buffer_lines(buf, lnum, end, TRUE, rettv);
|
get_buffer_lines(buf, lnum, end, TRUE, rettv);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_T *
|
|
||||||
ret_f_getline(int argcount, type_T **argtypes UNUSED)
|
|
||||||
{
|
|
||||||
return argcount == 1 ? &t_string : &t_list_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "getline(lnum, [end])" function
|
* "getline(lnum, [end])" function
|
||||||
*/
|
*/
|
||||||
|
|||||||
217
src/evalfunc.c
217
src/evalfunc.c
@@ -195,7 +195,7 @@ static void f_xor(typval_T *argvars, typval_T *rettv);
|
|||||||
// Context passed to an arg_ function.
|
// Context passed to an arg_ function.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int arg_count; // actual argument count
|
int arg_count; // actual argument count
|
||||||
type_T **arg_types; // list of argument types
|
type2_T *arg_types; // list of argument types
|
||||||
int arg_idx; // current argument index (first arg is zero)
|
int arg_idx; // current argument index (first arg is zero)
|
||||||
cctx_T *arg_cctx;
|
cctx_T *arg_cctx;
|
||||||
} argcontext_T;
|
} argcontext_T;
|
||||||
@@ -203,7 +203,7 @@ typedef struct {
|
|||||||
// A function to check one argument type. The first argument is the type to
|
// A function to check one argument type. The first argument is the type to
|
||||||
// check. If needed, other argument types can be obtained with the context.
|
// check. If needed, other argument types can be obtained with the context.
|
||||||
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
|
// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
|
||||||
typedef int (*argcheck_T)(type_T *, argcontext_T *);
|
typedef int (*argcheck_T)(type_T *, type_T *, argcontext_T *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call need_type() to check an argument type.
|
* Call need_type() to check an argument type.
|
||||||
@@ -225,7 +225,7 @@ check_arg_type(
|
|||||||
* Check "type" is a float or a number.
|
* Check "type" is a float or a number.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_float_or_nr(type_T *type, argcontext_T *context)
|
arg_float_or_nr(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -240,7 +240,7 @@ arg_float_or_nr(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a number.
|
* Check "type" is a number.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_number(type_T *type, argcontext_T *context)
|
arg_number(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_number, type, context);
|
return check_arg_type(&t_number, type, context);
|
||||||
}
|
}
|
||||||
@@ -249,7 +249,7 @@ arg_number(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a dict of 'any'.
|
* Check "type" is a dict of 'any'.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_dict_any(type_T *type, argcontext_T *context)
|
arg_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_dict_any, type, context);
|
return check_arg_type(&t_dict_any, type, context);
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ arg_dict_any(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of 'any'.
|
* Check "type" is a list of 'any'.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_any(type_T *type, argcontext_T *context)
|
arg_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_list_any, type, context);
|
return check_arg_type(&t_list_any, type, context);
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ arg_list_any(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of numbers.
|
* Check "type" is a list of numbers.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_number(type_T *type, argcontext_T *context)
|
arg_list_number(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_list_number, type, context);
|
return check_arg_type(&t_list_number, type, context);
|
||||||
}
|
}
|
||||||
@@ -276,7 +276,7 @@ arg_list_number(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of strings.
|
* Check "type" is a list of strings.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_string(type_T *type, argcontext_T *context)
|
arg_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_list_string, type, context);
|
return check_arg_type(&t_list_string, type, context);
|
||||||
}
|
}
|
||||||
@@ -285,7 +285,7 @@ arg_list_string(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a string.
|
* Check "type" is a string.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string(type_T *type, argcontext_T *context)
|
arg_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_string, type, context);
|
return check_arg_type(&t_string, type, context);
|
||||||
}
|
}
|
||||||
@@ -294,7 +294,7 @@ arg_string(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a blob
|
* Check "type" is a blob
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_blob(type_T *type, argcontext_T *context)
|
arg_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_blob, type, context);
|
return check_arg_type(&t_blob, type, context);
|
||||||
}
|
}
|
||||||
@@ -303,7 +303,7 @@ arg_blob(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a bool or number 0 or 1.
|
* Check "type" is a bool or number 0 or 1.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_bool(type_T *type, argcontext_T *context)
|
arg_bool(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_bool, type, context);
|
return check_arg_type(&t_bool, type, context);
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,7 @@ arg_bool(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of 'any' or a blob.
|
* Check "type" is a list of 'any' or a blob.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_or_blob(type_T *type, argcontext_T *context)
|
arg_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -327,7 +327,7 @@ arg_list_or_blob(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a string or a number
|
* Check "type" is a string or a number
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string_or_nr(type_T *type, argcontext_T *context)
|
arg_string_or_nr(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -342,7 +342,7 @@ arg_string_or_nr(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a buffer (string or a number)
|
* Check "type" is a buffer (string or a number)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_buffer(type_T *type, argcontext_T *context)
|
arg_buffer(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -357,7 +357,7 @@ arg_buffer(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a buffer or a dict of any
|
* Check "type" is a buffer or a dict of any
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_buffer_or_dict_any(type_T *type, argcontext_T *context)
|
arg_buffer_or_dict_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -373,7 +373,7 @@ arg_buffer_or_dict_any(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a line (string or a number)
|
* Check "type" is a line (string or a number)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_lnum(type_T *type, argcontext_T *context)
|
arg_lnum(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -388,7 +388,7 @@ arg_lnum(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a string or a list of strings.
|
* Check "type" is a string or a list of strings.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string_or_list_string(type_T *type, argcontext_T *context)
|
arg_string_or_list_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -411,7 +411,7 @@ arg_string_or_list_string(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a string or a list of 'any'
|
* Check "type" is a string or a list of 'any'
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string_or_list_any(type_T *type, argcontext_T *context)
|
arg_string_or_list_any(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -426,7 +426,7 @@ arg_string_or_list_any(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a string or a blob
|
* Check "type" is a string or a blob
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string_or_blob(type_T *type, argcontext_T *context)
|
arg_string_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -441,7 +441,7 @@ arg_string_or_blob(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of 'any' or a dict of 'any'.
|
* Check "type" is a list of 'any' or a dict of 'any'.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_or_dict(type_T *type, argcontext_T *context)
|
arg_list_or_dict(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -456,7 +456,7 @@ arg_list_or_dict(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of 'any' or a dict of 'any' or a blob.
|
* Check "type" is a list of 'any' or a dict of 'any' or a blob.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_or_dict_or_blob(type_T *type, argcontext_T *context)
|
arg_list_or_dict_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -472,7 +472,7 @@ arg_list_or_dict_or_blob(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of 'any' or a dict of 'any' or a blob or a string.
|
* Check "type" is a list of 'any' or a dict of 'any' or a blob or a string.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context)
|
arg_list_or_dict_or_blob_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -489,7 +489,7 @@ arg_list_or_dict_or_blob_or_string(type_T *type, argcontext_T *context)
|
|||||||
* Check second argument of filter(): func must return a bool.
|
* Check second argument of filter(): func must return a bool.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_filter_func(type_T *type, argcontext_T *context)
|
arg_filter_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_FUNC
|
if (type->tt_type == VAR_FUNC
|
||||||
&& !(type->tt_member->tt_type == VAR_BOOL
|
&& !(type->tt_member->tt_type == VAR_BOOL
|
||||||
@@ -507,7 +507,7 @@ arg_filter_func(type_T *type, argcontext_T *context)
|
|||||||
* Check second argument of map().
|
* Check second argument of map().
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_map_func(type_T *type, argcontext_T *context)
|
arg_map_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_FUNC
|
if (type->tt_type == VAR_FUNC
|
||||||
&& type->tt_member != &t_any
|
&& type->tt_member != &t_any
|
||||||
@@ -515,12 +515,12 @@ arg_map_func(type_T *type, argcontext_T *context)
|
|||||||
{
|
{
|
||||||
type_T *expected = NULL;
|
type_T *expected = NULL;
|
||||||
|
|
||||||
if (context->arg_types[0]->tt_type == VAR_LIST
|
if (context->arg_types[0].type_curr->tt_type == VAR_LIST
|
||||||
|| context->arg_types[0]->tt_type == VAR_DICT)
|
|| context->arg_types[0].type_curr->tt_type == VAR_DICT)
|
||||||
expected = context->arg_types[0]->tt_member;
|
expected = context->arg_types[0].type_curr->tt_member;
|
||||||
else if (context->arg_types[0]->tt_type == VAR_STRING)
|
else if (context->arg_types[0].type_curr->tt_type == VAR_STRING)
|
||||||
expected = &t_string;
|
expected = &t_string;
|
||||||
else if (context->arg_types[0]->tt_type == VAR_BLOB)
|
else if (context->arg_types[0].type_curr->tt_type == VAR_BLOB)
|
||||||
expected = &t_number;
|
expected = &t_number;
|
||||||
if (expected != NULL)
|
if (expected != NULL)
|
||||||
{
|
{
|
||||||
@@ -539,7 +539,7 @@ arg_map_func(type_T *type, argcontext_T *context)
|
|||||||
* Also accept a number, one and zero are accepted.
|
* Also accept a number, one and zero are accepted.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string_or_func(type_T *type, argcontext_T *context)
|
arg_string_or_func(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -557,7 +557,7 @@ arg_string_or_func(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a list of 'any' or a blob or a string.
|
* Check "type" is a list of 'any' or a blob or a string.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_string_list_or_blob(type_T *type, argcontext_T *context)
|
arg_string_list_or_blob(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -573,7 +573,7 @@ arg_string_list_or_blob(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a job.
|
* Check "type" is a job.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_job(type_T *type, argcontext_T *context)
|
arg_job(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
return check_arg_type(&t_job, type, context);
|
return check_arg_type(&t_job, type, context);
|
||||||
}
|
}
|
||||||
@@ -582,7 +582,7 @@ arg_job(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a channel or a job.
|
* Check "type" is a channel or a job.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_chan_or_job(type_T *type, argcontext_T *context)
|
arg_chan_or_job(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -594,13 +594,13 @@ arg_chan_or_job(type_T *type, argcontext_T *context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check "type" is the same type as the previous argument.
|
* Check "type" can be used as the type_decl of the previous argument.
|
||||||
* Must not be used for the first argcheck_T entry.
|
* Must not be used for the first argcheck_T entry.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_same_as_prev(type_T *type, argcontext_T *context)
|
arg_same_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
type_T *prev_type = context->arg_types[context->arg_idx - 1];
|
type_T *prev_type = context->arg_types[context->arg_idx - 1].type_decl;
|
||||||
|
|
||||||
return check_arg_type(prev_type, type, context);
|
return check_arg_type(prev_type, type, context);
|
||||||
}
|
}
|
||||||
@@ -611,11 +611,11 @@ arg_same_as_prev(type_T *type, argcontext_T *context)
|
|||||||
* Must not be used for the first argcheck_T entry.
|
* Must not be used for the first argcheck_T entry.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_same_struct_as_prev(type_T *type, argcontext_T *context)
|
arg_same_struct_as_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
type_T *prev_type = context->arg_types[context->arg_idx - 1];
|
type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr;
|
||||||
|
|
||||||
if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
|
if (prev_type->tt_type != context->arg_types[context->arg_idx].type_curr->tt_type)
|
||||||
return check_arg_type(prev_type, type, context);
|
return check_arg_type(prev_type, type, context);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -625,9 +625,9 @@ arg_same_struct_as_prev(type_T *type, argcontext_T *context)
|
|||||||
* Must not be used for the first argcheck_T entry.
|
* Must not be used for the first argcheck_T entry.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_item_of_prev(type_T *type, argcontext_T *context)
|
arg_item_of_prev(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
type_T *prev_type = context->arg_types[context->arg_idx - 1];
|
type_T *prev_type = context->arg_types[context->arg_idx - 1].type_curr;
|
||||||
type_T *expected;
|
type_T *expected;
|
||||||
|
|
||||||
if (prev_type->tt_type == VAR_LIST)
|
if (prev_type->tt_type == VAR_LIST)
|
||||||
@@ -645,7 +645,7 @@ arg_item_of_prev(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a string or a number or a list
|
* Check "type" is a string or a number or a list
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
|
arg_str_or_nr_or_list(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -661,7 +661,7 @@ arg_str_or_nr_or_list(type_T *type, argcontext_T *context)
|
|||||||
* Check "type" is a dict of 'any' or a string
|
* Check "type" is a dict of 'any' or a string
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_dict_any_or_string(type_T *type, argcontext_T *context)
|
arg_dict_any_or_string(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -677,14 +677,14 @@ arg_dict_any_or_string(type_T *type, argcontext_T *context)
|
|||||||
* any)
|
* any)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_extend3(type_T *type, argcontext_T *context)
|
arg_extend3(type_T *type, type_T *decl_type, argcontext_T *context)
|
||||||
{
|
{
|
||||||
type_T *first_type = context->arg_types[context->arg_idx - 2];
|
type_T *first_type = context->arg_types[context->arg_idx - 2].type_curr;
|
||||||
|
|
||||||
if (first_type->tt_type == VAR_LIST)
|
if (first_type->tt_type == VAR_LIST)
|
||||||
return arg_number(type, context);
|
return arg_number(type, decl_type, context);
|
||||||
if (first_type->tt_type == VAR_DICT)
|
if (first_type->tt_type == VAR_DICT)
|
||||||
return arg_string(type, context);
|
return arg_string(type, decl_type, context);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +693,7 @@ arg_extend3(type_T *type, argcontext_T *context)
|
|||||||
* funcref)
|
* funcref)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_get1(type_T *type, argcontext_T *context)
|
arg_get1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -713,7 +713,7 @@ arg_get1(type_T *type, argcontext_T *context)
|
|||||||
* blob or list or dict)
|
* blob or list or dict)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_len1(type_T *type, argcontext_T *context)
|
arg_len1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -733,14 +733,14 @@ arg_len1(type_T *type, argcontext_T *context)
|
|||||||
* any)
|
* any)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_remove2(type_T *type, argcontext_T *context)
|
arg_remove2(type_T *type, type_T *decl_type, argcontext_T *context)
|
||||||
{
|
{
|
||||||
type_T *first_type = context->arg_types[context->arg_idx - 1];
|
type_T *first_type = context->arg_types[context->arg_idx - 1].type_curr;
|
||||||
|
|
||||||
if (first_type->tt_type == VAR_LIST || first_type->tt_type == VAR_BLOB)
|
if (first_type->tt_type == VAR_LIST || first_type->tt_type == VAR_BLOB)
|
||||||
return arg_number(type, context);
|
return arg_number(type, decl_type, context);
|
||||||
if (first_type->tt_type == VAR_DICT)
|
if (first_type->tt_type == VAR_DICT)
|
||||||
return arg_string_or_nr(type, context);
|
return arg_string_or_nr(type, decl_type, context);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,7 +749,7 @@ arg_remove2(type_T *type, argcontext_T *context)
|
|||||||
* list or any)
|
* list or any)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_repeat1(type_T *type, argcontext_T *context)
|
arg_repeat1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -767,7 +767,7 @@ arg_repeat1(type_T *type, argcontext_T *context)
|
|||||||
* or any)
|
* or any)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_slice1(type_T *type, argcontext_T *context)
|
arg_slice1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -785,7 +785,7 @@ arg_slice1(type_T *type, argcontext_T *context)
|
|||||||
* or any)
|
* or any)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_count1(type_T *type, argcontext_T *context)
|
arg_count1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -803,7 +803,7 @@ arg_count1(type_T *type, argcontext_T *context)
|
|||||||
* list or any)
|
* list or any)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
arg_cursor1(type_T *type, argcontext_T *context)
|
arg_cursor1(type_T *type, type_T *decl_type UNUSED, argcontext_T *context)
|
||||||
{
|
{
|
||||||
if (type->tt_type == VAR_ANY
|
if (type->tt_type == VAR_ANY
|
||||||
|| type->tt_type == VAR_UNKNOWN
|
|| type->tt_type == VAR_UNKNOWN
|
||||||
@@ -960,152 +960,158 @@ static argcheck_T arg24_match_func[] = {arg_string_or_list_any, arg_string, arg_
|
|||||||
* Note that "argtypes" is NULL if "argcount" is zero.
|
* Note that "argtypes" is NULL if "argcount" is zero.
|
||||||
*/
|
*/
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_void(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_void;
|
return &t_void;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_any(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_any;
|
return &t_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_bool(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_bool(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_bool;
|
return &t_bool;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_number_bool(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_number_bool(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_number_bool;
|
return &t_number_bool;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_number(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_number;
|
return &t_number;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_float(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_float;
|
return &t_float;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_string(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_string;
|
return &t_string;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_list_any(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_list_any;
|
return &t_list_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_list_number(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_list_number;
|
return &t_list_number;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_list_string(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_list_string;
|
return &t_list_string;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_list_dict_any(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_list_dict_any;
|
return &t_list_dict_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_items(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_list_items(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_list_list_any;
|
return &t_list_list_any;
|
||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_string_items(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_list_string_items(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_list_list_string;
|
return &t_list_list_string;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_dict_any(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_dict_any;
|
return &t_dict_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_job_info(int argcount, type_T **argtypes UNUSED)
|
ret_job_info(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
if (argcount == 0)
|
if (argcount == 0)
|
||||||
return &t_list_job;
|
return &t_list_job;
|
||||||
return &t_dict_any;
|
return &t_dict_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_dict_number(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_dict_number;
|
return &t_dict_number;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_dict_string(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_dict_string;
|
return &t_dict_string;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_blob(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_blob;
|
return &t_blob;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_func_any(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_func_any;
|
return &t_func_any;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_func_unknown(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_func_unknown(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_func_unknown;
|
return &t_func_unknown;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_channel(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_channel;
|
return &t_channel;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
|
ret_job(int argcount UNUSED, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
return &t_job;
|
return &t_job;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_first_arg(int argcount, type_T **argtypes)
|
ret_first_arg(int argcount, type2_T *argtypes)
|
||||||
{
|
{
|
||||||
if (argcount > 0)
|
if (argcount > 0)
|
||||||
return argtypes[0];
|
return argtypes[0].type_curr;
|
||||||
return &t_void;
|
return &t_void;
|
||||||
}
|
}
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_repeat(int argcount, type_T **argtypes)
|
ret_repeat(int argcount, type2_T *argtypes)
|
||||||
{
|
{
|
||||||
if (argcount == 0)
|
if (argcount == 0)
|
||||||
return &t_any;
|
return &t_any;
|
||||||
if (argtypes[0] == &t_number)
|
if (argtypes[0].type_curr == &t_number)
|
||||||
return &t_string;
|
return &t_string;
|
||||||
return argtypes[0];
|
return argtypes[0].type_curr;
|
||||||
}
|
}
|
||||||
// for map(): returns first argument but item type may differ
|
// for map(): returns first argument but item type may differ
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_first_cont(int argcount, type_T **argtypes)
|
ret_first_cont(int argcount, type2_T *argtypes)
|
||||||
{
|
{
|
||||||
if (argcount > 0)
|
if (argcount > 0)
|
||||||
{
|
{
|
||||||
if (argtypes[0]->tt_type == VAR_LIST)
|
if (argtypes[0].type_curr->tt_type == VAR_LIST)
|
||||||
return &t_list_any;
|
return &t_list_any;
|
||||||
if (argtypes[0]->tt_type == VAR_DICT)
|
if (argtypes[0].type_curr->tt_type == VAR_DICT)
|
||||||
return &t_dict_any;
|
return &t_dict_any;
|
||||||
if (argtypes[0]->tt_type == VAR_BLOB)
|
if (argtypes[0].type_curr->tt_type == VAR_BLOB)
|
||||||
return argtypes[0];
|
return argtypes[0].type_curr;
|
||||||
}
|
}
|
||||||
return &t_any;
|
return &t_any;
|
||||||
}
|
}
|
||||||
|
// for getline()
|
||||||
|
static type_T *
|
||||||
|
ret_getline(int argcount, type2_T *argtypes UNUSED)
|
||||||
|
{
|
||||||
|
return argcount == 1 ? &t_string : &t_list_string;
|
||||||
|
}
|
||||||
// for finddir()
|
// for finddir()
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_finddir(int argcount, type_T **argtypes UNUSED)
|
ret_finddir(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
if (argcount < 3)
|
if (argcount < 3)
|
||||||
return &t_string;
|
return &t_string;
|
||||||
@@ -1118,7 +1124,7 @@ ret_finddir(int argcount, type_T **argtypes UNUSED)
|
|||||||
* one.
|
* one.
|
||||||
*/
|
*/
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
|
ret_list_or_dict_0(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
if (argcount > 0)
|
if (argcount > 0)
|
||||||
return &t_dict_any;
|
return &t_dict_any;
|
||||||
@@ -1130,7 +1136,7 @@ ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
|
|||||||
* are two.
|
* are two.
|
||||||
*/
|
*/
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
|
ret_list_or_dict_1(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
if (argcount > 1)
|
if (argcount > 1)
|
||||||
return &t_dict_any;
|
return &t_dict_any;
|
||||||
@@ -1138,7 +1144,7 @@ ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_argv(int argcount, type_T **argtypes UNUSED)
|
ret_argv(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
// argv() returns list of strings
|
// argv() returns list of strings
|
||||||
if (argcount == 0)
|
if (argcount == 0)
|
||||||
@@ -1149,21 +1155,21 @@ ret_argv(int argcount, type_T **argtypes UNUSED)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_remove(int argcount, type_T **argtypes)
|
ret_remove(int argcount, type2_T *argtypes)
|
||||||
{
|
{
|
||||||
if (argcount > 0)
|
if (argcount > 0)
|
||||||
{
|
{
|
||||||
if (argtypes[0]->tt_type == VAR_LIST
|
if (argtypes[0].type_curr->tt_type == VAR_LIST
|
||||||
|| argtypes[0]->tt_type == VAR_DICT)
|
|| argtypes[0].type_curr->tt_type == VAR_DICT)
|
||||||
return argtypes[0]->tt_member;
|
return argtypes[0].type_curr->tt_member;
|
||||||
if (argtypes[0]->tt_type == VAR_BLOB)
|
if (argtypes[0].type_curr->tt_type == VAR_BLOB)
|
||||||
return &t_number;
|
return &t_number;
|
||||||
}
|
}
|
||||||
return &t_any;
|
return &t_any;
|
||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_getreg(int argcount, type_T **argtypes UNUSED)
|
ret_getreg(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
// Assume that if the third argument is passed it's non-zero
|
// Assume that if the third argument is passed it's non-zero
|
||||||
if (argcount == 3)
|
if (argcount == 3)
|
||||||
@@ -1172,7 +1178,7 @@ ret_getreg(int argcount, type_T **argtypes UNUSED)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_maparg(int argcount, type_T **argtypes UNUSED)
|
ret_maparg(int argcount, type2_T *argtypes UNUSED)
|
||||||
{
|
{
|
||||||
// Assume that if the fourth argument is passed it's non-zero
|
// Assume that if the fourth argument is passed it's non-zero
|
||||||
if (argcount == 4)
|
if (argcount == 4)
|
||||||
@@ -1191,7 +1197,7 @@ typedef struct
|
|||||||
char f_max_argc; // maximal number of arguments
|
char f_max_argc; // maximal number of arguments
|
||||||
char f_argtype; // for method: FEARG_ values
|
char f_argtype; // for method: FEARG_ values
|
||||||
argcheck_T *f_argcheck; // list of functions to check argument types
|
argcheck_T *f_argcheck; // list of functions to check argument types
|
||||||
type_T *(*f_retfunc)(int argcount, type_T **argtypes);
|
type_T *(*f_retfunc)(int argcount, type2_T *argtypes);
|
||||||
// return type function
|
// return type function
|
||||||
void (*f_func)(typval_T *args, typval_T *rvar);
|
void (*f_func)(typval_T *args, typval_T *rvar);
|
||||||
// implementation of function
|
// implementation of function
|
||||||
@@ -1599,7 +1605,7 @@ static funcentry_T global_functions[] =
|
|||||||
{"getjumplist", 0, 2, FEARG_1, arg2_number,
|
{"getjumplist", 0, 2, FEARG_1, arg2_number,
|
||||||
ret_list_any, f_getjumplist},
|
ret_list_any, f_getjumplist},
|
||||||
{"getline", 1, 2, FEARG_1, arg2_lnum,
|
{"getline", 1, 2, FEARG_1, arg2_lnum,
|
||||||
ret_f_getline, f_getline},
|
ret_getline, f_getline},
|
||||||
{"getloclist", 1, 2, 0, arg2_number_dict_any,
|
{"getloclist", 1, 2, 0, arg2_number_dict_any,
|
||||||
ret_list_or_dict_1, f_getloclist},
|
ret_list_or_dict_1, f_getloclist},
|
||||||
{"getmarklist", 0, 1, FEARG_1, arg1_buffer,
|
{"getmarklist", 0, 1, FEARG_1, arg1_buffer,
|
||||||
@@ -2576,7 +2582,7 @@ internal_func_name(int idx)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
internal_func_check_arg_types(
|
internal_func_check_arg_types(
|
||||||
type_T **types,
|
type2_T *types,
|
||||||
int idx,
|
int idx,
|
||||||
int argcount,
|
int argcount,
|
||||||
cctx_T *cctx)
|
cctx_T *cctx)
|
||||||
@@ -2595,7 +2601,8 @@ internal_func_check_arg_types(
|
|||||||
if (argchecks[i] != NULL)
|
if (argchecks[i] != NULL)
|
||||||
{
|
{
|
||||||
context.arg_idx = i;
|
context.arg_idx = i;
|
||||||
if (argchecks[i](types[i], &context) == FAIL)
|
if (argchecks[i](types[i].type_curr, types[i].type_decl,
|
||||||
|
&context) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2621,7 +2628,7 @@ internal_func_get_argcount(int idx, int *argcount, int *min_argcount)
|
|||||||
* "argcount" may be less than the actual count when only getting the type.
|
* "argcount" may be less than the actual count when only getting the type.
|
||||||
*/
|
*/
|
||||||
type_T *
|
type_T *
|
||||||
internal_func_ret_type(int idx, int argcount, type_T **argtypes)
|
internal_func_ret_type(int idx, int argcount, type2_T *argtypes)
|
||||||
{
|
{
|
||||||
return global_functions[idx].f_retfunc(argcount, argtypes);
|
return global_functions[idx].f_retfunc(argcount, argtypes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ list_free_list(list_T *l)
|
|||||||
l->lv_used_next->lv_used_prev = l->lv_used_prev;
|
l->lv_used_next->lv_used_prev = l->lv_used_prev;
|
||||||
|
|
||||||
free_type(l->lv_type);
|
free_type(l->lv_type);
|
||||||
|
free_type(l->lv_decl_type);
|
||||||
vim_free(l);
|
vim_free(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,6 +1026,8 @@ flatten_common(typval_T *argvars, typval_T *rettv, int make_copy)
|
|||||||
// The type will change.
|
// The type will change.
|
||||||
free_type(l->lv_type);
|
free_type(l->lv_type);
|
||||||
l->lv_type = NULL;
|
l->lv_type = NULL;
|
||||||
|
free_type(l->lv_decl_type);
|
||||||
|
l->lv_decl_type = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1220,6 +1223,7 @@ list_copy(list_T *orig, int deep, int copyID)
|
|||||||
if (copy != NULL)
|
if (copy != NULL)
|
||||||
{
|
{
|
||||||
copy->lv_type = alloc_type(orig->lv_type);
|
copy->lv_type = alloc_type(orig->lv_type);
|
||||||
|
copy->lv_decl_type = alloc_type(orig->lv_decl_type);
|
||||||
if (copyID != 0)
|
if (copyID != 0)
|
||||||
{
|
{
|
||||||
// Do this before adding the items, because one of the items may
|
// Do this before adding the items, because one of the items may
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ void f_bufwinnr(typval_T *argvars, typval_T *rettv);
|
|||||||
void f_deletebufline(typval_T *argvars, typval_T *rettv);
|
void f_deletebufline(typval_T *argvars, typval_T *rettv);
|
||||||
void f_getbufinfo(typval_T *argvars, typval_T *rettv);
|
void f_getbufinfo(typval_T *argvars, typval_T *rettv);
|
||||||
void f_getbufline(typval_T *argvars, typval_T *rettv);
|
void f_getbufline(typval_T *argvars, typval_T *rettv);
|
||||||
type_T *ret_f_getline(int argcount, type_T **argtypes);
|
|
||||||
void f_getline(typval_T *argvars, typval_T *rettv);
|
void f_getline(typval_T *argvars, typval_T *rettv);
|
||||||
void f_setbufline(typval_T *argvars, typval_T *rettv);
|
void f_setbufline(typval_T *argvars, typval_T *rettv);
|
||||||
void f_setline(typval_T *argvars, typval_T *rettv);
|
void f_setline(typval_T *argvars, typval_T *rettv);
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ char_u *get_expr_name(expand_T *xp, int idx);
|
|||||||
int find_internal_func(char_u *name);
|
int find_internal_func(char_u *name);
|
||||||
int has_internal_func(char_u *name);
|
int has_internal_func(char_u *name);
|
||||||
char *internal_func_name(int idx);
|
char *internal_func_name(int idx);
|
||||||
int internal_func_check_arg_types(type_T **types, int idx, int argcount, cctx_T *cctx);
|
int internal_func_check_arg_types(type2_T *types, int idx, int argcount, cctx_T *cctx);
|
||||||
void internal_func_get_argcount(int idx, int *argcount, int *min_argcount);
|
void internal_func_get_argcount(int idx, int *argcount, int *min_argcount);
|
||||||
type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes);
|
type_T *internal_func_ret_type(int idx, int argcount, type2_T *argtypes);
|
||||||
int internal_func_is_map(int idx);
|
int internal_func_is_map(int idx);
|
||||||
int check_internal_func(int idx, int argcount);
|
int check_internal_func(int idx, int argcount);
|
||||||
int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
|
int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* vim9instr.c */
|
/* vim9instr.c */
|
||||||
isn_T *generate_instr(cctx_T *cctx, isntype_T isn_type);
|
isn_T *generate_instr(cctx_T *cctx, isntype_T isn_type);
|
||||||
isn_T *generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop);
|
isn_T *generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop);
|
||||||
|
isn_T *generate_instr_type2(cctx_T *cctx, isntype_T isn_type, type_T *type, type_T *decl_type);
|
||||||
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
|
isn_T *generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type);
|
||||||
isn_T *generate_instr_debug(cctx_T *cctx);
|
isn_T *generate_instr_debug(cctx_T *cctx);
|
||||||
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
|
int may_generate_2STRING(int offset, int tolerant, cctx_T *cctx);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ type_T *alloc_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
|
|||||||
type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
|
type_T *get_func_type(type_T *ret_type, int argcount, garray_T *type_gap);
|
||||||
int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
|
int func_type_add_arg_types(type_T *functype, int argcount, garray_T *type_gap);
|
||||||
int need_convert_to_bool(type_T *type, typval_T *tv);
|
int need_convert_to_bool(type_T *type, typval_T *tv);
|
||||||
type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int do_member);
|
type_T *typval2type(typval_T *tv, int copyID, garray_T *type_gap, int flags);
|
||||||
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
|
type_T *typval2type_vimvar(typval_T *tv, garray_T *type_gap);
|
||||||
int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
|
int check_typval_arg_type(type_T *expected, typval_T *actual_tv, char *func_name, int arg_idx);
|
||||||
int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
|
int check_typval_type(type_T *expected, typval_T *actual_tv, where_T where);
|
||||||
@@ -22,7 +22,11 @@ char_u *skip_type(char_u *start, int optional);
|
|||||||
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
|
type_T *parse_type(char_u **arg, garray_T *type_gap, int give_error);
|
||||||
int equal_type(type_T *type1, type_T *type2, int flags);
|
int equal_type(type_T *type1, type_T *type2, int flags);
|
||||||
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);
|
int push_type_stack(cctx_T *cctx, type_T *type);
|
||||||
|
int push_type_stack2(cctx_T *cctx, type_T *type, type_T *decl_type);
|
||||||
|
void set_type_on_stack(cctx_T *cctx, type_T *type, int offset);
|
||||||
|
type_T *get_type_on_stack(cctx_T *cctx, int offset);
|
||||||
|
type_T *get_member_type_from_stack(int count, int skip, type_T **decl_type, cctx_T *cctx);
|
||||||
char *vartype_name(vartype_T type);
|
char *vartype_name(vartype_T type);
|
||||||
char *type_name(type_T *type, char **tofree);
|
char *type_name(type_T *type, char **tofree);
|
||||||
void f_typename(typval_T *argvars, typval_T *rettv);
|
void f_typename(typval_T *argvars, typval_T *rettv);
|
||||||
|
|||||||
@@ -1422,6 +1422,11 @@ struct type_S {
|
|||||||
type_T **tt_args; // func argument types, allocated
|
type_T **tt_args; // func argument types, allocated
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
type_T *type_curr; // current type, value type
|
||||||
|
type_T *type_decl; // declared type or equal to type_current
|
||||||
|
} type2_T;
|
||||||
|
|
||||||
#define TTFLAG_VARARGS 1 // func args ends with "..."
|
#define TTFLAG_VARARGS 1 // func args ends with "..."
|
||||||
#define TTFLAG_OPTARG 2 // func arg type with "?"
|
#define TTFLAG_OPTARG 2 // func arg type with "?"
|
||||||
#define TTFLAG_BOOL_OK 4 // can be converted to bool
|
#define TTFLAG_BOOL_OK 4 // can be converted to bool
|
||||||
@@ -1507,7 +1512,8 @@ struct listvar_S
|
|||||||
int lv_idx; // cached index of an item
|
int lv_idx; // cached index of an item
|
||||||
} mat;
|
} mat;
|
||||||
} lv_u;
|
} lv_u;
|
||||||
type_T *lv_type; // allocated by alloc_type()
|
type_T *lv_type; // current type, allocated by alloc_type()
|
||||||
|
type_T *lv_decl_type; // declared type, allocated by alloc_type()
|
||||||
list_T *lv_copylist; // copied list used by deepcopy()
|
list_T *lv_copylist; // copied list used by deepcopy()
|
||||||
list_T *lv_used_next; // next list in used lists list
|
list_T *lv_used_next; // next list in used lists list
|
||||||
list_T *lv_used_prev; // previous list in used lists list
|
list_T *lv_used_prev; // previous list in used lists list
|
||||||
@@ -1571,7 +1577,8 @@ struct dictvar_S
|
|||||||
int dv_refcount; // reference count
|
int dv_refcount; // reference count
|
||||||
int dv_copyID; // ID used by deepcopy()
|
int dv_copyID; // ID used by deepcopy()
|
||||||
hashtab_T dv_hashtab; // hashtab that refers to the items
|
hashtab_T dv_hashtab; // hashtab that refers to the items
|
||||||
type_T *dv_type; // allocated by alloc_type()
|
type_T *dv_type; // current type, allocated by alloc_type()
|
||||||
|
type_T *dv_decl_type; // declared type, allocated by alloc_type()
|
||||||
dict_T *dv_copydict; // copied dict used by deepcopy()
|
dict_T *dv_copydict; // copied dict used by deepcopy()
|
||||||
dict_T *dv_used_next; // next dict in used dicts list
|
dict_T *dv_used_next; // next dict in used dicts list
|
||||||
dict_T *dv_used_prev; // previous dict in used dicts list
|
dict_T *dv_used_prev; // previous dict in used dicts list
|
||||||
|
|||||||
@@ -639,6 +639,23 @@ def Test_extend_list()
|
|||||||
extend(test_null_list(), ['x'])
|
extend(test_null_list(), ['x'])
|
||||||
END
|
END
|
||||||
CheckScriptFailure(lines, 'E1134:', 2)
|
CheckScriptFailure(lines, 'E1134:', 2)
|
||||||
|
|
||||||
|
# using global var has no declared type
|
||||||
|
g:myList = []
|
||||||
|
g:myList->extend([1])
|
||||||
|
g:myList->extend(['x'])
|
||||||
|
assert_equal([1, 'x'], g:myList)
|
||||||
|
unlet g:myList
|
||||||
|
|
||||||
|
# using declared list gives an error
|
||||||
|
lines =<< trim END
|
||||||
|
var l: list<number>
|
||||||
|
g:myList = l
|
||||||
|
g:myList->extend([1])
|
||||||
|
g:myList->extend(['x'])
|
||||||
|
END
|
||||||
|
CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 4)
|
||||||
|
unlet g:myList
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_extend_dict()
|
def Test_extend_dict()
|
||||||
@@ -963,6 +980,23 @@ def Test_assignment_dict()
|
|||||||
var anyDict: dict<any> = {a: 0}
|
var anyDict: dict<any> = {a: 0}
|
||||||
assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'}))
|
assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'}))
|
||||||
|
|
||||||
|
# using global var, which has no declared type
|
||||||
|
g:myDict = {}
|
||||||
|
g:myDict->extend({a: 1})
|
||||||
|
g:myDict->extend({b: 'x'})
|
||||||
|
assert_equal({a: 1, b: 'x'}, g:myDict)
|
||||||
|
unlet g:myDict
|
||||||
|
|
||||||
|
# using list with declared type gives an error
|
||||||
|
lines =<< trim END
|
||||||
|
var d: dict<number>
|
||||||
|
g:myDict = d
|
||||||
|
g:myDict->extend({a: 1})
|
||||||
|
g:myDict->extend({b: 'x'})
|
||||||
|
END
|
||||||
|
CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 4)
|
||||||
|
unlet g:myDict
|
||||||
|
|
||||||
# assignment to script-local dict
|
# assignment to script-local dict
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
|||||||
@@ -982,26 +982,22 @@ def Test_extend_arg_types()
|
|||||||
END
|
END
|
||||||
CheckDefAndScriptSuccess(lines)
|
CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
# FIXME: this should not fail when compiled
|
|
||||||
lines =<< trim END
|
lines =<< trim END
|
||||||
vim9script
|
|
||||||
assert_equal([1, 2, "x"], extend([1, 2], ["x"]))
|
assert_equal([1, 2, "x"], extend([1, 2], ["x"]))
|
||||||
assert_equal([1, "b", 1], extend([1], ["b", 1]))
|
assert_equal([1, "b", 1], extend([1], ["b", 1]))
|
||||||
|
|
||||||
|
assert_equal({a: 1, b: "x"}, extend({a: 1}, {b: "x"}))
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckDefAndScriptSuccess(lines)
|
||||||
|
|
||||||
CheckDefAndScriptFailure(['extend("a", 1)'], ['E1013: Argument 1: type mismatch, expected list<any> but got string', 'E712: Argument of extend() must be a List or Dictionary'])
|
CheckDefAndScriptFailure(['extend("a", 1)'], ['E1013: Argument 1: type mismatch, expected list<any> but got string', 'E712: Argument of extend() must be a List or Dictionary'])
|
||||||
CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list<number> but got number', 'E712: Argument of extend() must be a List or Dictionary'])
|
CheckDefAndScriptFailure(['extend([1, 2], 3)'], ['E1013: Argument 2: type mismatch, expected list<any> but got number', 'E712: Argument of extend() must be a List or Dictionary'])
|
||||||
CheckDefAndScriptFailure(['var ll = [1, 2]', 'extend(ll, ["x"])'], ['E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>'])
|
CheckDefAndScriptFailure(['var ll = [1, 2]', 'extend(ll, ["x"])'], ['E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>'])
|
||||||
CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string')
|
CheckDefFailure(['extend([1, 2], [3], "x")'], 'E1013: Argument 3: type mismatch, expected number but got string')
|
||||||
|
|
||||||
CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<number> but got number')
|
CheckDefFailure(['extend({a: 1}, 42)'], 'E1013: Argument 2: type mismatch, expected dict<any> but got number')
|
||||||
CheckDefFailure(['extend({a: 1}, {b: "x"})'], 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
|
|
||||||
CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
|
CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number')
|
||||||
|
|
||||||
CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>')
|
|
||||||
CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any>')
|
|
||||||
|
|
||||||
CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any> in extend()')
|
CheckScriptFailure(['vim9script', 'var l = [1]', 'extend(l, ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list<number> but got list<any> in extend()')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
/**/
|
||||||
|
3996,
|
||||||
/**/
|
/**/
|
||||||
3995,
|
3995,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
@@ -769,7 +769,6 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
int var_list = FALSE;
|
int var_list = FALSE;
|
||||||
int semicolon = FALSE;
|
int semicolon = FALSE;
|
||||||
size_t varlen;
|
size_t varlen;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
garray_T *instr = &cctx->ctx_instr;
|
garray_T *instr = &cctx->ctx_instr;
|
||||||
scope_T *scope;
|
scope_T *scope;
|
||||||
lvar_T *loop_lvar; // loop iteration variable
|
lvar_T *loop_lvar; // loop iteration variable
|
||||||
@@ -841,7 +840,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
{
|
{
|
||||||
// If we know the type of "var" and it is not a supported type we can
|
// If we know the type of "var" and it is not a supported type we can
|
||||||
// give an error now.
|
// give an error now.
|
||||||
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
vartype = get_type_on_stack(cctx, 0);
|
||||||
if (vartype->tt_type != VAR_LIST
|
if (vartype->tt_type != VAR_LIST
|
||||||
&& vartype->tt_type != VAR_STRING
|
&& vartype->tt_type != VAR_STRING
|
||||||
&& vartype->tt_type != VAR_BLOB
|
&& vartype->tt_type != VAR_BLOB
|
||||||
@@ -898,18 +897,19 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
generate_UNPACK(cctx, var_count, semicolon);
|
generate_UNPACK(cctx, var_count, semicolon);
|
||||||
arg = skipwhite(arg + 1); // skip white after '['
|
arg = skipwhite(arg + 1); // skip white after '['
|
||||||
|
|
||||||
// the list item is replaced by a number of items
|
// drop the list item
|
||||||
if (GA_GROW_FAILS(stack, var_count - 1))
|
--cctx->ctx_type_stack.ga_len;
|
||||||
|
|
||||||
|
// add type of the items
|
||||||
|
for (idx = 0; idx < var_count; ++idx)
|
||||||
|
{
|
||||||
|
type_T *type = (semicolon && idx == 0) ? vartype : item_type;
|
||||||
|
|
||||||
|
if (push_type_stack(cctx, type) == FAIL)
|
||||||
{
|
{
|
||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
--stack->ga_len;
|
|
||||||
for (idx = 0; idx < var_count; ++idx)
|
|
||||||
{
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] =
|
|
||||||
(semicolon && idx == 0) ? vartype : item_type;
|
|
||||||
++stack->ga_len;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1647,7 +1647,6 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
|
|||||||
char_u *expr_start;
|
char_u *expr_start;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int start_ctx_lnum = cctx->ctx_lnum;
|
int start_ctx_lnum = cctx->ctx_lnum;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@@ -1661,7 +1660,7 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
|
|||||||
if (cctx->ctx_skip != SKIP_YES)
|
if (cctx->ctx_skip != SKIP_YES)
|
||||||
{
|
{
|
||||||
// check for non-void type
|
// check for non-void type
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
if (type->tt_type == VAR_VOID)
|
if (type->tt_type == VAR_VOID)
|
||||||
{
|
{
|
||||||
semsg(_(e_expression_does_not_result_in_value_str), expr_start);
|
semsg(_(e_expression_does_not_result_in_value_str), expr_start);
|
||||||
@@ -2182,7 +2181,6 @@ compile_cexpr(char_u *line, exarg_T *eap, cctx_T *cctx)
|
|||||||
compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
|
compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
char_u *p = arg;
|
char_u *p = arg;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *stack_type;
|
type_T *stack_type;
|
||||||
|
|
||||||
if (*p != NUL && *p != '|' && *p != '\n')
|
if (*p != NUL && *p != '|' && *p != '\n')
|
||||||
@@ -2211,7 +2209,7 @@ compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx)
|
|||||||
// "check_return_type" with uf_ret_type set to &t_unknown is used
|
// "check_return_type" with uf_ret_type set to &t_unknown is used
|
||||||
// for an inline function without a specified return type. Set the
|
// for an inline function without a specified return type. Set the
|
||||||
// return type here.
|
// return type here.
|
||||||
stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
stack_type = get_type_on_stack(cctx, 0);
|
||||||
if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL
|
if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL
|
||||||
|| cctx->ctx_ufunc->uf_ret_type == &t_unknown
|
|| cctx->ctx_ufunc->uf_ret_type == &t_unknown
|
||||||
|| cctx->ctx_ufunc->uf_ret_type == &t_any))
|
|| cctx->ctx_ufunc->uf_ret_type == &t_any))
|
||||||
|
|||||||
@@ -1639,7 +1639,6 @@ compile_load_lhs(
|
|||||||
int c = var_start[varlen];
|
int c = var_start[varlen];
|
||||||
int lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
|
int lines_len = cctx->ctx_ufunc->uf_lines.ga_len;
|
||||||
char_u *p = var_start;
|
char_u *p = var_start;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
// Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and
|
// Evaluate "ll[expr]" of "ll[expr][idx]". End the line with a NUL and
|
||||||
@@ -1657,8 +1656,8 @@ compile_load_lhs(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
lhs->lhs_type = stack->ga_len == 0 ? &t_void
|
lhs->lhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
|
||||||
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
: get_type_on_stack(cctx, 0);
|
||||||
// now we can properly check the type
|
// now we can properly check the type
|
||||||
if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL
|
if (rhs_type != NULL && lhs->lhs_type->tt_member != NULL
|
||||||
&& rhs_type != &t_void
|
&& rhs_type != &t_void
|
||||||
@@ -1717,7 +1716,6 @@ compile_assign_unlet(
|
|||||||
cctx_T *cctx)
|
cctx_T *cctx)
|
||||||
{
|
{
|
||||||
vartype_T dest_type;
|
vartype_T dest_type;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
int range = FALSE;
|
int range = FALSE;
|
||||||
|
|
||||||
if (compile_assign_index(var_start, lhs, &range, cctx) == FAIL)
|
if (compile_assign_index(var_start, lhs, &range, cctx) == FAIL)
|
||||||
@@ -1753,12 +1751,12 @@ compile_assign_unlet(
|
|||||||
|
|
||||||
if (range)
|
if (range)
|
||||||
{
|
{
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
type = get_type_on_stack(cctx, 1);
|
||||||
if (need_type(type, &t_number,
|
if (need_type(type, &t_number,
|
||||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
if ((dest_type != VAR_BLOB && type != &t_special)
|
if ((dest_type != VAR_BLOB && type != &t_special)
|
||||||
&& need_type(type, &t_number,
|
&& need_type(type, &t_number,
|
||||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
@@ -1837,7 +1835,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
int semicolon = 0;
|
int semicolon = 0;
|
||||||
int did_generate_slice = FALSE;
|
int did_generate_slice = FALSE;
|
||||||
garray_T *instr = &cctx->ctx_instr;
|
garray_T *instr = &cctx->ctx_instr;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
char_u *op;
|
char_u *op;
|
||||||
int oplen = 0;
|
int oplen = 0;
|
||||||
int heredoc = FALSE;
|
int heredoc = FALSE;
|
||||||
@@ -1929,8 +1926,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
int needed_list_len;
|
int needed_list_len;
|
||||||
int did_check = FALSE;
|
int did_check = FALSE;
|
||||||
|
|
||||||
stacktype = stack->ga_len == 0 ? &t_void
|
stacktype = cctx->ctx_type_stack.ga_len == 0 ? &t_void
|
||||||
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
: get_type_on_stack(cctx, 0);
|
||||||
if (stacktype->tt_type == VAR_VOID)
|
if (stacktype->tt_type == VAR_VOID)
|
||||||
{
|
{
|
||||||
emsg(_(e_cannot_use_void_value));
|
emsg(_(e_cannot_use_void_value));
|
||||||
@@ -2073,8 +2070,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
|
||||||
rhs_type = stack->ga_len == 0 ? &t_void
|
rhs_type = cctx->ctx_type_stack.ga_len == 0 ? &t_void
|
||||||
: ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
: get_type_on_stack(cctx, 0);
|
||||||
if (lhs.lhs_lvar != NULL && (is_decl || !lhs.lhs_has_type))
|
if (lhs.lhs_lvar != NULL && (is_decl || !lhs.lhs_has_type))
|
||||||
{
|
{
|
||||||
if ((rhs_type->tt_type == VAR_FUNC
|
if ((rhs_type->tt_type == VAR_FUNC
|
||||||
@@ -2230,7 +2227,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
expected = lhs.lhs_member_type;
|
expected = lhs.lhs_member_type;
|
||||||
stacktype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
stacktype = get_type_on_stack(cctx, 0);
|
||||||
if (
|
if (
|
||||||
#ifdef FEAT_FLOAT
|
#ifdef FEAT_FLOAT
|
||||||
// If variable is float operation with number is OK.
|
// If variable is float operation with number is OK.
|
||||||
@@ -2527,7 +2524,8 @@ compile_def_function(
|
|||||||
cctx.ctx_lnum = -1;
|
cctx.ctx_lnum = -1;
|
||||||
cctx.ctx_outer = outer_cctx;
|
cctx.ctx_outer = outer_cctx;
|
||||||
ga_init2(&cctx.ctx_locals, sizeof(lvar_T), 10);
|
ga_init2(&cctx.ctx_locals, sizeof(lvar_T), 10);
|
||||||
ga_init2(&cctx.ctx_type_stack, sizeof(type_T *), 50);
|
// Each entry on the type stack consists of two type pointers.
|
||||||
|
ga_init2(&cctx.ctx_type_stack, sizeof(type2_T), 50);
|
||||||
ga_init2(&cctx.ctx_imports, sizeof(imported_T), 10);
|
ga_init2(&cctx.ctx_imports, sizeof(imported_T), 10);
|
||||||
cctx.ctx_type_list = &ufunc->uf_type_list;
|
cctx.ctx_type_list = &ufunc->uf_type_list;
|
||||||
ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50);
|
ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50);
|
||||||
@@ -2564,7 +2562,6 @@ compile_def_function(
|
|||||||
SOURCING_LNUM = 0; // line number unknown
|
SOURCING_LNUM = 0; // line number unknown
|
||||||
for (i = 0; i < count; ++i)
|
for (i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx.ctx_type_stack;
|
|
||||||
type_T *val_type;
|
type_T *val_type;
|
||||||
int arg_idx = first_def_arg + i;
|
int arg_idx = first_def_arg + i;
|
||||||
where_T where = WHERE_INIT;
|
where_T where = WHERE_INIT;
|
||||||
@@ -2588,7 +2585,7 @@ compile_def_function(
|
|||||||
// If no type specified use the type of the default value.
|
// If no type specified use the type of the default value.
|
||||||
// Otherwise check that the default value type matches the
|
// Otherwise check that the default value type matches the
|
||||||
// specified type.
|
// specified type.
|
||||||
val_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
val_type = get_type_on_stack(&cctx, 0);
|
||||||
where.wt_index = arg_idx + 1;
|
where.wt_index = arg_idx + 1;
|
||||||
if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
|
if (ufunc->uf_arg_types[arg_idx] == &t_unknown)
|
||||||
{
|
{
|
||||||
|
|||||||
111
src/vim9expr.c
111
src/vim9expr.c
@@ -77,7 +77,7 @@ clear_ppconst(ppconst_T *ppconst)
|
|||||||
int
|
int
|
||||||
compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
||||||
{
|
{
|
||||||
type_T **typep;
|
type2_T *typep;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
vartype_T vartype;
|
vartype_T vartype;
|
||||||
type_T *idxtype;
|
type_T *idxtype;
|
||||||
@@ -85,12 +85,13 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
// We can index a list, dict and blob. If we don't know the type
|
// We can index a list, dict and blob. If we don't know the type
|
||||||
// we can use the index value type. If we still don't know use an "ANY"
|
// we can use the index value type. If we still don't know use an "ANY"
|
||||||
// instruction.
|
// instruction.
|
||||||
typep = ((type_T **)stack->ga_data) + stack->ga_len
|
// TODO: what about the decl type?
|
||||||
- (is_slice ? 3 : 2);
|
typep = (((type2_T *)stack->ga_data) + stack->ga_len - (is_slice ? 3 : 2));
|
||||||
vartype = (*typep)->tt_type;
|
vartype = typep->type_curr->tt_type;
|
||||||
idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
idxtype = (((type2_T *)stack->ga_data) + stack->ga_len - 1)->type_curr;
|
||||||
// If the index is a string, the variable must be a Dict.
|
// If the index is a string, the variable must be a Dict.
|
||||||
if ((*typep == &t_any || *typep == &t_unknown) && idxtype == &t_string)
|
if ((typep->type_curr == &t_any || typep->type_curr == &t_unknown)
|
||||||
|
&& idxtype == &t_string)
|
||||||
vartype = VAR_DICT;
|
vartype = VAR_DICT;
|
||||||
if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB)
|
if (vartype == VAR_STRING || vartype == VAR_LIST || vartype == VAR_BLOB)
|
||||||
{
|
{
|
||||||
@@ -98,7 +99,7 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
idxtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
idxtype = get_type_on_stack(cctx, 1);
|
||||||
if (need_type(idxtype, &t_number, -2, 0, cctx,
|
if (need_type(idxtype, &t_number, -2, 0, cctx,
|
||||||
FALSE, FALSE) == FAIL)
|
FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -112,19 +113,29 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
emsg(_(e_cannot_slice_dictionary));
|
emsg(_(e_cannot_slice_dictionary));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if ((*typep)->tt_type == VAR_DICT)
|
if (typep->type_curr->tt_type == VAR_DICT)
|
||||||
{
|
{
|
||||||
*typep = (*typep)->tt_member;
|
typep->type_curr = typep->type_curr->tt_member;
|
||||||
if (*typep == &t_unknown)
|
if (typep->type_curr == &t_unknown)
|
||||||
// empty dict was used
|
// empty dict was used
|
||||||
*typep = &t_any;
|
typep->type_curr = &t_any;
|
||||||
|
if (typep->type_decl->tt_type == VAR_DICT)
|
||||||
|
{
|
||||||
|
typep->type_decl = typep->type_decl->tt_member;
|
||||||
|
if (typep->type_decl == &t_unknown)
|
||||||
|
// empty dict was used
|
||||||
|
typep->type_decl = &t_any;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
typep->type_decl = typep->type_curr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (need_type(*typep, &t_dict_any, -2, 0, cctx,
|
if (need_type(typep->type_curr, &t_dict_any, -2, 0, cctx,
|
||||||
FALSE, FALSE) == FAIL)
|
FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
*typep = &t_any;
|
typep->type_curr = &t_any;
|
||||||
|
typep->type_decl = &t_any;
|
||||||
}
|
}
|
||||||
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
if (may_generate_2STRING(-1, FALSE, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -135,7 +146,8 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
else if (vartype == VAR_STRING)
|
else if (vartype == VAR_STRING)
|
||||||
{
|
{
|
||||||
*typep = &t_string;
|
typep->type_curr = &t_string;
|
||||||
|
typep->type_decl = &t_string;
|
||||||
if ((is_slice
|
if ((is_slice
|
||||||
? generate_instr_drop(cctx, ISN_STRSLICE, 2)
|
? generate_instr_drop(cctx, ISN_STRSLICE, 2)
|
||||||
: generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
|
: generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
|
||||||
@@ -145,18 +157,21 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
{
|
{
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
*typep = &t_blob;
|
typep->type_curr = &t_blob;
|
||||||
|
typep->type_decl = &t_blob;
|
||||||
if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL)
|
if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*typep = &t_number;
|
typep->type_curr = &t_number;
|
||||||
|
typep->type_decl = &t_number;
|
||||||
if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL)
|
if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (vartype == VAR_LIST || *typep == &t_any || *typep == &t_unknown)
|
else if (vartype == VAR_LIST || typep->type_curr == &t_any
|
||||||
|
|| typep->type_curr == &t_unknown)
|
||||||
{
|
{
|
||||||
if (is_slice)
|
if (is_slice)
|
||||||
{
|
{
|
||||||
@@ -167,12 +182,21 @@ compile_member(int is_slice, int *keeping_dict, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((*typep)->tt_type == VAR_LIST)
|
if (typep->type_curr->tt_type == VAR_LIST)
|
||||||
{
|
{
|
||||||
*typep = (*typep)->tt_member;
|
typep->type_curr = typep->type_curr->tt_member;
|
||||||
if (*typep == &t_unknown)
|
if (typep->type_curr == &t_unknown)
|
||||||
// empty list was used
|
// empty list was used
|
||||||
*typep = &t_any;
|
typep->type_curr = &t_any;
|
||||||
|
if (typep->type_decl->tt_type == VAR_LIST)
|
||||||
|
{
|
||||||
|
typep->type_decl = typep->type_decl->tt_member;
|
||||||
|
if (typep->type_decl == &t_unknown)
|
||||||
|
// empty list was used
|
||||||
|
typep->type_decl = &t_any;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
typep->type_decl = typep->type_curr;
|
||||||
}
|
}
|
||||||
if (generate_instr_drop(cctx,
|
if (generate_instr_drop(cctx,
|
||||||
vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1)
|
vartype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1)
|
||||||
@@ -709,9 +733,7 @@ compile_call(
|
|||||||
|
|
||||||
if (STRCMP(name, "add") == 0 && argcount == 2)
|
if (STRCMP(name, "add") == 0 && argcount == 2)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *type = get_type_on_stack(cctx, 1);
|
||||||
type_T *type = ((type_T **)stack->ga_data)[
|
|
||||||
stack->ga_len - 2];
|
|
||||||
|
|
||||||
// add() can be compiled to instructions if we know the type
|
// add() can be compiled to instructions if we know the type
|
||||||
if (type->tt_type == VAR_LIST)
|
if (type->tt_type == VAR_LIST)
|
||||||
@@ -758,8 +780,7 @@ compile_call(
|
|||||||
if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
|
if (STRNCMP(namebuf, "g:", 2) != 0 && !is_autoload
|
||||||
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
|
&& compile_load(&p, namebuf + varlen, cctx, FALSE, FALSE) == OK)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *type = get_type_on_stack(cctx, 0);
|
||||||
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
|
||||||
|
|
||||||
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
|
res = generate_PCALL(cctx, argcount, namebuf, type, FALSE);
|
||||||
goto theend;
|
goto theend;
|
||||||
@@ -1421,10 +1442,9 @@ skip_expr_cctx(char_u **arg, cctx_T *cctx)
|
|||||||
int
|
int
|
||||||
bool_on_stack(cctx_T *cctx)
|
bool_on_stack(cctx_T *cctx)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
if (type == &t_bool)
|
if (type == &t_bool)
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
@@ -1470,10 +1490,9 @@ compile_leader(cctx_T *cctx, int numeric_only, char_u *start, char_u **end)
|
|||||||
{
|
{
|
||||||
int negate = *p == '-';
|
int negate = *p == '-';
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
if (type != &t_float && need_type(type, &t_number,
|
if (type != &t_float && need_type(type, &t_number,
|
||||||
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
-1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -1594,7 +1613,6 @@ compile_subscript(
|
|||||||
// is not a function call.
|
// is not a function call.
|
||||||
if (**arg == '(')
|
if (**arg == '(')
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
int argcount = 0;
|
int argcount = 0;
|
||||||
|
|
||||||
@@ -1603,7 +1621,7 @@ compile_subscript(
|
|||||||
ppconst->pp_is_const = FALSE;
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
// funcref(arg)
|
// funcref(arg)
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
|
|
||||||
*arg = skipwhite(p + 1);
|
*arg = skipwhite(p + 1);
|
||||||
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
|
if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
|
||||||
@@ -1672,12 +1690,13 @@ compile_subscript(
|
|||||||
// instructions of the expression and move the type of the
|
// instructions of the expression and move the type of the
|
||||||
// expression after the argument types. This is what ISN_PCALL
|
// expression after the argument types. This is what ISN_PCALL
|
||||||
// expects.
|
// expects.
|
||||||
stack = &cctx->ctx_type_stack;
|
|
||||||
arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end;
|
arg_isn_count = cctx->ctx_instr.ga_len - expr_isn_end;
|
||||||
if (arg_isn_count > 0)
|
if (arg_isn_count > 0)
|
||||||
{
|
{
|
||||||
int expr_isn_count = expr_isn_end - expr_isn_start;
|
int expr_isn_count = expr_isn_end - expr_isn_start;
|
||||||
isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count);
|
isn_T *isn = ALLOC_MULT(isn_T, expr_isn_count);
|
||||||
|
type_T *decl_type;
|
||||||
|
type2_T *typep;
|
||||||
|
|
||||||
if (isn == NULL)
|
if (isn == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -1693,15 +1712,19 @@ compile_subscript(
|
|||||||
isn, sizeof(isn_T) * expr_isn_count);
|
isn, sizeof(isn_T) * expr_isn_count);
|
||||||
vim_free(isn);
|
vim_free(isn);
|
||||||
|
|
||||||
type = ((type_T **)stack->ga_data)[type_idx_start];
|
typep = ((type2_T *)stack->ga_data) + type_idx_start;
|
||||||
mch_memmove(((type_T **)stack->ga_data) + type_idx_start,
|
type = typep->type_curr;
|
||||||
((type_T **)stack->ga_data) + type_idx_start + 1,
|
decl_type = typep->type_decl;
|
||||||
sizeof(type_T *)
|
mch_memmove(((type2_T *)stack->ga_data) + type_idx_start,
|
||||||
|
((type2_T *)stack->ga_data) + type_idx_start + 1,
|
||||||
|
sizeof(type2_T)
|
||||||
* (stack->ga_len - type_idx_start - 1));
|
* (stack->ga_len - type_idx_start - 1));
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
|
typep = ((type2_T *)stack->ga_data) + stack->ga_len - 1;
|
||||||
|
typep->type_curr = type;
|
||||||
|
typep->type_decl = decl_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL)
|
if (generate_PCALL(cctx, argcount, p - 2, type, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@@ -2152,12 +2175,11 @@ compile_expr7(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
|
|
||||||
if (want_type != NULL)
|
if (want_type != NULL)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *actual;
|
type_T *actual;
|
||||||
where_T where = WHERE_INIT;
|
where_T where = WHERE_INIT;
|
||||||
|
|
||||||
generate_ppconst(cctx, ppconst);
|
generate_ppconst(cctx, ppconst);
|
||||||
actual = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
actual = get_type_on_stack(cctx, 0);
|
||||||
if (check_type_maybe(want_type, actual, FALSE, where) != OK)
|
if (check_type_maybe(want_type, actual, FALSE, where) != OK)
|
||||||
{
|
{
|
||||||
if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE)
|
if (need_type(actual, want_type, -1, 0, cctx, FALSE, FALSE)
|
||||||
@@ -2781,7 +2803,7 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
generate_JUMP(cctx, op_falsy
|
generate_JUMP(cctx, op_falsy
|
||||||
? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0);
|
? JUMP_AND_KEEP_IF_TRUE : JUMP_IF_FALSE, 0);
|
||||||
if (op_falsy)
|
if (op_falsy)
|
||||||
type1 = ((type_T **)stack->ga_data)[stack->ga_len];
|
type1 = get_type_on_stack(cctx, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluate the second expression; any type is accepted
|
// evaluate the second expression; any type is accepted
|
||||||
@@ -2797,8 +2819,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
if (!op_falsy)
|
if (!op_falsy)
|
||||||
{
|
{
|
||||||
// remember the type and drop it
|
// remember the type and drop it
|
||||||
|
type1 = get_type_on_stack(cctx, 0);
|
||||||
--stack->ga_len;
|
--stack->ga_len;
|
||||||
type1 = ((type_T **)stack->ga_data)[stack->ga_len];
|
|
||||||
|
|
||||||
end_idx = instr->ga_len;
|
end_idx = instr->ga_len;
|
||||||
generate_JUMP(cctx, JUMP_ALWAYS, 0);
|
generate_JUMP(cctx, JUMP_ALWAYS, 0);
|
||||||
@@ -2849,7 +2871,8 @@ compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
|
|||||||
ppconst->pp_is_const = FALSE;
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
// If the types differ, the result has a more generic type.
|
// If the types differ, the result has a more generic type.
|
||||||
typep = ((type_T **)stack->ga_data) + stack->ga_len - 1;
|
typep = &((((type2_T *)stack->ga_data)
|
||||||
|
+ stack->ga_len - 1)->type_curr);
|
||||||
common_type(type1, *typep, typep, cctx->ctx_type_list);
|
common_type(type1, *typep, typep, cctx->ctx_type_list);
|
||||||
|
|
||||||
// jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE
|
// jump here from JUMP_ALWAYS or JUMP_AND_KEEP_IF_TRUE
|
||||||
|
|||||||
262
src/vim9instr.c
262
src/vim9instr.c
@@ -57,33 +57,45 @@ generate_instr(cctx_T *cctx, isntype_T isn_type)
|
|||||||
isn_T *
|
isn_T *
|
||||||
generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop)
|
generate_instr_drop(cctx_T *cctx, isntype_T isn_type, int drop)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_NULL_IF_SKIP(cctx);
|
RETURN_NULL_IF_SKIP(cctx);
|
||||||
stack->ga_len -= drop;
|
cctx->ctx_type_stack.ga_len -= drop;
|
||||||
return generate_instr(cctx, isn_type);
|
return generate_instr(cctx, isn_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate instruction "isn_type" and put "type" on the type stack.
|
* Generate instruction "isn_type" and put "type" on the type stack,
|
||||||
|
* use "decl_type" for the declared type.
|
||||||
*/
|
*/
|
||||||
isn_T *
|
isn_T *
|
||||||
generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
|
generate_instr_type2(
|
||||||
|
cctx_T *cctx,
|
||||||
|
isntype_T isn_type,
|
||||||
|
type_T *type,
|
||||||
|
type_T *decl_type)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
if ((isn = generate_instr(cctx, isn_type)) == NULL)
|
if ((isn = generate_instr(cctx, isn_type)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
if (push_type_stack2(cctx, type == NULL ? &t_any : type,
|
||||||
|
decl_type == NULL ? &t_any : decl_type) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = type == NULL ? &t_any : type;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return isn;
|
return isn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate instruction "isn_type" and put "type" on the type stack.
|
||||||
|
* Uses "any" for the declared type, which works for constants. For declared
|
||||||
|
* variables use generate_instr_type2().
|
||||||
|
*/
|
||||||
|
isn_T *
|
||||||
|
generate_instr_type(cctx_T *cctx, isntype_T isn_type, type_T *type)
|
||||||
|
{
|
||||||
|
return generate_instr_type2(cctx, isn_type, type, &t_any);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate an ISN_DEBUG instruction.
|
* Generate an ISN_DEBUG instruction.
|
||||||
*/
|
*/
|
||||||
@@ -111,12 +123,11 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
|
|||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
isntype_T isntype = ISN_2STRING;
|
isntype_T isntype = ISN_2STRING;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *type;
|
||||||
type_T **type;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
type = ((type_T **)stack->ga_data) + stack->ga_len + offset;
|
type = get_type_on_stack(cctx, -1 - offset);
|
||||||
switch ((*type)->tt_type)
|
switch (type->tt_type)
|
||||||
{
|
{
|
||||||
// nothing to be done
|
// nothing to be done
|
||||||
case VAR_STRING: return OK;
|
case VAR_STRING: return OK;
|
||||||
@@ -152,11 +163,11 @@ may_generate_2STRING(int offset, int tolerant, cctx_T *cctx)
|
|||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
case VAR_CHANNEL:
|
case VAR_CHANNEL:
|
||||||
case VAR_INSTR:
|
case VAR_INSTR:
|
||||||
to_string_error((*type)->tt_type);
|
to_string_error(type->tt_type);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*type = &t_string;
|
set_type_on_stack(cctx, &t_string, -1 - offset);
|
||||||
if ((isn = generate_instr(cctx, isntype)) == NULL)
|
if ((isn = generate_instr(cctx, isntype)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.tostring.offset = offset;
|
isn->isn_arg.tostring.offset = offset;
|
||||||
@@ -193,7 +204,6 @@ generate_add_instr(
|
|||||||
type_T *type2,
|
type_T *type2,
|
||||||
exprtype_T expr_type)
|
exprtype_T expr_type)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
isn_T *isn = generate_instr_drop(cctx,
|
isn_T *isn = generate_instr_drop(cctx,
|
||||||
vartype == VAR_NUMBER ? ISN_OPNR
|
vartype == VAR_NUMBER ? ISN_OPNR
|
||||||
: vartype == VAR_LIST ? ISN_ADDLIST
|
: vartype == VAR_LIST ? ISN_ADDLIST
|
||||||
@@ -225,7 +235,7 @@ generate_add_instr(
|
|||||||
if (vartype == VAR_LIST
|
if (vartype == VAR_LIST
|
||||||
&& type1->tt_type == VAR_LIST && type2->tt_type == VAR_LIST
|
&& type1->tt_type == VAR_LIST && type2->tt_type == VAR_LIST
|
||||||
&& type1->tt_member != type2->tt_member)
|
&& type1->tt_member != type2->tt_member)
|
||||||
(((type_T **)stack->ga_data)[stack->ga_len - 1]) = &t_list_any;
|
set_type_on_stack(cctx, &t_list_any, 0);
|
||||||
|
|
||||||
return isn == NULL ? FAIL : OK;
|
return isn == NULL ? FAIL : OK;
|
||||||
}
|
}
|
||||||
@@ -256,7 +266,6 @@ operator_type(type_T *type1, type_T *type2)
|
|||||||
int
|
int
|
||||||
generate_two_op(cctx_T *cctx, char_u *op)
|
generate_two_op(cctx_T *cctx, char_u *op)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *type1;
|
type_T *type1;
|
||||||
type_T *type2;
|
type_T *type2;
|
||||||
vartype_T vartype;
|
vartype_T vartype;
|
||||||
@@ -265,8 +274,8 @@ generate_two_op(cctx_T *cctx, char_u *op)
|
|||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
|
|
||||||
// Get the known type of the two items on the stack.
|
// Get the known type of the two items on the stack.
|
||||||
type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
type1 = get_type_on_stack(cctx, 1);
|
||||||
type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type2 = get_type_on_stack(cctx, 0);
|
||||||
vartype = operator_type(type1, type2);
|
vartype = operator_type(type1, type2);
|
||||||
|
|
||||||
switch (*op)
|
switch (*op)
|
||||||
@@ -323,7 +332,7 @@ generate_two_op(cctx_T *cctx, char_u *op)
|
|||||||
&& (type2->tt_type == VAR_NUMBER || type2->tt_type == VAR_FLOAT))
|
&& (type2->tt_type == VAR_NUMBER || type2->tt_type == VAR_FLOAT))
|
||||||
type = &t_float;
|
type = &t_float;
|
||||||
#endif
|
#endif
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = type;
|
set_type_on_stack(cctx, type, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -415,8 +424,8 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic)
|
|||||||
// Get the known type of the two items on the stack. If they are matching
|
// Get the known type of the two items on the stack. If they are matching
|
||||||
// use a type-specific instruction. Otherwise fall back to runtime type
|
// use a type-specific instruction. Otherwise fall back to runtime type
|
||||||
// checking.
|
// checking.
|
||||||
type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]->tt_type;
|
type1 = get_type_on_stack(cctx, 1)->tt_type;
|
||||||
type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type;
|
type2 = get_type_on_stack(cctx, 0)->tt_type;
|
||||||
isntype = get_compare_isn(exprtype, type1, type2);
|
isntype = get_compare_isn(exprtype, type1, type2);
|
||||||
if (isntype == ISN_DROP)
|
if (isntype == ISN_DROP)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -430,7 +439,7 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic)
|
|||||||
if (stack->ga_len >= 2)
|
if (stack->ga_len >= 2)
|
||||||
{
|
{
|
||||||
--stack->ga_len;
|
--stack->ga_len;
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
|
set_type_on_stack(cctx, &t_bool, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -444,7 +453,6 @@ generate_COMPARE(cctx_T *cctx, exprtype_T exprtype, int ic)
|
|||||||
generate_2BOOL(cctx_T *cctx, int invert, int offset)
|
generate_2BOOL(cctx_T *cctx, int invert, int offset)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
|
||||||
@@ -453,7 +461,7 @@ generate_2BOOL(cctx_T *cctx, int invert, int offset)
|
|||||||
isn->isn_arg.tobool.offset = offset;
|
isn->isn_arg.tobool.offset = offset;
|
||||||
|
|
||||||
// type becomes bool
|
// type becomes bool
|
||||||
((type_T **)stack->ga_data)[stack->ga_len + offset] = &t_bool;
|
set_type_on_stack(cctx, &t_bool, -1 - offset);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -465,14 +473,13 @@ generate_2BOOL(cctx_T *cctx, int invert, int offset)
|
|||||||
generate_COND2BOOL(cctx_T *cctx)
|
generate_COND2BOOL(cctx_T *cctx)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_COND2BOOL)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
// type becomes bool
|
// type becomes bool
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_bool;
|
set_type_on_stack(cctx, &t_bool, 0);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -485,7 +492,6 @@ generate_TYPECHECK(
|
|||||||
int argidx)
|
int argidx)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
|
||||||
@@ -495,7 +501,7 @@ generate_TYPECHECK(
|
|||||||
isn->isn_arg.type.ct_arg_idx = (int8_T)argidx;
|
isn->isn_arg.type.ct_arg_idx = (int8_T)argidx;
|
||||||
|
|
||||||
// type becomes expected
|
// type becomes expected
|
||||||
((type_T **)stack->ga_data)[stack->ga_len + offset] = expected;
|
set_type_on_stack(cctx, expected, -1 - offset);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -567,7 +573,6 @@ generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
|
|||||||
generate_PUSHNR(cctx_T *cctx, varnumber_T number)
|
generate_PUSHNR(cctx_T *cctx, varnumber_T number)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL)
|
if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL)
|
||||||
@@ -576,7 +581,7 @@ generate_PUSHNR(cctx_T *cctx, varnumber_T number)
|
|||||||
|
|
||||||
if (number == 0 || number == 1)
|
if (number == 0 || number == 1)
|
||||||
// A 0 or 1 number can also be used as a bool.
|
// A 0 or 1 number can also be used as a bool.
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_number_bool;
|
set_type_on_stack(cctx, &t_number_bool, 0);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,9 +752,7 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type)
|
|||||||
generate_GETITEM(cctx_T *cctx, int index, int with_op)
|
generate_GETITEM(cctx_T *cctx, int index, int with_op)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *type = get_type_on_stack(cctx, with_op ? 1 : 0);
|
||||||
type_T *type = ((type_T **)stack->ga_data)[stack->ga_len
|
|
||||||
- (with_op ? 2 : 1)];
|
|
||||||
type_T *item_type = &t_any;
|
type_T *item_type = &t_any;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
@@ -767,11 +770,7 @@ generate_GETITEM(cctx_T *cctx, int index, int with_op)
|
|||||||
isn->isn_arg.getitem.gi_with_op = with_op;
|
isn->isn_arg.getitem.gi_with_op = with_op;
|
||||||
|
|
||||||
// add the item type to the type stack
|
// add the item type to the type stack
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
return push_type_stack(cctx, item_type);
|
||||||
return FAIL;
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = item_type;
|
|
||||||
++stack->ga_len;
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -895,7 +894,7 @@ generate_LOAD(
|
|||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr_type(cctx, isn_type, type)) == NULL)
|
if ((isn = generate_instr_type2(cctx, isn_type, type, type)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
isn->isn_arg.string = vim_strsave(name);
|
isn->isn_arg.string = vim_strsave(name);
|
||||||
@@ -918,7 +917,7 @@ generate_LOADOUTER(
|
|||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr_type(cctx, ISN_LOADOUTER, type)) == NULL)
|
if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.outer.outer_idx = idx;
|
isn->isn_arg.outer.outer_idx = idx;
|
||||||
isn->isn_arg.outer.outer_depth = nesting;
|
isn->isn_arg.outer.outer_depth = nesting;
|
||||||
@@ -1050,34 +1049,27 @@ generate_VIM9SCRIPT(
|
|||||||
generate_NEWLIST(cctx_T *cctx, int count)
|
generate_NEWLIST(cctx_T *cctx, int count)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *member_type;
|
||||||
|
type_T *decl_member_type;
|
||||||
type_T *type;
|
type_T *type;
|
||||||
type_T *member;
|
type_T *decl_type;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.number = count;
|
isn->isn_arg.number = count;
|
||||||
|
|
||||||
// get the member type from all the items on the stack.
|
// Get the member type and the declared member type from all the items on
|
||||||
if (count == 0)
|
// the stack.
|
||||||
member = &t_unknown;
|
member_type = get_member_type_from_stack(count, 1, &decl_member_type, cctx);
|
||||||
else
|
type = get_list_type(member_type, cctx->ctx_type_list);
|
||||||
member = get_member_type_from_stack(
|
decl_type = get_list_type(decl_member_type, cctx->ctx_type_list);
|
||||||
((type_T **)stack->ga_data) + stack->ga_len, count, 1,
|
|
||||||
cctx->ctx_type_list);
|
|
||||||
type = get_list_type(member, cctx->ctx_type_list);
|
|
||||||
|
|
||||||
// drop the value types
|
// drop the value types
|
||||||
stack->ga_len -= count;
|
cctx->ctx_type_stack.ga_len -= count;
|
||||||
|
|
||||||
// add the list type to the type stack
|
// add the list type to the type stack
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
return push_type_stack2(cctx, type, decl_type);
|
||||||
return FAIL;
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = type;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1087,33 +1079,26 @@ generate_NEWLIST(cctx_T *cctx, int count)
|
|||||||
generate_NEWDICT(cctx_T *cctx, int count)
|
generate_NEWDICT(cctx_T *cctx, int count)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *member_type;
|
||||||
|
type_T *decl_member_type;
|
||||||
type_T *type;
|
type_T *type;
|
||||||
type_T *member;
|
type_T *decl_type;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.number = count;
|
isn->isn_arg.number = count;
|
||||||
|
|
||||||
if (count == 0)
|
member_type = get_member_type_from_stack(count, 2,
|
||||||
member = &t_void;
|
&decl_member_type, cctx);
|
||||||
else
|
type = get_dict_type(member_type, cctx->ctx_type_list);
|
||||||
member = get_member_type_from_stack(
|
decl_type = get_dict_type(decl_member_type, cctx->ctx_type_list);
|
||||||
((type_T **)stack->ga_data) + stack->ga_len, count, 2,
|
|
||||||
cctx->ctx_type_list);
|
|
||||||
type = get_dict_type(member, cctx->ctx_type_list);
|
|
||||||
|
|
||||||
// drop the key and value types
|
// drop the key and value types
|
||||||
stack->ga_len -= 2 * count;
|
cctx->ctx_type_stack.ga_len -= 2 * count;
|
||||||
|
|
||||||
// add the dict type to the type stack
|
// add the dict type to the type stack
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
return push_type_stack2(cctx, type, decl_type);
|
||||||
return FAIL;
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = type;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1123,7 +1108,7 @@ generate_NEWDICT(cctx_T *cctx, int count)
|
|||||||
generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
|
generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
type_T *type;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
|
||||||
@@ -1139,13 +1124,8 @@ generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc)
|
|||||||
if (ufunc->uf_flags & FC_CLOSURE)
|
if (ufunc->uf_flags & FC_CLOSURE)
|
||||||
cctx->ctx_ufunc->uf_flags |= FC_CLOSURE;
|
cctx->ctx_ufunc->uf_flags |= FC_CLOSURE;
|
||||||
|
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
type = ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type;
|
||||||
return FAIL;
|
return push_type_stack(cctx, type);
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] =
|
|
||||||
ufunc->uf_func_type == NULL ? &t_func_any : ufunc->uf_func_type;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1237,20 +1217,14 @@ generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off)
|
|||||||
generate_FOR(cctx_T *cctx, int loop_idx)
|
generate_FOR(cctx_T *cctx, int loop_idx)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.forloop.for_idx = loop_idx;
|
isn->isn_arg.forloop.for_idx = loop_idx;
|
||||||
|
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
|
||||||
return FAIL;
|
|
||||||
// type doesn't matter, will be stored next
|
// type doesn't matter, will be stored next
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
|
return push_type_stack(cctx, &t_any);
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Generate an ISN_TRYCONT instruction.
|
* Generate an ISN_TRYCONT instruction.
|
||||||
@@ -1281,9 +1255,11 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
|||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
int argoff;
|
int argoff;
|
||||||
type_T **argtypes = NULL;
|
type2_T *typep;
|
||||||
type_T *shuffled_argtypes[MAX_FUNC_ARGS];
|
type2_T *argtypes = NULL;
|
||||||
type_T *maptype = NULL;
|
type2_T shuffled_argtypes[MAX_FUNC_ARGS];
|
||||||
|
type2_T *maptype = NULL;
|
||||||
|
type_T *type;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
argoff = check_internal_func(func_idx, argcount);
|
argoff = check_internal_func(func_idx, argcount);
|
||||||
@@ -1301,22 +1277,30 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
|||||||
if (argcount > 0)
|
if (argcount > 0)
|
||||||
{
|
{
|
||||||
// Check the types of the arguments.
|
// Check the types of the arguments.
|
||||||
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
|
typep = ((type2_T *)stack->ga_data) + stack->ga_len - argcount;
|
||||||
if (method_call && argoff > 1)
|
if (method_call && argoff > 1)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < argcount; ++i)
|
for (i = 0; i < argcount; ++i)
|
||||||
shuffled_argtypes[i] = (i < argoff - 1)
|
shuffled_argtypes[i] = (i < argoff - 1)
|
||||||
? argtypes[i + 1]
|
? typep[i + 1]
|
||||||
: (i == argoff - 1) ? argtypes[0] : argtypes[i];
|
: (i == argoff - 1) ? typep[0] : typep[i];
|
||||||
|
argtypes = shuffled_argtypes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < argcount; ++i)
|
||||||
|
shuffled_argtypes[i] = typep[i];
|
||||||
argtypes = shuffled_argtypes;
|
argtypes = shuffled_argtypes;
|
||||||
}
|
}
|
||||||
if (internal_func_check_arg_types(argtypes, func_idx, argcount,
|
if (internal_func_check_arg_types(argtypes, func_idx, argcount,
|
||||||
cctx) == FAIL)
|
cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
if (internal_func_is_map(func_idx))
|
if (internal_func_is_map(func_idx))
|
||||||
maptype = *argtypes;
|
maptype = argtypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_BCALL)) == NULL)
|
||||||
@@ -1326,16 +1310,14 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
|||||||
|
|
||||||
// Drop the argument types and push the return type.
|
// Drop the argument types and push the return type.
|
||||||
stack->ga_len -= argcount;
|
stack->ga_len -= argcount;
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
type = internal_func_ret_type(func_idx, argcount, argtypes);
|
||||||
|
if (push_type_stack(cctx, type) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] =
|
|
||||||
internal_func_ret_type(func_idx, argcount, argtypes);
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
if (maptype != NULL && maptype->tt_member != NULL
|
if (maptype != NULL && maptype[0].type_curr->tt_member != NULL
|
||||||
&& maptype->tt_member != &t_any)
|
&& maptype[0].type_curr->tt_member != &t_any)
|
||||||
// Check that map() didn't change the item types.
|
// Check that map() didn't change the item types.
|
||||||
generate_TYPECHECK(cctx, maptype, -1, 1);
|
generate_TYPECHECK(cctx, maptype[0].type_curr, -1, 1);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -1347,14 +1329,13 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
|
|||||||
int
|
int
|
||||||
generate_LISTAPPEND(cctx_T *cctx)
|
generate_LISTAPPEND(cctx_T *cctx)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *list_type;
|
type_T *list_type;
|
||||||
type_T *item_type;
|
type_T *item_type;
|
||||||
type_T *expected;
|
type_T *expected;
|
||||||
|
|
||||||
// Caller already checked that list_type is a list.
|
// Caller already checked that list_type is a list.
|
||||||
list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
|
list_type = get_type_on_stack(cctx, 1);
|
||||||
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
item_type = get_type_on_stack(cctx, 0);
|
||||||
expected = list_type->tt_member;
|
expected = list_type->tt_member;
|
||||||
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
if (need_type(item_type, expected, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@@ -1362,7 +1343,7 @@ generate_LISTAPPEND(cctx_T *cctx)
|
|||||||
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
|
if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
--stack->ga_len; // drop the argument
|
--cctx->ctx_type_stack.ga_len; // drop the argument
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1373,18 +1354,17 @@ generate_LISTAPPEND(cctx_T *cctx)
|
|||||||
int
|
int
|
||||||
generate_BLOBAPPEND(cctx_T *cctx)
|
generate_BLOBAPPEND(cctx_T *cctx)
|
||||||
{
|
{
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *item_type;
|
type_T *item_type;
|
||||||
|
|
||||||
// Caller already checked that blob_type is a blob.
|
// Caller already checked that blob_type is a blob.
|
||||||
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
item_type = get_type_on_stack(cctx, 0);
|
||||||
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
if (need_type(item_type, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
|
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
|
||||||
--stack->ga_len; // drop the argument
|
--cctx->ctx_type_stack.ga_len; // drop the argument
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1396,7 +1376,6 @@ generate_BLOBAPPEND(cctx_T *cctx)
|
|||||||
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
int regular_args = ufunc->uf_args.ga_len;
|
int regular_args = ufunc->uf_args.ga_len;
|
||||||
int argcount = pushed_argcount;
|
int argcount = pushed_argcount;
|
||||||
|
|
||||||
@@ -1424,7 +1403,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
|||||||
type_T *expected;
|
type_T *expected;
|
||||||
type_T *actual;
|
type_T *actual;
|
||||||
|
|
||||||
actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i];
|
actual = get_type_on_stack(cctx, argcount - i - 1);
|
||||||
if (actual == &t_special
|
if (actual == &t_special
|
||||||
&& i >= regular_args - ufunc->uf_def_args.ga_len)
|
&& i >= regular_args - ufunc->uf_def_args.ga_len)
|
||||||
{
|
{
|
||||||
@@ -1479,14 +1458,11 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
|||||||
isn->isn_arg.ufunc.cuf_argcount = argcount;
|
isn->isn_arg.ufunc.cuf_argcount = argcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack->ga_len -= argcount; // drop the arguments
|
// drop the argument types
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
cctx->ctx_type_stack.ga_len -= argcount;
|
||||||
return FAIL;
|
|
||||||
// add return value
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = ufunc->uf_ret_type;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
// add return type
|
||||||
|
return push_type_stack(cctx, ufunc->uf_ret_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1496,7 +1472,6 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
|||||||
generate_UCALL(cctx_T *cctx, char_u *name, int argcount)
|
generate_UCALL(cctx_T *cctx, char_u *name, int argcount)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL)
|
||||||
@@ -1504,14 +1479,11 @@ generate_UCALL(cctx_T *cctx, char_u *name, int argcount)
|
|||||||
isn->isn_arg.ufunc.cuf_name = vim_strsave(name);
|
isn->isn_arg.ufunc.cuf_name = vim_strsave(name);
|
||||||
isn->isn_arg.ufunc.cuf_argcount = argcount;
|
isn->isn_arg.ufunc.cuf_argcount = argcount;
|
||||||
|
|
||||||
stack->ga_len -= argcount; // drop the arguments
|
// drop the argument types
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
cctx->ctx_type_stack.ga_len -= argcount;
|
||||||
return FAIL;
|
|
||||||
// add return value
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
// add return value
|
||||||
|
return push_type_stack(cctx, &t_any);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1527,7 +1499,6 @@ generate_PCALL(
|
|||||||
int at_top)
|
int at_top)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *ret_type;
|
type_T *ret_type;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
@@ -1557,8 +1528,7 @@ generate_PCALL(
|
|||||||
for (i = 0; i < argcount; ++i)
|
for (i = 0; i < argcount; ++i)
|
||||||
{
|
{
|
||||||
int offset = -argcount + i - (at_top ? 0 : 1);
|
int offset = -argcount + i - (at_top ? 0 : 1);
|
||||||
type_T *actual = ((type_T **)stack->ga_data)[
|
type_T *actual = get_type_on_stack(cctx, -1 - offset);
|
||||||
stack->ga_len + offset];
|
|
||||||
type_T *expected;
|
type_T *expected;
|
||||||
|
|
||||||
if (varargs && i >= type->tt_argcount - 1)
|
if (varargs && i >= type->tt_argcount - 1)
|
||||||
@@ -1594,10 +1564,11 @@ generate_PCALL(
|
|||||||
isn->isn_arg.pfunc.cpf_top = at_top;
|
isn->isn_arg.pfunc.cpf_top = at_top;
|
||||||
isn->isn_arg.pfunc.cpf_argcount = argcount;
|
isn->isn_arg.pfunc.cpf_argcount = argcount;
|
||||||
|
|
||||||
stack->ga_len -= argcount; // drop the arguments
|
// drop the arguments and the funcref/partial
|
||||||
|
cctx->ctx_type_stack.ga_len -= argcount + 1;
|
||||||
|
|
||||||
// drop the funcref/partial, get back the return value
|
// push the return value
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] = ret_type;
|
push_type_stack(cctx, ret_type);
|
||||||
|
|
||||||
// If partial is above the arguments it must be cleared and replaced with
|
// If partial is above the arguments it must be cleared and replaced with
|
||||||
// the return value.
|
// the return value.
|
||||||
@@ -1614,7 +1585,6 @@ generate_PCALL(
|
|||||||
generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
|
generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
@@ -1623,7 +1593,7 @@ generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
|
|||||||
isn->isn_arg.string = vim_strnsave(name, len);
|
isn->isn_arg.string = vim_strnsave(name, len);
|
||||||
|
|
||||||
// check for dict type
|
// check for dict type
|
||||||
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
type = get_type_on_stack(cctx, 0);
|
||||||
if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown)
|
if (type->tt_type != VAR_DICT && type != &t_any && type != &t_unknown)
|
||||||
{
|
{
|
||||||
char *tofree;
|
char *tofree;
|
||||||
@@ -1636,8 +1606,9 @@ generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len)
|
|||||||
// change dict type to dict member type
|
// change dict type to dict member type
|
||||||
if (type->tt_type == VAR_DICT)
|
if (type->tt_type == VAR_DICT)
|
||||||
{
|
{
|
||||||
((type_T **)stack->ga_data)[stack->ga_len - 1] =
|
type_T *ntype = type->tt_member == &t_unknown
|
||||||
type->tt_member == &t_unknown ? &t_any : type->tt_member;
|
? &t_any : type->tt_member;
|
||||||
|
set_type_on_stack(cctx, ntype, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -1734,19 +1705,13 @@ generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str)
|
|||||||
generate_LEGACY_EVAL(cctx_T *cctx, char_u *line)
|
generate_LEGACY_EVAL(cctx_T *cctx, char_u *line)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.string = vim_strsave(line);
|
isn->isn_arg.string = vim_strsave(line);
|
||||||
|
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
return push_type_stack(cctx, &t_any);
|
||||||
return FAIL;
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = &t_any;
|
|
||||||
++stack->ga_len;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -1767,17 +1732,12 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
|
|||||||
generate_RANGE(cctx_T *cctx, char_u *range)
|
generate_RANGE(cctx_T *cctx, char_u *range)
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
garray_T *stack = &cctx->ctx_type_stack;
|
|
||||||
|
|
||||||
if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.string = range;
|
isn->isn_arg.string = range;
|
||||||
|
|
||||||
if (GA_GROW_FAILS(stack, 1))
|
return push_type_stack(cctx, &t_number);
|
||||||
return FAIL;
|
|
||||||
((type_T **)stack->ga_data)[stack->ga_len] = &t_number;
|
|
||||||
++stack->ga_len;
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
@@ -1192,38 +1192,110 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the member type of a dict or list from the items on the stack.
|
* Push an entry onto the type stack. "type" used both for the current type
|
||||||
* "stack_top" points just after the last type on the type stack.
|
* and the declared type.
|
||||||
|
* Returns FAIL when out of memory.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
push_type_stack(cctx_T *cctx, type_T *type)
|
||||||
|
{
|
||||||
|
return push_type_stack2(cctx, type, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Push an entry onto the type stack. "type" is the current type, "decl_type"
|
||||||
|
* is the declared type.
|
||||||
|
* Returns FAIL when out of memory.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
push_type_stack2(cctx_T *cctx, type_T *type, type_T *decl_type)
|
||||||
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
type2_T *typep;
|
||||||
|
|
||||||
|
if (GA_GROW_FAILS(stack, 1))
|
||||||
|
return FAIL;
|
||||||
|
typep = ((type2_T *)stack->ga_data) + stack->ga_len;
|
||||||
|
typep->type_curr = type;
|
||||||
|
typep->type_decl = decl_type;
|
||||||
|
++stack->ga_len;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the type of the top of the stack to "type".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
set_type_on_stack(cctx_T *cctx, type_T *type, int offset)
|
||||||
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
type2_T *typep = ((type2_T *)stack->ga_data)
|
||||||
|
+ stack->ga_len - 1 - offset;
|
||||||
|
|
||||||
|
typep->type_curr = type;
|
||||||
|
typep->type_decl = &t_any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the type from the type stack. If "offset" is zero the one at the top,
|
||||||
|
* if "offset" is one the type above that, etc.
|
||||||
|
* Returns &t_unknown if there is no such stack entry.
|
||||||
|
*/
|
||||||
|
type_T *
|
||||||
|
get_type_on_stack(cctx_T *cctx, int offset)
|
||||||
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
|
||||||
|
if (offset + 1 > stack->ga_len)
|
||||||
|
return &t_unknown;
|
||||||
|
return (((type2_T *)stack->ga_data) + stack->ga_len - offset - 1)
|
||||||
|
->type_curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the member type of a dict or list from the items on the stack of "cctx".
|
||||||
|
* The declared type is stored in "decl_type".
|
||||||
* For a list "skip" is 1, for a dict "skip" is 2, keys are skipped.
|
* For a list "skip" is 1, for a dict "skip" is 2, keys are skipped.
|
||||||
* Returns &t_void for an empty list or dict.
|
* Returns &t_void for an empty list or dict.
|
||||||
* Otherwise finds the common type of all items.
|
* Otherwise finds the common type of all items.
|
||||||
*/
|
*/
|
||||||
type_T *
|
type_T *
|
||||||
get_member_type_from_stack(
|
get_member_type_from_stack(
|
||||||
type_T **stack_top,
|
|
||||||
int count,
|
int count,
|
||||||
int skip,
|
int skip,
|
||||||
garray_T *type_gap)
|
type_T **decl_type,
|
||||||
|
cctx_T *cctx)
|
||||||
{
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
type2_T *typep = ((type2_T *)stack->ga_data) + stack->ga_len;
|
||||||
|
garray_T *type_gap = cctx->ctx_type_list;
|
||||||
int i;
|
int i;
|
||||||
type_T *result;
|
type_T *result;
|
||||||
|
type_T *decl_result;
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
// Use "any" for an empty list or dict.
|
// Use "unknown" for an empty list or dict.
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
|
{
|
||||||
|
*decl_type = &t_unknown;
|
||||||
return &t_unknown;
|
return &t_unknown;
|
||||||
|
}
|
||||||
|
|
||||||
// Use the first value type for the list member type, then find the common
|
// Use the first value type for the list member type, then find the common
|
||||||
// type from following items.
|
// type from following items.
|
||||||
result = *(stack_top -(count * skip) + skip - 1);
|
result = (typep -(count * skip) + skip - 1)->type_curr;
|
||||||
|
decl_result = (typep -(count * skip) + skip - 1)->type_decl;
|
||||||
for (i = 1; i < count; ++i)
|
for (i = 1; i < count; ++i)
|
||||||
{
|
{
|
||||||
if (result == &t_any)
|
if (result == &t_any)
|
||||||
break; // won't get more common
|
break; // won't get more common
|
||||||
type = *(stack_top -((count - i) * skip) + skip - 1);
|
type = (typep -((count - i) * skip) + skip - 1)->type_curr;
|
||||||
common_type(type, result, &result, type_gap);
|
common_type(type, result, &result, type_gap);
|
||||||
|
type = (typep -((count - i) * skip) + skip - 1)->type_decl;
|
||||||
|
common_type(type, decl_result, &decl_result, type_gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*decl_type = decl_result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user