Skip to content

Commit 8aa6b1d

Browse files
authored
Merge pull request #672 from dictu-lang/feature/enum
Add new Enum.values() method
2 parents 9d51366 + a9facd1 commit 8aa6b1d

File tree

8 files changed

+104
-3
lines changed

8 files changed

+104
-3
lines changed

docs/docs/enum.md

+14
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,18 @@ enum HeterogeneousEnum {
4949
b = "string",
5050
c = def () => 10
5151
}
52+
```
53+
54+
### Enum.values()
55+
56+
To get all values within an Enum you can use the `.values()` method. This will return a dictionary.
57+
58+
```cs
59+
enum Test {
60+
a = 10, // 10
61+
b, // 1
62+
c // 2
63+
}
64+
65+
print(Test.values()); // {"c": 2, "a": 10, "b": 1}
5266
```

src/vm/compiler.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,7 @@ static void enumDeclaration(Compiler *compiler) {
19771977

19781978
do {
19791979
if (check(compiler, TOKEN_RIGHT_BRACE)) {
1980-
error(compiler->parser, "Trailing comma in enum declaration");
1980+
break;
19811981
}
19821982

19831983
consume(compiler, TOKEN_IDENTIFIER, "Expect enum value identifier.");

src/vm/datatypes/enums.c

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "enums.h"
2+
3+
static Value values(DictuVM *vm, int argCount, Value *args) {
4+
if (argCount != 0) {
5+
runtimeError(vm, "values() takes 0 arguments (%d given)", argCount);
6+
return EMPTY_VAL;
7+
}
8+
9+
ObjEnum *objEnum = AS_ENUM(args[0]);
10+
ObjDict *dict = newDict(vm);
11+
push(vm, OBJ_VAL(dict));
12+
13+
for (int i = 0; i < objEnum->values.capacityMask + 1; ++i) {
14+
if (objEnum->values.entries[i].key == NULL) {
15+
continue;
16+
}
17+
18+
dictSet(vm, dict, OBJ_VAL(objEnum->values.entries[i].key), objEnum->values.entries[i].value);
19+
}
20+
21+
pop(vm);
22+
23+
return OBJ_VAL(dict);
24+
}
25+
26+
void declareEnumMethods(DictuVM *vm) {
27+
defineNative(vm, &vm->enumMethods, "values", values);
28+
}

src/vm/datatypes/enums.h

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef dictu_api_enums_h
2+
#define dictu_api_enums_h
3+
4+
#include "../common.h"
5+
#include "../util.h"
6+
7+
void declareEnumMethods(DictuVM *vm);
8+
9+
#endif //dictu_api_enums_h

src/vm/memory.c

+1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ void collectGarbage(DictuVM *vm) {
349349
grayTable(vm, &vm->classMethods);
350350
grayTable(vm, &vm->instanceMethods);
351351
grayTable(vm, &vm->resultMethods);
352+
grayTable(vm, &vm->enumMethods);
352353
grayCompilerRoots(vm);
353354
grayObject(vm, (Obj *) vm->initString);
354355
grayObject(vm, (Obj *) vm->annotationString);

src/vm/vm.c

+20-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "datatypes/class.h"
2424
#include "datatypes/instance.h"
2525
#include "datatypes/result/result.h"
26+
#include "datatypes/enums.h"
2627
#include "natives.h"
2728
#include "../optionals/optionals.h"
2829

@@ -120,6 +121,7 @@ DictuVM *dictuInitVM(bool repl, int argc, char **argv) {
120121
initTable(&vm->classMethods);
121122
initTable(&vm->instanceMethods);
122123
initTable(&vm->resultMethods);
124+
initTable(&vm->enumMethods);
123125

124126
vm->frames = ALLOCATE(vm, CallFrame, vm->frameCapacity);
125127
vm->initString = copyString(vm, "init", 4);
@@ -140,6 +142,7 @@ DictuVM *dictuInitVM(bool repl, int argc, char **argv) {
140142
declareClassMethods(vm);
141143
declareInstanceMethods(vm);
142144
declareResultMethods(vm);
145+
declareEnumMethods(vm);
143146

144147
if (vm->repl) {
145148
vm->replVar = copyString(vm, "_", 1);
@@ -168,6 +171,7 @@ void dictuFreeVM(DictuVM *vm) {
168171
freeTable(vm, &vm->classMethods);
169172
freeTable(vm, &vm->instanceMethods);
170173
freeTable(vm, &vm->resultMethods);
174+
freeTable(vm, &vm->enumMethods);
171175
FREE_ARRAY(vm, CallFrame, vm->frames, vm->frameCapacity);
172176
vm->initString = NULL;
173177
vm->replVar = NULL;
@@ -647,14 +651,28 @@ static bool invoke(DictuVM *vm, ObjString *name, int argCount, bool unpack) {
647651
}
648652

649653
case OBJ_ENUM: {
654+
Value value;
655+
if (tableGet(&vm->enumMethods, name, &value)) {
656+
if (IS_NATIVE(value)) {
657+
return callNativeMethod(vm, value, argCount);
658+
}
659+
660+
push(vm, peek(vm, 0));
661+
662+
for (int i = 2; i <= argCount + 1; i++) {
663+
vm->stackTop[-i] = peek(vm, i);
664+
}
665+
666+
return call(vm, AS_CLOSURE(value), argCount + 1);
667+
}
668+
650669
ObjEnum *enumObj = AS_ENUM(receiver);
651670

652-
Value value;
653671
if (tableGet(&enumObj->values, name, &value)) {
654672
return callValue(vm, value, argCount, false);
655673
}
656674

657-
runtimeError(vm, "'%s' enum has no value '%s'.", enumObj->name->chars, name->chars);
675+
runtimeError(vm, "Enum has no method '%s'.", name->chars);
658676
return false;
659677
}
660678

src/vm/vm.h

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct _vm {
3939
Table classMethods;
4040
Table instanceMethods;
4141
Table resultMethods;
42+
Table enumMethods;
4243
ObjString *initString;
4344
ObjString *annotationString;
4445
ObjString *replVar;

tests/enum/enum.du

+30
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,36 @@ class TestEnums < UnitTest {
5858
this.assertEquals(HeterogeneousEnum.c, func);
5959
this.assertEquals(HeterogeneousEnum.c(), 10);
6060
}
61+
62+
testGetValues() {
63+
enum MyEnum {
64+
a,
65+
b,
66+
c
67+
}
68+
69+
const values = MyEnum.values();
70+
71+
this.assertEquals(values["a"], 0);
72+
this.assertEquals(values["b"], 1);
73+
this.assertEquals(values["c"], 2);
74+
}
75+
76+
testGetValuesHeterogeneousEnum() {
77+
const func = def () => 10;
78+
79+
enum HeterogeneousEnum {
80+
a = 0,
81+
b = "string",
82+
c = func
83+
}
84+
85+
const values = HeterogeneousEnum.values();
86+
87+
this.assertEquals(values["a"], 0);
88+
this.assertEquals(values["b"], "string");
89+
this.assertEquals(values["c"], func);
90+
}
6191
}
6292

6393
TestEnums().run();

0 commit comments

Comments
 (0)