Mercurial > vim
comparison src/vim9execute.c @ 20244:23d75968ca5e
patch 8.2.0677: Vim9: no support for closures
Commit: https://github.com/vim/vim/commit/c8cd2b34d1027c93fbca90f3cdc8123fe22dfa25
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri May 1 19:29:08 2020 +0200
patch 8.2.0677: Vim9: no support for closures
Problem: Vim9: no support for closures.
Solution: Find variables in the outer function scope, so long as the scope
exists.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 01 May 2020 19:30:04 +0200 |
parents | eaaee0dfa435 |
children | e46e72aaff74 |
comparison
equal
deleted
inserted
replaced
20243:6e7fd8949651 | 20244:23d75968ca5e |
---|---|
55 * Execution context. | 55 * Execution context. |
56 */ | 56 */ |
57 typedef struct { | 57 typedef struct { |
58 garray_T ec_stack; // stack of typval_T values | 58 garray_T ec_stack; // stack of typval_T values |
59 int ec_frame; // index in ec_stack: context of ec_dfunc_idx | 59 int ec_frame; // index in ec_stack: context of ec_dfunc_idx |
60 | |
61 garray_T *ec_outer_stack; // stack used for closures | |
62 int ec_outer_frame; // stack frame in ec_outer_stack | |
60 | 63 |
61 garray_T ec_trystack; // stack of trycmd_T values | 64 garray_T ec_trystack; // stack of trycmd_T values |
62 int ec_in_catch; // when TRUE in catch or finally block | 65 int ec_in_catch; // when TRUE in catch or finally block |
63 | 66 |
64 int ec_dfunc_idx; // current function index | 67 int ec_dfunc_idx; // current function index |
227 // Set execution state to the start of the called function. | 230 // Set execution state to the start of the called function. |
228 ectx->ec_dfunc_idx = cdf_idx; | 231 ectx->ec_dfunc_idx = cdf_idx; |
229 ectx->ec_instr = dfunc->df_instr; | 232 ectx->ec_instr = dfunc->df_instr; |
230 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); | 233 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); |
231 | 234 |
235 // used for closures | |
236 ectx->ec_outer_stack = ufunc->uf_ectx_stack; | |
237 ectx->ec_outer_frame = ufunc->uf_ectx_frame; | |
238 | |
232 // Decide where to start execution, handles optional arguments. | 239 // Decide where to start execution, handles optional arguments. |
233 init_instr_idx(ufunc, argcount, ectx); | 240 init_instr_idx(ufunc, argcount, ectx); |
234 | 241 |
235 return OK; | 242 return OK; |
236 } | 243 } |
505 #undef STACK_TV_BOT | 512 #undef STACK_TV_BOT |
506 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) | 513 #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) |
507 | 514 |
508 // Get pointer to a local variable on the stack. Negative for arguments. | 515 // Get pointer to a local variable on the stack. Negative for arguments. |
509 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) | 516 #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) |
517 | |
518 // Like STACK_TV_VAR but use the outer scope | |
519 #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) | |
510 | 520 |
511 CLEAR_FIELD(ectx); | 521 CLEAR_FIELD(ectx); |
512 ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); | 522 ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); |
513 if (ga_grow(&ectx.ec_stack, 20) == FAIL) | 523 if (ga_grow(&ectx.ec_stack, 20) == FAIL) |
514 return FAIL; | 524 return FAIL; |
781 // load local variable or argument | 791 // load local variable or argument |
782 case ISN_LOAD: | 792 case ISN_LOAD: |
783 if (ga_grow(&ectx.ec_stack, 1) == FAIL) | 793 if (ga_grow(&ectx.ec_stack, 1) == FAIL) |
784 goto failed; | 794 goto failed; |
785 copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); | 795 copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); |
796 ++ectx.ec_stack.ga_len; | |
797 break; | |
798 | |
799 // load variable or argument from outer scope | |
800 case ISN_LOADOUTER: | |
801 if (ga_grow(&ectx.ec_stack, 1) == FAIL) | |
802 goto failed; | |
803 copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number), | |
804 STACK_TV_BOT(0)); | |
786 ++ectx.ec_stack.ga_len; | 805 ++ectx.ec_stack.ga_len; |
787 break; | 806 break; |
788 | 807 |
789 // load v: variable | 808 // load v: variable |
790 case ISN_LOADV: | 809 case ISN_LOADV: |
1302 + iptr->isn_arg.number; | 1321 + iptr->isn_arg.number; |
1303 pt->pt_func = dfunc->df_ufunc; | 1322 pt->pt_func = dfunc->df_ufunc; |
1304 pt->pt_refcount = 1; | 1323 pt->pt_refcount = 1; |
1305 ++dfunc->df_ufunc->uf_refcount; | 1324 ++dfunc->df_ufunc->uf_refcount; |
1306 | 1325 |
1326 if (dfunc->df_ufunc->uf_flags & FC_CLOSURE) | |
1327 { | |
1328 // Closure needs to find local variables in the current | |
1329 // stack. | |
1330 dfunc->df_ufunc->uf_ectx_stack = &ectx.ec_stack; | |
1331 dfunc->df_ufunc->uf_ectx_frame = ectx.ec_frame; | |
1332 } | |
1333 | |
1307 if (ga_grow(&ectx.ec_stack, 1) == FAIL) | 1334 if (ga_grow(&ectx.ec_stack, 1) == FAIL) |
1308 goto failed; | 1335 goto failed; |
1309 tv = STACK_TV_BOT(0); | 1336 tv = STACK_TV_BOT(0); |
1310 ++ectx.ec_stack.ga_len; | 1337 ++ectx.ec_stack.ga_len; |
1311 tv->vval.v_partial = pt; | 1338 tv->vval.v_partial = pt; |
1860 case ISN_CHECKTYPE: | 1887 case ISN_CHECKTYPE: |
1861 { | 1888 { |
1862 checktype_T *ct = &iptr->isn_arg.type; | 1889 checktype_T *ct = &iptr->isn_arg.type; |
1863 | 1890 |
1864 tv = STACK_TV_BOT(ct->ct_off); | 1891 tv = STACK_TV_BOT(ct->ct_off); |
1865 if (tv->v_type != ct->ct_type) | 1892 // TODO: better type comparison |
1893 if (tv->v_type != ct->ct_type | |
1894 && !((tv->v_type == VAR_PARTIAL | |
1895 && ct->ct_type == VAR_FUNC) | |
1896 || (tv->v_type == VAR_FUNC | |
1897 && ct->ct_type == VAR_PARTIAL))) | |
1866 { | 1898 { |
1867 semsg(_("E1029: Expected %s but got %s"), | 1899 semsg(_("E1029: Expected %s but got %s"), |
1868 vartype_name(ct->ct_type), | 1900 vartype_name(ct->ct_type), |
1869 vartype_name(tv->v_type)); | 1901 vartype_name(tv->v_type)); |
1870 goto failed; | 1902 goto failed; |
2027 case ISN_ECHOERR: | 2059 case ISN_ECHOERR: |
2028 smsg("%4d ECHOERR %lld", current, | 2060 smsg("%4d ECHOERR %lld", current, |
2029 (long long)(iptr->isn_arg.number)); | 2061 (long long)(iptr->isn_arg.number)); |
2030 break; | 2062 break; |
2031 case ISN_LOAD: | 2063 case ISN_LOAD: |
2032 if (iptr->isn_arg.number < 0) | 2064 case ISN_LOADOUTER: |
2033 smsg("%4d LOAD arg[%lld]", current, | 2065 { |
2034 (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE)); | 2066 char *add = iptr->isn_type == ISN_LOAD ? "" : "OUTER"; |
2035 else | 2067 |
2036 smsg("%4d LOAD $%lld", current, | 2068 if (iptr->isn_arg.number < 0) |
2069 smsg("%4d LOAD%s arg[%lld]", current, add, | |
2070 (long long)(iptr->isn_arg.number | |
2071 + STACK_FRAME_SIZE)); | |
2072 else | |
2073 smsg("%4d LOAD%s $%lld", current, add, | |
2037 (long long)(iptr->isn_arg.number)); | 2074 (long long)(iptr->isn_arg.number)); |
2075 } | |
2038 break; | 2076 break; |
2039 case ISN_LOADV: | 2077 case ISN_LOADV: |
2040 smsg("%4d LOADV v:%s", current, | 2078 smsg("%4d LOADV v:%s", current, |
2041 get_vim_var_name(iptr->isn_arg.number)); | 2079 get_vim_var_name(iptr->isn_arg.number)); |
2042 break; | 2080 break; |