patch 9.1.0219: Vim9: No enum support
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>
This commit is contained in:
committed by
Christian Brabandt
parent
8ede7a0694
commit
3164cf8f12
@ -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
|
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}
|
Dictionary {key: value, key: value}
|
||||||
Class class SomeName
|
Class class SomeName
|
||||||
Object object of SomeName {lnum: 1, col: 3}
|
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
|
When a |List| or |Dictionary| has a recursive reference it is
|
||||||
replaced by "[...]" or "{...}". Using eval() on the result
|
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|
|
Class: 12 |v:t_class|
|
||||||
Object: 13 |v:t_object|
|
Object: 13 |v:t_object|
|
||||||
Typealias: 14 |v:t_typealias|
|
Typealias: 14 |v:t_typealias|
|
||||||
|
Enum: 15 |v:t_enum|
|
||||||
|
EnumValue: 16 |v:t_enumvalue|
|
||||||
For backward compatibility, this method can be used: >
|
For backward compatibility, this method can be used: >
|
||||||
:if type(myvar) == type(0)
|
:if type(myvar) == type(0)
|
||||||
:if type(myvar) == type("")
|
:if type(myvar) == type("")
|
||||||
|
|||||||
@ -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
|
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_object Value of |object| type. Read-only. See: |type()|
|
||||||
*v:t_typealias* *t_typealias-variable*
|
*v:t_typealias* *t_typealias-variable*
|
||||||
v:t_typealias Value of |typealias| type. Read-only. See: |type()|
|
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* *termresponse-variable*
|
||||||
v:termresponse The escape sequence returned by the terminal for the |t_RV|
|
v:termresponse The escape sequence returned by the terminal for the |t_RV|
|
||||||
|
|||||||
@ -4520,7 +4520,20 @@ E1410 vim9class.txt /*E1410*
|
|||||||
E1411 vim9class.txt /*E1411*
|
E1411 vim9class.txt /*E1411*
|
||||||
E1412 vim9class.txt /*E1412*
|
E1412 vim9class.txt /*E1412*
|
||||||
E1413 vim9class.txt /*E1413*
|
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*
|
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*
|
E143 autocmd.txt /*E143*
|
||||||
E144 various.txt /*E144*
|
E144 various.txt /*E144*
|
||||||
E145 starting.txt /*E145*
|
E145 starting.txt /*E145*
|
||||||
@ -6874,6 +6887,12 @@ encryption editing.txt /*encryption*
|
|||||||
end intro.txt /*end*
|
end intro.txt /*end*
|
||||||
end-of-file pattern.txt /*end-of-file*
|
end-of-file pattern.txt /*end-of-file*
|
||||||
enlightened-terminal syntax.txt /*enlightened-terminal*
|
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()*
|
environ() builtin.txt /*environ()*
|
||||||
eol-and-eof editing.txt /*eol-and-eof*
|
eol-and-eof editing.txt /*eol-and-eof*
|
||||||
erlang.vim syntax.txt /*erlang.vim*
|
erlang.vim syntax.txt /*erlang.vim*
|
||||||
@ -10290,6 +10309,8 @@ t_dl term.txt /*t_dl*
|
|||||||
t_ds term.txt /*t_ds*
|
t_ds term.txt /*t_ds*
|
||||||
t_ed version4.txt /*t_ed*
|
t_ed version4.txt /*t_ed*
|
||||||
t_el version4.txt /*t_el*
|
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_f1 version4.txt /*t_f1*
|
||||||
t_f10 version4.txt /*t_f10*
|
t_f10 version4.txt /*t_f10*
|
||||||
t_f2 version4.txt /*t_f2*
|
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_channel eval.txt /*v:t_channel*
|
||||||
v:t_class eval.txt /*v:t_class*
|
v:t_class eval.txt /*v:t_class*
|
||||||
v:t_dict eval.txt /*v:t_dict*
|
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_float eval.txt /*v:t_float*
|
||||||
v:t_func eval.txt /*v:t_func*
|
v:t_func eval.txt /*v:t_func*
|
||||||
v:t_job eval.txt /*v:t_job*
|
v:t_job eval.txt /*v:t_job*
|
||||||
|
|||||||
@ -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
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -144,7 +144,6 @@ Further Vim9 improvements:
|
|||||||
- More efficient way for interface member index than iterating over list?
|
- More efficient way for interface member index than iterating over list?
|
||||||
- a variant of type() that returns a different type for each class?
|
- a variant of type() that returns a different type for each class?
|
||||||
list<number> and list<string> should also differ.
|
list<number> and list<string> should also differ.
|
||||||
- implement :enum
|
|
||||||
- Promise class, could be used to wait on a popup close callback?
|
- Promise class, could be used to wait on a popup close callback?
|
||||||
- class local to a function
|
- class local to a function
|
||||||
- Use Vim9 for more runtime files.
|
- Use Vim9 for more runtime files.
|
||||||
|
|||||||
@ -41548,6 +41548,8 @@ Vim9 script
|
|||||||
Add support for internal builtin functions with vim9 objects, see
|
Add support for internal builtin functions with vim9 objects, see
|
||||||
|builtin-object-methods|
|
|builtin-object-methods|
|
||||||
|
|
||||||
|
Enum support for Vim9 script |:enum|
|
||||||
|
|
||||||
Other improvements *new-other-9.2*
|
Other improvements *new-other-9.2*
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
@ -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
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -904,19 +904,125 @@ aliased: >
|
|||||||
|
|
||||||
8. Enum *Vim9-enum* *:enum* *:endenum*
|
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: >
|
An enum is a type that can have one of a list of values. Example: >
|
||||||
|
|
||||||
:enum Color
|
:enum Color
|
||||||
White
|
White,
|
||||||
Red
|
Red,
|
||||||
Green
|
Green, Blue, Black
|
||||||
Blue
|
:endenum
|
||||||
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
|
9. Rationale
|
||||||
|
|||||||
32
src/errors.h
32
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"));
|
INIT(= N_("E1412: Builtin object method \"%s\" not supported"));
|
||||||
EXTERN char e_builtin_class_method_not_supported[]
|
EXTERN char e_builtin_class_method_not_supported[]
|
||||||
INIT(= N_("E1413: Builtin class method not supported"));
|
INIT(= N_("E1413: Builtin class method not supported"));
|
||||||
|
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
|
#endif
|
||||||
// E1415 - E1499 unused (reserved for Vim9 class support)
|
// E1429 - E1499 unused (reserved for Vim9 class support)
|
||||||
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
|
EXTERN char e_cannot_mix_positional_and_non_positional_str[]
|
||||||
INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s"));
|
INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s"));
|
||||||
EXTERN char e_fmt_arg_nr_unused_str[]
|
EXTERN char e_fmt_arg_nr_unused_str[]
|
||||||
|
|||||||
23
src/eval.c
23
src/eval.c
@ -1119,7 +1119,18 @@ get_lval_check_access(
|
|||||||
if (*p == '[' || *p == '.')
|
if (*p == '[' || *p == '.')
|
||||||
break;
|
break;
|
||||||
if ((flags & GLV_READ_ONLY) == 0)
|
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;
|
break;
|
||||||
case VIM_ACCESS_ALL:
|
case VIM_ACCESS_ALL:
|
||||||
break;
|
break;
|
||||||
@ -6310,9 +6321,15 @@ echo_string_core(
|
|||||||
case VAR_CLASS:
|
case VAR_CLASS:
|
||||||
{
|
{
|
||||||
class_T *cl = tv->vval.v_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);
|
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);
|
cl == NULL ? "[unknown]" : (char *)cl->class_name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -11486,15 +11486,31 @@ f_type(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
|
case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
|
||||||
case VAR_BLOB: n = VAR_TYPE_BLOB; break;
|
case VAR_BLOB: n = VAR_TYPE_BLOB; break;
|
||||||
case VAR_INSTR: n = VAR_TYPE_INSTR; 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_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_UNKNOWN:
|
||||||
case VAR_ANY:
|
case VAR_ANY:
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
internal_error_no_abort("f_type(UNKNOWN)");
|
internal_error_no_abort("f_type(UNKNOWN)");
|
||||||
n = -1;
|
n = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rettv->vval.v_number = n;
|
rettv->vval.v_number = n;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -159,6 +159,8 @@ static struct vimvar
|
|||||||
{VV_NAME("maxcol", VAR_NUMBER), NULL, VV_RO},
|
{VV_NAME("maxcol", VAR_NUMBER), NULL, VV_RO},
|
||||||
{VV_NAME("python3_version", 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_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
|
// shorthand
|
||||||
@ -262,6 +264,8 @@ evalvars_init(void)
|
|||||||
set_vim_var_nr(VV_TYPE_CLASS, VAR_TYPE_CLASS);
|
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_OBJECT, VAR_TYPE_OBJECT);
|
||||||
set_vim_var_nr(VV_TYPE_TYPEALIAS, VAR_TYPE_TYPEALIAS);
|
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);
|
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
|
||||||
|
|
||||||
|
|||||||
@ -595,7 +595,7 @@ EXCMD(CMD_endwhile, "endwhile", ex_endwhile,
|
|||||||
EXCMD(CMD_enew, "enew", ex_edit,
|
EXCMD(CMD_enew, "enew", ex_edit,
|
||||||
EX_BANG|EX_TRLBAR,
|
EX_BANG|EX_TRLBAR,
|
||||||
ADDR_NONE),
|
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,
|
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
||||||
ADDR_NONE),
|
ADDR_NONE),
|
||||||
EXCMD(CMD_eval, "eval", ex_eval,
|
EXCMD(CMD_eval, "eval", ex_eval,
|
||||||
|
|||||||
@ -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);
|
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);
|
ufunc_T *class_get_builtin_method(class_T *cl, class_builtin_T builtin_method, int *method_idx);
|
||||||
void ex_class(exarg_T *eap);
|
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(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);
|
type_T *oc_member_type_by_idx(class_T *cl, int is_object, int member_idx);
|
||||||
void ex_enum(exarg_T *eap);
|
void ex_enum(exarg_T *eap);
|
||||||
|
|||||||
@ -1562,9 +1562,10 @@ struct itf2class_S {
|
|||||||
// array with ints follows
|
// array with ints follows
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CLASS_INTERFACE 1
|
#define CLASS_INTERFACE 0x1
|
||||||
#define CLASS_EXTENDED 2 // another class extends this one
|
#define CLASS_EXTENDED 0x2 // another class extends this one
|
||||||
#define CLASS_ABSTRACT 4 // abstract class
|
#define CLASS_ABSTRACT 0x4 // abstract class
|
||||||
|
#define CLASS_ENUM 0x8 // enum
|
||||||
|
|
||||||
// "class_T": used for v_class of typval of VAR_CLASS
|
// "class_T": used for v_class of typval of VAR_CLASS
|
||||||
// Also used for an interface (class_flags has CLASS_INTERFACE).
|
// 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
|
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.
|
// Used for v_object of typval of VAR_OBJECT.
|
||||||
// The member variables follow in an array of typval_T.
|
// The member variables follow in an array of typval_T.
|
||||||
struct object_S
|
struct object_S
|
||||||
|
|||||||
@ -40,6 +40,7 @@ TEST_VIM9 = \
|
|||||||
test_vim9_class \
|
test_vim9_class \
|
||||||
test_vim9_cmd \
|
test_vim9_cmd \
|
||||||
test_vim9_disassemble \
|
test_vim9_disassemble \
|
||||||
|
test_vim9_enum \
|
||||||
test_vim9_expr \
|
test_vim9_expr \
|
||||||
test_vim9_fails \
|
test_vim9_fails \
|
||||||
test_vim9_func \
|
test_vim9_func \
|
||||||
@ -53,6 +54,7 @@ TEST_VIM9_RES = \
|
|||||||
test_vim9_class.res \
|
test_vim9_class.res \
|
||||||
test_vim9_cmd.res \
|
test_vim9_cmd.res \
|
||||||
test_vim9_disassemble.res \
|
test_vim9_disassemble.res \
|
||||||
|
test_vim9_enum.res \
|
||||||
test_vim9_expr.res \
|
test_vim9_expr.res \
|
||||||
test_vim9_fails.res \
|
test_vim9_fails.res \
|
||||||
test_vim9_func.res \
|
test_vim9_func.res \
|
||||||
|
|||||||
@ -2275,6 +2275,18 @@ def Test_interface_basics()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
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()
|
def Test_class_implements_interface()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
@ -10391,6 +10403,23 @@ def Test_compound_op_in_objmethod_lambda()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
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
|
" call a lambda function in one object from another object
|
||||||
def Test_lambda_invocation_across_classes()
|
def Test_lambda_invocation_across_classes()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
@ -10420,4 +10449,18 @@ def Test_lambda_invocation_across_classes()
|
|||||||
v9.CheckScriptSuccess(lines)
|
v9.CheckScriptSuccess(lines)
|
||||||
enddef
|
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
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
|||||||
1476
src/testdir/test_vim9_enum.vim
Normal file
1476
src/testdir/test_vim9_enum.vim
Normal file
File diff suppressed because it is too large
Load Diff
@ -1091,9 +1091,8 @@ f_test_refcount(typval_T *argvars, typval_T *rettv)
|
|||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL:
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
case VAR_INSTR:
|
case VAR_INSTR:
|
||||||
case VAR_CLASS:
|
|
||||||
case VAR_OBJECT:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
if (argvars[0].vval.v_job != NULL)
|
if (argvars[0].vval.v_job != NULL)
|
||||||
@ -1132,6 +1131,14 @@ f_test_refcount(typval_T *argvars, typval_T *rettv)
|
|||||||
if (argvars[0].vval.v_dict != NULL)
|
if (argvars[0].vval.v_dict != NULL)
|
||||||
retval = argvars[0].vval.v_dict->dv_refcount - 1;
|
retval = argvars[0].vval.v_dict->dv_refcount - 1;
|
||||||
break;
|
break;
|
||||||
|
case VAR_CLASS:
|
||||||
|
if (argvars[0].vval.v_class != NULL)
|
||||||
|
retval = argvars[0].vval.v_class->class_refcount - 1;
|
||||||
|
break;
|
||||||
|
case VAR_OBJECT:
|
||||||
|
if (argvars[0].vval.v_object != NULL)
|
||||||
|
retval = argvars[0].vval.v_object->obj_refcount - 1;
|
||||||
|
break;
|
||||||
case VAR_TYPEALIAS:
|
case VAR_TYPEALIAS:
|
||||||
if (argvars[0].vval.v_typealias != NULL)
|
if (argvars[0].vval.v_typealias != NULL)
|
||||||
retval = argvars[0].vval.v_typealias->ta_refcount - 1;
|
retval = argvars[0].vval.v_typealias->ta_refcount - 1;
|
||||||
|
|||||||
16
src/typval.c
16
src/typval.c
@ -266,7 +266,13 @@ tv_get_bool_or_number_chk(
|
|||||||
check_typval_is_value(varp);
|
check_typval_is_value(varp);
|
||||||
break;
|
break;
|
||||||
case VAR_OBJECT:
|
case VAR_OBJECT:
|
||||||
emsg(_(e_using_object_as_number));
|
{
|
||||||
|
class_T *cl = varp->vval.v_object->obj_class;
|
||||||
|
if (cl != NULL && IS_ENUM(cl))
|
||||||
|
semsg(_(e_using_enum_str_as_number), cl->class_name);
|
||||||
|
else
|
||||||
|
emsg(_(e_using_object_as_number));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case VAR_VOID:
|
case VAR_VOID:
|
||||||
emsg(_(e_cannot_use_void_value));
|
emsg(_(e_cannot_use_void_value));
|
||||||
@ -1139,7 +1145,13 @@ tv_get_string_buf_chk_strict(typval_T *varp, char_u *buf, int strict)
|
|||||||
check_typval_is_value(varp);
|
check_typval_is_value(varp);
|
||||||
break;
|
break;
|
||||||
case VAR_OBJECT:
|
case VAR_OBJECT:
|
||||||
emsg(_(e_using_object_as_string));
|
{
|
||||||
|
class_T *cl = varp->vval.v_object->obj_class;
|
||||||
|
if (cl != NULL && IS_ENUM(cl))
|
||||||
|
semsg(_(e_using_enum_str_as_string), cl->class_name);
|
||||||
|
else
|
||||||
|
emsg(_(e_using_object_as_string));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case VAR_JOB:
|
case VAR_JOB:
|
||||||
#ifdef FEAT_JOB_CHANNEL
|
#ifdef FEAT_JOB_CHANNEL
|
||||||
|
|||||||
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
219,
|
||||||
/**/
|
/**/
|
||||||
218,
|
218,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
@ -2164,7 +2164,9 @@ typedef int sock_T;
|
|||||||
#define VV_MAXCOL 105
|
#define VV_MAXCOL 105
|
||||||
#define VV_PYTHON3_VERSION 106
|
#define VV_PYTHON3_VERSION 106
|
||||||
#define VV_TYPE_TYPEALIAS 107
|
#define VV_TYPE_TYPEALIAS 107
|
||||||
#define VV_LEN 108 // number of v: vars
|
#define VV_TYPE_ENUM 108
|
||||||
|
#define VV_TYPE_ENUMVALUE 109
|
||||||
|
#define VV_LEN 110 // number of v: vars
|
||||||
|
|
||||||
// used for v_number in VAR_BOOL and VAR_SPECIAL
|
// used for v_number in VAR_BOOL and VAR_SPECIAL
|
||||||
#define VVAL_FALSE 0L // VAR_BOOL
|
#define VVAL_FALSE 0L // VAR_BOOL
|
||||||
@ -2188,6 +2190,8 @@ typedef int sock_T;
|
|||||||
#define VAR_TYPE_CLASS 12
|
#define VAR_TYPE_CLASS 12
|
||||||
#define VAR_TYPE_OBJECT 13
|
#define VAR_TYPE_OBJECT 13
|
||||||
#define VAR_TYPE_TYPEALIAS 14
|
#define VAR_TYPE_TYPEALIAS 14
|
||||||
|
#define VAR_TYPE_ENUM 15
|
||||||
|
#define VAR_TYPE_ENUMVALUE 16
|
||||||
|
|
||||||
#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
|
#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
|
||||||
|
|
||||||
|
|||||||
519
src/vim9class.c
519
src/vim9class.c
@ -168,7 +168,8 @@ struct oc_newmember_S
|
|||||||
/*
|
/*
|
||||||
* Add a member to an object or a class.
|
* Add a member to an object or a class.
|
||||||
* Returns OK when successful, "init_expr" will be consumed then.
|
* Returns OK when successful, "init_expr" will be consumed then.
|
||||||
* Returns FAIL otherwise, caller might need to free "init_expr".
|
* Returns OK on success and FAIL on memory allocation failure (caller might
|
||||||
|
* need to free "init_expr").
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
add_member(
|
add_member(
|
||||||
@ -323,13 +324,15 @@ validate_extends_class(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tv.v_type != VAR_CLASS || tv.vval.v_class == NULL
|
if (tv.v_type != VAR_CLASS || tv.vval.v_class == NULL
|
||||||
|| (is_class
|
|| (is_class && IS_INTERFACE(tv.vval.v_class))
|
||||||
&& (tv.vval.v_class->class_flags & CLASS_INTERFACE) != 0)
|
|| (!is_class && !IS_INTERFACE(tv.vval.v_class))
|
||||||
|| (!is_class
|
|| (is_class && IS_ENUM(tv.vval.v_class)))
|
||||||
&& (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0))
|
{
|
||||||
// a interface cannot extend a class and a class cannot extend an
|
// a class cannot extend an interface
|
||||||
// interface.
|
// an interface cannot extend a class
|
||||||
|
// a class cannot extend an enum.
|
||||||
semsg(_(e_cannot_extend_str), extends_name);
|
semsg(_(e_cannot_extend_str), extends_name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
class_T *extends_cl = tv.vval.v_class;
|
class_T *extends_cl = tv.vval.v_class;
|
||||||
@ -793,7 +796,7 @@ validate_implements_classes(
|
|||||||
|
|
||||||
if (tv.v_type != VAR_CLASS
|
if (tv.v_type != VAR_CLASS
|
||||||
|| tv.vval.v_class == NULL
|
|| tv.vval.v_class == NULL
|
||||||
|| (tv.vval.v_class->class_flags & CLASS_INTERFACE) == 0)
|
|| !IS_INTERFACE(tv.vval.v_class))
|
||||||
{
|
{
|
||||||
semsg(_(e_not_valid_interface_str), impl);
|
semsg(_(e_not_valid_interface_str), impl);
|
||||||
success = FALSE;
|
success = FALSE;
|
||||||
@ -1234,14 +1237,14 @@ add_lookup_tables(class_T *cl, class_T *extends_cl, garray_T *objmethods_gap)
|
|||||||
* Add class members to a new class. Allocate a typval for each class member
|
* Add class members to a new class. Allocate a typval for each class member
|
||||||
* and initialize it.
|
* and initialize it.
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
add_class_members(class_T *cl, exarg_T *eap, garray_T *type_list_gap)
|
add_class_members(class_T *cl, exarg_T *eap, garray_T *type_list_gap)
|
||||||
{
|
{
|
||||||
// Allocate a typval for each class member and initialize it.
|
// Allocate a typval for each class member and initialize it.
|
||||||
cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
|
cl->class_members_tv = ALLOC_CLEAR_MULT(typval_T,
|
||||||
cl->class_class_member_count);
|
cl->class_class_member_count);
|
||||||
if (cl->class_members_tv == NULL)
|
if (cl->class_members_tv == NULL)
|
||||||
return;
|
return FAIL;
|
||||||
|
|
||||||
for (int i = 0; i < cl->class_class_member_count; ++i)
|
for (int i = 0; i < cl->class_class_member_count; ++i)
|
||||||
{
|
{
|
||||||
@ -1250,19 +1253,19 @@ add_class_members(class_T *cl, exarg_T *eap, garray_T *type_list_gap)
|
|||||||
if (m->ocm_init != NULL)
|
if (m->ocm_init != NULL)
|
||||||
{
|
{
|
||||||
typval_T *etv = eval_expr(m->ocm_init, eap);
|
typval_T *etv = eval_expr(m->ocm_init, eap);
|
||||||
if (etv != NULL)
|
if (etv == NULL)
|
||||||
{
|
return FAIL;
|
||||||
if (m->ocm_type->tt_type == VAR_ANY
|
|
||||||
&& !(m->ocm_flags & OCMFLAG_HAS_TYPE)
|
if (m->ocm_type->tt_type == VAR_ANY
|
||||||
&& etv->v_type != VAR_SPECIAL)
|
&& !(m->ocm_flags & OCMFLAG_HAS_TYPE)
|
||||||
// If the member variable type is not yet set, then use
|
&& etv->v_type != VAR_SPECIAL)
|
||||||
// the initialization expression type.
|
// If the member variable type is not yet set, then use
|
||||||
m->ocm_type = typval2type(etv, get_copyID(),
|
// the initialization expression type.
|
||||||
type_list_gap,
|
m->ocm_type = typval2type(etv, get_copyID(),
|
||||||
TVTT_DO_MEMBER|TVTT_MORE_SPECIFIC);
|
type_list_gap,
|
||||||
*tv = *etv;
|
TVTT_DO_MEMBER|TVTT_MORE_SPECIFIC);
|
||||||
vim_free(etv);
|
*tv = *etv;
|
||||||
}
|
vim_free(etv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1273,6 +1276,8 @@ add_class_members(class_T *cl, exarg_T *eap, garray_T *type_list_gap)
|
|||||||
if (m->ocm_flags & OCMFLAG_CONST)
|
if (m->ocm_flags & OCMFLAG_CONST)
|
||||||
item_lock(tv, DICT_MAXNEST, TRUE, TRUE);
|
item_lock(tv, DICT_MAXNEST, TRUE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1284,13 +1289,21 @@ add_default_constructor(
|
|||||||
garray_T *classfunctions_gap,
|
garray_T *classfunctions_gap,
|
||||||
garray_T *type_list_gap)
|
garray_T *type_list_gap)
|
||||||
{
|
{
|
||||||
garray_T fga;
|
garray_T fga;
|
||||||
|
int is_enum = IS_ENUM(cl);
|
||||||
|
|
||||||
ga_init2(&fga, 1, 1000);
|
ga_init2(&fga, 1, 1000);
|
||||||
ga_concat(&fga, (char_u *)"new(");
|
ga_concat(&fga, (char_u *)"new(");
|
||||||
for (int i = 0; i < cl->class_obj_member_count; ++i)
|
for (int i = 0; i < cl->class_obj_member_count; ++i)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i < 2 && is_enum)
|
||||||
|
// The first two object variables in an enum are the enum value
|
||||||
|
// name and ordinal. Don't initialize these object variables in
|
||||||
|
// the default constructor as they are already initialized right
|
||||||
|
// after creating the object.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (i > (is_enum ? 2 : 0))
|
||||||
ga_concat(&fga, (char_u *)", ");
|
ga_concat(&fga, (char_u *)", ");
|
||||||
ga_concat(&fga, (char_u *)"this.");
|
ga_concat(&fga, (char_u *)"this.");
|
||||||
ocmember_T *m = cl->class_obj_members + i;
|
ocmember_T *m = cl->class_obj_members + i;
|
||||||
@ -1336,6 +1349,7 @@ add_default_constructor(
|
|||||||
* Add the class methods and object methods to the new class "cl".
|
* Add the class methods and object methods to the new class "cl".
|
||||||
* When extending a class "extends_cl", add the instance methods from the
|
* When extending a class "extends_cl", add the instance methods from the
|
||||||
* parent class also.
|
* parent class also.
|
||||||
|
* Returns OK on success and FAIL on memory allocation failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
add_classfuncs_objmethods(
|
add_classfuncs_objmethods(
|
||||||
@ -1373,7 +1387,7 @@ add_classfuncs_objmethods(
|
|||||||
|
|
||||||
if (gap->ga_len != 0)
|
if (gap->ga_len != 0)
|
||||||
mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
|
mch_memmove(*fup, gap->ga_data, sizeof(ufunc_T *) * gap->ga_len);
|
||||||
vim_free(gap->ga_data);
|
VIM_CLEAR(gap->ga_data);
|
||||||
if (loop == 1)
|
if (loop == 1)
|
||||||
cl->class_class_function_count_child = gap->ga_len;
|
cl->class_class_function_count_child = gap->ga_len;
|
||||||
else
|
else
|
||||||
@ -1422,6 +1436,8 @@ add_classfuncs_objmethods(
|
|||||||
if (loop == 2)
|
if (loop == 2)
|
||||||
fp->uf_flags |= FC_OBJECT;
|
fp->uf_flags |= FC_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ga_clear(gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@ -1471,6 +1487,246 @@ find_class_name_end(char_u *arg)
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns TRUE if the enum value "varname" is already defined.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
is_duplicate_enum(
|
||||||
|
garray_T *enum_gap,
|
||||||
|
char_u *varname,
|
||||||
|
char_u *varname_end)
|
||||||
|
{
|
||||||
|
char_u *name = vim_strnsave(varname, varname_end - varname);
|
||||||
|
int dup = FALSE;
|
||||||
|
|
||||||
|
for (int i = 0; i < enum_gap->ga_len; ++i)
|
||||||
|
{
|
||||||
|
ocmember_T *m = ((ocmember_T *)enum_gap->ga_data) + i;
|
||||||
|
if (STRCMP(name, m->ocm_name) == 0)
|
||||||
|
{
|
||||||
|
semsg(_(e_duplicate_enum_str), name);
|
||||||
|
dup = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vim_free(name);
|
||||||
|
return dup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the enum values in "line" separated by comma and add them to "gap".
|
||||||
|
* If the last enum value is found, then "enum_end" is set to TRUE.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
enum_parse_values(
|
||||||
|
exarg_T *eap,
|
||||||
|
class_T *en,
|
||||||
|
char_u *line,
|
||||||
|
garray_T *gap,
|
||||||
|
int *num_enum_values,
|
||||||
|
int *enum_end)
|
||||||
|
{
|
||||||
|
evalarg_T evalarg;
|
||||||
|
char_u *p = line;
|
||||||
|
char initexpr_buf[1024];
|
||||||
|
char_u last_char = NUL;
|
||||||
|
int rc = OK;
|
||||||
|
|
||||||
|
fill_evalarg_from_eap(&evalarg, eap, FALSE);
|
||||||
|
|
||||||
|
int did_emsg_before = did_emsg;
|
||||||
|
while (*p != NUL)
|
||||||
|
{
|
||||||
|
// ignore comment
|
||||||
|
if (*p == '#')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!eval_isnamec1(*p))
|
||||||
|
{
|
||||||
|
semsg(_(e_invalid_enum_value_declaration_str), p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char_u *eni_name_start = p;
|
||||||
|
char_u *eni_name_end = to_name_end(p, FALSE);
|
||||||
|
|
||||||
|
if (is_duplicate_enum(gap, eni_name_start, eni_name_end))
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = skipwhite(eni_name_end);
|
||||||
|
|
||||||
|
char_u *init_expr = NULL;
|
||||||
|
if (*p == '(')
|
||||||
|
{
|
||||||
|
if (VIM_ISWHITE(p[-1]))
|
||||||
|
{
|
||||||
|
semsg(_(e_no_white_space_allowed_before_str_str), "(", line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char_u *expr_start, *expr_end;
|
||||||
|
|
||||||
|
p = eni_name_start;
|
||||||
|
(void)skip_expr_concatenate(&p, &expr_start, &expr_end, &evalarg);
|
||||||
|
|
||||||
|
while (*expr_start && *expr_start != '(')
|
||||||
|
expr_start++;
|
||||||
|
|
||||||
|
if (expr_end > expr_start)
|
||||||
|
init_expr = vim_strnsave(expr_start, expr_end - expr_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_expr == NULL)
|
||||||
|
vim_snprintf(initexpr_buf, sizeof(initexpr_buf), "%s.new()",
|
||||||
|
en->class_name);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vim_snprintf(initexpr_buf, sizeof(initexpr_buf), "%s.new%s",
|
||||||
|
en->class_name, init_expr);
|
||||||
|
vim_free(init_expr);
|
||||||
|
}
|
||||||
|
if (add_member(gap, eni_name_start, eni_name_end, FALSE,
|
||||||
|
TRUE, TRUE, TRUE, &en->class_object_type,
|
||||||
|
vim_strsave((char_u *)initexpr_buf)) == FAIL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
++*num_enum_values;
|
||||||
|
|
||||||
|
if (*p != '#')
|
||||||
|
last_char = *p;
|
||||||
|
|
||||||
|
if (*p != NUL && *p != ',')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*p == ',')
|
||||||
|
{
|
||||||
|
if (!IS_WHITE_OR_NUL(p[1]))
|
||||||
|
{
|
||||||
|
semsg(_(e_white_space_required_after_str_str), ",", line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (VIM_ISWHITE(p[-1]))
|
||||||
|
{
|
||||||
|
semsg(_(e_no_white_space_allowed_before_str_str), ",", line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = skipwhite(p + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p != NUL && *p != '#')
|
||||||
|
{
|
||||||
|
if (did_emsg == did_emsg_before)
|
||||||
|
semsg(_(e_missing_comma_before_argument_str), p);
|
||||||
|
rc = FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_char != ',')
|
||||||
|
// last enum value should not be terminated by ","
|
||||||
|
*enum_end = TRUE;
|
||||||
|
|
||||||
|
// Free the memory pointed by expr_start.
|
||||||
|
clear_evalarg(&evalarg, NULL);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the "values" class variable (List of enum value objects) to the enum
|
||||||
|
* class "en"
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
enum_add_values_member(
|
||||||
|
class_T *en,
|
||||||
|
garray_T *gap,
|
||||||
|
int num_enum_values,
|
||||||
|
garray_T *type_list_gap)
|
||||||
|
{
|
||||||
|
garray_T fga;
|
||||||
|
int rc = FAIL;
|
||||||
|
|
||||||
|
ga_init2(&fga, 1, 1000);
|
||||||
|
ga_concat(&fga, (char_u *)"[");
|
||||||
|
for (int i = 0; i < num_enum_values; ++i)
|
||||||
|
{
|
||||||
|
ocmember_T *m = ((ocmember_T *)gap->ga_data) + i;
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
ga_concat(&fga, (char_u *)", ");
|
||||||
|
ga_concat(&fga, en->class_name);
|
||||||
|
ga_concat(&fga, (char_u *)".");
|
||||||
|
ga_concat(&fga, (char_u *)m->ocm_name);
|
||||||
|
}
|
||||||
|
ga_concat(&fga, (char_u *)"]");
|
||||||
|
ga_append(&fga, NUL);
|
||||||
|
|
||||||
|
char_u *varname = (char_u *)"values";
|
||||||
|
|
||||||
|
type_T *type = get_type_ptr(type_list_gap);
|
||||||
|
if (type == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
type->tt_type = VAR_LIST;
|
||||||
|
type->tt_member = get_type_ptr(type_list_gap);
|
||||||
|
if (type->tt_member != NULL)
|
||||||
|
{
|
||||||
|
type->tt_member->tt_type = VAR_OBJECT;
|
||||||
|
type->tt_member->tt_class = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = add_member(gap, varname, varname + 6, FALSE, FALSE, TRUE, TRUE, type,
|
||||||
|
vim_strsave((char_u *)fga.ga_data));
|
||||||
|
|
||||||
|
done:
|
||||||
|
vim_free(fga.ga_data);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the constructor method names in a enum class, so that an enum class
|
||||||
|
* cannot be instantiated.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
enum_clear_constructors(class_T *en)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < en->class_class_function_count; ++i)
|
||||||
|
{
|
||||||
|
ufunc_T *fp = en->class_class_functions[i];
|
||||||
|
|
||||||
|
if (fp->uf_flags & FC_NEW)
|
||||||
|
*fp->uf_name = NUL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the name and ordinal object variable in the enum value "enval" in
|
||||||
|
* the enum "en". These values are set during the enum value object creation.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
enum_set_internal_obj_vars(class_T *en, object_T *enval)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < en->class_class_member_count; ++i)
|
||||||
|
{
|
||||||
|
typval_T *en_tv = en->class_members_tv + i;
|
||||||
|
if (en_tv != NULL && en_tv->v_type == VAR_UNKNOWN)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First object variable is the name
|
||||||
|
ocmember_T *value_ocm = en->class_class_members + i;
|
||||||
|
typval_T *name_tv = (typval_T *)(enval + 1);
|
||||||
|
name_tv->v_type = VAR_STRING;
|
||||||
|
name_tv->vval.v_string = vim_strsave(value_ocm->ocm_name);
|
||||||
|
|
||||||
|
// Second object variable is the ordinal
|
||||||
|
typval_T *ord_tv = (typval_T *)(name_tv + 1);
|
||||||
|
ord_tv->v_type = VAR_NUMBER;
|
||||||
|
ord_tv->vval.v_number = i;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle ":class" and ":abstract class" up to ":endclass".
|
* Handle ":class" and ":abstract class" up to ":endclass".
|
||||||
@ -1479,10 +1735,12 @@ find_class_name_end(char_u *arg)
|
|||||||
void
|
void
|
||||||
ex_class(exarg_T *eap)
|
ex_class(exarg_T *eap)
|
||||||
{
|
{
|
||||||
int is_class = eap->cmdidx == CMD_class; // FALSE for :interface
|
int is_class = eap->cmdidx == CMD_class;
|
||||||
|
int is_abstract = eap->cmdidx == CMD_abstract;
|
||||||
|
int is_enum = eap->cmdidx == CMD_enum;
|
||||||
|
int is_interface;
|
||||||
long start_lnum = SOURCING_LNUM;
|
long start_lnum = SOURCING_LNUM;
|
||||||
char_u *arg = eap->arg;
|
char_u *arg = eap->arg;
|
||||||
int is_abstract = eap->cmdidx == CMD_abstract;
|
|
||||||
|
|
||||||
if (is_abstract)
|
if (is_abstract)
|
||||||
{
|
{
|
||||||
@ -1495,12 +1753,16 @@ ex_class(exarg_T *eap)
|
|||||||
is_class = TRUE;
|
is_class = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_interface = !is_class && !is_enum;
|
||||||
|
|
||||||
if (!current_script_is_vim9()
|
if (!current_script_is_vim9()
|
||||||
|| (cmdmod.cmod_flags & CMOD_LEGACY)
|
|| (cmdmod.cmod_flags & CMOD_LEGACY)
|
||||||
|| !getline_equal(eap->ea_getline, eap->cookie, getsourceline))
|
|| !getline_equal(eap->ea_getline, eap->cookie, getsourceline))
|
||||||
{
|
{
|
||||||
if (is_class)
|
if (is_class)
|
||||||
emsg(_(e_class_can_only_be_defined_in_vim9_script));
|
emsg(_(e_class_can_only_be_defined_in_vim9_script));
|
||||||
|
else if (is_enum)
|
||||||
|
emsg(_(e_enum_can_only_be_defined_in_vim9_script));
|
||||||
else
|
else
|
||||||
emsg(_(e_interface_can_only_be_defined_in_vim9_script));
|
emsg(_(e_interface_can_only_be_defined_in_vim9_script));
|
||||||
return;
|
return;
|
||||||
@ -1510,6 +1772,8 @@ ex_class(exarg_T *eap)
|
|||||||
{
|
{
|
||||||
if (is_class)
|
if (is_class)
|
||||||
semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
|
semsg(_(e_class_name_must_start_with_uppercase_letter_str), arg);
|
||||||
|
else if (is_enum)
|
||||||
|
semsg(_(e_enum_name_must_start_with_uppercase_letter_str), arg);
|
||||||
else
|
else
|
||||||
semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
|
semsg(_(e_interface_name_must_start_with_uppercase_letter_str),
|
||||||
arg);
|
arg);
|
||||||
@ -1523,11 +1787,6 @@ ex_class(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
char_u *name_start = arg;
|
char_u *name_start = arg;
|
||||||
|
|
||||||
// "export class" gets used when creating the class, don't use "is_export"
|
|
||||||
// for the items inside the class.
|
|
||||||
int class_export = is_export;
|
|
||||||
is_export = FALSE;
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// generics: <Tkey, Tentry>
|
// generics: <Tkey, Tentry>
|
||||||
|
|
||||||
@ -1545,6 +1804,11 @@ ex_class(exarg_T *eap)
|
|||||||
// specifies SomeInterface
|
// specifies SomeInterface
|
||||||
if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7]))
|
if (STRNCMP(arg, "extends", 7) == 0 && IS_WHITE_OR_NUL(arg[7]))
|
||||||
{
|
{
|
||||||
|
if (is_enum)
|
||||||
|
{
|
||||||
|
emsg(_(e_enum_cannot_extend_class));
|
||||||
|
goto early_ret;
|
||||||
|
}
|
||||||
if (extends != NULL)
|
if (extends != NULL)
|
||||||
{
|
{
|
||||||
emsg(_(e_duplicate_extends));
|
emsg(_(e_duplicate_extends));
|
||||||
@ -1567,7 +1831,7 @@ ex_class(exarg_T *eap)
|
|||||||
else if (STRNCMP(arg, "implements", 10) == 0
|
else if (STRNCMP(arg, "implements", 10) == 0
|
||||||
&& IS_WHITE_OR_NUL(arg[10]))
|
&& IS_WHITE_OR_NUL(arg[10]))
|
||||||
{
|
{
|
||||||
if (!is_class)
|
if (is_interface)
|
||||||
{
|
{
|
||||||
emsg(_(e_interface_cannot_use_implements));
|
emsg(_(e_interface_cannot_use_implements));
|
||||||
goto early_ret;
|
goto early_ret;
|
||||||
@ -1652,11 +1916,15 @@ early_ret:
|
|||||||
class_T *cl = NULL;
|
class_T *cl = NULL;
|
||||||
class_T *extends_cl = NULL; // class from "extends" argument
|
class_T *extends_cl = NULL; // class from "extends" argument
|
||||||
class_T **intf_classes = NULL;
|
class_T **intf_classes = NULL;
|
||||||
|
int num_enum_values = 0;
|
||||||
|
|
||||||
cl = ALLOC_CLEAR_ONE(class_T);
|
cl = ALLOC_CLEAR_ONE(class_T);
|
||||||
if (cl == NULL)
|
if (cl == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
if (!is_class)
|
|
||||||
|
if (is_enum)
|
||||||
|
cl->class_flags = CLASS_ENUM;
|
||||||
|
else if (is_interface)
|
||||||
cl->class_flags = CLASS_INTERFACE;
|
cl->class_flags = CLASS_INTERFACE;
|
||||||
else if (is_abstract)
|
else if (is_abstract)
|
||||||
cl->class_flags = CLASS_ABSTRACT;
|
cl->class_flags = CLASS_ABSTRACT;
|
||||||
@ -1666,22 +1934,48 @@ early_ret:
|
|||||||
if (cl->class_name == NULL)
|
if (cl->class_name == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
cl->class_type.tt_type = VAR_CLASS;
|
||||||
|
cl->class_type.tt_class = cl;
|
||||||
|
cl->class_object_type.tt_type = VAR_OBJECT;
|
||||||
|
cl->class_object_type.tt_class = cl;
|
||||||
|
|
||||||
// Add the class to the script-local variables.
|
// Add the class to the script-local variables.
|
||||||
// TODO: handle other context, e.g. in a function
|
// TODO: handle other context, e.g. in a function
|
||||||
// TODO: does uf_hash need to be cleared?
|
// TODO: does uf_hash need to be cleared?
|
||||||
typval_T tv;
|
typval_T tv;
|
||||||
tv.v_type = VAR_CLASS;
|
tv.v_type = VAR_CLASS;
|
||||||
tv.vval.v_class = cl;
|
tv.vval.v_class = cl;
|
||||||
is_export = class_export;
|
|
||||||
SOURCING_LNUM = start_lnum;
|
SOURCING_LNUM = start_lnum;
|
||||||
int rc = set_var_const(cl->class_name, current_sctx.sc_sid,
|
int rc = set_var_const(cl->class_name, current_sctx.sc_sid,
|
||||||
NULL, &tv, FALSE, 0, 0);
|
NULL, &tv, FALSE, 0, 0);
|
||||||
if (rc == FAIL)
|
if (rc == FAIL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
if (is_enum)
|
||||||
|
{
|
||||||
|
// All the enum classes have the name and ordinal object variables.
|
||||||
|
char_u *varname = (char_u *)"name";
|
||||||
|
if (add_member(&objmembers, varname, varname + 4, FALSE, FALSE, TRUE,
|
||||||
|
TRUE, &t_string, NULL) == FAIL)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
varname = (char_u *)"ordinal";
|
||||||
|
if (add_member(&objmembers, varname, varname + 7, FALSE, FALSE, TRUE,
|
||||||
|
TRUE, &t_number, NULL) == FAIL)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "export class" gets used when creating the class, don't use "is_export"
|
||||||
|
// for the items inside the class.
|
||||||
|
is_export = FALSE;
|
||||||
|
|
||||||
|
// When parsing an enum definition, this denotes whether all the enumerated
|
||||||
|
// values are parsed or not.
|
||||||
|
int enum_end = FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go over the body of the class/interface until "endclass" or
|
* Go over the body of the class/interface until "endclass" or
|
||||||
* "endinterface" is found.
|
* "endinterface" or "endenum" is found.
|
||||||
*/
|
*/
|
||||||
char_u *theline = NULL;
|
char_u *theline = NULL;
|
||||||
int success = FALSE;
|
int success = FALSE;
|
||||||
@ -1704,10 +1998,32 @@ early_ret:
|
|||||||
}
|
}
|
||||||
|
|
||||||
char_u *p = line;
|
char_u *p = line;
|
||||||
char *end_name = is_class ? "endclass" : "endinterface";
|
|
||||||
if (checkforcmd(&p, end_name, is_class ? 4 : 5))
|
char *end_name;
|
||||||
|
int shortlen;
|
||||||
|
int fullen;
|
||||||
|
if (is_class)
|
||||||
{
|
{
|
||||||
if (STRNCMP(line, end_name, is_class ? 8 : 12) != 0)
|
end_name = "endclass";
|
||||||
|
shortlen = 4;
|
||||||
|
fullen = 8;
|
||||||
|
}
|
||||||
|
else if (is_enum)
|
||||||
|
{
|
||||||
|
end_name = "endenum";
|
||||||
|
shortlen = 4;
|
||||||
|
fullen = 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
end_name = "endinterface";
|
||||||
|
shortlen = 5;
|
||||||
|
fullen = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkforcmd(&p, end_name, shortlen))
|
||||||
|
{
|
||||||
|
if (STRNCMP(line, end_name, fullen) != 0)
|
||||||
semsg(_(e_command_cannot_be_shortened_str), line);
|
semsg(_(e_command_cannot_be_shortened_str), line);
|
||||||
else if (*p == '|' || !ends_excmd2(line, p))
|
else if (*p == '|' || !ends_excmd2(line, p))
|
||||||
semsg(_(e_trailing_characters_str), p);
|
semsg(_(e_trailing_characters_str), p);
|
||||||
@ -1715,13 +2031,34 @@ early_ret:
|
|||||||
success = TRUE;
|
success = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
char *wrong_name = is_class ? "endinterface" : "endclass";
|
|
||||||
if (checkforcmd(&p, wrong_name, is_class ? 5 : 4))
|
int wrong_endname = FALSE;
|
||||||
|
if (is_class)
|
||||||
|
wrong_endname = checkforcmd(&p, "endinterface", 5)
|
||||||
|
|| checkforcmd(&p, "endenum", 4);
|
||||||
|
else if (is_enum)
|
||||||
|
wrong_endname = checkforcmd(&p, "endclass", 4)
|
||||||
|
|| checkforcmd(&p, "endinterface", 5);
|
||||||
|
else
|
||||||
|
wrong_endname = checkforcmd(&p, "endclass", 4)
|
||||||
|
|| checkforcmd(&p, "endenum", 4);
|
||||||
|
if (wrong_endname)
|
||||||
{
|
{
|
||||||
semsg(_(e_invalid_command_str_expected_str), line, end_name);
|
semsg(_(e_invalid_command_str_expected_str), line, end_name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_enum && !enum_end)
|
||||||
|
{
|
||||||
|
// In an enum, all the enumerated values are at the beginning
|
||||||
|
// separated by comma. The class and object variables/methods
|
||||||
|
// follow the values.
|
||||||
|
if (enum_parse_values(eap, cl, line, &classmembers,
|
||||||
|
&num_enum_values, &enum_end) == FAIL)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int has_public = FALSE;
|
int has_public = FALSE;
|
||||||
if (checkforcmd(&p, "public", 3))
|
if (checkforcmd(&p, "public", 3))
|
||||||
{
|
{
|
||||||
@ -1730,7 +2067,7 @@ early_ret:
|
|||||||
semsg(_(e_command_cannot_be_shortened_str), line);
|
semsg(_(e_command_cannot_be_shortened_str), line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!is_class)
|
if (is_interface)
|
||||||
{
|
{
|
||||||
emsg(_(e_public_variable_not_supported_in_interface));
|
emsg(_(e_public_variable_not_supported_in_interface));
|
||||||
break;
|
break;
|
||||||
@ -1756,7 +2093,14 @@ early_ret:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_class)
|
if (is_enum)
|
||||||
|
{
|
||||||
|
// "abstract" not supported in an enum
|
||||||
|
emsg(_(e_abstract_cannot_be_used_in_enum));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_interface)
|
||||||
{
|
{
|
||||||
// "abstract" not supported in an interface
|
// "abstract" not supported in an interface
|
||||||
emsg(_(e_abstract_cannot_be_used_in_interface));
|
emsg(_(e_abstract_cannot_be_used_in_interface));
|
||||||
@ -1789,7 +2133,7 @@ early_ret:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_class)
|
if (is_interface)
|
||||||
{
|
{
|
||||||
emsg(_(e_static_member_not_supported_in_interface));
|
emsg(_(e_static_member_not_supported_in_interface));
|
||||||
break;
|
break;
|
||||||
@ -1812,7 +2156,7 @@ early_ret:
|
|||||||
has_var = TRUE;
|
has_var = TRUE;
|
||||||
else if (checkforcmd(&p, "final", 5))
|
else if (checkforcmd(&p, "final", 5))
|
||||||
{
|
{
|
||||||
if (!is_class)
|
if (is_interface)
|
||||||
{
|
{
|
||||||
emsg(_(e_final_variable_not_supported_in_interface));
|
emsg(_(e_final_variable_not_supported_in_interface));
|
||||||
break;
|
break;
|
||||||
@ -1821,7 +2165,7 @@ early_ret:
|
|||||||
}
|
}
|
||||||
else if (checkforcmd(&p, "const", 5))
|
else if (checkforcmd(&p, "const", 5))
|
||||||
{
|
{
|
||||||
if (!is_class)
|
if (is_interface)
|
||||||
{
|
{
|
||||||
emsg(_(e_const_variable_not_supported_in_interface));
|
emsg(_(e_const_variable_not_supported_in_interface));
|
||||||
break;
|
break;
|
||||||
@ -1867,7 +2211,7 @@ early_ret:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_class && *varname == '_')
|
if (is_interface && *varname == '_')
|
||||||
{
|
{
|
||||||
// private variables are not supported in an interface
|
// private variables are not supported in an interface
|
||||||
semsg(_(e_protected_variable_not_supported_in_interface),
|
semsg(_(e_protected_variable_not_supported_in_interface),
|
||||||
@ -1877,7 +2221,7 @@ early_ret:
|
|||||||
|
|
||||||
if (parse_member(eap, line, varname, has_public,
|
if (parse_member(eap, line, varname, has_public,
|
||||||
&varname_end, &has_type, &type_list, &type,
|
&varname_end, &has_type, &type_list, &type,
|
||||||
is_class ? &init_expr: NULL) == FAIL)
|
!is_interface ? &init_expr: NULL) == FAIL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (is_reserved_varname(varname, varname_end)
|
if (is_reserved_varname(varname, varname_end)
|
||||||
@ -1930,7 +2274,7 @@ early_ret:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_class && *p == '_')
|
if (is_interface && *p == '_')
|
||||||
{
|
{
|
||||||
// private methods are not supported in an interface
|
// private methods are not supported in an interface
|
||||||
semsg(_(e_protected_method_not_supported_in_interface), p);
|
semsg(_(e_protected_method_not_supported_in_interface), p);
|
||||||
@ -1953,10 +2297,10 @@ early_ret:
|
|||||||
|
|
||||||
ga_init2(&lines_to_free, sizeof(char_u *), 50);
|
ga_init2(&lines_to_free, sizeof(char_u *), 50);
|
||||||
int class_flags;
|
int class_flags;
|
||||||
if (is_class)
|
if (is_interface)
|
||||||
class_flags = abstract_method ? CF_ABSTRACT_METHOD : CF_CLASS;
|
|
||||||
else
|
|
||||||
class_flags = CF_INTERFACE;
|
class_flags = CF_INTERFACE;
|
||||||
|
else
|
||||||
|
class_flags = abstract_method ? CF_ABSTRACT_METHOD : CF_CLASS;
|
||||||
ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
|
ufunc_T *uf = define_function(&ea, NULL, &lines_to_free,
|
||||||
class_flags, objmembers.ga_data, objmembers.ga_len);
|
class_flags, objmembers.ga_data, objmembers.ga_len);
|
||||||
ga_clear_strings(&lines_to_free);
|
ga_clear_strings(&lines_to_free);
|
||||||
@ -2011,15 +2355,25 @@ early_ret:
|
|||||||
{
|
{
|
||||||
if (is_class)
|
if (is_class)
|
||||||
semsg(_(e_not_valid_command_in_class_str), line);
|
semsg(_(e_not_valid_command_in_class_str), line);
|
||||||
|
else if (is_enum)
|
||||||
|
semsg(_(e_not_valid_command_in_enum_str), line);
|
||||||
else
|
else
|
||||||
semsg(_(e_not_valid_command_in_interface_str), line);
|
semsg(_(e_not_valid_command_in_interface_str), line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theline == NULL && !success && is_enum)
|
||||||
|
emsg(_(e_missing_endenum));
|
||||||
|
|
||||||
vim_free(theline);
|
vim_free(theline);
|
||||||
|
|
||||||
|
if (success && is_enum)
|
||||||
|
// Add the enum "values" class variable.
|
||||||
|
enum_add_values_member(cl, &classmembers, num_enum_values, &type_list);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check a few things before defining the class.
|
* Check a few things
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Check the "extends" class is valid.
|
// Check the "extends" class is valid.
|
||||||
@ -2067,7 +2421,8 @@ early_ret:
|
|||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
// "endclass" encountered without failures: Create the class.
|
// "endclass" or "endinterface" or "endenum" encountered without any
|
||||||
|
// failures
|
||||||
|
|
||||||
if (extends_cl != NULL)
|
if (extends_cl != NULL)
|
||||||
{
|
{
|
||||||
@ -2114,10 +2469,6 @@ early_ret:
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate a typval for each class member and initialize it.
|
|
||||||
if (is_class && cl->class_class_member_count > 0)
|
|
||||||
add_class_members(cl, eap, &type_list);
|
|
||||||
|
|
||||||
int have_new = FALSE;
|
int have_new = FALSE;
|
||||||
ufunc_T *class_func = NULL;
|
ufunc_T *class_func = NULL;
|
||||||
for (int i = 0; i < classfunctions.ga_len; ++i)
|
for (int i = 0; i < classfunctions.ga_len; ++i)
|
||||||
@ -2133,7 +2484,7 @@ early_ret:
|
|||||||
if (have_new)
|
if (have_new)
|
||||||
// The return type of new() is an object of class "cl"
|
// The return type of new() is an object of class "cl"
|
||||||
class_func->uf_ret_type->tt_class = cl;
|
class_func->uf_ret_type->tt_class = cl;
|
||||||
else if (is_class && !is_abstract && !have_new)
|
else if ((is_class || is_enum) && !is_abstract && !have_new)
|
||||||
// No new() method was defined, add the default constructor.
|
// No new() method was defined, add the default constructor.
|
||||||
add_default_constructor(cl, &classfunctions, &type_list);
|
add_default_constructor(cl, &classfunctions, &type_list);
|
||||||
|
|
||||||
@ -2144,13 +2495,21 @@ early_ret:
|
|||||||
|
|
||||||
update_builtin_method_index(cl);
|
update_builtin_method_index(cl);
|
||||||
|
|
||||||
cl->class_type.tt_type = VAR_CLASS;
|
class_created(cl);
|
||||||
cl->class_type.tt_class = cl;
|
|
||||||
cl->class_object_type.tt_type = VAR_OBJECT;
|
// Allocate a typval for each class member and initialize it.
|
||||||
cl->class_object_type.tt_class = cl;
|
if ((is_class || is_enum) && cl->class_class_member_count > 0)
|
||||||
|
if (add_class_members(cl, eap, &type_list) == FAIL)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
cl->class_type_list = type_list;
|
cl->class_type_list = type_list;
|
||||||
|
|
||||||
class_created(cl);
|
if (is_enum)
|
||||||
|
{
|
||||||
|
// clear the constructor method names, so that an enum class cannot
|
||||||
|
// be instantiated
|
||||||
|
enum_clear_constructors(cl);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - Fill hashtab with object members and methods ?
|
// - Fill hashtab with object members and methods ?
|
||||||
@ -2264,15 +2623,6 @@ oc_member_type_by_idx(
|
|||||||
return m[member_idx].ocm_type;
|
return m[member_idx].ocm_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle ":enum" up to ":endenum".
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ex_enum(exarg_T *eap UNUSED)
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type aliases (:type)
|
* Type aliases (:type)
|
||||||
*/
|
*/
|
||||||
@ -3334,8 +3684,14 @@ member_not_found_msg(class_T *cl, vartype_T v_type, char_u *name, size_t len)
|
|||||||
semsg(_(e_object_variable_str_accessible_only_using_object_str),
|
semsg(_(e_object_variable_str_accessible_only_using_object_str),
|
||||||
varname, cl->class_name);
|
varname, cl->class_name);
|
||||||
else
|
else
|
||||||
semsg(_(e_class_variable_str_not_found_in_class_str),
|
{
|
||||||
varname, cl->class_name);
|
if (IS_ENUM(cl))
|
||||||
|
semsg(_(e_enum_value_str_not_found_in_enum_str),
|
||||||
|
varname, cl->class_name);
|
||||||
|
else
|
||||||
|
semsg(_(e_class_variable_str_not_found_in_class_str),
|
||||||
|
varname, cl->class_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vim_free(varname);
|
vim_free(varname);
|
||||||
}
|
}
|
||||||
@ -3480,8 +3836,17 @@ object_string(
|
|||||||
garray_T ga;
|
garray_T ga;
|
||||||
ga_init2(&ga, 1, 50);
|
ga_init2(&ga, 1, 50);
|
||||||
|
|
||||||
ga_concat(&ga, (char_u *)"object of ");
|
|
||||||
class_T *cl = obj == NULL ? NULL : obj->obj_class;
|
class_T *cl = obj == NULL ? NULL : obj->obj_class;
|
||||||
|
if (cl != NULL && IS_ENUM(cl))
|
||||||
|
{
|
||||||
|
ga_concat(&ga, cl->class_name);
|
||||||
|
char_u *name = ((typval_T *)(obj + 1))->vval.v_string;
|
||||||
|
ga_concat(&ga, (char_u *)".");
|
||||||
|
ga_concat(&ga, name);
|
||||||
|
return ga.ga_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ga_concat(&ga, (char_u *)"object of ");
|
||||||
ga_concat(&ga, cl == NULL ? (char_u *)"[unknown]"
|
ga_concat(&ga, cl == NULL ? (char_u *)"[unknown]"
|
||||||
: cl->class_name);
|
: cl->class_name);
|
||||||
if (cl != NULL)
|
if (cl != NULL)
|
||||||
|
|||||||
@ -1614,6 +1614,13 @@ lhs_class_member_modifiable(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_ENUM(cl))
|
||||||
|
{
|
||||||
|
semsg(_(e_enumvalue_str_cannot_be_modified), cl->class_name,
|
||||||
|
m->ocm_name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// If it is private member variable, then accessing it outside the
|
// If it is private member variable, then accessing it outside the
|
||||||
// class is not allowed.
|
// class is not allowed.
|
||||||
// If it is a read only class variable, then it can be modified
|
// If it is a read only class variable, then it can be modified
|
||||||
@ -2037,6 +2044,25 @@ compile_lhs(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_ENUM(cl))
|
||||||
|
{
|
||||||
|
if (!inside_class(cctx, cl))
|
||||||
|
{
|
||||||
|
semsg(_(e_enumvalue_str_cannot_be_modified),
|
||||||
|
cl->class_name, m->ocm_name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (lhs->lhs_type->tt_type == VAR_OBJECT &&
|
||||||
|
lhs->lhs_member_idx < 2)
|
||||||
|
{
|
||||||
|
char *msg = lhs->lhs_member_idx == 0 ?
|
||||||
|
e_enum_str_name_cannot_be_modified :
|
||||||
|
e_enum_str_ordinal_cannot_be_modified;
|
||||||
|
semsg(_(msg), cl->class_name);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If it is private member variable, then accessing it outside the
|
// If it is private member variable, then accessing it outside the
|
||||||
// class is not allowed.
|
// class is not allowed.
|
||||||
// If it is a read only class variable, then it can be modified
|
// If it is a read only class variable, then it can be modified
|
||||||
@ -2304,7 +2330,7 @@ compile_load_lhs_with_index(lhs_T *lhs, char_u *var_start, cctx_T *cctx)
|
|||||||
if (compile_load_lhs(lhs, var_start, lhs->lhs_type, cctx) == FAIL)
|
if (compile_load_lhs(lhs, var_start, lhs->lhs_type, cctx) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (cl->class_flags & CLASS_INTERFACE)
|
if (IS_INTERFACE(cl))
|
||||||
return generate_GET_ITF_MEMBER(cctx, cl, lhs->lhs_member_idx, type);
|
return generate_GET_ITF_MEMBER(cctx, cl, lhs->lhs_member_idx, type);
|
||||||
return generate_GET_OBJ_MEMBER(cctx, lhs->lhs_member_idx, type);
|
return generate_GET_OBJ_MEMBER(cctx, lhs->lhs_member_idx, type);
|
||||||
}
|
}
|
||||||
@ -2453,7 +2479,7 @@ compile_assign_unlet(
|
|||||||
{
|
{
|
||||||
class_T *cl = lhs->lhs_type->tt_class;
|
class_T *cl = lhs->lhs_type->tt_class;
|
||||||
|
|
||||||
if (cl->class_flags & CLASS_INTERFACE)
|
if (IS_INTERFACE(cl))
|
||||||
{
|
{
|
||||||
// "this.value": load "this" object and get the value
|
// "this.value": load "this" object and get the value
|
||||||
// at index for an object or class member get the type
|
// at index for an object or class member get the type
|
||||||
@ -3375,6 +3401,14 @@ compile_def_function(
|
|||||||
for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
|
for (int i = 0; i < ufunc->uf_class->class_obj_member_count; ++i)
|
||||||
{
|
{
|
||||||
ocmember_T *m = &ufunc->uf_class->class_obj_members[i];
|
ocmember_T *m = &ufunc->uf_class->class_obj_members[i];
|
||||||
|
|
||||||
|
if (i < 2 && IS_ENUM(ufunc->uf_class))
|
||||||
|
// The first two object variables in an enum are the name
|
||||||
|
// and the ordinal. These are set by the ISN_CONSTRUCT
|
||||||
|
// instruction. So don't generate instructions to set
|
||||||
|
// these variables.
|
||||||
|
continue;
|
||||||
|
|
||||||
if (m->ocm_init != NULL)
|
if (m->ocm_init != NULL)
|
||||||
{
|
{
|
||||||
char_u *expr = m->ocm_init;
|
char_u *expr = m->ocm_init;
|
||||||
@ -3481,8 +3515,7 @@ compile_def_function(
|
|||||||
|
|
||||||
// Compiling a function in an interface is done to get the function type.
|
// Compiling a function in an interface is done to get the function type.
|
||||||
// No code is actually compiled.
|
// No code is actually compiled.
|
||||||
if (ufunc->uf_class != NULL
|
if (ufunc->uf_class != NULL && IS_INTERFACE(ufunc->uf_class))
|
||||||
&& (ufunc->uf_class->class_flags & CLASS_INTERFACE))
|
|
||||||
{
|
{
|
||||||
ufunc->uf_def_status = UF_NOT_COMPILED;
|
ufunc->uf_def_status = UF_NOT_COMPILED;
|
||||||
ret = OK;
|
ret = OK;
|
||||||
|
|||||||
@ -3258,6 +3258,12 @@ exec_instructions(ectx_T *ectx)
|
|||||||
++tv->vval.v_object->obj_class->class_refcount;
|
++tv->vval.v_object->obj_class->class_refcount;
|
||||||
tv->vval.v_object->obj_refcount = 1;
|
tv->vval.v_object->obj_refcount = 1;
|
||||||
object_created(tv->vval.v_object);
|
object_created(tv->vval.v_object);
|
||||||
|
|
||||||
|
// When creating an enum value object, initialize the name and
|
||||||
|
// ordinal object variables.
|
||||||
|
class_T *en = tv->vval.v_object->obj_class;
|
||||||
|
if (IS_ENUM(en))
|
||||||
|
enum_set_internal_obj_vars(en, tv->vval.v_object);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// execute Ex command line
|
// execute Ex command line
|
||||||
|
|||||||
@ -446,7 +446,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
|||||||
if (m_idx >= 0)
|
if (m_idx >= 0)
|
||||||
{
|
{
|
||||||
ufunc_T *fp = cl->class_obj_methods[m_idx];
|
ufunc_T *fp = cl->class_obj_methods[m_idx];
|
||||||
// Private methods are not accessible outside the class
|
// Private object methods are not accessible outside the class
|
||||||
if (*name == '_' && !inside_class(cctx, cl))
|
if (*name == '_' && !inside_class(cctx, cl))
|
||||||
{
|
{
|
||||||
semsg(_(e_cannot_access_protected_method_str), fp->uf_name);
|
semsg(_(e_cannot_access_protected_method_str), fp->uf_name);
|
||||||
@ -488,7 +488,7 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
|
|||||||
if (m_idx >= 0)
|
if (m_idx >= 0)
|
||||||
{
|
{
|
||||||
ufunc_T *fp = cl->class_class_functions[m_idx];
|
ufunc_T *fp = cl->class_class_functions[m_idx];
|
||||||
// Private methods are not accessible outside the class
|
// Private class methods are not accessible outside the class
|
||||||
if (*name == '_' && !inside_class(cctx, cl))
|
if (*name == '_' && !inside_class(cctx, cl))
|
||||||
{
|
{
|
||||||
semsg(_(e_cannot_access_protected_method_str), fp->uf_name);
|
semsg(_(e_cannot_access_protected_method_str), fp->uf_name);
|
||||||
@ -2462,7 +2462,8 @@ compile_subscript(
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
ppconst->pp_is_const = FALSE;
|
ppconst->pp_is_const = FALSE;
|
||||||
|
|
||||||
if ((type = get_type_on_stack(cctx, 0)) != &t_unknown
|
type = get_type_on_stack(cctx, 0);
|
||||||
|
if (type != &t_unknown
|
||||||
&& (type->tt_type == VAR_CLASS
|
&& (type->tt_type == VAR_CLASS
|
||||||
|| type->tt_type == VAR_OBJECT))
|
|| type->tt_type == VAR_OBJECT))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -719,7 +719,7 @@ check_typval_type(type_T *expected, typval_T *actual_tv, where_T where)
|
|||||||
|
|
||||||
if (expected == NULL)
|
if (expected == NULL)
|
||||||
return OK; // didn't expect anything.
|
return OK; // didn't expect anything.
|
||||||
//
|
|
||||||
ga_init2(&type_list, sizeof(type_T *), 10);
|
ga_init2(&type_list, sizeof(type_T *), 10);
|
||||||
|
|
||||||
// A null_function and null_partial are special cases, they can be used to
|
// A null_function and null_partial are special cases, they can be used to
|
||||||
@ -1739,8 +1739,15 @@ type_name(type_T *type, char **tofree)
|
|||||||
|
|
||||||
if (type->tt_type == VAR_OBJECT || type->tt_type == VAR_CLASS)
|
if (type->tt_type == VAR_OBJECT || type->tt_type == VAR_CLASS)
|
||||||
{
|
{
|
||||||
char_u *class_name = type->tt_class == NULL ? (char_u *)"Unknown"
|
char_u *class_name;
|
||||||
: type->tt_class->class_name;
|
if (type->tt_class != NULL)
|
||||||
|
{
|
||||||
|
class_name = type->tt_class->class_name;
|
||||||
|
if (IS_ENUM(type->tt_class))
|
||||||
|
name = "enum";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
class_name = (char_u *)"Unknown";
|
||||||
size_t len = STRLEN(name) + STRLEN(class_name) + 3;
|
size_t len = STRLEN(name) + STRLEN(class_name) + 3;
|
||||||
*tofree = alloc(len);
|
*tofree = alloc(len);
|
||||||
if (*tofree != NULL)
|
if (*tofree != NULL)
|
||||||
@ -1869,18 +1876,26 @@ check_typval_is_value(typval_T *tv)
|
|||||||
{
|
{
|
||||||
if (tv == NULL)
|
if (tv == NULL)
|
||||||
return OK;
|
return OK;
|
||||||
if (tv->v_type == VAR_CLASS)
|
|
||||||
|
switch (tv->v_type)
|
||||||
{
|
{
|
||||||
if (tv->vval.v_class != NULL)
|
case VAR_CLASS:
|
||||||
semsg(_(e_using_class_as_value_str), tv->vval.v_class->class_name);
|
{
|
||||||
else
|
class_T *cl = tv->vval.v_class;
|
||||||
emsg(e_using_class_as_var_val);
|
if (IS_ENUM(cl))
|
||||||
return FAIL;
|
semsg(_(e_using_enum_as_value_str), cl->class_name);
|
||||||
}
|
else
|
||||||
else if (tv->v_type == VAR_TYPEALIAS)
|
semsg(_(e_using_class_as_value_str), cl->class_name);
|
||||||
{
|
}
|
||||||
semsg(_(e_using_typealias_as_value_str), tv->vval.v_typealias->ta_name);
|
return FAIL;
|
||||||
return FAIL;
|
|
||||||
|
case VAR_TYPEALIAS:
|
||||||
|
semsg(_(e_using_typealias_as_value_str),
|
||||||
|
tv->vval.v_typealias->ta_name);
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -1893,17 +1908,25 @@ check_type_is_value(type_T *type)
|
|||||||
{
|
{
|
||||||
if (type == NULL)
|
if (type == NULL)
|
||||||
return OK;
|
return OK;
|
||||||
if (type->tt_type == VAR_CLASS)
|
switch (type->tt_type)
|
||||||
{
|
{
|
||||||
semsg(_(e_using_class_as_value_str), type->tt_class->class_name);
|
case VAR_CLASS:
|
||||||
return FAIL;
|
if (IS_ENUM(type->tt_class))
|
||||||
}
|
semsg(_(e_using_enum_as_value_str),
|
||||||
else if (type->tt_type == VAR_TYPEALIAS)
|
type->tt_class->class_name);
|
||||||
{
|
else
|
||||||
// TODO: Not sure what could be done here to get a name.
|
semsg(_(e_using_class_as_value_str),
|
||||||
// Maybe an optional argument?
|
type->tt_class->class_name);
|
||||||
emsg(_(e_using_typealias_as_var_val));
|
return FAIL;
|
||||||
return FAIL;
|
|
||||||
|
case VAR_TYPEALIAS:
|
||||||
|
// TODO: Not sure what could be done here to get a name.
|
||||||
|
// Maybe an optional argument?
|
||||||
|
emsg(_(e_using_typealias_as_var_val));
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user