mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 9.0.0502: a closure in a nested loop in a :def function does not work
Problem: A closure in a nested loop in a :def function does not work. Solution: Use an array of loopvars, one per loop level.
This commit is contained in:
parent
18ee0feb5d
commit
cc34181f99
@ -3329,3 +3329,7 @@ EXTERN char e_cannot_use_type_with_this_variable_str[]
|
|||||||
EXTERN char e_cannot_use_length_endcol_and_endlnum_with_text[]
|
EXTERN char e_cannot_use_length_endcol_and_endlnum_with_text[]
|
||||||
INIT(= N_("E1305: Cannot use \"length\", \"end_col\" and \"end_lnum\" with \"text\""));
|
INIT(= N_("E1305: Cannot use \"length\", \"end_col\" and \"end_lnum\" with \"text\""));
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
EXTERN char e_loop_nesting_too_deep[]
|
||||||
|
INIT(= N_("E1306: Loop nesting too deep"));
|
||||||
|
#endif
|
||||||
|
18
src/eval.c
18
src/eval.c
@ -4807,10 +4807,11 @@ partial_free(partial_T *pt)
|
|||||||
funcstack_check_refcount(pt->pt_funcstack);
|
funcstack_check_refcount(pt->pt_funcstack);
|
||||||
}
|
}
|
||||||
// Similarly for loop variables.
|
// Similarly for loop variables.
|
||||||
if (pt->pt_loopvars != NULL)
|
for (i = 0; i < MAX_LOOP_DEPTH; ++i)
|
||||||
|
if (pt->pt_loopvars[i] != NULL)
|
||||||
{
|
{
|
||||||
--pt->pt_loopvars->lvs_refcount;
|
--pt->pt_loopvars[i]->lvs_refcount;
|
||||||
loopvars_check_refcount(pt->pt_loopvars);
|
loopvars_check_refcount(pt->pt_loopvars[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
vim_free(pt);
|
vim_free(pt);
|
||||||
@ -4839,8 +4840,15 @@ partial_unref(partial_T *pt)
|
|||||||
if (pt->pt_funcstack != NULL)
|
if (pt->pt_funcstack != NULL)
|
||||||
done = funcstack_check_refcount(pt->pt_funcstack);
|
done = funcstack_check_refcount(pt->pt_funcstack);
|
||||||
|
|
||||||
if (!done && pt->pt_loopvars != NULL)
|
if (!done)
|
||||||
loopvars_check_refcount(pt->pt_loopvars);
|
{
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
for (depth = 0; depth < MAX_LOOP_DEPTH; ++depth)
|
||||||
|
if (pt->pt_loopvars[depth] != NULL
|
||||||
|
&& loopvars_check_refcount(pt->pt_loopvars[depth]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ int func_is_global(ufunc_T *ufunc);
|
|||||||
int func_requires_g_prefix(ufunc_T *ufunc);
|
int func_requires_g_prefix(ufunc_T *ufunc);
|
||||||
int func_name_refcount(char_u *name);
|
int func_name_refcount(char_u *name);
|
||||||
void func_clear_free(ufunc_T *fp, int force);
|
void func_clear_free(ufunc_T *fp, int force);
|
||||||
int copy_lambda_to_global_func(char_u *lambda, char_u *global, short loop_var_idx, short loop_var_count, ectx_T *ectx);
|
int copy_lambda_to_global_func(char_u *lambda, char_u *global, loopvarinfo_T *loopvarinfo, ectx_T *ectx);
|
||||||
int funcdepth_increment(void);
|
int funcdepth_increment(void);
|
||||||
void funcdepth_decrement(void);
|
void funcdepth_decrement(void);
|
||||||
int funcdepth_get(void);
|
int funcdepth_get(void);
|
||||||
|
@ -11,8 +11,8 @@ char_u *compile_for(char_u *arg_start, cctx_T *cctx);
|
|||||||
char_u *compile_endfor(char_u *arg, cctx_T *cctx);
|
char_u *compile_endfor(char_u *arg, cctx_T *cctx);
|
||||||
char_u *compile_while(char_u *arg, cctx_T *cctx);
|
char_u *compile_while(char_u *arg, cctx_T *cctx);
|
||||||
char_u *compile_endwhile(char_u *arg, cctx_T *cctx);
|
char_u *compile_endwhile(char_u *arg, cctx_T *cctx);
|
||||||
short get_loop_var_info(cctx_T *cctx, short *loop_var_idx);
|
int get_loop_var_info(cctx_T *cctx, loopvarinfo_T *lvi);
|
||||||
int get_loop_var_idx(cctx_T *cctx);
|
void get_loop_var_idx(cctx_T *cctx, int idx, lvar_T *lvar);
|
||||||
char_u *compile_continue(char_u *arg, cctx_T *cctx);
|
char_u *compile_continue(char_u *arg, cctx_T *cctx);
|
||||||
char_u *compile_break(char_u *arg, cctx_T *cctx);
|
char_u *compile_break(char_u *arg, cctx_T *cctx);
|
||||||
char_u *compile_block(char_u *arg, cctx_T *cctx);
|
char_u *compile_block(char_u *arg, cctx_T *cctx);
|
||||||
|
@ -9,11 +9,11 @@ void restore_current_ectx(ectx_T *ectx);
|
|||||||
int add_defer_function(char_u *name, int argcount, typval_T *argvars);
|
int add_defer_function(char_u *name, int argcount, typval_T *argvars);
|
||||||
char_u *char_from_string(char_u *str, varnumber_T index);
|
char_u *char_from_string(char_u *str, varnumber_T index);
|
||||||
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
|
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
|
||||||
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, short loop_var_idx, short loop_var_count, ectx_T *ectx);
|
int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, loopvarinfo_T *loopvarinfo, ectx_T *ectx);
|
||||||
int may_load_script(int sid, int *loaded);
|
int may_load_script(int sid, int *loaded);
|
||||||
typval_T *lookup_debug_var(char_u *name);
|
typval_T *lookup_debug_var(char_u *name);
|
||||||
int may_break_in_function(ufunc_T *ufunc);
|
int may_break_in_function(ufunc_T *ufunc);
|
||||||
void loopvars_check_refcount(loopvars_T *loopvars);
|
int loopvars_check_refcount(loopvars_T *loopvars);
|
||||||
int set_ref_in_loopvars(int copyID);
|
int set_ref_in_loopvars(int copyID);
|
||||||
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
||||||
char_u *exe_substitute_instr(void);
|
char_u *exe_substitute_instr(void);
|
||||||
|
@ -31,7 +31,7 @@ int generate_CHECKLEN(cctx_T *cctx, int min_len, int more_OK);
|
|||||||
int generate_STORE(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name);
|
int generate_STORE(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name);
|
||||||
int generate_STORENR(cctx_T *cctx, int idx, varnumber_T value);
|
int generate_STORENR(cctx_T *cctx, int idx, varnumber_T value);
|
||||||
int generate_LOAD(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name, type_T *type);
|
int generate_LOAD(cctx_T *cctx, isntype_T isn_type, int idx, char_u *name, type_T *type);
|
||||||
int generate_LOADOUTER(cctx_T *cctx, int idx, int nesting, int loop_idx, type_T *type);
|
int generate_LOADOUTER(cctx_T *cctx, int idx, int nesting, int loop_depth, int loop_idx, type_T *type);
|
||||||
int generate_LOADV(cctx_T *cctx, char_u *name);
|
int generate_LOADV(cctx_T *cctx, char_u *name);
|
||||||
int generate_UNLET(cctx_T *cctx, isntype_T isn_type, char_u *name, int forceit);
|
int generate_UNLET(cctx_T *cctx, isntype_T isn_type, char_u *name, int forceit);
|
||||||
int generate_LOCKCONST(cctx_T *cctx);
|
int generate_LOCKCONST(cctx_T *cctx);
|
||||||
@ -40,13 +40,13 @@ int generate_VIM9SCRIPT(cctx_T *cctx, isntype_T isn_type, int sid, int idx, type
|
|||||||
int generate_NEWLIST(cctx_T *cctx, int count, int use_null);
|
int generate_NEWLIST(cctx_T *cctx, int count, int use_null);
|
||||||
int generate_NEWDICT(cctx_T *cctx, int count, int use_null);
|
int generate_NEWDICT(cctx_T *cctx, int count, int use_null);
|
||||||
int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp);
|
int generate_FUNCREF(cctx_T *cctx, ufunc_T *ufunc, isn_T **isnp);
|
||||||
int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name, short loop_var_idx, short loop_var_count);
|
int generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name);
|
||||||
int generate_DEF(cctx_T *cctx, char_u *name, size_t len);
|
int generate_DEF(cctx_T *cctx, char_u *name, size_t len);
|
||||||
int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
|
int generate_JUMP(cctx_T *cctx, jumpwhen_T when, int where);
|
||||||
int generate_WHILE(cctx_T *cctx, int funcref_idx);
|
int generate_WHILE(cctx_T *cctx, int funcref_idx);
|
||||||
int generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off);
|
int generate_JUMP_IF_ARG_SET(cctx_T *cctx, int arg_off);
|
||||||
int generate_FOR(cctx_T *cctx, int loop_idx);
|
int generate_FOR(cctx_T *cctx, int loop_idx);
|
||||||
int generate_ENDLOOP(cctx_T *cctx, int funcref_idx, int prev_local_count);
|
int generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info);
|
||||||
int generate_TRYCONT(cctx_T *cctx, int levels, int where);
|
int generate_TRYCONT(cctx_T *cctx, int levels, int where);
|
||||||
int check_internal_func_args(cctx_T *cctx, int func_idx, int argcount, int method_call, type2_T **argtypes, type2_T *shuffled_argtypes);
|
int check_internal_func_args(cctx_T *cctx, int func_idx, int argcount, int method_call, type2_T **argtypes, type2_T *shuffled_argtypes);
|
||||||
int generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call);
|
int generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call);
|
||||||
|
@ -2108,6 +2108,9 @@ struct loopvars_S
|
|||||||
int lvs_copyID; // for garbage collection
|
int lvs_copyID; // for garbage collection
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// maximum nesting of :while and :for loops in a :def function
|
||||||
|
#define MAX_LOOP_DEPTH 10
|
||||||
|
|
||||||
typedef struct outer_S outer_T;
|
typedef struct outer_S outer_T;
|
||||||
struct outer_S {
|
struct outer_S {
|
||||||
garray_T *out_stack; // stack from outer scope, or a copy
|
garray_T *out_stack; // stack from outer scope, or a copy
|
||||||
@ -2116,11 +2119,13 @@ struct outer_S {
|
|||||||
outer_T *out_up; // outer scope of outer scope or NULL
|
outer_T *out_up; // outer scope of outer scope or NULL
|
||||||
partial_T *out_up_partial; // partial owning out_up or NULL
|
partial_T *out_up_partial; // partial owning out_up or NULL
|
||||||
|
|
||||||
garray_T *out_loop_stack; // stack from outer scope, or a copy
|
struct {
|
||||||
|
garray_T *stack; // stack from outer scope, or a copy
|
||||||
// containing only vars inside the loop
|
// containing only vars inside the loop
|
||||||
short out_loop_var_idx; // first variable defined in a loop
|
short var_idx; // first variable defined in a loop in
|
||||||
// in out_loop_stack
|
// out_loop_stack
|
||||||
short out_loop_var_count; // number of variables defined in a loop
|
short var_count; // number of variables defined in a loop
|
||||||
|
} out_loop[MAX_LOOP_DEPTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct partial_S
|
struct partial_S
|
||||||
@ -2141,7 +2146,8 @@ struct partial_S
|
|||||||
|
|
||||||
funcstack_T *pt_funcstack; // copy of stack, used after context
|
funcstack_T *pt_funcstack; // copy of stack, used after context
|
||||||
// function returns
|
// function returns
|
||||||
loopvars_T *pt_loopvars; // copy of loop variables, used after loop
|
loopvars_T *(pt_loopvars[MAX_LOOP_DEPTH]);
|
||||||
|
// copy of loop variables, used after loop
|
||||||
// block ends
|
// block ends
|
||||||
|
|
||||||
typval_T *pt_argv; // arguments in allocated array
|
typval_T *pt_argv; // arguments in allocated array
|
||||||
@ -2151,6 +2157,14 @@ struct partial_S
|
|||||||
dict_T *pt_dict; // dict for "self"
|
dict_T *pt_dict; // dict for "self"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short lvi_depth; // current nested loop depth
|
||||||
|
struct {
|
||||||
|
short var_idx; // index of first variable inside loop
|
||||||
|
short var_count; // number of variables inside loop
|
||||||
|
} lvi_loop[MAX_LOOP_DEPTH];
|
||||||
|
} loopvarinfo_T;
|
||||||
|
|
||||||
typedef struct AutoPatCmd_S AutoPatCmd_T;
|
typedef struct AutoPatCmd_S AutoPatCmd_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1023,15 +1023,15 @@ def Test_disassemble_closure_in_loop()
|
|||||||
|
|
||||||
'endif\_s*' ..
|
'endif\_s*' ..
|
||||||
'g:Ref = () => ii\_s*' ..
|
'g:Ref = () => ii\_s*' ..
|
||||||
'\d\+ FUNCREF <lambda>4 var $3 - $3\_s*' ..
|
'\d\+ FUNCREF <lambda>4 vars $3-$3\_s*' ..
|
||||||
'\d\+ STOREG g:Ref\_s*' ..
|
'\d\+ STOREG g:Ref\_s*' ..
|
||||||
|
|
||||||
'continue\_s*' ..
|
'continue\_s*' ..
|
||||||
'\d\+ ENDLOOP $1 save $3 - $3\_s*' ..
|
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
|
||||||
'\d\+ JUMP -> \d\+\_s*' ..
|
'\d\+ JUMP -> \d\+\_s*' ..
|
||||||
|
|
||||||
'break\_s*' ..
|
'break\_s*' ..
|
||||||
'\d\+ ENDLOOP $1 save $3 - $3\_s*' ..
|
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
|
||||||
'\d\+ JUMP -> \d\+\_s*' ..
|
'\d\+ JUMP -> \d\+\_s*' ..
|
||||||
|
|
||||||
'if g:val\_s*' ..
|
'if g:val\_s*' ..
|
||||||
@ -1041,12 +1041,12 @@ def Test_disassemble_closure_in_loop()
|
|||||||
|
|
||||||
' return\_s*' ..
|
' return\_s*' ..
|
||||||
'\d\+ PUSHNR 0\_s*' ..
|
'\d\+ PUSHNR 0\_s*' ..
|
||||||
'\d\+ ENDLOOP $1 save $3 - $3\_s*' ..
|
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
|
||||||
'\d\+ RETURN\_s*' ..
|
'\d\+ RETURN\_s*' ..
|
||||||
|
|
||||||
'endif\_s*' ..
|
'endif\_s*' ..
|
||||||
'endfor\_s*' ..
|
'endfor\_s*' ..
|
||||||
'\d\+ ENDLOOP $1 save $3 - $3\_s*' ..
|
'\d\+ ENDLOOP ref $1 save $3-$3 depth 0\_s*' ..
|
||||||
'\d\+ JUMP -> \d\+\_s*' ..
|
'\d\+ JUMP -> \d\+\_s*' ..
|
||||||
'\d\+ DROP\_s*' ..
|
'\d\+ DROP\_s*' ..
|
||||||
'\d\+ RETURN void',
|
'\d\+ RETURN void',
|
||||||
|
@ -2322,10 +2322,46 @@ def Test_for_loop_with_closure()
|
|||||||
endfor
|
endfor
|
||||||
endfor
|
endfor
|
||||||
END
|
END
|
||||||
v9.CheckScriptSuccess(['vim9script'] + lines)
|
v9.CheckDefAndScriptSuccess(lines)
|
||||||
# FIXME: not yet right for :def
|
enddef
|
||||||
lines[14] = 'assert_equal(2 .. a, flist[n]())'
|
|
||||||
v9.CheckDefSuccess(lines)
|
def Test_define_global_closure_in_loops()
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
def Func()
|
||||||
|
for i in range(3)
|
||||||
|
var ii = i
|
||||||
|
for a in ['a', 'b', 'c']
|
||||||
|
var aa = a
|
||||||
|
if ii == 0 && aa == 'a'
|
||||||
|
def g:Global_0a(): string
|
||||||
|
return ii .. aa
|
||||||
|
enddef
|
||||||
|
endif
|
||||||
|
if ii == 1 && aa == 'b'
|
||||||
|
def g:Global_1b(): string
|
||||||
|
return ii .. aa
|
||||||
|
enddef
|
||||||
|
endif
|
||||||
|
if ii == 2 && aa == 'c'
|
||||||
|
def g:Global_2c(): string
|
||||||
|
return ii .. aa
|
||||||
|
enddef
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
enddef
|
||||||
|
Func()
|
||||||
|
END
|
||||||
|
v9.CheckScriptSuccess(lines)
|
||||||
|
assert_equal("0a", g:Global_0a())
|
||||||
|
assert_equal("1b", g:Global_1b())
|
||||||
|
assert_equal("2c", g:Global_2c())
|
||||||
|
|
||||||
|
delfunc g:Global_0a
|
||||||
|
delfunc g:Global_1b
|
||||||
|
delfunc g:Global_2c
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_for_loop_fails()
|
def Test_for_loop_fails()
|
||||||
@ -2418,6 +2454,32 @@ def Test_for_loop_fails()
|
|||||||
endfor
|
endfor
|
||||||
END
|
END
|
||||||
v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
|
v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>')
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
for a in range(3)
|
||||||
|
while a > 3
|
||||||
|
for b in range(2)
|
||||||
|
while b < 0
|
||||||
|
for c in range(5)
|
||||||
|
while c > 6
|
||||||
|
while c < 0
|
||||||
|
for d in range(1)
|
||||||
|
for e in range(3)
|
||||||
|
while e > 3
|
||||||
|
endwhile
|
||||||
|
endfor
|
||||||
|
endfor
|
||||||
|
endwhile
|
||||||
|
endwhile
|
||||||
|
endfor
|
||||||
|
endwhile
|
||||||
|
endfor
|
||||||
|
endwhile
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
v9.CheckDefSuccess(lines)
|
||||||
|
|
||||||
|
v9.CheckDefFailure(['for x in range(3)'] + lines + ['endfor'], 'E1306:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_for_loop_script_var()
|
def Test_for_loop_script_var()
|
||||||
|
@ -2455,8 +2455,7 @@ func_clear_free(ufunc_T *fp, int force)
|
|||||||
copy_lambda_to_global_func(
|
copy_lambda_to_global_func(
|
||||||
char_u *lambda,
|
char_u *lambda,
|
||||||
char_u *global,
|
char_u *global,
|
||||||
short loop_var_idx,
|
loopvarinfo_T *loopvarinfo,
|
||||||
short loop_var_count,
|
|
||||||
ectx_T *ectx)
|
ectx_T *ectx)
|
||||||
{
|
{
|
||||||
ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
|
ufunc_T *ufunc = find_func_even_dead(lambda, FFED_IS_GLOBAL);
|
||||||
@ -2524,14 +2523,12 @@ copy_lambda_to_global_func(
|
|||||||
|
|
||||||
if (pt == NULL)
|
if (pt == NULL)
|
||||||
goto failed;
|
goto failed;
|
||||||
if (fill_partial_and_closure(pt, ufunc, loop_var_idx, loop_var_count,
|
if (fill_partial_and_closure(pt, ufunc, loopvarinfo, ectx) == FAIL)
|
||||||
ectx) == FAIL)
|
|
||||||
{
|
{
|
||||||
vim_free(pt);
|
vim_free(pt);
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
ufunc->uf_partial = pt;
|
ufunc->uf_partial = pt;
|
||||||
--pt->pt_refcount; // not actually referenced here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -699,6 +699,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 */
|
||||||
|
/**/
|
||||||
|
502,
|
||||||
/**/
|
/**/
|
||||||
501,
|
501,
|
||||||
/**/
|
/**/
|
||||||
|
14
src/vim9.h
14
src/vim9.h
@ -263,19 +263,20 @@ typedef struct {
|
|||||||
|
|
||||||
// arguments to ISN_FOR
|
// arguments to ISN_FOR
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int for_idx; // loop variable index
|
short for_loop_idx; // loop variable index
|
||||||
int for_end; // position to jump to after done
|
int for_end; // position to jump to after done
|
||||||
} forloop_T;
|
} forloop_T;
|
||||||
|
|
||||||
// arguments to ISN_WHILE
|
// arguments to ISN_WHILE
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int while_funcref_idx; // variable index for funcref count
|
short while_funcref_idx; // variable index for funcref count
|
||||||
int while_end; // position to jump to after done
|
int while_end; // position to jump to after done
|
||||||
} whileloop_T;
|
} whileloop_T;
|
||||||
|
|
||||||
// arguments to ISN_ENDLOOP
|
// arguments to ISN_ENDLOOP
|
||||||
typedef struct {
|
typedef struct {
|
||||||
short end_funcref_idx; // variable index of funcrefs.ga_len
|
short end_funcref_idx; // variable index of funcrefs.ga_len
|
||||||
|
short end_depth; // nested loop depth
|
||||||
short end_var_idx; // first variable declared in the loop
|
short end_var_idx; // first variable declared in the loop
|
||||||
short end_var_count; // number of variables declared in the loop
|
short end_var_count; // number of variables declared in the loop
|
||||||
} endloop_T;
|
} endloop_T;
|
||||||
@ -357,8 +358,7 @@ typedef struct {
|
|||||||
// extra arguments for funcref_T
|
// extra arguments for funcref_T
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char_u *fre_func_name; // function name for legacy function
|
char_u *fre_func_name; // function name for legacy function
|
||||||
short fre_loop_var_idx; // index of first variable inside loop
|
loopvarinfo_T fre_loopvar_info; // info about variables inside loops
|
||||||
short fre_loop_var_count; // number of variables inside loop
|
|
||||||
} funcref_extra_T;
|
} funcref_extra_T;
|
||||||
|
|
||||||
// arguments to ISN_FUNCREF
|
// arguments to ISN_FUNCREF
|
||||||
@ -371,8 +371,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char_u *nfa_lambda; // name of the lambda already defined
|
char_u *nfa_lambda; // name of the lambda already defined
|
||||||
char_u *nfa_global; // name of the global function to be created
|
char_u *nfa_global; // name of the global function to be created
|
||||||
short nfa_loop_var_idx; // index of first variable inside loop
|
loopvarinfo_T nfa_loopvar_info; // ifno about variables inside loops
|
||||||
short nfa_loop_var_count; // number of variables inside loop
|
|
||||||
} newfuncarg_T;
|
} newfuncarg_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -628,6 +627,7 @@ typedef struct {
|
|||||||
int li_local_count; // ctx_locals.ga_len at loop start
|
int li_local_count; // ctx_locals.ga_len at loop start
|
||||||
int li_closure_count; // ctx_closure_count at loop start
|
int li_closure_count; // ctx_closure_count at loop start
|
||||||
int li_funcref_idx; // index of var that holds funcref count
|
int li_funcref_idx; // index of var that holds funcref count
|
||||||
|
int li_depth; // nested loop depth
|
||||||
} loop_info_T;
|
} loop_info_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -678,6 +678,7 @@ struct scope_S {
|
|||||||
scopetype_T se_type;
|
scopetype_T se_type;
|
||||||
int se_local_count; // ctx_locals.ga_len before scope
|
int se_local_count; // ctx_locals.ga_len before scope
|
||||||
skip_T se_skip_save; // ctx_skip before the block
|
skip_T se_skip_save; // ctx_skip before the block
|
||||||
|
int se_loop_depth; // number of loop scopes, including this
|
||||||
union {
|
union {
|
||||||
ifscope_T se_if;
|
ifscope_T se_if;
|
||||||
whilescope_T se_while;
|
whilescope_T se_while;
|
||||||
@ -693,6 +694,7 @@ typedef struct {
|
|||||||
char_u *lv_name;
|
char_u *lv_name;
|
||||||
type_T *lv_type;
|
type_T *lv_type;
|
||||||
int lv_idx; // index of the variable on the stack
|
int lv_idx; // index of the variable on the stack
|
||||||
|
int lv_loop_depth; // depth for variable inside a loop or -1
|
||||||
int lv_loop_idx; // index of first variable inside a loop or -1
|
int lv_loop_idx; // index of first variable inside a loop or -1
|
||||||
int lv_from_outer; // nesting level, using ctx_outer scope
|
int lv_from_outer; // nesting level, using ctx_outer scope
|
||||||
int lv_const; // when TRUE cannot be assigned to
|
int lv_const; // when TRUE cannot be assigned to
|
||||||
|
114
src/vim9cmds.c
114
src/vim9cmds.c
@ -347,6 +347,8 @@ new_scope(cctx_T *cctx, scopetype_T type)
|
|||||||
cctx->ctx_scope = scope;
|
cctx->ctx_scope = scope;
|
||||||
scope->se_type = type;
|
scope->se_type = type;
|
||||||
scope->se_local_count = cctx->ctx_locals.ga_len;
|
scope->se_local_count = cctx->ctx_locals.ga_len;
|
||||||
|
if (scope->se_outer != NULL)
|
||||||
|
scope->se_loop_depth = scope->se_outer->se_loop_depth;
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -823,7 +825,9 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
scope_T *scope;
|
scope_T *scope;
|
||||||
forscope_T *forscope;
|
forscope_T *forscope;
|
||||||
lvar_T *loop_lvar; // loop iteration variable
|
lvar_T *loop_lvar; // loop iteration variable
|
||||||
|
int loop_lvar_idx;
|
||||||
lvar_T *funcref_lvar;
|
lvar_T *funcref_lvar;
|
||||||
|
int funcref_lvar_idx;
|
||||||
lvar_T *var_lvar; // variable for "var"
|
lvar_T *var_lvar; // variable for "var"
|
||||||
type_T *vartype;
|
type_T *vartype;
|
||||||
type_T *item_type = &t_any;
|
type_T *item_type = &t_any;
|
||||||
@ -867,6 +871,12 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
scope = new_scope(cctx, FOR_SCOPE);
|
scope = new_scope(cctx, FOR_SCOPE);
|
||||||
if (scope == NULL)
|
if (scope == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (scope->se_loop_depth == MAX_LOOP_DEPTH)
|
||||||
|
{
|
||||||
|
emsg(_(e_loop_nesting_too_deep));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
++scope->se_loop_depth;
|
||||||
forscope = &scope->se_u.se_for;
|
forscope = &scope->se_u.se_for;
|
||||||
|
|
||||||
// Reserve a variable to store the loop iteration counter and initialize it
|
// Reserve a variable to store the loop iteration counter and initialize it
|
||||||
@ -877,7 +887,9 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL; // out of memory
|
return NULL; // out of memory
|
||||||
}
|
}
|
||||||
generate_STORENR(cctx, loop_lvar->lv_idx, -1);
|
// get the index before a following reserve_local() makes the lval invalid
|
||||||
|
loop_lvar_idx = loop_lvar->lv_idx;
|
||||||
|
generate_STORENR(cctx, loop_lvar_idx, -1);
|
||||||
|
|
||||||
// Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP.
|
// Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP.
|
||||||
// The variable index is always the loop var index plus one.
|
// The variable index is always the loop var index plus one.
|
||||||
@ -888,6 +900,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL; // out of memory
|
return NULL; // out of memory
|
||||||
}
|
}
|
||||||
|
// get the index before a following reserve_local() makes the lval invalid
|
||||||
|
funcref_lvar_idx = funcref_lvar->lv_idx;
|
||||||
|
|
||||||
// compile "expr", it remains on the stack until "endfor"
|
// compile "expr", it remains on the stack until "endfor"
|
||||||
arg = p;
|
arg = p;
|
||||||
@ -951,7 +965,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
cctx->ctx_prev_lnum = save_prev_lnum;
|
cctx->ctx_prev_lnum = save_prev_lnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_FOR(cctx, loop_lvar->lv_idx);
|
generate_FOR(cctx, loop_lvar_idx);
|
||||||
|
|
||||||
arg = arg_start;
|
arg = arg_start;
|
||||||
if (var_list)
|
if (var_list)
|
||||||
@ -1053,8 +1067,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remember the number of variables and closures, used for ENDLOOP
|
// remember the number of variables and closures, used for ENDLOOP
|
||||||
compile_fill_loop_info(&forscope->fs_loop_info,
|
compile_fill_loop_info(&forscope->fs_loop_info, funcref_lvar_idx, cctx);
|
||||||
funcref_lvar->lv_idx, cctx);
|
forscope->fs_loop_info.li_depth = scope->se_loop_depth - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return arg_end;
|
return arg_end;
|
||||||
@ -1075,8 +1089,7 @@ compile_loop_end(loop_info_T *loop_info, cctx_T *cctx)
|
|||||||
{
|
{
|
||||||
if (cctx->ctx_locals.ga_len > loop_info->li_local_count
|
if (cctx->ctx_locals.ga_len > loop_info->li_local_count
|
||||||
&& cctx->ctx_closure_count > loop_info->li_closure_count)
|
&& cctx->ctx_closure_count > loop_info->li_closure_count)
|
||||||
return generate_ENDLOOP(cctx, loop_info->li_funcref_idx,
|
return generate_ENDLOOP(cctx, loop_info);
|
||||||
loop_info->li_local_count);
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,10 +1164,17 @@ compile_while(char_u *arg, cctx_T *cctx)
|
|||||||
scope_T *scope;
|
scope_T *scope;
|
||||||
whilescope_T *whilescope;
|
whilescope_T *whilescope;
|
||||||
lvar_T *funcref_lvar;
|
lvar_T *funcref_lvar;
|
||||||
|
int funcref_lvar_idx;
|
||||||
|
|
||||||
scope = new_scope(cctx, WHILE_SCOPE);
|
scope = new_scope(cctx, WHILE_SCOPE);
|
||||||
if (scope == NULL)
|
if (scope == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (scope->se_loop_depth == MAX_LOOP_DEPTH)
|
||||||
|
{
|
||||||
|
emsg(_(e_loop_nesting_too_deep));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
++scope->se_loop_depth;
|
||||||
whilescope = &scope->se_u.se_while;
|
whilescope = &scope->se_u.se_while;
|
||||||
|
|
||||||
// "endwhile" jumps back here, one before when profiling or using cmdmods
|
// "endwhile" jumps back here, one before when profiling or using cmdmods
|
||||||
@ -1168,10 +1188,12 @@ compile_while(char_u *arg, cctx_T *cctx)
|
|||||||
drop_scope(cctx);
|
drop_scope(cctx);
|
||||||
return NULL; // out of memory
|
return NULL; // out of memory
|
||||||
}
|
}
|
||||||
|
// get the index before a following reserve_local() makes the lval invalid
|
||||||
|
funcref_lvar_idx = funcref_lvar->lv_idx;
|
||||||
|
|
||||||
// remember the number of variables and closures, used for ENDLOOP
|
// remember the number of variables and closures, used for ENDLOOP
|
||||||
compile_fill_loop_info(&whilescope->ws_loop_info,
|
compile_fill_loop_info(&whilescope->ws_loop_info, funcref_lvar_idx, cctx);
|
||||||
funcref_lvar->lv_idx, cctx);
|
whilescope->ws_loop_info.li_depth = scope->se_loop_depth - 1;
|
||||||
|
|
||||||
// compile "expr"
|
// compile "expr"
|
||||||
if (compile_expr0(&p, cctx) == FAIL)
|
if (compile_expr0(&p, cctx) == FAIL)
|
||||||
@ -1193,7 +1215,7 @@ compile_while(char_u *arg, cctx_T *cctx)
|
|||||||
|
|
||||||
// "while_end" is set when ":endwhile" is found
|
// "while_end" is set when ":endwhile" is found
|
||||||
if (compile_jump_to_end(&whilescope->ws_end_label,
|
if (compile_jump_to_end(&whilescope->ws_end_label,
|
||||||
JUMP_WHILE_FALSE, funcref_lvar->lv_idx, cctx) == FAIL)
|
JUMP_WHILE_FALSE, funcref_lvar_idx, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1249,45 +1271,83 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the current information about variables declared inside a loop.
|
* Get the current information about variables declared inside a loop.
|
||||||
* Returns zero if there are none, otherwise the count.
|
* Returns TRUE if there are any and fills "lvi".
|
||||||
* "loop_var_idx" is then set to the index of the first variable.
|
|
||||||
*/
|
*/
|
||||||
short
|
int
|
||||||
get_loop_var_info(cctx_T *cctx, short *loop_var_idx)
|
get_loop_var_info(cctx_T *cctx, loopvarinfo_T *lvi)
|
||||||
{
|
{
|
||||||
scope_T *scope = cctx->ctx_scope;
|
scope_T *scope = cctx->ctx_scope;
|
||||||
|
int prev_local_count = 0;
|
||||||
|
|
||||||
|
CLEAR_POINTER(lvi);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
loop_info_T *loopinfo;
|
||||||
|
int cur_local_last;
|
||||||
int start_local_count;
|
int start_local_count;
|
||||||
|
|
||||||
while (scope != NULL && scope->se_type != WHILE_SCOPE
|
while (scope != NULL && scope->se_type != WHILE_SCOPE
|
||||||
&& scope->se_type != FOR_SCOPE)
|
&& scope->se_type != FOR_SCOPE)
|
||||||
scope = scope->se_outer;
|
scope = scope->se_outer;
|
||||||
if (scope == NULL)
|
if (scope == NULL)
|
||||||
return 0;
|
break;
|
||||||
|
|
||||||
if (scope->se_type == WHILE_SCOPE)
|
if (scope->se_type == WHILE_SCOPE)
|
||||||
start_local_count = scope->se_u.se_while.ws_loop_info.li_local_count;
|
{
|
||||||
|
loopinfo = &scope->se_u.se_while.ws_loop_info;
|
||||||
|
// :while reserves one variable for funcref count
|
||||||
|
cur_local_last = loopinfo->li_local_count - 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
start_local_count = scope->se_u.se_for.fs_loop_info.li_local_count;
|
{
|
||||||
|
loopinfo = &scope->se_u.se_for.fs_loop_info;
|
||||||
|
// :for reserves three variable: loop count, funcref count and loop
|
||||||
|
// var
|
||||||
|
cur_local_last = loopinfo->li_local_count - 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_local_count = loopinfo->li_local_count;
|
||||||
if (cctx->ctx_locals.ga_len > start_local_count)
|
if (cctx->ctx_locals.ga_len > start_local_count)
|
||||||
{
|
{
|
||||||
*loop_var_idx = (short)start_local_count;
|
lvi->lvi_loop[loopinfo->li_depth].var_idx =
|
||||||
return (short)(cctx->ctx_locals.ga_len - start_local_count);
|
(short)start_local_count;
|
||||||
|
lvi->lvi_loop[loopinfo->li_depth].var_count =
|
||||||
|
(short)(cctx->ctx_locals.ga_len - start_local_count
|
||||||
|
- prev_local_count);
|
||||||
|
if (lvi->lvi_depth == 0)
|
||||||
|
lvi->lvi_depth = loopinfo->li_depth + 1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
scope = scope->se_outer;
|
||||||
|
prev_local_count = cctx->ctx_locals.ga_len - cur_local_last;
|
||||||
|
}
|
||||||
|
return lvi->lvi_depth > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the index of the first variable in a loop, if any.
|
* Get the index of the variable "idx" in a loop, if any.
|
||||||
* Returns -1 if none.
|
|
||||||
*/
|
*/
|
||||||
int
|
void
|
||||||
get_loop_var_idx(cctx_T *cctx)
|
get_loop_var_idx(cctx_T *cctx, int idx, lvar_T *lvar)
|
||||||
{
|
{
|
||||||
short loop_var_idx;
|
loopvarinfo_T lvi;
|
||||||
|
|
||||||
if (get_loop_var_info(cctx, &loop_var_idx) > 0)
|
lvar->lv_loop_depth = -1;
|
||||||
return loop_var_idx;
|
lvar->lv_loop_idx = -1;
|
||||||
return -1;
|
if (get_loop_var_info(cctx, &lvi))
|
||||||
|
{
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
for (depth = lvi.lvi_depth - 1; depth >= 0; --depth)
|
||||||
|
if (idx >= lvi.lvi_loop[depth].var_idx
|
||||||
|
&& idx < lvi.lvi_loop[depth].var_idx
|
||||||
|
+ lvi.lvi_loop[depth].var_count)
|
||||||
|
{
|
||||||
|
lvar->lv_loop_depth = depth;
|
||||||
|
lvar->lv_loop_idx = lvi.lvi_loop[depth].var_idx;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1827,8 +1827,7 @@ call_eval_func(
|
|||||||
fill_partial_and_closure(
|
fill_partial_and_closure(
|
||||||
partial_T *pt,
|
partial_T *pt,
|
||||||
ufunc_T *ufunc,
|
ufunc_T *ufunc,
|
||||||
short loop_var_idx,
|
loopvarinfo_T *lvi,
|
||||||
short loop_var_count,
|
|
||||||
ectx_T *ectx)
|
ectx_T *ectx)
|
||||||
{
|
{
|
||||||
pt->pt_func = ufunc;
|
pt->pt_func = ufunc;
|
||||||
@ -1854,13 +1853,22 @@ fill_partial_and_closure(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The closure may need to find variables defined inside a loop. A
|
if (lvi != NULL)
|
||||||
// new reference is made every time, ISN_ENDLOOP will check if they
|
{
|
||||||
// are actually used.
|
int depth;
|
||||||
pt->pt_outer.out_loop_stack = &ectx->ec_stack;
|
|
||||||
pt->pt_outer.out_loop_var_idx = ectx->ec_frame_idx + STACK_FRAME_SIZE
|
// The closure may need to find variables defined inside a loop,
|
||||||
+ loop_var_idx;
|
// for every nested loop. A new reference is made every time,
|
||||||
pt->pt_outer.out_loop_var_count = loop_var_count;
|
// ISN_ENDLOOP will check if they are actually used.
|
||||||
|
for (depth = 0; depth < lvi->lvi_depth; ++depth)
|
||||||
|
{
|
||||||
|
pt->pt_outer.out_loop[depth].stack = &ectx->ec_stack;
|
||||||
|
pt->pt_outer.out_loop[depth].var_idx = ectx->ec_frame_idx
|
||||||
|
+ STACK_FRAME_SIZE + lvi->lvi_loop[depth].var_idx;
|
||||||
|
pt->pt_outer.out_loop[depth].var_count =
|
||||||
|
lvi->lvi_loop[depth].var_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the function currently executing returns and the closure is still
|
// If the function currently executing returns and the closure is still
|
||||||
// being referenced, we need to make a copy of the context (arguments
|
// being referenced, we need to make a copy of the context (arguments
|
||||||
@ -2507,7 +2515,7 @@ execute_for(isn_T *iptr, ectx_T *ectx)
|
|||||||
int jump = FALSE;
|
int jump = FALSE;
|
||||||
typval_T *ltv = STACK_TV_BOT(-1);
|
typval_T *ltv = STACK_TV_BOT(-1);
|
||||||
typval_T *idxtv =
|
typval_T *idxtv =
|
||||||
STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
|
STACK_TV_VAR(iptr->isn_arg.forloop.for_loop_idx);
|
||||||
|
|
||||||
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -2613,7 +2621,7 @@ execute_for(isn_T *iptr, ectx_T *ectx)
|
|||||||
// Store the current number of funcrefs, this may be used in
|
// Store the current number of funcrefs, this may be used in
|
||||||
// ISN_LOOPEND. The variable index is always one more than the loop
|
// ISN_LOOPEND. The variable index is always one more than the loop
|
||||||
// variable index.
|
// variable index.
|
||||||
tv = STACK_TV_VAR(iptr->isn_arg.forloop.for_idx + 1);
|
tv = STACK_TV_VAR(iptr->isn_arg.forloop.for_loop_idx + 1);
|
||||||
tv->vval.v_number = ectx->ec_funcrefs.ga_len;
|
tv->vval.v_number = ectx->ec_funcrefs.ga_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2661,18 +2669,20 @@ execute_endloop(isn_T *iptr, ectx_T *ectx)
|
|||||||
endloop_T *endloop = &iptr->isn_arg.endloop;
|
endloop_T *endloop = &iptr->isn_arg.endloop;
|
||||||
typval_T *tv_refcount = STACK_TV_VAR(endloop->end_funcref_idx);
|
typval_T *tv_refcount = STACK_TV_VAR(endloop->end_funcref_idx);
|
||||||
int prev_closure_count = tv_refcount->vval.v_number;
|
int prev_closure_count = tv_refcount->vval.v_number;
|
||||||
|
int depth = endloop->end_depth;
|
||||||
garray_T *gap = &ectx->ec_funcrefs;
|
garray_T *gap = &ectx->ec_funcrefs;
|
||||||
int closure_in_use = FALSE;
|
int closure_in_use = FALSE;
|
||||||
loopvars_T *loopvars;
|
loopvars_T *loopvars;
|
||||||
typval_T *stack;
|
typval_T *stack;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
// Check if any created closure is still being referenced.
|
// Check if any created closure is still being referenced and loopvars have
|
||||||
|
// not been saved yet for the current depth.
|
||||||
for (idx = prev_closure_count; idx < gap->ga_len; ++idx)
|
for (idx = prev_closure_count; idx < gap->ga_len; ++idx)
|
||||||
{
|
{
|
||||||
partial_T *pt = ((partial_T **)gap->ga_data)[idx];
|
partial_T *pt = ((partial_T **)gap->ga_data)[idx];
|
||||||
|
|
||||||
if (pt->pt_refcount > 1 && pt->pt_loopvars == NULL)
|
if (pt->pt_refcount > 1 && pt->pt_loopvars[depth] == NULL)
|
||||||
{
|
{
|
||||||
int refcount = pt->pt_refcount;
|
int refcount = pt->pt_refcount;
|
||||||
int i;
|
int i;
|
||||||
@ -2728,14 +2738,14 @@ execute_endloop(isn_T *iptr, ectx_T *ectx)
|
|||||||
{
|
{
|
||||||
partial_T *pt = ((partial_T **)gap->ga_data)[idx];
|
partial_T *pt = ((partial_T **)gap->ga_data)[idx];
|
||||||
|
|
||||||
if (pt->pt_refcount > 1 && pt->pt_loopvars == NULL)
|
if (pt->pt_refcount > 1 && pt->pt_loopvars[depth] == NULL)
|
||||||
{
|
{
|
||||||
++loopvars->lvs_refcount;
|
++loopvars->lvs_refcount;
|
||||||
pt->pt_loopvars = loopvars;
|
pt->pt_loopvars[depth] = loopvars;
|
||||||
|
|
||||||
pt->pt_outer.out_loop_stack = &loopvars->lvs_ga;
|
pt->pt_outer.out_loop[depth].stack = &loopvars->lvs_ga;
|
||||||
pt->pt_outer.out_loop_var_idx -= ectx->ec_frame_idx
|
pt->pt_outer.out_loop[depth].var_idx -=
|
||||||
+ STACK_FRAME_SIZE + endloop->end_var_idx;
|
ectx->ec_frame_idx + STACK_FRAME_SIZE + endloop->end_var_idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2747,37 +2757,44 @@ execute_endloop(isn_T *iptr, ectx_T *ectx)
|
|||||||
* loopvars may be the only reference to the partials in the local variables.
|
* loopvars may be the only reference to the partials in the local variables.
|
||||||
* Go over all of them, the funcref and can be freed if all partials
|
* Go over all of them, the funcref and can be freed if all partials
|
||||||
* referencing the loopvars have a reference count of one.
|
* referencing the loopvars have a reference count of one.
|
||||||
|
* Return TRUE if it was freed.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
loopvars_check_refcount(loopvars_T *loopvars)
|
loopvars_check_refcount(loopvars_T *loopvars)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
garray_T *gap = &loopvars->lvs_ga;
|
garray_T *gap = &loopvars->lvs_ga;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
typval_T *stack = gap->ga_data;
|
||||||
|
|
||||||
if (loopvars->lvs_refcount > loopvars->lvs_min_refcount)
|
if (loopvars->lvs_refcount > loopvars->lvs_min_refcount)
|
||||||
return;
|
return FALSE;
|
||||||
for (i = 0; i < gap->ga_len; ++i)
|
for (i = 0; i < gap->ga_len; ++i)
|
||||||
{
|
{
|
||||||
typval_T *tv = ((typval_T *)gap->ga_data) + i;
|
typval_T *tv = ((typval_T *)gap->ga_data) + i;
|
||||||
|
|
||||||
if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
|
if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL
|
||||||
&& tv->vval.v_partial->pt_loopvars == loopvars
|
|
||||||
&& tv->vval.v_partial->pt_refcount == 1)
|
&& tv->vval.v_partial->pt_refcount == 1)
|
||||||
|
{
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
for (depth = 0; depth < MAX_LOOP_DEPTH; ++depth)
|
||||||
|
if (tv->vval.v_partial->pt_loopvars[depth] == loopvars)
|
||||||
++done;
|
++done;
|
||||||
}
|
}
|
||||||
if (done == loopvars->lvs_min_refcount)
|
}
|
||||||
{
|
if (done != loopvars->lvs_min_refcount)
|
||||||
typval_T *stack = gap->ga_data;
|
return FALSE;
|
||||||
|
|
||||||
// All partials referencing the loopvars have a reference count of
|
// All partials referencing the loopvars have a reference count of
|
||||||
// one, thus the loopvars is no longer of use.
|
// one, thus the loopvars is no longer of use.
|
||||||
|
stack = gap->ga_data;
|
||||||
for (i = 0; i < gap->ga_len; ++i)
|
for (i = 0; i < gap->ga_len; ++i)
|
||||||
clear_tv(stack + i);
|
clear_tv(stack + i);
|
||||||
vim_free(stack);
|
vim_free(stack);
|
||||||
remove_loopvars_from_list(loopvars);
|
remove_loopvars_from_list(loopvars);
|
||||||
vim_free(loopvars);
|
vim_free(loopvars);
|
||||||
}
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3804,11 +3821,12 @@ exec_instructions(ectx_T *ectx)
|
|||||||
iemsg("LOADOUTER depth more than scope levels");
|
iemsg("LOADOUTER depth more than scope levels");
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
if (depth == OUTER_LOOP_DEPTH)
|
if (depth < 0)
|
||||||
// Variable declared in loop. May be copied if the
|
// Variable declared in loop. May be copied if the
|
||||||
// loop block has already ended.
|
// loop block has already ended.
|
||||||
tv = ((typval_T *)outer->out_loop_stack->ga_data)
|
tv = ((typval_T *)outer->out_loop[-depth - 1]
|
||||||
+ outer->out_loop_var_idx
|
.stack->ga_data)
|
||||||
|
+ outer->out_loop[-depth - 1].var_idx
|
||||||
+ iptr->isn_arg.outer.outer_idx;
|
+ iptr->isn_arg.outer.outer_idx;
|
||||||
else
|
else
|
||||||
// Variable declared in a function. May be copied if
|
// Variable declared in a function. May be copied if
|
||||||
@ -4142,8 +4160,7 @@ exec_instructions(ectx_T *ectx)
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
if (fill_partial_and_closure(pt, ufunc,
|
if (fill_partial_and_closure(pt, ufunc,
|
||||||
extra == NULL ? 0 : extra->fre_loop_var_idx,
|
extra == NULL ? NULL : &extra->fre_loopvar_info,
|
||||||
extra == NULL ? 0 : extra->fre_loop_var_count,
|
|
||||||
ectx) == FAIL)
|
ectx) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
tv = STACK_TV_BOT(0);
|
tv = STACK_TV_BOT(0);
|
||||||
@ -4160,8 +4177,8 @@ exec_instructions(ectx_T *ectx)
|
|||||||
newfuncarg_T *arg = iptr->isn_arg.newfunc.nf_arg;
|
newfuncarg_T *arg = iptr->isn_arg.newfunc.nf_arg;
|
||||||
|
|
||||||
if (copy_lambda_to_global_func(arg->nfa_lambda,
|
if (copy_lambda_to_global_func(arg->nfa_lambda,
|
||||||
arg->nfa_global, arg->nfa_loop_var_idx,
|
arg->nfa_global, &arg->nfa_loopvar_info,
|
||||||
arg->nfa_loop_var_count, ectx) == FAIL)
|
ectx) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -4236,7 +4253,7 @@ exec_instructions(ectx_T *ectx)
|
|||||||
ectx->ec_iidx = iptr->isn_arg.whileloop.while_end;
|
ectx->ec_iidx = iptr->isn_arg.whileloop.while_end;
|
||||||
|
|
||||||
// Store the current funccal count, may be used by
|
// Store the current funccal count, may be used by
|
||||||
// ISN_LOOPEND later
|
// ISN_ENDLOOP later
|
||||||
tv = STACK_TV_VAR(
|
tv = STACK_TV_VAR(
|
||||||
iptr->isn_arg.whileloop.while_funcref_idx);
|
iptr->isn_arg.whileloop.while_funcref_idx);
|
||||||
tv->vval.v_number = ectx->ec_funcrefs.ga_len;
|
tv->vval.v_number = ectx->ec_funcrefs.ga_len;
|
||||||
@ -5581,6 +5598,11 @@ call_def_function(
|
|||||||
// Check the function was really compiled.
|
// Check the function was really compiled.
|
||||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
+ ufunc->uf_dfunc_idx;
|
+ ufunc->uf_dfunc_idx;
|
||||||
|
if (dfunc->df_ufunc == NULL)
|
||||||
|
{
|
||||||
|
semsg(_(e_function_was_deleted_str), printable_func_name(ufunc));
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
if (INSTRUCTIONS(dfunc) == NULL)
|
if (INSTRUCTIONS(dfunc) == NULL)
|
||||||
{
|
{
|
||||||
iemsg("using call_def_function() on not compiled function");
|
iemsg("using call_def_function() on not compiled function");
|
||||||
@ -5717,8 +5739,13 @@ call_def_function(
|
|||||||
if (partial != NULL)
|
if (partial != NULL)
|
||||||
{
|
{
|
||||||
outer_T *outer = get_pt_outer(partial);
|
outer_T *outer = get_pt_outer(partial);
|
||||||
|
int depth;
|
||||||
|
void *ptr = outer->out_stack;
|
||||||
|
|
||||||
if (outer->out_stack == NULL && outer->out_loop_stack == NULL)
|
// see if any stack was set
|
||||||
|
for (depth = 0; ptr == NULL && depth < MAX_LOOP_DEPTH; ++depth)
|
||||||
|
ptr = outer->out_loop[depth].stack;
|
||||||
|
if (ptr == NULL)
|
||||||
{
|
{
|
||||||
if (current_ectx != NULL)
|
if (current_ectx != NULL)
|
||||||
{
|
{
|
||||||
@ -5767,6 +5794,8 @@ call_def_function(
|
|||||||
ectx.ec_stack.ga_len += dfunc->df_varcount;
|
ectx.ec_stack.ga_len += dfunc->df_varcount;
|
||||||
if (dfunc->df_has_closure)
|
if (dfunc->df_has_closure)
|
||||||
{
|
{
|
||||||
|
// Initialize the variable that counts how many closures were
|
||||||
|
// created. This is used in handle_closure_in_use().
|
||||||
STACK_TV_VAR(idx)->v_type = VAR_NUMBER;
|
STACK_TV_VAR(idx)->v_type = VAR_NUMBER;
|
||||||
STACK_TV_VAR(idx)->vval.v_number = 0;
|
STACK_TV_VAR(idx)->vval.v_number = 0;
|
||||||
++ectx.ec_stack.ga_len;
|
++ectx.ec_stack.ga_len;
|
||||||
@ -5911,6 +5940,32 @@ may_invoke_defer_funcs(ectx_T *ectx)
|
|||||||
invoke_defer_funcs(ectx);
|
invoke_defer_funcs(ectx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return loopvarinfo in a printable form in allocated memory.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
printable_loopvarinfo(loopvarinfo_T *lvi)
|
||||||
|
{
|
||||||
|
garray_T ga;
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
ga_init2(&ga, 1, 100);
|
||||||
|
for (depth = 0; depth < lvi->lvi_depth; ++depth)
|
||||||
|
{
|
||||||
|
if (ga_grow(&ga, 50) == FAIL)
|
||||||
|
break;
|
||||||
|
if (lvi->lvi_loop[depth].var_idx == 0)
|
||||||
|
STRCPY(ga.ga_data + ga.ga_len, " -");
|
||||||
|
else
|
||||||
|
vim_snprintf(ga.ga_data + ga.ga_len, 50, " $%d-$%d",
|
||||||
|
lvi->lvi_loop[depth].var_idx,
|
||||||
|
lvi->lvi_loop[depth].var_idx
|
||||||
|
+ lvi->lvi_loop[depth].var_count - 1);
|
||||||
|
ga.ga_len = STRLEN(ga.ga_data);
|
||||||
|
}
|
||||||
|
return ga.ga_data;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List instructions "instr" up to "instr_count" or until ISN_FINISH.
|
* List instructions "instr" up to "instr_count" or until ISN_FINISH.
|
||||||
* "ufunc" has the source lines, NULL for the instructions of ISN_SUBSTITUTE.
|
* "ufunc" has the source lines, NULL for the instructions of ISN_SUBSTITUTE.
|
||||||
@ -6073,11 +6128,12 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
if (outer->outer_idx < 0)
|
if (outer->outer_idx < 0)
|
||||||
smsg("%s%4d LOADOUTER level %d arg[%d]", pfx, current,
|
smsg("%s%4d LOADOUTER level %d arg[%d]", pfx, current,
|
||||||
outer->outer_depth,
|
outer->outer_depth,
|
||||||
outer->outer_idx
|
outer->outer_idx + STACK_FRAME_SIZE);
|
||||||
+ STACK_FRAME_SIZE);
|
else if (outer->outer_depth < 0)
|
||||||
else if (outer->outer_depth == OUTER_LOOP_DEPTH)
|
smsg("%s%4d LOADOUTER $%d in loop level %d",
|
||||||
smsg("%s%4d LOADOUTER level 1 $%d in loop",
|
pfx, current,
|
||||||
pfx, current, outer->outer_idx);
|
outer->outer_idx,
|
||||||
|
-outer->outer_depth);
|
||||||
else
|
else
|
||||||
smsg("%s%4d LOADOUTER level %d $%d", pfx, current,
|
smsg("%s%4d LOADOUTER level %d $%d", pfx, current,
|
||||||
outer->outer_depth,
|
outer->outer_depth,
|
||||||
@ -6400,14 +6456,17 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
name = extra->fre_func_name;
|
name = extra->fre_func_name;
|
||||||
if (extra == NULL || extra->fre_loop_var_count == 0)
|
if (extra == NULL || extra->fre_loopvar_info.lvi_depth == 0)
|
||||||
smsg("%s%4d FUNCREF %s", pfx, current, name);
|
smsg("%s%4d FUNCREF %s", pfx, current, name);
|
||||||
else
|
else
|
||||||
smsg("%s%4d FUNCREF %s var $%d - $%d", pfx, current,
|
{
|
||||||
name,
|
char_u *info = printable_loopvarinfo(
|
||||||
extra->fre_loop_var_idx,
|
&extra->fre_loopvar_info);
|
||||||
extra->fre_loop_var_idx
|
|
||||||
+ extra->fre_loop_var_count - 1);
|
smsg("%s%4d FUNCREF %s vars %s", pfx, current,
|
||||||
|
name, info);
|
||||||
|
vim_free(info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -6415,14 +6474,18 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
{
|
{
|
||||||
newfuncarg_T *arg = iptr->isn_arg.newfunc.nf_arg;
|
newfuncarg_T *arg = iptr->isn_arg.newfunc.nf_arg;
|
||||||
|
|
||||||
if (arg->nfa_loop_var_count == 0)
|
if (arg->nfa_loopvar_info.lvi_depth == 0)
|
||||||
smsg("%s%4d NEWFUNC %s %s", pfx, current,
|
smsg("%s%4d NEWFUNC %s %s", pfx, current,
|
||||||
arg->nfa_lambda, arg->nfa_global);
|
arg->nfa_lambda, arg->nfa_global);
|
||||||
else
|
else
|
||||||
smsg("%s%4d NEWFUNC %s %s var $%d - $%d", pfx, current,
|
{
|
||||||
arg->nfa_lambda, arg->nfa_global,
|
char_u *info = printable_loopvarinfo(
|
||||||
arg->nfa_loop_var_idx,
|
&arg->nfa_loopvar_info);
|
||||||
arg->nfa_loop_var_idx + arg->nfa_loop_var_count - 1);
|
|
||||||
|
smsg("%s%4d NEWFUNC %s %s vars %s", pfx, current,
|
||||||
|
arg->nfa_lambda, arg->nfa_global, info);
|
||||||
|
vim_free(info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -6479,7 +6542,7 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
forloop_T *forloop = &iptr->isn_arg.forloop;
|
forloop_T *forloop = &iptr->isn_arg.forloop;
|
||||||
|
|
||||||
smsg("%s%4d FOR $%d -> %d", pfx, current,
|
smsg("%s%4d FOR $%d -> %d", pfx, current,
|
||||||
forloop->for_idx, forloop->for_end);
|
forloop->for_loop_idx, forloop->for_end);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -6487,10 +6550,12 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
|
|||||||
{
|
{
|
||||||
endloop_T *endloop = &iptr->isn_arg.endloop;
|
endloop_T *endloop = &iptr->isn_arg.endloop;
|
||||||
|
|
||||||
smsg("%s%4d ENDLOOP $%d save $%d - $%d", pfx, current,
|
smsg("%s%4d ENDLOOP ref $%d save $%d-$%d depth %d",
|
||||||
|
pfx, current,
|
||||||
endloop->end_funcref_idx,
|
endloop->end_funcref_idx,
|
||||||
endloop->end_var_idx,
|
endloop->end_var_idx,
|
||||||
endloop->end_var_idx + endloop->end_var_count - 1);
|
endloop->end_var_idx + endloop->end_var_count - 1,
|
||||||
|
endloop->end_depth);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -997,6 +997,7 @@ generate_LOADOUTER(
|
|||||||
cctx_T *cctx,
|
cctx_T *cctx,
|
||||||
int idx,
|
int idx,
|
||||||
int nesting,
|
int nesting,
|
||||||
|
int loop_depth,
|
||||||
int loop_idx,
|
int loop_idx,
|
||||||
type_T *type)
|
type_T *type)
|
||||||
{
|
{
|
||||||
@ -1008,9 +1009,9 @@ generate_LOADOUTER(
|
|||||||
if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx)
|
if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx)
|
||||||
{
|
{
|
||||||
// Load a variable defined in a loop. A copy will be made at the end
|
// Load a variable defined in a loop. A copy will be made at the end
|
||||||
// of the loop. TODO: how about deeper nesting?
|
// of the loop.
|
||||||
isn->isn_arg.outer.outer_idx = idx - loop_idx;
|
isn->isn_arg.outer.outer_idx = idx - loop_idx;
|
||||||
isn->isn_arg.outer.outer_depth = OUTER_LOOP_DEPTH;
|
isn->isn_arg.outer.outer_depth = -loop_depth - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1207,8 +1208,8 @@ generate_FUNCREF(
|
|||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
type_T *type;
|
type_T *type;
|
||||||
funcref_extra_T *extra;
|
funcref_extra_T *extra;
|
||||||
short loop_var_idx;
|
loopvarinfo_T loopinfo;
|
||||||
short loop_var_count;
|
int has_vars;
|
||||||
|
|
||||||
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)
|
||||||
@ -1216,20 +1217,22 @@ generate_FUNCREF(
|
|||||||
if (isnp != NULL)
|
if (isnp != NULL)
|
||||||
*isnp = isn;
|
*isnp = isn;
|
||||||
|
|
||||||
loop_var_count = get_loop_var_info(cctx, &loop_var_idx);
|
has_vars = get_loop_var_info(cctx, &loopinfo);
|
||||||
if (ufunc->uf_def_status == UF_NOT_COMPILED || loop_var_count > 0)
|
if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars)
|
||||||
{
|
{
|
||||||
extra = ALLOC_CLEAR_ONE(funcref_extra_T);
|
extra = ALLOC_CLEAR_ONE(funcref_extra_T);
|
||||||
if (extra == NULL)
|
if (extra == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.funcref.fr_extra = extra;
|
isn->isn_arg.funcref.fr_extra = extra;
|
||||||
extra->fre_loop_var_idx = loop_var_idx;
|
extra->fre_loopvar_info = loopinfo;
|
||||||
extra->fre_loop_var_count = loop_var_count;
|
|
||||||
}
|
}
|
||||||
if (ufunc->uf_def_status == UF_NOT_COMPILED)
|
if (ufunc->uf_def_status == UF_NOT_COMPILED)
|
||||||
extra->fre_func_name = vim_strsave(ufunc->uf_name);
|
extra->fre_func_name = vim_strsave(ufunc->uf_name);
|
||||||
else
|
else
|
||||||
isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
|
isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx;
|
||||||
|
|
||||||
|
// Reserve an extra variable to keep track of the number of closures
|
||||||
|
// created.
|
||||||
cctx->ctx_has_closure = 1;
|
cctx->ctx_has_closure = 1;
|
||||||
|
|
||||||
// If the referenced function is a closure, it may use items further up in
|
// If the referenced function is a closure, it may use items further up in
|
||||||
@ -1252,9 +1255,7 @@ generate_FUNCREF(
|
|||||||
generate_NEWFUNC(
|
generate_NEWFUNC(
|
||||||
cctx_T *cctx,
|
cctx_T *cctx,
|
||||||
char_u *lambda_name,
|
char_u *lambda_name,
|
||||||
char_u *func_name,
|
char_u *func_name)
|
||||||
short loop_var_idx,
|
|
||||||
short loop_var_count)
|
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
@ -1271,11 +1272,14 @@ generate_NEWFUNC(
|
|||||||
ret = FAIL;
|
ret = FAIL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Reserve an extra variable to keep track of the number of
|
||||||
|
// closures created.
|
||||||
|
cctx->ctx_has_closure = 1;
|
||||||
|
|
||||||
isn->isn_arg.newfunc.nf_arg = arg;
|
isn->isn_arg.newfunc.nf_arg = arg;
|
||||||
arg->nfa_lambda = lambda_name;
|
arg->nfa_lambda = lambda_name;
|
||||||
arg->nfa_global = func_name;
|
arg->nfa_global = func_name;
|
||||||
arg->nfa_loop_var_idx = loop_var_idx;
|
(void)get_loop_var_info(cctx, &arg->nfa_loopvar_info);
|
||||||
arg->nfa_loop_var_count = loop_var_count;
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1371,27 +1375,25 @@ generate_FOR(cctx_T *cctx, int loop_idx)
|
|||||||
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_loop_idx = loop_idx;
|
||||||
|
|
||||||
// type doesn't matter, will be stored next
|
// type doesn't matter, will be stored next
|
||||||
return push_type_stack(cctx, &t_any);
|
return push_type_stack(cctx, &t_any);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
generate_ENDLOOP(
|
generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info)
|
||||||
cctx_T *cctx,
|
|
||||||
int funcref_idx,
|
|
||||||
int prev_local_count)
|
|
||||||
{
|
{
|
||||||
isn_T *isn;
|
isn_T *isn;
|
||||||
|
|
||||||
RETURN_OK_IF_SKIP(cctx);
|
RETURN_OK_IF_SKIP(cctx);
|
||||||
if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL)
|
if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
isn->isn_arg.endloop.end_funcref_idx = funcref_idx;
|
isn->isn_arg.endloop.end_depth = loop_info->li_depth;
|
||||||
isn->isn_arg.endloop.end_var_idx = prev_local_count;
|
isn->isn_arg.endloop.end_funcref_idx = loop_info->li_funcref_idx;
|
||||||
|
isn->isn_arg.endloop.end_var_idx = loop_info->li_local_count;
|
||||||
isn->isn_arg.endloop.end_var_count =
|
isn->isn_arg.endloop.end_var_count =
|
||||||
cctx->ctx_locals.ga_len - prev_local_count;
|
cctx->ctx_locals.ga_len - loop_info->li_local_count;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user