Mercurial > vim
comparison src/userfunc.c @ 31416:f088f1d97eee v9.0.1041
patch 9.0.1041: cannot define a method in a class
Commit: https://github.com/vim/vim/commit/ffdaca9e6f3d39af6857ac52ced9385df203a152
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Dec 9 21:41:48 2022 +0000
patch 9.0.1041: cannot define a method in a class
Problem: Cannot define a method in a class.
Solution: Implement defining an object method. Make calling an object
method work.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 09 Dec 2022 22:45:03 +0100 |
parents | 307f68a41b03 |
children | e31fc75f6aff |
comparison
equal
deleted
inserted
replaced
31415:4fd33db887f2 | 31416:f088f1d97eee |
---|---|
186 else | 186 else |
187 theline = eap->getline(':', eap->cookie, indent, getline_options); | 187 theline = eap->getline(':', eap->cookie, indent, getline_options); |
188 if (theline != NULL) | 188 if (theline != NULL) |
189 { | 189 { |
190 if (lines_to_free->ga_len > 0 | 190 if (lines_to_free->ga_len > 0 |
191 && eap->cmdlinep != NULL | |
191 && *eap->cmdlinep == ((char_u **)lines_to_free->ga_data) | 192 && *eap->cmdlinep == ((char_u **)lines_to_free->ga_data) |
192 [lines_to_free->ga_len - 1]) | 193 [lines_to_free->ga_len - 1]) |
193 *eap->cmdlinep = theline; | 194 *eap->cmdlinep = theline; |
194 ga_add_string(lines_to_free, theline); | 195 ga_add_string(lines_to_free, theline); |
195 } | 196 } |
212 evalarg_T *evalarg, // context or NULL | 213 evalarg_T *evalarg, // context or NULL |
213 int *varargs, | 214 int *varargs, |
214 garray_T *default_args, | 215 garray_T *default_args, |
215 int skip, | 216 int skip, |
216 exarg_T *eap, // can be NULL | 217 exarg_T *eap, // can be NULL |
217 class_T *class_arg, | 218 int in_class, // TRUE when inside a class |
218 garray_T *newlines, // function body lines | 219 garray_T *newlines, // function body lines |
219 garray_T *lines_to_free) | 220 garray_T *lines_to_free) |
220 { | 221 { |
221 int mustend = FALSE; | 222 int mustend = FALSE; |
222 char_u *arg; | 223 char_u *arg; |
292 emsg(_(e_cannot_use_default_for_variable_arguments)); | 293 emsg(_(e_cannot_use_default_for_variable_arguments)); |
293 break; | 294 break; |
294 } | 295 } |
295 } | 296 } |
296 } | 297 } |
297 else if (class_arg != NULL && STRNCMP(p, "this.", 5) == 0) | 298 else if (in_class && STRNCMP(p, "this.", 5) == 0) |
298 { | 299 { |
299 // this.memberName | 300 // this.memberName |
300 p += 5; | 301 p += 5; |
301 arg = p; | 302 arg = p; |
302 while (ASCII_ISALNUM(*p) || *p == '_') | 303 while (ASCII_ISALNUM(*p) || *p == '_') |
1434 // First, check if this is really a lambda expression. "->" or "=>" must | 1435 // First, check if this is really a lambda expression. "->" or "=>" must |
1435 // be found after the arguments. | 1436 // be found after the arguments. |
1436 s = *arg + 1; | 1437 s = *arg + 1; |
1437 ret = get_function_args(&s, equal_arrow ? ')' : '-', NULL, | 1438 ret = get_function_args(&s, equal_arrow ? ')' : '-', NULL, |
1438 types_optional ? &argtypes : NULL, types_optional, evalarg, | 1439 types_optional ? &argtypes : NULL, types_optional, evalarg, |
1439 NULL, &default_args, TRUE, NULL, NULL, NULL, NULL); | 1440 NULL, &default_args, TRUE, NULL, FALSE, NULL, NULL); |
1440 if (ret == FAIL || skip_arrow(s, equal_arrow, &ret_type, NULL) == NULL) | 1441 if (ret == FAIL || skip_arrow(s, equal_arrow, &ret_type, NULL) == NULL) |
1441 { | 1442 { |
1442 if (types_optional) | 1443 if (types_optional) |
1443 ga_clear_strings(&argtypes); | 1444 ga_clear_strings(&argtypes); |
1444 return called_emsg == called_emsg_start ? NOTDONE : FAIL; | 1445 return called_emsg == called_emsg_start ? NOTDONE : FAIL; |
1451 pnewargs = NULL; | 1452 pnewargs = NULL; |
1452 *arg += 1; | 1453 *arg += 1; |
1453 ret = get_function_args(arg, equal_arrow ? ')' : '-', pnewargs, | 1454 ret = get_function_args(arg, equal_arrow ? ')' : '-', pnewargs, |
1454 types_optional ? &argtypes : NULL, types_optional, evalarg, | 1455 types_optional ? &argtypes : NULL, types_optional, evalarg, |
1455 &varargs, &default_args, | 1456 &varargs, &default_args, |
1456 FALSE, NULL, NULL, NULL, NULL); | 1457 FALSE, NULL, FALSE, NULL, NULL); |
1457 if (ret == FAIL | 1458 if (ret == FAIL |
1458 || (s = skip_arrow(*arg, equal_arrow, &ret_type, | 1459 || (s = skip_arrow(*arg, equal_arrow, &ret_type, |
1459 equal_arrow || vim9script ? &white_error : NULL)) == NULL) | 1460 equal_arrow || vim9script ? &white_error : NULL)) == NULL) |
1460 { | 1461 { |
1461 if (types_optional) | 1462 if (types_optional) |
2731 #ifdef FEAT_PROFILE | 2732 #ifdef FEAT_PROFILE |
2732 if (do_profiling == PROF_YES) | 2733 if (do_profiling == PROF_YES) |
2733 profile_may_start_func(&profile_info, fp, caller); | 2734 profile_may_start_func(&profile_info, fp, caller); |
2734 #endif | 2735 #endif |
2735 sticky_cmdmod_flags = 0; | 2736 sticky_cmdmod_flags = 0; |
2736 call_def_function(fp, argcount, argvars, 0, funcexe->fe_partial, | 2737 call_def_function(fp, argcount, argvars, 0, |
2737 fc, rettv); | 2738 funcexe->fe_partial, funcexe->fe_object, fc, rettv); |
2738 funcdepth_decrement(); | 2739 funcdepth_decrement(); |
2739 #ifdef FEAT_PROFILE | 2740 #ifdef FEAT_PROFILE |
2740 if (do_profiling == PROF_YES && (fp->uf_profiling | 2741 if (do_profiling == PROF_YES && (fp->uf_profiling |
2741 || (caller != NULL && caller->uf_profiling))) | 2742 || (caller != NULL && caller->uf_profiling))) |
2742 profile_may_end_func(&profile_info, fp, caller); | 2743 profile_may_end_func(&profile_info, fp, caller); |
3955 * Returns the function name in allocated memory, or NULL for failure. | 3956 * Returns the function name in allocated memory, or NULL for failure. |
3956 * Set "*is_global" to TRUE when the function must be global, unless | 3957 * Set "*is_global" to TRUE when the function must be global, unless |
3957 * "is_global" is NULL. | 3958 * "is_global" is NULL. |
3958 * flags: | 3959 * flags: |
3959 * TFN_INT: internal function name OK | 3960 * TFN_INT: internal function name OK |
3961 * TFN_IN_CLASS: function in a class | |
3960 * TFN_QUIET: be quiet | 3962 * TFN_QUIET: be quiet |
3961 * TFN_NO_AUTOLOAD: do not use script autoloading | 3963 * TFN_NO_AUTOLOAD: do not use script autoloading |
3962 * TFN_NO_DEREF: do not dereference a Funcref | 3964 * TFN_NO_DEREF: do not dereference a Funcref |
3963 * Advances "pp" to just after the function name (if no error). | 3965 * Advances "pp" to just after the function name (if no error). |
3964 */ | 3966 */ |
4170 emsg(_(e_function_name_required)); | 4172 emsg(_(e_function_name_required)); |
4171 goto theend; | 4173 goto theend; |
4172 } | 4174 } |
4173 | 4175 |
4174 // In Vim9 script a user function is script-local by default, unless it | 4176 // In Vim9 script a user function is script-local by default, unless it |
4175 // starts with a lower case character: dict.func(). | 4177 // starts with a lower case character: dict.func(). Or when in a class. |
4176 vim9_local = ASCII_ISUPPER(*start) && vim9script; | 4178 vim9_local = ASCII_ISUPPER(*start) && vim9script |
4179 && (flags & TFN_IN_CLASS) == 0; | |
4177 | 4180 |
4178 /* | 4181 /* |
4179 * Copy the function name to allocated memory. | 4182 * Copy the function name to allocated memory. |
4180 * Accept <SID>name() inside a script, translate into <SNR>123_name(). | 4183 * Accept <SID>name() inside a script, translate into <SNR>123_name(). |
4181 * Accept <SNR>123_name() outside a script. | 4184 * Accept <SNR>123_name() outside a script. |
4209 extra = 3 + (int)STRLEN(sid_buf); | 4212 extra = 3 + (int)STRLEN(sid_buf); |
4210 else | 4213 else |
4211 lead += (int)STRLEN(sid_buf); | 4214 lead += (int)STRLEN(sid_buf); |
4212 } | 4215 } |
4213 } | 4216 } |
4214 else if (!(flags & TFN_INT) && (builtin_function(lv.ll_name, len) | 4217 else if (!(flags & TFN_INT) |
4215 || (vim9script && *lv.ll_name == '_'))) | 4218 && (builtin_function(lv.ll_name, len) |
4219 || (vim9script && *lv.ll_name == '_')) | |
4220 && !((flags & TFN_IN_CLASS) && STRNCMP(lv.ll_name, "new", 3) == 0)) | |
4216 { | 4221 { |
4217 semsg(_(vim9script ? e_function_name_must_start_with_capital_str | 4222 semsg(_(vim9script ? e_function_name_must_start_with_capital_str |
4218 : e_function_name_must_start_with_capital_or_s_str), | 4223 : e_function_name_must_start_with_capital_or_s_str), |
4219 start); | 4224 start); |
4220 goto theend; | 4225 goto theend; |
4415 /* | 4420 /* |
4416 * ":function" also supporting nested ":def". | 4421 * ":function" also supporting nested ":def". |
4417 * When "name_arg" is not NULL this is a nested function, using "name_arg" for | 4422 * When "name_arg" is not NULL this is a nested function, using "name_arg" for |
4418 * the function name. | 4423 * the function name. |
4419 * "lines_to_free" is a list of strings to be freed later. | 4424 * "lines_to_free" is a list of strings to be freed later. |
4420 * If "class_arg" is not NULL then the function is defined in this class. | 4425 * If "in_class" is TRUE then the function is defined inside a class. |
4421 * Returns a pointer to the function or NULL if no function defined. | 4426 * Returns a pointer to the function or NULL if no function defined. |
4422 */ | 4427 */ |
4423 ufunc_T * | 4428 ufunc_T * |
4424 define_function( | 4429 define_function( |
4425 exarg_T *eap, | 4430 exarg_T *eap, |
4426 char_u *name_arg, | 4431 char_u *name_arg, |
4427 garray_T *lines_to_free, | 4432 garray_T *lines_to_free, |
4428 class_T *class_arg) | 4433 int in_class) |
4429 { | 4434 { |
4430 int j; | 4435 int j; |
4431 int c; | 4436 int c; |
4432 int saved_did_emsg = FALSE; | 4437 int saved_did_emsg = FALSE; |
4433 char_u *name = name_arg; | 4438 char_u *name = name_arg; |
4498 ga_init(&argtypes); | 4503 ga_init(&argtypes); |
4499 ga_init(&default_args); | 4504 ga_init(&default_args); |
4500 | 4505 |
4501 /* | 4506 /* |
4502 * Get the function name. There are these situations: | 4507 * Get the function name. There are these situations: |
4503 * func normal function name | 4508 * func normal function name, also when "in_class" is TRUE |
4504 * "name" == func, "fudi.fd_dict" == NULL | 4509 * "name" == func, "fudi.fd_dict" == NULL |
4505 * dict.func new dictionary entry | 4510 * dict.func new dictionary entry |
4506 * "name" == NULL, "fudi.fd_dict" set, | 4511 * "name" == NULL, "fudi.fd_dict" set, |
4507 * "fudi.fd_di" == NULL, "fudi.fd_newkey" == func | 4512 * "fudi.fd_di" == NULL, "fudi.fd_newkey" == func |
4508 * dict.func existing dict entry with a Funcref | 4513 * dict.func existing dict entry with a Funcref |
4539 } | 4544 } |
4540 p = eap->arg; | 4545 p = eap->arg; |
4541 } | 4546 } |
4542 | 4547 |
4543 int tfn_flags = TFN_NO_AUTOLOAD | TFN_NEW_FUNC | 4548 int tfn_flags = TFN_NO_AUTOLOAD | TFN_NEW_FUNC |
4544 | (class_arg == 0 ? 0 : TFN_INT); | 4549 | (in_class ? TFN_IN_CLASS : 0); |
4545 name = save_function_name(&p, &is_global, eap->skip, tfn_flags, &fudi); | 4550 name = save_function_name(&p, &is_global, eap->skip, tfn_flags, &fudi); |
4546 paren = (vim_strchr(p, '(') != NULL); | 4551 paren = (vim_strchr(p, '(') != NULL); |
4547 if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) | 4552 if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) |
4548 { | 4553 { |
4549 /* | 4554 /* |
4741 // invalid. | 4746 // invalid. |
4742 ++p; | 4747 ++p; |
4743 if (get_function_args(&p, ')', &newargs, | 4748 if (get_function_args(&p, ')', &newargs, |
4744 eap->cmdidx == CMD_def ? &argtypes : NULL, FALSE, | 4749 eap->cmdidx == CMD_def ? &argtypes : NULL, FALSE, |
4745 NULL, &varargs, &default_args, eap->skip, | 4750 NULL, &varargs, &default_args, eap->skip, |
4746 eap, class_arg, &newlines, lines_to_free) == FAIL) | 4751 eap, in_class, &newlines, lines_to_free) == FAIL) |
4747 goto errret_2; | 4752 goto errret_2; |
4748 whitep = p; | 4753 whitep = p; |
4749 | 4754 |
4750 if (eap->cmdidx == CMD_def) | 4755 if (eap->cmdidx == CMD_def) |
4751 { | 4756 { |
4858 goto erret; | 4863 goto erret; |
4859 | 4864 |
4860 /* | 4865 /* |
4861 * If there are no errors, add the function | 4866 * If there are no errors, add the function |
4862 */ | 4867 */ |
4863 if (fudi.fd_dict == NULL) | 4868 if (fudi.fd_dict != NULL) |
4869 { | |
4870 char numbuf[20]; | |
4871 | |
4872 fp = NULL; | |
4873 if (fudi.fd_newkey == NULL && !eap->forceit) | |
4874 { | |
4875 emsg(_(e_dictionary_entry_already_exists)); | |
4876 goto erret; | |
4877 } | |
4878 if (fudi.fd_di == NULL) | |
4879 { | |
4880 // Can't add a function to a locked dictionary | |
4881 if (value_check_lock(fudi.fd_dict->dv_lock, eap->arg, FALSE)) | |
4882 goto erret; | |
4883 } | |
4884 // Can't change an existing function if it is locked | |
4885 else if (value_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, FALSE)) | |
4886 goto erret; | |
4887 | |
4888 // Give the function a sequential number. Can only be used with a | |
4889 // Funcref! | |
4890 vim_free(name); | |
4891 sprintf(numbuf, "%d", ++func_nr); | |
4892 name = vim_strsave((char_u *)numbuf); | |
4893 if (name == NULL) | |
4894 goto erret; | |
4895 } | |
4896 else if (!in_class) | |
4864 { | 4897 { |
4865 hashtab_T *ht; | 4898 hashtab_T *ht; |
4866 char_u *find_name = name; | 4899 char_u *find_name = name; |
4867 int var_conflict = FALSE; | 4900 int var_conflict = FALSE; |
4868 int ffed_flags = is_global ? FFED_IS_GLOBAL : 0; | 4901 int ffed_flags = is_global ? FFED_IS_GLOBAL : 0; |
4964 fp->uf_prof_initialized = FALSE; | 4997 fp->uf_prof_initialized = FALSE; |
4965 #endif | 4998 #endif |
4966 fp->uf_def_status = UF_NOT_COMPILED; | 4999 fp->uf_def_status = UF_NOT_COMPILED; |
4967 } | 5000 } |
4968 } | 5001 } |
4969 } | |
4970 else | |
4971 { | |
4972 char numbuf[20]; | |
4973 | |
4974 fp = NULL; | |
4975 if (fudi.fd_newkey == NULL && !eap->forceit) | |
4976 { | |
4977 emsg(_(e_dictionary_entry_already_exists)); | |
4978 goto erret; | |
4979 } | |
4980 if (fudi.fd_di == NULL) | |
4981 { | |
4982 // Can't add a function to a locked dictionary | |
4983 if (value_check_lock(fudi.fd_dict->dv_lock, eap->arg, FALSE)) | |
4984 goto erret; | |
4985 } | |
4986 // Can't change an existing function if it is locked | |
4987 else if (value_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, FALSE)) | |
4988 goto erret; | |
4989 | |
4990 // Give the function a sequential number. Can only be used with a | |
4991 // Funcref! | |
4992 vim_free(name); | |
4993 sprintf(numbuf, "%d", ++func_nr); | |
4994 name = vim_strsave((char_u *)numbuf); | |
4995 if (name == NULL) | |
4996 goto erret; | |
4997 } | 5002 } |
4998 | 5003 |
4999 if (fp == NULL) | 5004 if (fp == NULL) |
5000 { | 5005 { |
5001 if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) | 5006 if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) |
5111 if (overwrite) | 5116 if (overwrite) |
5112 { | 5117 { |
5113 hi = hash_find(&func_hashtab, name); | 5118 hi = hash_find(&func_hashtab, name); |
5114 hi->hi_key = UF2HIKEY(fp); | 5119 hi->hi_key = UF2HIKEY(fp); |
5115 } | 5120 } |
5116 else if (hash_add(&func_hashtab, UF2HIKEY(fp), "add function") == FAIL) | 5121 else if (!in_class && hash_add(&func_hashtab, |
5122 UF2HIKEY(fp), "add function") == FAIL) | |
5117 { | 5123 { |
5118 free_fp = TRUE; | 5124 free_fp = TRUE; |
5119 goto erret; | 5125 goto erret; |
5120 } | 5126 } |
5121 fp->uf_refcount = 1; | 5127 fp->uf_refcount = 1; |
5196 ex_function(exarg_T *eap) | 5202 ex_function(exarg_T *eap) |
5197 { | 5203 { |
5198 garray_T lines_to_free; | 5204 garray_T lines_to_free; |
5199 | 5205 |
5200 ga_init2(&lines_to_free, sizeof(char_u *), 50); | 5206 ga_init2(&lines_to_free, sizeof(char_u *), 50); |
5201 (void)define_function(eap, NULL, &lines_to_free, NULL); | 5207 (void)define_function(eap, NULL, &lines_to_free, FALSE); |
5202 ga_clear_strings(&lines_to_free); | 5208 ga_clear_strings(&lines_to_free); |
5203 } | 5209 } |
5204 | 5210 |
5205 /* | 5211 /* |
5206 * Find a function by name, including "<lambda>123". | 5212 * Find a function by name, including "<lambda>123". |