Skip to content

Commit

Permalink
patch 9.1.0219: Vim9: No enum support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
yegappan authored and chrisbra committed Mar 28, 2024
1 parent 8ede7a0 commit 3164cf8
Show file tree
Hide file tree
Showing 25 changed files with 2,325 additions and 141 deletions.
6 changes: 5 additions & 1 deletion 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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("")
Expand Down
6 changes: 5 additions & 1 deletion 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
Expand Down Expand Up @@ -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|
Expand Down
23 changes: 23 additions & 0 deletions runtime/doc/tags
Expand Up @@ -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*
Expand Down Expand Up @@ -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*
Expand Down Expand Up @@ -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*
Expand Down Expand Up @@ -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*
Expand Down
3 changes: 1 addition & 2 deletions 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
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions runtime/doc/version9.txt
Expand Up @@ -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*
------------------

Expand Down
126 changes: 116 additions & 10 deletions 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
Expand Down Expand Up @@ -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
Expand Down
34 changes: 32 additions & 2 deletions src/errors.h
Expand Up @@ -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[]
Expand Down
23 changes: 20 additions & 3 deletions src/eval.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
26 changes: 21 additions & 5 deletions src/evalfunc.c
Expand Up @@ -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;
}
Expand Down
4 changes: 4 additions & 0 deletions src/evalvars.c
Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion src/ex_cmds.h
Expand Up @@ -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,
Expand Down

0 comments on commit 3164cf8

Please sign in to comment.