Mercurial > vim
comparison src/vim9execute.c @ 19328:e99e6d794597 v8.2.0222
patch 8.2.0222: Vim9: optional function arguments don't work yet
Commit: https://github.com/vim/vim/commit/170fcfcf250954d76fca86e3fed088ddfdb49383
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Feb 6 17:51:35 2020 +0100
patch 8.2.0222: Vim9: optional function arguments don't work yet
Problem: Vim9: optional function arguments don't work yet.
Solution: Implement optional function arguments.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 06 Feb 2020 18:00:04 +0100 |
parents | 17dc6282f370 |
children | 61646c189622 |
comparison
equal
deleted
inserted
replaced
19327:6bbb4ad91d21 | 19328:e99e6d794597 |
---|---|
68 | 68 |
69 // Get pointer to item relative to the bottom of the stack, -1 is the last one. | 69 // Get pointer to item relative to the bottom of the stack, -1 is the last one. |
70 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx) | 70 #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx) |
71 | 71 |
72 /* | 72 /* |
73 * Return the number of arguments, including any vararg. | 73 * Return the number of arguments, including optional arguments and any vararg. |
74 */ | 74 */ |
75 static int | 75 static int |
76 ufunc_argcount(ufunc_T *ufunc) | 76 ufunc_argcount(ufunc_T *ufunc) |
77 { | 77 { |
78 return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0); | 78 return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0); |
79 } | |
80 | |
81 /* | |
82 * Set the instruction index, depending on omitted arguments, where the default | |
83 * values are to be computed. If all optional arguments are present, start | |
84 * with the function body. | |
85 * The expression evaluation is at the start of the instructions: | |
86 * 0 -> EVAL default1 | |
87 * STORE arg[-2] | |
88 * 1 -> EVAL default2 | |
89 * STORE arg[-1] | |
90 * 2 -> function body | |
91 */ | |
92 static void | |
93 init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx) | |
94 { | |
95 if (ufunc->uf_def_args.ga_len == 0) | |
96 ectx->ec_iidx = 0; | |
97 else | |
98 { | |
99 int defcount = ufunc->uf_args.ga_len - argcount; | |
100 | |
101 // If there is a varargs argument defcount can be negative, no defaults | |
102 // to evaluate then. | |
103 if (defcount < 0) | |
104 defcount = 0; | |
105 ectx->ec_iidx = ufunc->uf_def_arg_idx[ | |
106 ufunc->uf_def_args.ga_len - defcount]; | |
107 } | |
79 } | 108 } |
80 | 109 |
81 /* | 110 /* |
82 * Call compiled function "cdf_idx" from compiled code. | 111 * Call compiled function "cdf_idx" from compiled code. |
83 * | 112 * |
105 } | 134 } |
106 | 135 |
107 if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL) | 136 if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL) |
108 return FAIL; | 137 return FAIL; |
109 | 138 |
110 // TODO: Put omitted argument default values on the stack. | |
111 if (optcount > 0) | |
112 { | |
113 emsg("optional arguments not implemented yet"); | |
114 return FAIL; | |
115 } | |
116 if (optcount < 0) | 139 if (optcount < 0) |
117 { | 140 { |
118 emsg("argument count wrong?"); | 141 emsg("argument count wrong?"); |
119 return FAIL; | 142 return FAIL; |
120 } | 143 } |
121 // for (idx = argcount - dfunc->df_minarg; | 144 |
122 // idx < dfunc->df_maxarg; ++idx) | 145 // Reserve space for omitted optional arguments, filled in soon. |
123 // { | 146 // Also any empty varargs argument. |
124 // copy_tv(&dfunc->df_defarg[idx], STACK_TV_BOT(0)); | 147 ectx->ec_stack.ga_len += optcount; |
125 // ++ectx->ec_stack.ga_len; | |
126 // } | |
127 | 148 |
128 // Store current execution state in stack frame for ISN_RETURN. | 149 // Store current execution state in stack frame for ISN_RETURN. |
129 // TODO: If the actual number of arguments doesn't match what the called | 150 // TODO: If the actual number of arguments doesn't match what the called |
130 // function expects things go bad. | 151 // function expects things go bad. |
131 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; | 152 STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; |
140 | 161 |
141 // Set execution state to the start of the called function. | 162 // Set execution state to the start of the called function. |
142 ectx->ec_dfunc_idx = cdf_idx; | 163 ectx->ec_dfunc_idx = cdf_idx; |
143 ectx->ec_instr = dfunc->df_instr; | 164 ectx->ec_instr = dfunc->df_instr; |
144 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); | 165 estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); |
145 ectx->ec_iidx = 0; | 166 |
167 // Decide where to start execution, handles optional arguments. | |
168 init_instr_idx(ufunc, argcount, ectx); | |
146 | 169 |
147 return OK; | 170 return OK; |
148 } | 171 } |
149 | 172 |
150 // Get pointer to item in the stack. | 173 // Get pointer to item in the stack. |
154 * Return from the current function. | 177 * Return from the current function. |
155 */ | 178 */ |
156 static void | 179 static void |
157 func_return(ectx_T *ectx) | 180 func_return(ectx_T *ectx) |
158 { | 181 { |
159 int ret_idx = ectx->ec_stack.ga_len - 1; | |
160 int idx; | 182 int idx; |
161 dfunc_T *dfunc; | 183 dfunc_T *dfunc; |
184 int top; | |
162 | 185 |
163 // execution context goes one level up | 186 // execution context goes one level up |
164 estack_pop(); | 187 estack_pop(); |
165 | 188 |
166 // Clear the local variables and temporary values, but not | 189 // Clear the local variables and temporary values, but not |
167 // the return value. | 190 // the return value. |
168 for (idx = ectx->ec_frame + STACK_FRAME_SIZE; | 191 for (idx = ectx->ec_frame + STACK_FRAME_SIZE; |
169 idx < ectx->ec_stack.ga_len - 1; ++idx) | 192 idx < ectx->ec_stack.ga_len - 1; ++idx) |
170 clear_tv(STACK_TV(idx)); | 193 clear_tv(STACK_TV(idx)); |
194 | |
195 // Clear the arguments. | |
171 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; | 196 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; |
172 ectx->ec_stack.ga_len = ectx->ec_frame | 197 top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc); |
173 - ufunc_argcount(dfunc->df_ufunc) + 1; | 198 for (idx = top; idx < ectx->ec_frame; ++idx) |
199 clear_tv(STACK_TV(idx)); | |
200 | |
201 // Restore the previous frame. | |
174 ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number; | 202 ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number; |
175 ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number; | 203 ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number; |
176 ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number; | 204 ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number; |
177 *STACK_TV_BOT(-1) = *STACK_TV(ret_idx); | |
178 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; | 205 dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; |
179 ectx->ec_instr = dfunc->df_instr; | 206 ectx->ec_instr = dfunc->df_instr; |
207 | |
208 // Reset the stack to the position before the call, move the return value | |
209 // to the top of the stack. | |
210 idx = ectx->ec_stack.ga_len - 1; | |
211 ectx->ec_stack.ga_len = top + 1; | |
212 *STACK_TV_BOT(-1) = *STACK_TV(idx); | |
180 } | 213 } |
181 | 214 |
182 #undef STACK_TV | 215 #undef STACK_TV |
183 | 216 |
184 /* | 217 /* |
360 int initial_frame_ptr; | 393 int initial_frame_ptr; |
361 typval_T *tv; | 394 typval_T *tv; |
362 int idx; | 395 int idx; |
363 int ret = FAIL; | 396 int ret = FAIL; |
364 dfunc_T *dfunc; | 397 dfunc_T *dfunc; |
365 int optcount = ufunc_argcount(ufunc) - argc; | 398 int defcount = ufunc->uf_args.ga_len - argc; |
366 | 399 |
367 // Get pointer to item in the stack. | 400 // Get pointer to item in the stack. |
368 #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) | 401 #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) |
369 | 402 |
370 // Get pointer to item at the bottom of the stack, -1 is the bottom. | 403 // Get pointer to item at the bottom of the stack, -1 is the bottom. |
386 for (idx = 0; idx < argc; ++idx) | 419 for (idx = 0; idx < argc; ++idx) |
387 { | 420 { |
388 copy_tv(&argv[idx], STACK_TV_BOT(0)); | 421 copy_tv(&argv[idx], STACK_TV_BOT(0)); |
389 ++ectx.ec_stack.ga_len; | 422 ++ectx.ec_stack.ga_len; |
390 } | 423 } |
424 // Make space for omitted arguments, will store default value below. | |
425 if (defcount > 0) | |
426 for (idx = 0; idx < defcount; ++idx) | |
427 { | |
428 STACK_TV_BOT(0)->v_type = VAR_UNKNOWN; | |
429 ++ectx.ec_stack.ga_len; | |
430 } | |
391 | 431 |
392 // Frame pointer points to just after arguments. | 432 // Frame pointer points to just after arguments. |
393 ectx.ec_frame = ectx.ec_stack.ga_len; | 433 ectx.ec_frame = ectx.ec_stack.ga_len; |
394 initial_frame_ptr = ectx.ec_frame; | 434 initial_frame_ptr = ectx.ec_frame; |
395 | 435 |
396 // TODO: Put omitted argument default values on the stack. | |
397 if (optcount > 0) | |
398 { | |
399 emsg("optional arguments not implemented yet"); | |
400 return FAIL; | |
401 } | |
402 // dummy frame entries | 436 // dummy frame entries |
403 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) | 437 for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) |
404 { | 438 { |
405 STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN; | 439 STACK_TV(ectx.ec_stack.ga_len)->v_type = VAR_UNKNOWN; |
406 ++ectx.ec_stack.ga_len; | 440 ++ectx.ec_stack.ga_len; |
411 for (idx = 0; idx < dfunc->df_varcount; ++idx) | 445 for (idx = 0; idx < dfunc->df_varcount; ++idx) |
412 STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; | 446 STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; |
413 ectx.ec_stack.ga_len += dfunc->df_varcount; | 447 ectx.ec_stack.ga_len += dfunc->df_varcount; |
414 | 448 |
415 ectx.ec_instr = dfunc->df_instr; | 449 ectx.ec_instr = dfunc->df_instr; |
416 ectx.ec_iidx = 0; | 450 |
451 // Decide where to start execution, handles optional arguments. | |
452 init_instr_idx(ufunc, argc, &ectx); | |
453 | |
417 for (;;) | 454 for (;;) |
418 { | 455 { |
419 isn_T *iptr; | 456 isn_T *iptr; |
420 trycmd_T *trycmd = NULL; | 457 trycmd_T *trycmd = NULL; |
421 | 458 |
1655 case ISN_LOADREG: | 1692 case ISN_LOADREG: |
1656 smsg("%4d LOADREG @%c", current, iptr->isn_arg.number); | 1693 smsg("%4d LOADREG @%c", current, iptr->isn_arg.number); |
1657 break; | 1694 break; |
1658 | 1695 |
1659 case ISN_STORE: | 1696 case ISN_STORE: |
1660 smsg("%4d STORE $%lld", current, iptr->isn_arg.number); | 1697 if (iptr->isn_arg.number < 0) |
1698 smsg("%4d STORE arg[%lld]", current, | |
1699 iptr->isn_arg.number + STACK_FRAME_SIZE); | |
1700 else | |
1701 smsg("%4d STORE $%lld", current, iptr->isn_arg.number); | |
1661 break; | 1702 break; |
1662 case ISN_STOREV: | 1703 case ISN_STOREV: |
1663 smsg("%4d STOREV v:%s", current, | 1704 smsg("%4d STOREV v:%s", current, |
1664 get_vim_var_name(iptr->isn_arg.number)); | 1705 get_vim_var_name(iptr->isn_arg.number)); |
1665 break; | 1706 break; |