commit 2621ec2fcb906c4363a4f750b6b5ca5248ff0997
parent ca5eef54e32d74a9b35269063918bf6754006f02
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 15 Apr 2021 10:37:59 -0400
hare::parse: implement enum types
Diffstat:
3 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/hare/parse/+test/types.ha b/hare/parse/+test/types.ha
@@ -24,3 +24,19 @@ export type baz = [_]int;
export type bat = [void]int;
");
};
+
+@test fn enum_type() void = {
+ roundtrip("export type foo = enum {
+ X = void,
+ Y = void,
+ Z,
+ Q,
+};
+export type bar = enum uint {
+ X = void,
+ Y = void,
+ Z,
+ Q,
+};
+");
+};
diff --git a/hare/parse/type.ha b/hare/parse/type.ha
@@ -331,6 +331,54 @@ fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = {
};
};
+fn enum_type(lexer: *lex::lexer) (ast::_type | error) = {
+ let start = want(lexer, ltok::ENUM)?;
+
+ const storage = match (try(lexer, ltok::LBRACE)?) {
+ void => {
+ let storage = integer_type(lexer)?;
+ want(lexer, ltok::LBRACE)?;
+ storage;
+ },
+ lex::token => builtin_type::INT,
+ };
+
+ let membs: []ast::enum_field = [];
+ for (true) {
+ if (try(lexer, ltok::RBRACE) is lex::token) {
+ synassert(mkloc(lexer), len(membs) != 0,
+ "Expected member list")?;
+ break;
+ };
+
+ let name = want(lexer, ltok::NAME)?;
+ let value: nullable *ast::expr =
+ if (try(lexer, ltok::EQUAL) is lex::token)
+ alloc(expression(lexer)?)
+ else null;
+
+ append(membs, ast::enum_field {
+ name = name.1 as str,
+ value = value,
+ });
+
+ switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) {
+ ltok::COMMA => void,
+ ltok::RBRACE => break,
+ * => abort(),
+ };
+ };
+
+ return ast::_type {
+ loc = start.2,
+ _type = ast::enum_type {
+ storage = storage,
+ values = membs,
+ },
+ ...
+ };
+};
+
// Parses a type
export fn _type(lexer: *lex::lexer) (ast::_type | error) = {
let flags: ast::type_flags = match (try(lexer, ltok::CONST)?) {
@@ -345,7 +393,7 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = {
ltok::U8, ltok::UINT, ltok::UINTPTR, ltok::RUNE,
ltok::STR, ltok::F32, ltok::F64, ltok::BOOL,
ltok::VOID, ltok::NULL => primitive_type(lexer)?,
- ltok::ENUM => abort(), // TODO
+ ltok::ENUM => enum_type(lexer)?,
ltok::NULLABLE, ltok::TIMES => pointer_type(lexer)?,
ltok::STRUCT, ltok::UNION => struct_union_type(lexer)?,
ltok::LBRACKET => array_slice_type(lexer)?,
diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha
@@ -122,8 +122,12 @@ export fn _type(
},
b: ast::builtin_type => n += fmt::fprint(out, builtin_type(b))?,
e: ast::enum_type => {
- n += fmt::fprint(out, "enum",
- builtin_type(e.storage), "{")?;
+ if (e.storage != ast::builtin_type::INT) {
+ n += fmt::fprint(out, "enum",
+ builtin_type(e.storage), "{")?;
+ } else {
+ n += fmt::fprint(out, "enum {")?;
+ };
indent += 1;
for (let i = 0z; i < len(e.values); i += 1) {
n += newline(out, indent)?;
@@ -132,7 +136,7 @@ export fn _type(
match (value.value) {
null => void,
e: *ast::expr => {
- n += fmt::fprint(out, ": ")?;
+ n += fmt::fprint(out, " = ")?;
n += expr(out, indent, *e)?;
},
};
@@ -251,7 +255,7 @@ fn type_test(t: ast::_type, expected: str) bool = {
},
],
};
- assert(type_test(t, "const enum u32 {\n\tFOO,\n\tBAR: void,\n}!"));
+ assert(type_test(t, "const enum u32 {\n\tFOO,\n\tBAR = void,\n}!"));
t.flags = 0;