hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mhare/parse/+test/types.ha | 16++++++++++++++++
Mhare/parse/type.ha | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
Mhare/unparse/type.ha | 12++++++++----
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;