Mercurial > vim
comparison src/userfunc.c @ 16615:1a911bd57f11 v8.1.1310
patch 8.1.1310: named function arguments are never optional
commit https://github.com/vim/vim/commit/42ae78cfff171fbd7412306083fe200245d7a7a6
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu May 9 21:08:58 2019 +0200
patch 8.1.1310: named function arguments are never optional
Problem: Named function arguments are never optional.
Solution: Support optional function arguments with a default value. (Andy
Massimino, closes #3952)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 09 May 2019 21:15:05 +0200 |
parents | 7e733046db1d |
children | a1ba0bd74e7d |
comparison
equal
deleted
inserted
replaced
16614:306acde1a598 | 16615:1a911bd57f11 |
---|---|
73 get_function_args( | 73 get_function_args( |
74 char_u **argp, | 74 char_u **argp, |
75 char_u endchar, | 75 char_u endchar, |
76 garray_T *newargs, | 76 garray_T *newargs, |
77 int *varargs, | 77 int *varargs, |
78 garray_T *default_args, | |
78 int skip) | 79 int skip) |
79 { | 80 { |
80 int mustend = FALSE; | 81 int mustend = FALSE; |
81 char_u *arg = *argp; | 82 char_u *arg = *argp; |
82 char_u *p = arg; | 83 char_u *p = arg; |
83 int c; | 84 int c; |
84 int i; | 85 int i; |
86 int any_default = FALSE; | |
87 char_u *expr; | |
85 | 88 |
86 if (newargs != NULL) | 89 if (newargs != NULL) |
87 ga_init2(newargs, (int)sizeof(char_u *), 3); | 90 ga_init2(newargs, (int)sizeof(char_u *), 3); |
91 if (default_args != NULL) | |
92 ga_init2(default_args, (int)sizeof(char_u *), 3); | |
88 | 93 |
89 if (varargs != NULL) | 94 if (varargs != NULL) |
90 *varargs = FALSE; | 95 *varargs = FALSE; |
91 | 96 |
92 /* | 97 /* |
138 ((char_u **)(newargs->ga_data))[newargs->ga_len] = arg; | 143 ((char_u **)(newargs->ga_data))[newargs->ga_len] = arg; |
139 newargs->ga_len++; | 144 newargs->ga_len++; |
140 | 145 |
141 *p = c; | 146 *p = c; |
142 } | 147 } |
148 if (*skipwhite(p) == '=' && default_args != NULL) | |
149 { | |
150 typval_T rettv; | |
151 | |
152 any_default = TRUE; | |
153 p = skipwhite(p) + 1; | |
154 p = skipwhite(p); | |
155 expr = p; | |
156 if (eval1(&p, &rettv, FALSE) != FAIL) | |
157 { | |
158 if (ga_grow(default_args, 1) == FAIL) | |
159 goto err_ret; | |
160 | |
161 // trim trailing whitespace | |
162 while (p > expr && VIM_ISWHITE(p[-1])) | |
163 p--; | |
164 c = *p; | |
165 *p = NUL; | |
166 expr = vim_strsave(expr); | |
167 if (expr == NULL) | |
168 { | |
169 *p = c; | |
170 goto err_ret; | |
171 } | |
172 ((char_u **)(default_args->ga_data)) | |
173 [default_args->ga_len] = expr; | |
174 default_args->ga_len++; | |
175 *p = c; | |
176 } | |
177 else | |
178 mustend = TRUE; | |
179 } | |
180 else if (any_default) | |
181 { | |
182 emsg(_("E989: Non-default argument follows default argument")); | |
183 mustend = TRUE; | |
184 } | |
143 if (*p == ',') | 185 if (*p == ',') |
144 ++p; | 186 ++p; |
145 else | 187 else |
146 mustend = TRUE; | 188 mustend = TRUE; |
147 } | 189 } |
161 return OK; | 203 return OK; |
162 | 204 |
163 err_ret: | 205 err_ret: |
164 if (newargs != NULL) | 206 if (newargs != NULL) |
165 ga_clear_strings(newargs); | 207 ga_clear_strings(newargs); |
208 if (default_args != NULL) | |
209 ga_clear_strings(default_args); | |
166 return FAIL; | 210 return FAIL; |
167 } | 211 } |
168 | 212 |
169 /* | 213 /* |
170 * Register function "fp" as using "current_funccal" as its scope. | 214 * Register function "fp" as using "current_funccal" as its scope. |
208 | 252 |
209 ga_init(&newargs); | 253 ga_init(&newargs); |
210 ga_init(&newlines); | 254 ga_init(&newlines); |
211 | 255 |
212 /* First, check if this is a lambda expression. "->" must exist. */ | 256 /* First, check if this is a lambda expression. "->" must exist. */ |
213 ret = get_function_args(&start, '-', NULL, NULL, TRUE); | 257 ret = get_function_args(&start, '-', NULL, NULL, NULL, TRUE); |
214 if (ret == FAIL || *start != '>') | 258 if (ret == FAIL || *start != '>') |
215 return NOTDONE; | 259 return NOTDONE; |
216 | 260 |
217 /* Parse the arguments again. */ | 261 /* Parse the arguments again. */ |
218 if (evaluate) | 262 if (evaluate) |
219 pnewargs = &newargs; | 263 pnewargs = &newargs; |
220 else | 264 else |
221 pnewargs = NULL; | 265 pnewargs = NULL; |
222 *arg = skipwhite(*arg + 1); | 266 *arg = skipwhite(*arg + 1); |
223 ret = get_function_args(arg, '-', pnewargs, &varargs, FALSE); | 267 ret = get_function_args(arg, '-', pnewargs, &varargs, NULL, FALSE); |
224 if (ret == FAIL || **arg != '>') | 268 if (ret == FAIL || **arg != '>') |
225 goto errret; | 269 goto errret; |
226 | 270 |
227 /* Set up a flag for checking local variables and arguments. */ | 271 /* Set up a flag for checking local variables and arguments. */ |
228 if (evaluate) | 272 if (evaluate) |
270 | 314 |
271 fp->uf_refcount = 1; | 315 fp->uf_refcount = 1; |
272 STRCPY(fp->uf_name, name); | 316 STRCPY(fp->uf_name, name); |
273 hash_add(&func_hashtab, UF2HIKEY(fp)); | 317 hash_add(&func_hashtab, UF2HIKEY(fp)); |
274 fp->uf_args = newargs; | 318 fp->uf_args = newargs; |
319 ga_init(&fp->uf_def_args); | |
275 fp->uf_lines = newlines; | 320 fp->uf_lines = newlines; |
276 if (current_funccal != NULL && eval_lavars) | 321 if (current_funccal != NULL && eval_lavars) |
277 { | 322 { |
278 flags |= FC_CLOSURE; | 323 flags |= FC_CLOSURE; |
279 if (register_closure(fp) == FAIL) | 324 if (register_closure(fp) == FAIL) |
727 linenr_T save_sourcing_lnum; | 772 linenr_T save_sourcing_lnum; |
728 sctx_T save_current_sctx; | 773 sctx_T save_current_sctx; |
729 int using_sandbox = FALSE; | 774 int using_sandbox = FALSE; |
730 funccall_T *fc; | 775 funccall_T *fc; |
731 int save_did_emsg; | 776 int save_did_emsg; |
777 int default_arg_err = FALSE; | |
732 static int depth = 0; | 778 static int depth = 0; |
733 dictitem_T *v; | 779 dictitem_T *v; |
734 int fixvar_idx = 0; /* index in fixvar[] */ | 780 int fixvar_idx = 0; /* index in fixvar[] */ |
735 int i; | 781 int i; |
736 int ai; | 782 int ai; |
803 ++selfdict->dv_refcount; | 849 ++selfdict->dv_refcount; |
804 } | 850 } |
805 | 851 |
806 /* | 852 /* |
807 * Init a: variables. | 853 * Init a: variables. |
808 * Set a:0 to "argcount". | 854 * Set a:0 to "argcount" less number of named arguments, if >= 0. |
809 * Set a:000 to a list with room for the "..." arguments. | 855 * Set a:000 to a list with room for the "..." arguments. |
810 */ | 856 */ |
811 init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE); | 857 init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE); |
812 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0", | 858 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0", |
813 (varnumber_T)(argcount - fp->uf_args.ga_len)); | 859 (varnumber_T)(argcount >= fp->uf_args.ga_len |
860 ? argcount - fp->uf_args.ga_len : 0)); | |
814 fc->l_avars.dv_lock = VAR_FIXED; | 861 fc->l_avars.dv_lock = VAR_FIXED; |
815 /* Use "name" to avoid a warning from some compiler that checks the | 862 /* Use "name" to avoid a warning from some compiler that checks the |
816 * destination size. */ | 863 * destination size. */ |
817 v = &fc->fixvar[fixvar_idx++].var; | 864 v = &fc->fixvar[fixvar_idx++].var; |
818 name = v->di_key; | 865 name = v->di_key; |
833 */ | 880 */ |
834 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline", | 881 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline", |
835 (varnumber_T)firstline); | 882 (varnumber_T)firstline); |
836 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", | 883 add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", |
837 (varnumber_T)lastline); | 884 (varnumber_T)lastline); |
838 for (i = 0; i < argcount; ++i) | 885 for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i) |
839 { | 886 { |
840 int addlocal = FALSE; | 887 int addlocal = FALSE; |
888 typval_T def_rettv; | |
889 int isdefault = FALSE; | |
841 | 890 |
842 ai = i - fp->uf_args.ga_len; | 891 ai = i - fp->uf_args.ga_len; |
843 if (ai < 0) | 892 if (ai < 0) |
844 { | 893 { |
845 /* named argument a:name */ | 894 /* named argument a:name */ |
846 name = FUNCARG(fp, i); | 895 name = FUNCARG(fp, i); |
847 if (islambda) | 896 if (islambda) |
848 addlocal = TRUE; | 897 addlocal = TRUE; |
898 | |
899 // evaluate named argument default expression | |
900 isdefault = ai + fp->uf_def_args.ga_len >= 0 | |
901 && (i >= argcount || (argvars[i].v_type == VAR_SPECIAL | |
902 && argvars[i].vval.v_number == VVAL_NONE)); | |
903 if (isdefault) | |
904 { | |
905 char_u *default_expr = NULL; | |
906 def_rettv.v_type = VAR_NUMBER; | |
907 def_rettv.vval.v_number = -1; | |
908 | |
909 default_expr = ((char_u **)(fp->uf_def_args.ga_data)) | |
910 [ai + fp->uf_def_args.ga_len]; | |
911 if (eval1(&default_expr, &def_rettv, TRUE) == FAIL) | |
912 { | |
913 default_arg_err = 1; | |
914 break; | |
915 } | |
916 } | |
849 } | 917 } |
850 else | 918 else |
851 { | 919 { |
852 /* "..." argument a:1, a:2, etc. */ | 920 /* "..." argument a:1, a:2, etc. */ |
853 sprintf((char *)numbuf, "%d", ai + 1); | 921 sprintf((char *)numbuf, "%d", ai + 1); |
865 if (v == NULL) | 933 if (v == NULL) |
866 break; | 934 break; |
867 v->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; | 935 v->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX; |
868 } | 936 } |
869 | 937 |
870 /* Note: the values are copied directly to avoid alloc/free. | 938 if (isdefault) |
871 * "argvars" must have VAR_FIXED for v_lock. */ | 939 v->di_tv = def_rettv; |
872 v->di_tv = argvars[i]; | 940 else |
941 // Note: the values are copied directly to avoid alloc/free. | |
942 // "argvars" must have VAR_FIXED for v_lock. | |
943 v->di_tv = argvars[i]; | |
873 v->di_tv.v_lock = VAR_FIXED; | 944 v->di_tv.v_lock = VAR_FIXED; |
874 | 945 |
875 if (addlocal) | 946 if (addlocal) |
876 { | 947 { |
877 /* Named arguments should be accessed without the "a:" prefix in | 948 /* Named arguments should be accessed without the "a:" prefix in |
986 save_current_sctx = current_sctx; | 1057 save_current_sctx = current_sctx; |
987 current_sctx = fp->uf_script_ctx; | 1058 current_sctx = fp->uf_script_ctx; |
988 save_did_emsg = did_emsg; | 1059 save_did_emsg = did_emsg; |
989 did_emsg = FALSE; | 1060 did_emsg = FALSE; |
990 | 1061 |
991 /* call do_cmdline() to execute the lines */ | 1062 if (default_arg_err && (fp->uf_flags & FC_ABORT)) |
992 do_cmdline(NULL, get_func_line, (void *)fc, | 1063 did_emsg = TRUE; |
1064 else | |
1065 // call do_cmdline() to execute the lines | |
1066 do_cmdline(NULL, get_func_line, (void *)fc, | |
993 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); | 1067 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); |
994 | 1068 |
995 --RedrawingDisabled; | 1069 --RedrawingDisabled; |
996 | 1070 |
997 /* when the function was aborted because of an error, return -1 */ | 1071 /* when the function was aborted because of an error, return -1 */ |
1143 | 1217 |
1144 static void | 1218 static void |
1145 func_clear_items(ufunc_T *fp) | 1219 func_clear_items(ufunc_T *fp) |
1146 { | 1220 { |
1147 ga_clear_strings(&(fp->uf_args)); | 1221 ga_clear_strings(&(fp->uf_args)); |
1222 ga_clear_strings(&(fp->uf_def_args)); | |
1148 ga_clear_strings(&(fp->uf_lines)); | 1223 ga_clear_strings(&(fp->uf_lines)); |
1149 #ifdef FEAT_PROFILE | 1224 #ifdef FEAT_PROFILE |
1150 vim_free(fp->uf_tml_count); | 1225 vim_free(fp->uf_tml_count); |
1151 fp->uf_tml_count = NULL; | 1226 fp->uf_tml_count = NULL; |
1152 vim_free(fp->uf_tml_total); | 1227 vim_free(fp->uf_tml_total); |
1496 if (argv_func != NULL) | 1571 if (argv_func != NULL) |
1497 argcount = argv_func(argcount, argvars, fp->uf_args.ga_len); | 1572 argcount = argv_func(argcount, argvars, fp->uf_args.ga_len); |
1498 | 1573 |
1499 if (fp->uf_flags & FC_RANGE) | 1574 if (fp->uf_flags & FC_RANGE) |
1500 *doesrange = TRUE; | 1575 *doesrange = TRUE; |
1501 if (argcount < fp->uf_args.ga_len) | 1576 if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) |
1502 error = ERROR_TOOFEW; | 1577 error = ERROR_TOOFEW; |
1503 else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) | 1578 else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len) |
1504 error = ERROR_TOOMANY; | 1579 error = ERROR_TOOMANY; |
1505 else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) | 1580 else if ((fp->uf_flags & FC_DICT) && selfdict == NULL) |
1506 error = ERROR_DICT; | 1581 error = ERROR_DICT; |
1622 for (j = 0; j < fp->uf_args.ga_len; ++j) | 1697 for (j = 0; j < fp->uf_args.ga_len; ++j) |
1623 { | 1698 { |
1624 if (j) | 1699 if (j) |
1625 msg_puts(", "); | 1700 msg_puts(", "); |
1626 msg_puts((char *)FUNCARG(fp, j)); | 1701 msg_puts((char *)FUNCARG(fp, j)); |
1702 if (j >= fp->uf_args.ga_len - fp->uf_def_args.ga_len) | |
1703 { | |
1704 msg_puts(" = "); | |
1705 msg_puts(((char **)(fp->uf_def_args.ga_data)) | |
1706 [j - fp->uf_args.ga_len + fp->uf_def_args.ga_len]); | |
1707 } | |
1627 } | 1708 } |
1628 if (fp->uf_varargs) | 1709 if (fp->uf_varargs) |
1629 { | 1710 { |
1630 if (j) | 1711 if (j) |
1631 msg_puts(", "); | 1712 msg_puts(", "); |
1887 char_u *name = NULL; | 1968 char_u *name = NULL; |
1888 char_u *p; | 1969 char_u *p; |
1889 char_u *arg; | 1970 char_u *arg; |
1890 char_u *line_arg = NULL; | 1971 char_u *line_arg = NULL; |
1891 garray_T newargs; | 1972 garray_T newargs; |
1973 garray_T default_args; | |
1892 garray_T newlines; | 1974 garray_T newlines; |
1893 int varargs = FALSE; | 1975 int varargs = FALSE; |
1894 int flags = 0; | 1976 int flags = 0; |
1895 ufunc_T *fp; | 1977 ufunc_T *fp; |
1896 int overwrite = FALSE; | 1978 int overwrite = FALSE; |
2101 /* Disallow using the g: dict. */ | 2183 /* Disallow using the g: dict. */ |
2102 if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) | 2184 if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) |
2103 emsg(_("E862: Cannot use g: here")); | 2185 emsg(_("E862: Cannot use g: here")); |
2104 } | 2186 } |
2105 | 2187 |
2106 if (get_function_args(&p, ')', &newargs, &varargs, eap->skip) == FAIL) | 2188 if (get_function_args(&p, ')', &newargs, &varargs, |
2189 &default_args, eap->skip) == FAIL) | |
2107 goto errret_2; | 2190 goto errret_2; |
2108 | 2191 |
2109 /* find extra arguments "range", "dict", "abort" and "closure" */ | 2192 /* find extra arguments "range", "dict", "abort" and "closure" */ |
2110 for (;;) | 2193 for (;;) |
2111 { | 2194 { |
2509 goto erret; | 2592 goto erret; |
2510 } | 2593 } |
2511 fp->uf_refcount = 1; | 2594 fp->uf_refcount = 1; |
2512 } | 2595 } |
2513 fp->uf_args = newargs; | 2596 fp->uf_args = newargs; |
2597 fp->uf_def_args = default_args; | |
2514 fp->uf_lines = newlines; | 2598 fp->uf_lines = newlines; |
2515 if ((flags & FC_CLOSURE) != 0) | 2599 if ((flags & FC_CLOSURE) != 0) |
2516 { | 2600 { |
2517 if (register_closure(fp) == FAIL) | 2601 if (register_closure(fp) == FAIL) |
2518 goto erret; | 2602 goto erret; |
2533 fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1; | 2617 fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1; |
2534 goto ret_free; | 2618 goto ret_free; |
2535 | 2619 |
2536 erret: | 2620 erret: |
2537 ga_clear_strings(&newargs); | 2621 ga_clear_strings(&newargs); |
2622 ga_clear_strings(&default_args); | |
2538 errret_2: | 2623 errret_2: |
2539 ga_clear_strings(&newlines); | 2624 ga_clear_strings(&newlines); |
2540 ret_free: | 2625 ret_free: |
2541 vim_free(skip_until); | 2626 vim_free(skip_until); |
2542 vim_free(line_to_free); | 2627 vim_free(line_to_free); |