summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/errors.h34
-rw-r--r--src/eval.c23
-rw-r--r--src/evalfunc.c26
-rw-r--r--src/evalvars.c4
-rw-r--r--src/ex_cmds.h2
-rw-r--r--src/proto/vim9class.pro1
-rw-r--r--src/structs.h10
-rw-r--r--src/testdir/Make_all.mak2
-rw-r--r--src/testdir/test_vim9_class.vim43
-rw-r--r--src/testdir/test_vim9_enum.vim1476
-rw-r--r--src/testing.c11
-rw-r--r--src/typval.c16
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h6
-rw-r--r--src/vim9class.c519
-rw-r--r--src/vim9compile.c41
-rw-r--r--src/vim9execute.c6
-rw-r--r--src/vim9expr.c7
-rw-r--r--src/vim9type.c71
19 files changed, 2173 insertions, 127 deletions
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
+ apple,
+ orange
+ endenum
+ var a: Foo = Foo.apple
+ var b: Foo = Foo.orange
+ assert_equal(a, Foo.apple)
+ assert_equal(b, Foo.orange)
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # Multiple enums in a single line
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple, orange
+ endenum
+ assert_equal('enum<Foo>', typename(Foo.apple))
+ assert_equal('enum<Foo>', typename(Foo.orange))
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # Comments and empty lines are supported between enum items
+ lines =<< trim END
+ vim9script
+ enum Foo
+ # Apple
+ apple,
+
+ # Orange
+ orange
+ endenum
+ def Fn()
+ var a: Foo = Foo.apple
+ var b: Foo = Foo.orange
+ assert_equal(a, Foo.apple)
+ assert_equal(b, Foo.orange)
+ enddef
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # Try using a non-existing enum value
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple,
+ orange
+ endenum
+ var a: Foo = Foo.pear
+ END
+ v9.CheckSourceFailure(lines, 'E1422: Enum value "pear" not found in enum "Foo"', 6)
+
+ # Enum function argument
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple,
+ orange
+ endenum
+ def Fn(a: Foo): Foo
+ return a
+ enddef
+ assert_equal(Foo.apple, Fn(Foo.apple))
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # Enum function argument
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple,
+ orange
+ endenum
+ def Fn(a: Foo): Foo
+ return a
+ enddef
+ Fn({})
+ END
+ v9.CheckSourceFailure(lines, 'E1013: Argument 1: type mismatch, expected enum<Foo> but got dict<any>', 9)
+
+ # Returning an enum in a function returning number
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple,
+ orange
+ endenum
+ def Fn(): number
+ return Foo.orange
+ enddef
+ Fn()
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected number but got enum<Foo>', 1)
+
+ # Returning a number in a function returning enum
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple,
+ orange
+ endenum
+ def Fn(): Foo
+ return 20
+ enddef
+ Fn()
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum<Foo> but got number', 1)
+
+ # Use a List of enums
+ lines =<< trim END
+ vim9script
+ enum Planet
+ Mercury,
+ Venus,
+ Earth
+ endenum
+ var l1: list<Planet> = [Planet.Mercury, Planet.Venus]
+ assert_equal(Planet.Venus, l1[1])
+ def Fn()
+ var l2: list<Planet> = [Planet.Mercury, Planet.Venus]
+ assert_equal(Planet.Venus, l2[1])
+ enddef
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # Try using an enum as a value
+ lines =<< trim END
+ vim9script
+ enum Fruit
+ Apple,
+ Orange
+ endenum
+ var a = Fruit
+ END
+ v9.CheckSourceFailure(lines, 'E1421: Enum "Fruit" cannot be used as a value', 6)
+enddef
+
+" Test for type() and typename() of an enum
+def Test_enum_type()
+ var lines =<< trim END
+ vim9script
+ enum Fruit
+ Apple,
+ Orange
+ endenum
+ assert_equal('enum<Fruit>', typename(Fruit))
+ assert_equal('enum<Fruit>', typename(Fruit.Apple))
+ assert_equal(v:t_enum, type(Fruit))
+ assert_equal(v:t_enumvalue, type(Fruit.Apple))
+ assert_equal(15, type(Fruit))
+ assert_equal(16, type(Fruit.Apple))
+ END
+ v9.CheckSourceSuccess(lines)
+
+ # Assign an enum to a variable with any type
+ lines =<< trim END
+ vim9script
+ enum Fruit
+ Apple,
+ Orange
+ endenum
+ var a = Fruit.Apple
+ var b: any = Fruit.Orange
+ assert_equal('enum<Fruit>', typename(a))
+ assert_equal('enum<Fruit>', typename(b))
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
+" Try modifying an enum or an enum item
+def Test_enum_modify()
+ # Try assigning an unsupported value to an enum
+ var lines =<< trim END
+ vim9script
+ enum Foo
+ apple
+ endenum
+ var a: Foo = 30
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum<Foo> but got number', 5)
+
+ # Try assigning an unsupported value to an enum in a function
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple
+ endenum
+ def Fn()
+ var a: Foo = 30
+ enddef
+ defcompile
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum<Foo> but got number', 1)
+
+ # Try assigning a number to an enum
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple,
+ orange
+ endenum
+ Foo = 10
+ END
+ v9.CheckSourceFailure(lines, 'E1421: Enum "Foo" cannot be used as a value', 6)
+
+ # Try assigning a number to an enum in a function
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple
+ endenum
+ def Fn()
+ Foo = 10
+ enddef
+ defcompile
+ END
+ v9.CheckSourceFailure(lines, 'E1012: Type mismatch; expected enum<Foo> but got number', 1)
+
+ # Try assigning a number to an enum value
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple
+ endenum
+ Foo.apple = 20
+ END
+ v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.apple" cannot be modified', 5)
+
+ # Try assigning a number to an enum value in a function
+ lines =<< trim END
+ vim9script
+ enum Foo
+ apple
+ endenum
+ def Fn()
+ Foo.apple = 20
+ enddef
+ defcompile
+ END
+ v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.apple" cannot be modified', 1)
+
+ # Try assigning one enum to another
+ lines =<< trim END
+ vim9script
+ enum Foo
+ endenum
+ enum Bar
+ endenum
+ Foo = Bar
+ END
+ v9.CheckSourceFailure(lines, 'E1421: Enum "Bar" cannot be used as a value', 6)
+
+ # Try assigning one enum to another in a function
+ lines =<< trim END
+ vim9script
+ enum Foo
+ endenum
+ enum Bar
+ endenum
+ def Fn()
+ Foo = Bar
+ enddef
+ defcompile
+ END
+ v9.CheckSourceFailure(lines, 'E1421: Enum "Bar" cannot be used as a value', 1)
+
+ # Try assigning one enum item to another enum item
+ lines =<< trim END
+ vim9script
+ enum Foo
+ Apple
+ endenum
+ enum Bar
+ Orange
+ endenum
+ Foo.Apple = Bar.Orange
+ END
+ v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.Apple" cannot be modified', 8)
+
+ # Try assigning one enum item to another enum item in a function
+ lines =<< trim END
+ vim9script
+ enum Foo
+ Apple
+ endenum
+ enum Bar
+ Orange
+ endenum
+ def Fn()
+ Foo.Apple = Bar.Orange
+ enddef
+ defcompile
+ END
+ v9.CheckSourceFailure(lines, 'E1423: Enum value "Foo.Apple" cannot be modified', 1)
+enddef
+
+" Test for using enum in an expression
+def Test_enum_expr()
+ var lines =<< trim END
+ vim9script
+ enum Color
+ Red, Blue, Green
+ endenum
+ var a: number = 1 + Color
+ END
+ v9.CheckSourceFailure(lines, 'E1421: Enum "Color" cannot be used as a value', 5)
+
+ lines =<< trim END
+ vim9script
+ enum Color
+ Red, Blue, Green
+ endenum
+ var a: number = 1 + Color.Red
+ END
+ v9.CheckSourceFailure(lines, 'E1424: Using an Enum "Color" as a Number', 5)
+
+ lines =<< trim END
+ vim9script
+ enum Color
+ Red, Blue, Green
+ endenum
+ var s: string = "abc" .. Color
+ END
+ v9.CheckSourceFailure(lines, 'E1421: Enum "Color" cannot be used as a value', 5)
+
+ lines =<< trim END
+ vim9script
+ enum Color
+ Red, Blue, Green
+ endenum
+ var s: string = "abc" .. Color.Red
+ END
+ v9.CheckSourceFailure(lines, 'E1425: Using an Enum "Color" as a String', 5)
+enddef
+
+" Using an enum in a lambda function
+def Test_enum_lambda()
+ var lines =<< trim END
+ vim9script
+ enum Planet
+ Mercury,
+ Venus,
+ Earth,
+ endenum
+ var Fn = (p: Planet): Planet => p
+ for [idx, v] in items([Planet.Mercury, Planet.Venus, Planet.Earth])
+ assert_equal(idx, Fn(v).ordinal)
+ endfor
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
+" Comparison using enums
+def Test_enum_compare()
+ var lines =<< trim END
+ vim9script
+ enum Planet
+ Mercury,
+ Venus,
+ Earth,
+ endenum
+ enum Fruit
+ Apple,
+ Orange
+ endenum
+
+ var p: Planet = Planet.Venus
+ var f: Fruit = Fruit.Orange
+ assert_equal(true, p == Planet.Venus)
+ assert_equal(false, p == Planet.Earth)
+ assert_equal(false, p == f)
+ assert_equal(true, Planet.Mercury == Planet.Mercury)
+ assert_equal(true, Planet.Venus != Planet.Earth)
+ assert_equal(true, Planet.Mercury != Fruit.Apple)
+
+ def Fn1()
+ var p2: Planet = Planet.Venus
+ var f2: Fruit = Fruit.Orange
+ assert_equal(true, p2 == Planet.Venus)
+ assert_equal(false, p2 == Planet.Earth)
+ assert_equal(false, p2 == f2)
+ enddef
+ Fn1()
+
+ # comparison using "is" and "isnot"
+ assert_equal(true, p is Planet.Venus)
+ assert_equal(true, p isnot Planet.Earth)
+ assert_equal(false, p is Fruit.Orange)
+ assert_equal(true, p isnot Fruit.Orange)
+ def Fn2(arg: Planet)
+ assert_equal(true, arg is Planet.Venus)
+ assert_equal(true, arg isnot Planet.Earth)
+ assert_equal(false, arg is Fruit.Orange)
+ assert_equal(true, arg isnot Fruit.Orange)
+ enddef
+ Fn2(p)
+
+ class A
+ endclass
+ var o: A = A.new()
+ assert_equal(false, p == o)
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
+" Test for using an enum as a default argument to a function
+def Test_enum_default_arg()
+ var lines =<< trim END
+ vim9script
+ enum Day
+ Monday, Tuesday, Wednesday
+ endenum
+ def Fn(d: Day = Day.Tuesday): Day
+ return d
+ enddef
+ assert_equal(Day.Tuesday, Fn())
+ assert_equal(Day.Wednesday, Fn(Day.Wednesday))
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
+" Test for enum garbage collection
+func Test_enum_garbagecollect()
+ let lines =<< trim END
+ vim9script
+ enum Car
+ Honda, Ford, Tesla
+ endenum
+ assert_equal(1, Car.Ford.ordinal)
+ call test_garbagecollect_now()
+ assert_equal(1, Car.Ford.ordinal)
+ var c: Car = Car.Tesla
+ assert_equal(2, c.ordinal)
+ call test_garbagecollect_now()
+ assert_equa