hare

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

commit 2ecee055f6865c8a1e41e3cc050ae7d9626d5ae0
parent 6021f2780d7b968914ffab2ee186c82eded19658
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Mon,  8 Mar 2021 18:03:10 -0500

Refactor hare::lex::literal to be a tagged union

Diffstat:
Mhare/lex/+test.ha | 127++++++++++++++++++++++++++++++++-----------------------------------------------
Mhare/lex/lex.ha | 10++--------
Mhare/lex/token.ha | 49++++++++++++++++++++++++++++---------------------
3 files changed, 81 insertions(+), 105 deletions(-)

diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha @@ -31,29 +31,24 @@ use strings; assert(t.1.line == 1234 && t.1.col == 1234); }; -fn liteq(expected: literal, actual: literal) bool = { - if (expected.storage != actual.storage) { - return false; - }; - return switch (expected.storage) { - literal_type::U8, - literal_type::U16, - literal_type::U32, - literal_type::U64, - literal_type::UINT, - literal_type::UINTPTR => expected._uint == actual._uint, - literal_type::I8, - literal_type::I16, - literal_type::I32, - literal_type::I64, - literal_type::INT, - literal_type::ICONST => expected._int == actual._int, - literal_type::F32, - literal_type::F64, - literal_type::FCONST => expected.float == actual.float, - literal_type::RUNE => expected._rune == actual._rune, - literal_type::STR => expected.string == actual.string, - }; +fn litassert(expected: literal, actual: literal) void = match (expected) { + e: u8 => assert(actual as u8 == e), + e: u16 => assert(actual as u16 == e), + e: u32 => assert(actual as u32 == e), + e: u64 => assert(actual as u64 == e), + e: uint => assert(actual as uint == e), + e: uintptr => assert(actual as uintptr == e), + e: i8 => assert(actual as i8 == e), + e: i16 => assert(actual as i16 == e), + e: i32 => assert(actual as i32 == e), + e: i64 => assert(actual as i64 == e), + e: int => assert(actual as int == e), + e: iconst => assert(actual as iconst == e), + e: f32 => assert(actual as f32 == e), + e: f64 => assert(actual as f64 == e), + e: fconst => assert(actual as fconst == e), + e: rune => assert(actual as rune == e), + e: str => assert(actual as str == e), }; fn lextest(in: str, expected: [](uint, uint, token)) void = { @@ -90,12 +85,7 @@ fn lextest(in: str, expected: [](uint, uint, token)) void = { i, tokstr(tok), tokstr(etok)); abort(); } else { - let e = etok as literal; - if (!liteq(l, e)) { - fmt::errorfln("bad token at {}: got '{}', wanted '{}'", - i, tokstr(tok), tokstr(etok)); - abort(); - }; + litassert(l, etok as literal); }, * => abort("TODO"), }; @@ -218,21 +208,21 @@ fn lextest(in: str, expected: [](uint, uint, token)) void = { const in = "'a' 'b' '\\a' '\\b' '\\f' '\\n' '\\r' '\\t' '\\v' '\\0' " "'\\\\' '\\\'' '\\x0A' '\\u1234' '\\U12345678'"; const expected: [_](uint, uint, token) = [ - (1, 1, literal { storage = literal_type::RUNE, _rune = 'a' }), - (1, 5, literal { storage = literal_type::RUNE, _rune = 'b' }), - (1, 9, literal { storage = literal_type::RUNE, _rune = '\a' }), - (1, 14, literal { storage = literal_type::RUNE, _rune = '\b' }), - (1, 19, literal { storage = literal_type::RUNE, _rune = '\f' }), - (1, 24, literal { storage = literal_type::RUNE, _rune = '\n' }), - (1, 29, literal { storage = literal_type::RUNE, _rune = '\r' }), - (1, 34, literal { storage = literal_type::RUNE, _rune = '\t' }), - (1, 39, literal { storage = literal_type::RUNE, _rune = '\v' }), - (1, 44, literal { storage = literal_type::RUNE, _rune = '\0' }), - (1, 49, literal { storage = literal_type::RUNE, _rune = '\\' }), - (1, 54, literal { storage = literal_type::RUNE, _rune = '\'' }), - (1, 59, literal { storage = literal_type::RUNE, _rune = '\x0A' }), - (1, 66, literal { storage = literal_type::RUNE, _rune = '\u1234' }), - (1, 75, literal { storage = literal_type::RUNE, _rune = '\U12345678' }), + (1, 1, 'a'), + (1, 5, 'b'), + (1, 9, '\a'), + (1, 14, '\b'), + (1, 19, '\f'), + (1, 24, '\n'), + (1, 29, '\r'), + (1, 34, '\t'), + (1, 39, '\v'), + (1, 44, '\0'), + (1, 49, '\\'), + (1, 54, '\''), + (1, 59, '\x0A'), + (1, 66, '\u1234'), + (1, 75, '\U12345678'), ]; lextest(in, expected); }; @@ -241,47 +231,32 @@ fn lextest(in: str, expected: [](uint, uint, token)) void = { const in = "\"a\" \"b\" \"\\a\" \"\\b\" \"\\f\" \"\\n\" \"\\r\" " "\"\\t\" \"\\v\" \"\\0\" \"\\\\\" \"\\\'\""; const expected: [_](uint, uint, token) = [ - (1, 1, literal { storage = literal_type::STR, string = "a" }), - (1, 5, literal { storage = literal_type::STR, string = "b" }), - (1, 9, literal { storage = literal_type::STR, string = "\a" }), - (1, 14, literal { storage = literal_type::STR, string = "\b" }), - (1, 19, literal { storage = literal_type::STR, string = "\f" }), - (1, 24, literal { storage = literal_type::STR, string = "\n" }), - (1, 29, literal { storage = literal_type::STR, string = "\r" }), - (1, 34, literal { storage = literal_type::STR, string = "\t" }), - (1, 39, literal { storage = literal_type::STR, string = "\v" }), - (1, 44, literal { storage = literal_type::STR, string = "\0" }), - (1, 49, literal { storage = literal_type::STR, string = "\\" }), - (1, 54, literal { storage = literal_type::STR, string = "\'" }), + (1, 1, "a": literal), + (1, 5, "b": literal), + (1, 9, "\a": literal), + (1, 14, "\b": literal), + (1, 19, "\f": literal), + (1, 24, "\n": literal), + (1, 29, "\r": literal), + (1, 34, "\t": literal), + (1, 39, "\v": literal), + (1, 44, "\0": literal), + (1, 49, "\\": literal), + (1, 54, "\'": literal), ]; // TODO: test \x and \u and \U lextest(in, expected); const in = "\"ab\\a\\b\\f\\n\\r\\t\\v\\0\\\\\\'\""; const expected: [_](uint, uint, token) = [ - (1, 1, literal { - storage = literal_type::STR, - string = "ab\a\b\f\n\r\t\v\0\\\'", - }), + (1, 1, "ab\a\b\f\n\r\t\v\0\\\'": literal), ]; lextest(in, expected); const in = "\"hello world\" \"こんにちは\" \"return\" \"foo\""; const expected: [_](uint, uint, token) = [ - (1, 1, literal { - storage = literal_type::STR, - string = "hello world", - }), - (1, 15, literal { - storage = literal_type::STR, - string = "こんにちは", - }), - (1, 23, literal { - storage = literal_type::STR, - string = "return", - }), - (1, 32, literal { - storage = literal_type::STR, - string = "foo", - }), + (1, 1, "hello world": literal), + (1, 15, "こんにちは": literal), + (1, 23, "return": literal), + (1, 32, "foo": literal), ]; lextest(in, expected); }; diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha @@ -172,10 +172,7 @@ fn lex_string( append(chars, ...utf8::encode_rune(r)); }, }; - return (literal { - storage = literal_type::STR, - string = strings::from_utf8(chars), - }: token, loc); + return (strings::from_utf8(chars): literal, loc); }; fn lex_rn_str( @@ -193,10 +190,7 @@ fn lex_rn_str( }; // Rune literal - let ret = (literal { - storage = literal_type::RUNE, - _rune = lex_rune(lex, loc)?, - }: token, loc); + let ret: (token, location) = (lex_rune(lex, loc)?: literal, loc); match (next(lex)?) { io::EOF => return syntaxerr(loc, "unexpected EOF"), diff --git a/hare/lex/token.ha b/hare/lex/token.ha @@ -255,17 +255,12 @@ export type literal_type = enum { STR, }; +export type iconst = i64; +export type fconst = f64; + // A token for a literal value, such as '1337u32' -export type literal = struct { - storage: literal_type, - union { - string: str, - _rune: rune, - _int: i64, - _uint: u64, - float: f64, - }, -}; +export type literal = (u8 | u16 | u32 | u64 | uint | uintptr | i8 | i16 | i32 | + i64 | int | iconst | f32 | f64 | fconst | rune | str); // A location within a source file. export type location = struct { @@ -278,15 +273,27 @@ export type location = struct { export type token = (btoken | label | name | literal); // Converts a token to its string representation -export fn tokstr(tok: token) const str = { - return match (tok) { - b: btoken => bmap[b: int], - n: name => n: str, - l: literal => switch (l.storage) { - literal_type::RUNE => "rune", - literal_type::STR => "string", - * => abort(), // TODO - }, - * => abort(), // TODO - }; +export fn tokstr(tok: token) const str = match (tok) { + b: btoken => bmap[b: int], + n: name => n: str, + l: literal => match (l) { + u8 => "u8", + u16 => "u16", + u32 => "u32", + u64 => "u64", + uint => "uint", + uintptr => "uintptr", + i8 => "i8", + i16 => "i16", + i32 => "i32", + i64 => "i64", + int => "int", + iconst => "iconst", + f32 => "f32", + f64 => "f64", + fconst => "fconst", + rune => "rune", + str => "str", + }, + * => abort(), // TODO };