diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2024-03-28 10:36:42 +0100 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2024-03-28 10:38:28 +0100 |
commit | 3164cf8f12f14b725b918e3170bb0a9085af8298 (patch) | |
tree | 3bd541655187532df3adead11c8f2afb3a733b8f | |
parent | 8ede7a069419e0e01368c65a2d0c79d6332aa6cd (diff) |
patch 9.1.0219: Vim9: No enum supportv9.1.0219
Problem: No enum support
Solution: Implement enums for Vim9 script
(Yegappan Lakshmanan)
closes: #14224
Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r-- | runtime/doc/builtin.txt | 6 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 6 | ||||
-rw-r--r-- | runtime/doc/tags | 23 | ||||
-rw-r--r-- | runtime/doc/todo.txt | 3 | ||||
-rw-r--r-- | runtime/doc/version9.txt | 2 | ||||
-rw-r--r-- | runtime/doc/vim9class.txt | 126 | ||||
-rw-r--r-- | src/errors.h | 34 | ||||
-rw-r--r-- | src/eval.c | 23 | ||||
-rw-r--r-- | src/evalfunc.c | 26 | ||||
-rw-r--r-- | src/evalvars.c | 4 | ||||
-rw-r--r-- | src/ex_cmds.h | 2 | ||||
-rw-r--r-- | src/proto/vim9class.pro | 1 | ||||
-rw-r--r-- | src/structs.h | 10 | ||||
-rw-r--r-- | src/testdir/Make_all.mak | 2 | ||||
-rw-r--r-- | src/testdir/test_vim9_class.vim | 43 | ||||
-rw-r--r-- | src/testdir/test_vim9_enum.vim | 1476 | ||||
-rw-r--r-- | src/testing.c | 11 | ||||
-rw-r--r-- | src/typval.c | 16 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 6 | ||||
-rw-r--r-- | src/vim9class.c | 519 | ||||
-rw-r--r-- | src/vim9compile.c | 41 | ||||
-rw-r--r-- | src/vim9execute.c | 6 | ||||
-rw-r--r-- | src/vim9expr.c | 7 | ||||
-rw-r--r-- | src/vim9type.c | 71 |
25 files changed, 2325 insertions, 141 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index ec702201d5..1f7a4f1bd7 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.1. Last change: 2024 Mar 23 +*builtin.txt* For Vim version 9.1. Last change: 2024 Mar 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -9598,6 +9598,8 @@ string({expr}) Return {expr} converted to a String. If {expr} is a Number, Dictionary {key: value, key: value} Class class SomeName Object object of SomeName {lnum: 1, col: 3} + Enum enum EnumName + EnumValue enum.value When a |List| or |Dictionary| has a recursive reference it is replaced by "[...]" or "{...}". Using eval() on the result @@ -10461,6 +10463,8 @@ type({expr}) The result is a Number representing the type of {expr}. Class: 12 |v:t_class| Object: 13 |v:t_object| Typealias: 14 |v:t_typealias| + Enum: 15 |v:t_enum| + EnumValue: 16 |v:t_enumvalue| For backward compatibility, this method can be used: > :if type(myvar) == type(0) :if type(myvar) == type("") diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index f2ff3a883f..fd37d974ee 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 9.1. Last change: 2024 Mar 20 +*eval.txt* For Vim version 9.1. Last change: 2024 Mar 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2601,6 +2601,10 @@ v:t_class Value of |class| type. Read-only. See: |type()| v:t_object Value of |object| type. Read-only. See: |type()| *v:t_typealias* *t_typealias-variable* v:t_typealias Value of |typealias| type. Read-only. See: |type()| + *v:t_enum* *t_enum-variable* +v:t_enum Value of |enum| type. Read-only. See: |type()| + *v:t_enumvalue* *t_enumvalue-variable* +v:t_enumvalue Value of |enumvalue| type. Read-only. See: |type()| *v:termresponse* *termresponse-variable* v:termresponse The escape sequence returned by the terminal for the |t_RV| diff --git a/runtime/doc/tags b/runtime/doc/tags index 4ff7095e0b..528538ebe9 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -4520,7 +4520,20 @@ E1410 vim9class.txt /*E1410* E1411 vim9class.txt /*E1411* E1412 vim9class.txt /*E1412* E1413 vim9class.txt /*E1413* +E1414 vim9class.txt /*E1414* +E1415 vim9class.txt /*E1415* +E1416 vim9class.txt /*E1416* +E1417 vim9class.txt /*E1417* +E1418 vim9class.txt /*E1418* +E1419 vim9class.txt /*E1419* E142 message.txt /*E142* +E1420 vim9class.txt /*E1420* +E1421 vim9class.txt /*E1421* +E1422 vim9class.txt /*E1422* +E1423 vim9class.txt /*E1423* +E1424 vim9class.txt /*E1424* +E1425 vim9class.txt /*E1425* +E1426 vim9class.txt /*E1426* E143 autocmd.txt /*E143* E144 various.txt /*E144* E145 starting.txt /*E145* @@ -6874,6 +6887,12 @@ encryption editing.txt /*encryption* end intro.txt /*end* end-of-file pattern.txt /*end-of-file* enlightened-terminal syntax.txt /*enlightened-terminal* +enum vim9class.txt /*enum* +enum-constructor vim9class.txt /*enum-constructor* +enum-name vim9class.txt /*enum-name* +enum-ordinal vim9class.txt /*enum-ordinal* +enum-values vim9class.txt /*enum-values* +enumvalue vim9class.txt /*enumvalue* environ() builtin.txt /*environ()* eol-and-eof editing.txt /*eol-and-eof* erlang.vim syntax.txt /*erlang.vim* @@ -10290,6 +10309,8 @@ t_dl term.txt /*t_dl* t_ds term.txt /*t_ds* t_ed version4.txt /*t_ed* t_el version4.txt /*t_el* +t_enum-variable eval.txt /*t_enum-variable* +t_enumvalue-variable eval.txt /*t_enumvalue-variable* t_f1 version4.txt /*t_f1* t_f10 version4.txt /*t_f10* t_f2 version4.txt /*t_f2* @@ -10863,6 +10884,8 @@ v:t_bool eval.txt /*v:t_bool* v:t_channel eval.txt /*v:t_channel* v:t_class eval.txt /*v:t_class* v:t_dict eval.txt /*v:t_dict* +v:t_enum eval.txt /*v:t_enum* +v:t_enumvalue eval.txt /*v:t_enumvalue* v:t_float eval.txt /*v:t_float* v:t_func eval.txt /*v:t_func* v:t_job eval.txt /*v:t_job* diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 2b4a70a3a6..8712008cfe 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 9.1. Last change: 2024 Mar 03 +*todo.txt* For Vim version 9.1. Last change: 2024 Mar 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -144,7 +144,6 @@ Further Vim9 improvements: - More efficient way for interface member index than iterating over list? - a variant of type() that returns a different type for each class? list<number> and list<string> should also differ. -- implement :enum - Promise class, could be used to wait on a popup close callback? - class local to a function - Use Vim9 for more runtime files. diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 8ea30a4c8a..587cdd5322 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -41548,6 +41548,8 @@ Vim9 script Add support for internal builtin functions with vim9 objects, see |builtin-object-methods| +Enum support for Vim9 script |:enum| + Other improvements *new-other-9.2* ------------------ diff --git a/runtime/doc/vim9class.txt b/runtime/doc/vim9class.txt index a00a5b787d..8820d77b54 100644 --- a/runtime/doc/vim9class.txt +++ b/runtime/doc/vim9class.txt @@ -1,4 +1,4 @@ -*vim9class.txt* For Vim version 9.1. Last change: 2024 Mar 03 +*vim9class.txt* For Vim version 9.1. Last change: 2024 Mar 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -904,19 +904,125 @@ aliased: > 8. Enum *Vim9-enum* *:enum* *:endenum* -{not implemented yet} - + *enum* *E1418* *E1419* *E1420* An enum is a type that can have one of a list of values. Example: > - :enum Color - White - Red - Green - Blue - Black - :endenum + :enum Color + White, + Red, + Green, Blue, Black + :endenum +< + *enumvalue* *E1422* +The enum values are separated by commas. More than one enum value can be +listed in a single line. The final enum value should not be followed by a +comma. + +An enum value is accessed using the enum name followed by the value name: > + + var a: Color = Color.Blue +< +Enums are treated as classes, where each enum value is essentially an instance +of that class. Unlike typical object instantiation with the |new()| method, +enum instances cannot be created this way. + +An enum can only be defined in a |Vim9| script file. *E1414* +An enum cannot be defined inside a function. + + *E1415* +An enum name must start with an uppercase letter. The name of an enum value +in an enum can start with an upper or lowercase letter. + + *E1416* +An enum can implement an interface but cannot extend a class: > + + enum MyEnum implements MyIntf + Value1, + Value2 + + def SomeMethod() + enddef + endenum +< + *enum-constructor* +The enum value objects in an enum are constructed like any other objects using +the |new()| method. Arguments can be passed to the enum constructor by +specifying them after the enum value name, just like calling a function. The +default constructor doesn't have any arguments. + + *E1417* +An enum can contain class variables, class methods, object variables and +object methods. The methods in an enum cannot be |:abstract| methods. + +The following example shows an enum with object variables and methods: > + + vim9script + enum Planet + Earth(1, false), + Jupiter(95, true), + Saturn(146, true) + + var moons: number + var has_rings: bool + def GetMoons(): number + return this.moons + enddef + endenum + echo Planet.Jupiter.GetMoons() + echo Planet.Earth.has_rings +< + *E1421* *E1423* *E1424* *E1425* +Enums and their values are immutable. They cannot be modified after +declaration and cannot be utilized as numerical or string types. + + *enum-name* +Each enum value object has a "name" instance variable which contains the name +of the enum value. This is a readonly variable. + + *enum-ordinal* *E1426* +Each enum value has an associated ordinal number starting with 0. The ordinal +number of an enum value can be accessed using the "ordinal" instance variable. +This is a readonly variable. Note that if the ordering of the enum values in +an enum is changed, then their ordinal values will also change. + + *enum-values* +All the values in an enum can be accessed using the "values" class variable +which is a List of the enum objects. This is a readonly variable. + +Example: > + enum Planet + Mercury, + Venus, + Earth + endenum + + echo Planet.Mercury + echo Planet.Venus.name + echo Planet.Venus.ordinal + for p in Planet.values + # ... + endfor +< +An enum is a class with class variables for the enum value objects and object +variables for the enum value name and the enum value ordinal: > + + enum Planet + Mercury, + Venus + endenum +< +The above enum definition is equivalent to the following class definition: > + + class Planet + public static final Mercury: Planet = Planet.new('Mercury', 0) + public static final Venus: Planet = Planet.new('Venus', 1) + public static const values: list<Planet> = [Planet.Mercury, Planet.Venus] + public const name: string + public const ordinal: number + endclass +< ============================================================================== 9. Rationale diff --git a/src/errors.h b/src/errors.h index 5dccc63b7a..18d3f0cb61 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3585,8 +3585,38 @@ EXTERN char e_builtin_object_method_str_not_supported[] INIT(= N_("E1412: Builtin object method \"%s\" not supported")); EXTERN char e_builtin_class_method_not_supported[] INIT(= N_("E1413: Builtin class method not supported")); -#endif -// E1415 - E1499 unused (reserved for Vim9 class support) +EXTERN char e_enum_can_only_be_defined_in_vim9_script[] + INIT(= N_("E1414: Enum can only be defined in Vim9 script")); +EXTERN char e_enum_name_must_start_with_uppercase_letter_str[] + INIT(= N_("E1415: Enum name must start with an uppercase letter: %s")); +EXTERN char e_enum_cannot_extend_class[] + INIT(= N_("E1416: Enum cannot extend a class or enum")); +EXTERN char e_abstract_cannot_be_used_in_enum[] + INIT(= N_("E1417: Abstract cannot be used in an Enum")); +EXTERN char e_invalid_enum_value_declaration_str[] + INIT(= N_("E1418: Invalid enum value declaration: %s")); +EXTERN char e_not_valid_command_in_enum_str[] + INIT(= N_("E1419: Not a valid command in an Enum: %s")); +EXTERN char e_missing_endenum[] + INIT(= N_("E1420: Missing :endenum")); +EXTERN char e_using_enum_as_value_str[] + INIT(= N_("E1421: Enum \"%s\" cannot be used as a value")); +EXTERN char e_enum_value_str_not_found_in_enum_str[] + INIT(= N_("E1422: Enum value \"%s\" not found in enum \"%s\"")); +EXTERN char e_enumvalue_str_cannot_be_modified[] + INIT(= N_("E1423: Enum value \"%s.%s\" cannot be modified")); +EXTERN char e_using_enum_str_as_number[] + INIT(= N_("E1424: Using an Enum \"%s\" as a Number")); +EXTERN char e_using_enum_str_as_string[] + INIT(= N_("E1425: Using an Enum \"%s\" as a String")); +EXTERN char e_enum_str_ordinal_cannot_be_modified[] + INIT(= N_("E1426: Enum \"%s\" ordinal value cannot be modified")); +EXTERN char e_enum_str_name_cannot_be_modified[] + INIT(= N_("E1427: Enum \"%s\" name cannot be modified")); +EXTERN char e_duplicate_enum_str[] + INIT(= N_("E1428: Duplicate enum value: %s")); +#endif +// E1429 - E1499 unused (reserved for Vim9 class support) EXTERN char e_cannot_mix_positional_and_non_positional_str[] INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s")); EXTERN char e_fmt_arg_nr_unused_str[] diff --git a/src/eval.c b/src/eval.c index 69b837402c..2647e7a591 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1119,7 +1119,18 @@ get_lval_check_access( if (*p == '[' || *p == '.') break; if ((flags & GLV_READ_ONLY) == 0) - msg = e_variable_is_not_writable_str; + { + if (IS_ENUM(cl)) + { + if (om->ocm_type->tt_type == VAR_OBJECT) + semsg(_(e_enumvalue_str_cannot_be_modified), + cl->class_name, om->ocm_name); + else + msg = e_variable_is_not_writable_str; + } + else + msg = e_variable_is_not_writable_str; + } break; case VIM_ACCESS_ALL: break; @@ -6310,9 +6321,15 @@ echo_string_core( case VAR_CLASS: { class_T *cl = tv->vval.v_class; - size_t len = 6 + (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1; + char *s = "class"; + if (IS_INTERFACE(cl)) + s = "interface"; + else if (IS_ENUM(cl)) + s = "enum"; + size_t len = STRLEN(s) + 1 + + (cl == NULL ? 9 : STRLEN(cl->class_name)) + 1; r = *tofree = alloc(len); - vim_snprintf((char *)r, len, "class %s", + vim_snprintf((char *)r, len, "%s %s", s, cl == NULL ? "[unknown]" : (char *)cl->class_name); } break; diff --git a/src/evalfunc.c b/src/evalfunc.c index 14650caf6b..8c27986b42 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -11486,15 +11486,31 @@ f_type(typval_T *argvars, typval_T *rettv) case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break; case VAR_BLOB: n = VAR_TYPE_BLOB; break; case VAR_INSTR: n = VAR_TYPE_INSTR; break; - case VAR_CLASS: n = VAR_TYPE_CLASS; break; - case VAR_OBJECT: n = VAR_TYPE_OBJECT; break; case VAR_TYPEALIAS: n = VAR_TYPE_TYPEALIAS; break; + case VAR_CLASS: + { + class_T *cl = argvars[0].vval.v_class; + if (IS_ENUM(cl)) + n = VAR_TYPE_ENUM; + else + n = VAR_TYPE_CLASS; + break; + } + case VAR_OBJECT: + { + class_T *cl = argvars[0].vval.v_object->obj_class; + if (IS_ENUM(cl)) + n = VAR_TYPE_ENUMVALUE; + else + n = VAR_TYPE_OBJECT; + break; + } case VAR_UNKNOWN: case VAR_ANY: case VAR_VOID: - internal_error_no_abort("f_type(UNKNOWN)"); - n = -1; - break; + internal_error_no_abort("f_type(UNKNOWN)"); + n = -1; + break; } rettv->vval.v_number = n; } diff --git a/src/evalvars.c b/src/evalvars.c index de9d5b26b3..f16d4757f2 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -159,6 +159,8 @@ static struct vimvar {VV_NAME("maxcol", VAR_NUMBER), NULL, VV_RO}, {VV_NAME("python3_version", VAR_NUMBER), NULL, VV_RO}, {VV_NAME("t_typealias", VAR_NUMBER), NULL, VV_RO}, + {VV_NAME("t_enum", VAR_NUMBER), NULL, VV_RO}, + {VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO}, }; // shorthand @@ -262,6 +264,8 @@ evalvars_init(void) set_vim_var_nr(VV_TYPE_CLASS, VAR_TYPE_CLASS); set_vim_var_nr(VV_TYPE_OBJECT, VAR_TYPE_OBJECT); set_vim_var_nr(VV_TYPE_TYPEALIAS, VAR_TYPE_TYPEALIAS); + set_vim_var_nr(VV_TYPE_ENUM, VAR_TYPE_ENUM); + set_vim_var_nr(VV_TYPE_ENUMVALUE, VAR_TYPE_ENUMVALUE); set_vim_var_nr(VV_ECHOSPACE, sc_col - 1); diff --git a/src/ex_cmds.h b/src/ex_cmds.h index bd26e81dcc..cb758aa7c3 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -595,7 +595,7 @@ EXCMD(CMD_endwhile, "endwhile", ex_endwhile, EXCMD(CMD_enew, "enew", ex_edit, EX_BANG|EX_TRLBAR, ADDR_NONE), -EXCMD(CMD_enum, "enum", ex_enum, +EXCMD(CMD_enum, "enum", ex_class, EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT, ADDR_NONE), EXCMD(CMD_eval, "eval", ex_eval, diff --git a/src/proto/vim9class.pro b/src/proto/vim9class.pro index 1ed175e69f..d3d3b99be3 100644 --- a/src/proto/vim9class.pro +++ b/src/proto/vim9class.pro @@ -3,6 +3,7 @@ int object_index_from_itf_index(class_T *itf, int is_method, int idx, class_T *c int is_valid_builtin_obj_methodname(char_u *funcname); ufunc_T *class_get_builtin_method(class_T *cl, class_builtin_T builtin_method, int *method_idx); void ex_class(exarg_T *eap); +void enum_set_internal_obj_vars(class_T *en, object_T *enval); type_T *oc_member_type(class_T *cl, int is_object, char_u *name, char_u *name_end, int *member_idx); type_T *oc_member_type_by_idx(class_T *cl, int is_object, int member_idx); void ex_enum(exarg_T *eap); diff --git a/src/structs.h b/src/structs.h index 47a0050ddb..0d3f60acb4 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1562,9 +1562,10 @@ struct itf2class_S { // array with ints follows }; -#define CLASS_INTERFACE 1 -#define CLASS_EXTENDED 2 // another class extends this one -#define CLASS_ABSTRACT 4 // abstract class +#define CLASS_INTERFACE 0x1 +#define CLASS_EXTENDED 0x2 // another class extends this one +#define CLASS_ABSTRACT 0x4 // abstract class +#define CLASS_ENUM 0x8 // enum // "class_T": used for v_class of typval of VAR_CLASS // Also used for an interface (class_flags has CLASS_INTERFACE). @@ -1613,6 +1614,9 @@ struct class_S type_T class_object_type; // same as class_type but VAR_OBJECT }; +#define IS_INTERFACE(cl) ((cl)->class_flags & CLASS_INTERFACE) +#define IS_ENUM(cl) ((cl)->class_flags & CLASS_ENUM) + // Used for v_object of typval of VAR_OBJECT. // The member variables follow in an array of typval_T. struct object_S diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index c4403e67ae..ab4d42a67c 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -40,6 +40,7 @@ TEST_VIM9 = \ test_vim9_class \ test_vim9_cmd \ test_vim9_disassemble \ + test_vim9_enum \ test_vim9_expr \ test_vim9_fails \ test_vim9_func \ @@ -53,6 +54,7 @@ TEST_VIM9_RES = \ test_vim9_class.res \ test_vim9_cmd.res \ test_vim9_disassemble.res \ + test_vim9_enum.res \ test_vim9_expr.res \ test_vim9_fails.res \ test_vim9_func.res \ diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim index d6c55bfffa..f0c6f0cd00 100644 --- a/src/testdir/test_vim9_class.vim +++ b/src/testdir/test_vim9_class.vim @@ -2275,6 +2275,18 @@ def Test_interface_basics() v9.CheckScriptSuccess(lines) enddef +" Test for using string() with an interface +def Test_interface_to_string() + var lines =<< trim END + vim9script + interface Intf + def Method(nr: number) + endinterface + assert_equal("interface Intf", string(Intf)) + END + v9.CheckSourceSuccess(lines) +enddef + def Test_class_implements_interface() var lines =<< trim END vim9script @@ -10391,6 +10403,23 @@ def Test_compound_op_in_objmethod_lambda() v9.CheckScriptSuccess(lines) enddef +" Test for using test_refcount() with a class and an object +def Test_class_object_refcount() + var lines =<< trim END + vim9script + class A + endclass + var a: A = A.new() + assert_equal(2, test_refcount(A)) + assert_equal(1, test_refcount(a)) + var b = a + assert_equal(2, test_refcount(A)) + assert_equal(2, test_refcount(a)) + assert_equal(2, test_refcount(b)) + END + v9.CheckScriptSuccess(lines) +enddef + " call a lambda function in one object from another object def Test_lambda_invocation_across_classes() var lines =<< trim END @@ -10420,4 +10449,18 @@ def Test_lambda_invocation_across_classes() v9.CheckScriptSuccess(lines) enddef +" Test for using a class member which is an object of the current class +def Test_current_class_object_class_member() + var lines =<< trim END + vim9script + class A + public static var obj1: A = A.new(10) + var n: number + endclass + defcompile + assert_equal(10, A.obj1.n) + END + v9.CheckScriptSuccess(lines) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_enum.vim b/src/testdir/test_vim9_enum.vim new file mode 100644 index 0000000000..6e10e0c705 --- /dev/null +++ b/src/testdir/test_vim9_enum.vim @@ -0,0 +1,1476 @@ +" Test Vim9 enums + +source check.vim +import './vim9.vim' as v9 + +" Test for parsing an enum definition +def Test_enum_parse() + # enum supported only in a Vim9 script + var lines =<< trim END + enum Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1414: Enum can only be defined in Vim9 script', 1) + + # First character in an enum name should be capitalized. + lines =<< trim END + vim9script + enum foo + endenum + END + v9.CheckSourceFailure(lines, 'E1415: Enum name must start with an uppercase letter: foo', 2) + + # Only alphanumeric characters are supported in an enum name + lines =<< trim END + vim9script + enum Foo@bar + endenum + END + v9.CheckSourceFailure(lines, 'E1315: White space required after name: Foo@bar', 2) + + # Unsupported keyword (instead of enum) + lines =<< trim END + vim9script + noenum Something + endenum + END + v9.CheckSourceFailure(lines, 'E492: Not an editor command: noenum Something', 2) + + # Only the complete word "enum" should be recognized + lines =<< trim END + vim9script + enums Something + endenum + END + v9.CheckSourceFailure(lines, 'E492: Not an editor command: enums Something', 2) + + # The complete "endenum" should be specified. + lines =<< trim END + vim9script + enum Something + enden + END + v9.CheckSourceFailure(lines, 'E1065: Command cannot be shortened: enden', 3) + + # Only the complete word "endenum" should be recognized + lines =<< trim END + vim9script + enum Something + endenums + END + v9.CheckSourceFailure(lines, 'E1420: Missing :endenum', 4) + + # all lower case should be used for "enum" + lines =<< trim END + vim9script + Enum Something + endenum + END + v9.CheckSourceFailure(lines, 'E492: Not an editor command: Enum Something', 2) + + # all lower case should be used for "endenum" + lines =<< trim END + vim9script + enum Something + Endenum + END + v9.CheckSourceFailure(lines, 'E1420: Missing :endenum', 4) + + # Additional words after "endenum" + lines =<< trim END + vim9script + enum Something + endenum school's out + END + v9.CheckSourceFailure(lines, "E488: Trailing characters: school's out", 3) + + # Additional commands after "endenum" + lines =<< trim END + vim9script + enum Something + endenum | echo 'done' + END + v9.CheckSourceFailure(lines, "E488: Trailing characters: | echo 'done'", 3) + + # Try to define enum in a single command + lines =<< trim END + vim9script + enum Something | endenum + END + v9.CheckSourceFailure(lines, 'E1420: Missing :endenum', 3) + + # Try to define an enum with the same name as an existing variable + lines =<< trim END + vim9script + var Something: list<number> = [1] + enum Something + endenum + END + v9.CheckSourceFailure(lines, 'E1041: Redefining script item: "Something"', 3) + + # Unsupported special character following enum name + lines =<< trim END + vim9script + enum Foo + first, + second : 20 + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: : 20', 4) + + # Try initializing an enum item with a number + lines =<< trim END + vim9script + enum Foo + first, + second = 2 + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: = 2', 4) + + # Try initializing an enum item with a String + lines =<< trim END + vim9script + enum Foo + first, + second = 'second' + endenum + defcompile + END + v9.CheckSourceFailure(lines, "E1123: Missing comma before argument: = 'second'", 4) + + # Try initializing an enum item with a List + lines =<< trim END + vim9script + enum Foo + first, + second = [] + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: = []', 4) + + # Use a colon after name + lines =<< trim END + vim9script + enum Foo + + # first + first: + second + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: :', 5) + + # Use a '==' + lines =<< trim END + vim9script + enum Foo + first == 1 + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: == 1', 3) + + # Missing comma after an enum item + lines =<< trim END + vim9script + enum Planet + mercury + venus + endenum + END + v9.CheckSourceFailure(lines, 'E1419: Not a valid command in an Enum: venus', 4) + + # Comma at the beginning of an item + lines =<< trim END + vim9script + enum Planet + mercury + ,venus + endenum + END + v9.CheckSourceFailure(lines, 'E1419: Not a valid command in an Enum: ,venus', 4) + # Space before comma + lines =<< trim END + vim9script + enum Planet + mercury , + venus + endenum + END + v9.CheckSourceFailure(lines, "E1068: No white space allowed before ','", 3) + + # No space after comma + lines =<< trim END + vim9script + enum Planet + mercury,venus + endenum + END + v9.CheckSourceFailure(lines, "E1069: White space required after ',': mercury,venus", 3) + + # no comma between items in the same line + lines =<< trim END + vim9script + enum Planet + mercury venus earth + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: venus earth', 3) + + # No space after an item and comment between items + lines =<< trim END + vim9script + enum Planet + mercury + + # Venus + venus + endenum + END + v9.CheckSourceFailure(lines, 'E1419: Not a valid command in an Enum: venus', 6) + + # Comma is supported for the last item + lines =<< trim END + vim9script + enum Planet + mercury, + venus, + endenum + var p: Planet + p = Planet.mercury + p = Planet.venus + END + v9.CheckSourceSuccess(lines) + + # invalid enum value declaration + lines =<< trim END + vim9script + enum Fruit + Apple, + $%@ + endenum + defcompile + END + v9.CheckSourceFailure(lines, 'E1418: Invalid enum value declaration: $%@', 4) + + # Duplicate enum value + lines =<< trim END + vim9script + enum A + Foo, + Bar, + Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1428: Duplicate enum value: Foo', 5) + + # Duplicate enum value in the same line + lines =<< trim END + vim9script + enum A + Foo, Bar, Foo, + Bar + endenum + END + v9.CheckSourceFailure(lines, 'E1428: Duplicate enum value: Foo', 3) + + # Try extending a class when defining an enum + lines =<< trim END + vim9script + class Foo + endclass + enum Bar extends Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1416: Enum cannot extend a class or enum', 4) + + # Try extending an enum + lines =<< trim END + vim9script + enum Foo + endenum + enum Bar extends Foo + endenum + END + v9.CheckSourceFailure(lines, 'E1416: Enum cannot extend a class or enum', 4) + + # Try extending an enum using a class + lines =<< trim END + vim9script + enum Foo + endenum + class Bar extends Foo + endclass + END + v9.CheckSourceFailure(lines, 'E1354: Cannot extend Foo', 5) + + # Try implementing an enum using a class + lines =<< trim END + vim9script + enum Foo + endenum + class Bar implements Foo + endclass + END + v9.CheckSourceFailure(lines, 'E1347: Not a valid interface: Foo', 5) + + # abstract method is not supported in an enum + lines =<< trim END + vim9script + enum Foo + Apple + abstract def Bar() + endenum + END + v9.CheckSourceFailure(lines, 'E1417: Abstract cannot be used in an Enum', 4) + + # Define an enum without any enum values but only with an object variable + lines =<< trim END + vim9script + enum Foo + final n: number = 10 + endenum + END + v9.CheckSourceFailure(lines, 'E1123: Missing comma before argument: n: number = 10', 3) +enddef + +def Test_basic_enum() + # Declare a simple enum + var lines =<< trim END + vim9script + enum Foo + |