cino-} indent.txt /*cino-}*
cinoptions-values indent.txt /*cinoptions-values*
class vim9class.txt /*class*
+class-compile vim9class.txt /*class-compile*
class-method vim9class.txt /*class-method*
clear-undo undo.txt /*clear-undo*
clearmatches() builtin.txt /*clearmatches()*
Issue #11822: any.Func() can be a dict or an object call, need to handle
this at runtime. Also see #12198 for an example.
Possibly issue #11981 can be fixed at the same time (has two examples).
- - Make ":defcompile ClassName" compile all functions and methods in the
- class.
- Forward declaration of a class? E.g. for Clone() function.
Email lifepillar 2023 Mar 26
- object empty(), len() - can class define a method to be used for them?
-*vim9.txt* For Vim version 9.1. Last change: 2023 Dec 24
+*vim9.txt* For Vim version 9.1. Last change: 2024 Jan 12
VIM REFERENCE MANUAL by Bram Moolenaar
level. They cannot be created in a function, also not in a legacy function.
*:defc* *:defcompile*
-:defc[ompile] Compile functions defined in the current script that
- were not compiled yet.
- This will report any errors found during compilation.
- This excludes functions defined inside a class.
+:defc[ompile] Compile functions and classes (|class-compile|)
+ defined in the current script that were not compiled
+ yet. This will report any errors found during
+ compilation.
+
+:defc[ompile] MyClass Compile all methods in a class |class-compile|.
:defc[ompile] {func}
:defc[ompile] debug {func}
-*vim9class.txt* For Vim version 9.1. Last change: 2024 Jan 06
+*vim9class.txt* For Vim version 9.1. Last change: 2024 Jan 12
VIM REFERENCE MANUAL by Bram Moolenaar
"new()" then the default constructor is added, even though there are other
constructor methods.
+Compiling methods in a Class ~
+ *class-compile*
+The |:defcompile| command can be used to compile all the class and object
+methods defined in a class: >
+ defcompile MyClass # Compile class "MyClass"
+ defcompile # Compile the classes in the current script
+<
==============================================================================
7. Type definition *typealias* *Vim9-type* *:type*
ufunc_T *define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free, int class_flags, ocmember_T *obj_members, int obj_member_count);
void ex_function(exarg_T *eap);
ufunc_T *find_func_by_name(char_u *name, compiletype_T *compile_type);
+void defcompile_function(ufunc_T *ufunc, class_T *cl);
void ex_defcompile(exarg_T *eap);
int eval_fname_script(char_u *p);
int translated_function_exists(char_u *name, int is_global);
void emsg_var_cl_define(char *msg, char_u *name, size_t len, class_T *cl);
void method_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
void member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len);
+void defcompile_class(class_T *cl);
+void defcompile_classes_in_script(void);
+int is_class_name(char_u *name, typval_T *rettv);
int class_instance_of(class_T *cl, class_T *other_cl);
void f_instanceof(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
v9.CheckSourceFailure(lines, 'E1034: Cannot use reserved name __foo()', 3)
enddef
+" Test for compiling class/object methods using :defcompile
+def Test_defcompile_class()
+ # defcompile all the classes in the current script
+ var lines =<< trim END
+ vim9script
+ class A
+ def Foo()
+ var i = 10
+ enddef
+ endclass
+ class B
+ def Bar()
+ var i = 20
+ xxx
+ enddef
+ endclass
+ defcompile
+ END
+ v9.CheckSourceFailure(lines, 'E476: Invalid command: xxx', 2)
+
+ # defcompile a specific class
+ lines =<< trim END
+ vim9script
+ class A
+ def Foo()
+ xxx
+ enddef
+ endclass
+ class B
+ def Bar()
+ yyy
+ enddef
+ endclass
+ defcompile B
+ END
+ v9.CheckSourceFailure(lines, 'E476: Invalid command: yyy', 1)
+
+ # defcompile a non-class
+ lines =<< trim END
+ vim9script
+ class A
+ def Foo()
+ enddef
+ endclass
+ var X: list<number> = []
+ defcompile X
+ END
+ v9.CheckSourceFailure(lines, 'E1061: Cannot find function X', 7)
+
+ # defcompile a class twice
+ lines =<< trim END
+ vim9script
+ class A
+ def new()
+ enddef
+ endclass
+ defcompile A
+ defcompile A
+ assert_equal('Function A.new does not need compiling', v:statusmsg)
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # defcompile should not compile an imported class
+ lines =<< trim END
+ vim9script
+ export class A
+ def Foo()
+ xxx
+ enddef
+ endclass
+ END
+ writefile(lines, 'Xdefcompileimport.vim', 'D')
+ lines =<< trim END
+ vim9script
+
+ import './Xdefcompileimport.vim'
+ class B
+ endclass
+ defcompile
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
return ufunc;
}
+/*
+ * Compile the :def function "ufunc". If "cl" is not NULL, then compile the
+ * class or object method "ufunc" in "cl".
+ */
+ void
+defcompile_function(ufunc_T *ufunc, class_T *cl)
+{
+ compiletype_T compile_type = CT_NONE;
+
+ if (func_needs_compiling(ufunc, compile_type))
+ (void)compile_def_function(ufunc, FALSE, compile_type, NULL);
+ else
+ smsg(_("Function %s%s%s does not need compiling"),
+ cl != NULL ? cl->class_name : (char_u *)"",
+ cl != NULL ? (char_u *)"." : (char_u *)"",
+ ufunc->uf_name);
+}
+
+/*
+ * Compile all the :def functions defined in the current script
+ */
+ static void
+defcompile_funcs_in_script(void)
+{
+ long todo = (long)func_hashtab.ht_used;
+ int changed = func_hashtab.ht_changed;
+ hashitem_T *hi;
+
+ for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ --todo;
+ ufunc_T *ufunc = HI2UF(hi);
+ if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
+ && ufunc->uf_def_status == UF_TO_BE_COMPILED
+ && (ufunc->uf_flags & FC_DEAD) == 0)
+ {
+ (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
+
+ if (func_hashtab.ht_changed != changed)
+ {
+ // a function has been added or removed, need to start
+ // over
+ todo = (long)func_hashtab.ht_used;
+ changed = func_hashtab.ht_changed;
+ hi = func_hashtab.ht_array;
+ --hi;
+ }
+ }
+ }
+ }
+}
+
/*
* :defcompile - compile all :def functions in the current script that need to
* be compiled or the one specified by the argument.
{
if (*eap->arg != NUL)
{
- compiletype_T compile_type = CT_NONE;
- ufunc_T *ufunc = find_func_by_name(eap->arg, &compile_type);
- if (ufunc != NULL)
+ typval_T tv;
+
+ if (is_class_name(eap->arg, &tv))
{
- if (func_needs_compiling(ufunc, compile_type))
- (void)compile_def_function(ufunc, FALSE, compile_type, NULL);
- else
- smsg(_("Function %s does not need compiling"), eap->arg);
+ class_T *cl = tv.vval.v_class;
+
+ if (cl != NULL)
+ defcompile_class(cl);
+ }
+ else
+ {
+ compiletype_T compile_type = CT_NONE;
+ ufunc_T *ufunc = find_func_by_name(eap->arg, &compile_type);
+ if (ufunc != NULL)
+ defcompile_function(ufunc, NULL);
}
}
else
{
- long todo = (long)func_hashtab.ht_used;
- int changed = func_hashtab.ht_changed;
- hashitem_T *hi;
-
- for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
- {
- if (!HASHITEM_EMPTY(hi))
- {
- --todo;
- ufunc_T *ufunc = HI2UF(hi);
- if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
- && ufunc->uf_def_status == UF_TO_BE_COMPILED
- && (ufunc->uf_flags & FC_DEAD) == 0)
- {
- (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
+ defcompile_funcs_in_script();
- if (func_hashtab.ht_changed != changed)
- {
- // a function has been added or removed, need to start
- // over
- todo = (long)func_hashtab.ht_used;
- changed = func_hashtab.ht_changed;
- hi = func_hashtab.ht_array;
- --hi;
- }
- }
- }
- }
+ // compile all the class defined in the current script
+ defcompile_classes_in_script();
}
}
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 20,
/**/
19,
/**/
vim_free(varname);
}
+/*
+ * Compile all the class and object methods in "cl".
+ */
+ void
+defcompile_class(class_T *cl)
+{
+ for (int loop = 1; loop <= 2; ++loop)
+ {
+ int func_count = loop == 1 ? cl->class_class_function_count
+ : cl->class_obj_method_count;
+ for (int i = 0; i < func_count; i++)
+ {
+ ufunc_T *ufunc = loop == 1 ? cl->class_class_functions[i]
+ : cl->class_obj_methods[i];
+ defcompile_function(ufunc, cl);
+ }
+ }
+}
+
+/*
+ * Compile all the classes defined in the current script
+ */
+ void
+defcompile_classes_in_script(void)
+{
+ for (class_T *cl = first_class; cl != NULL; cl = cl->class_next_used)
+ {
+ if (eval_variable(cl->class_name, 0, 0, NULL, NULL,
+ EVAL_VAR_NOAUTOLOAD | EVAL_VAR_NO_FUNC) != FAIL)
+ defcompile_class(cl);
+ }
+}
+
+/*
+ * Returns TRUE if "name" is the name of a class. The typval for the class is
+ * returned in "rettv".
+ */
+ int
+is_class_name(char_u *name, typval_T *rettv)
+{
+ rettv->v_type = VAR_UNKNOWN;
+
+ if (eval_variable(name, 0, 0, rettv, NULL, EVAL_VAR_NOAUTOLOAD |
+ EVAL_VAR_NO_FUNC) != FAIL)
+ return rettv->v_type == VAR_CLASS;
+ return FALSE;
+}
+
/*
* Return TRUE when the class "cl", its base class or one of the implemented
* interfaces matches the class "other_cl".