hare

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

commit 100592f84465faf5590add0417cd77c000b59be7
parent 05681f7b44582e8d7a3f2fd88f106a51d04bcf7c
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon, 22 Feb 2021 15:42:33 -0500

hare::parse: retype ident as []str

Diffstat:
Mhare/ast/types.ha | 17+++++++----------
Mhare/parse/+test.ha | 58+++++++++++++++++++---------------------------------------
Mhare/parse/parse.ha | 13++++++-------
Aslice/reverse.ha | 23+++++++++++++++++++++++
4 files changed, 55 insertions(+), 56 deletions(-)

diff --git a/hare/ast/types.ha b/hare/ast/types.ha @@ -1,16 +1,13 @@ -// Identifies a single object, e.g. foo::bar::baz -export type ident = struct { - name: str, - ns: nullable *ident, -}; +// Identifies a single object, e.g. foo::bar::baz, ordered from least to most +// significant part (foo::bar::baz becomes ["baz", "bar", "foo"]. +export type ident = []str; // Frees resources associated with an identifier -export fn ident_finish(ident: *ident) void = { - match (ident.ns) { - null => void, - ns: *ident => ident_finish(ns), +export fn ident_free(ident: ident) void = { + for (let i = 0z; i < len(ident); i += 1) { + free(ident[i]); }; - free(ident.name); + free(ident); }; // A sub-unit, typically representing a single source file diff --git a/hare/parse/+test.ha b/hare/parse/+test.ha @@ -10,9 +10,9 @@ use fmt; let buf = bufio::fixed(strings::to_utf8(in)); let lexer = lex::lexer_init(buf, "<test>"); let ident = ident(&lexer) as ast::ident; - defer ast::ident_finish(&ident); - assert(ident.name == "foo"); - assert(ident.ns == null); + defer ast::ident_free(ident); + assert(len(ident) == 1); + assert(ident[0] == "foo"); assert(lex::lex(&lexer) is io::EOF); }; @@ -21,15 +21,9 @@ use fmt; let buf = bufio::fixed(strings::to_utf8(in)); let lexer = lex::lexer_init(buf, "<test>"); let ident = ident(&lexer) as ast::ident; - defer ast::ident_finish(&ident); - assert(ident.name == "foo"); - match (ident.ns) { - null => abort(), - ns: *ast::ident => { - assert(ns.name == "bar"); - assert(ns.ns == null); - }, - }; + defer ast::ident_free(ident); + assert(len(ident) == 2); + assert(ident[0] == "bar" && ident[1] == "foo"); assert(lex::lex(&lexer) is io::EOF); }; @@ -38,21 +32,10 @@ use fmt; let buf = bufio::fixed(strings::to_utf8(in)); let lexer = lex::lexer_init(buf, "<test>"); let ident = ident(&lexer) as ast::ident; - defer ast::ident_finish(&ident); - assert(ident.name == "foo"); - match (ident.ns) { - null => abort(), - ns: *ast::ident => { - assert(ns.name == "bar"); - match (ns.ns) { - null => abort(), - ns: *ast::ident => { - assert(ns.name == "baz"); - assert(ns.ns == null); - }, - }; - }, - }; + defer ast::ident_free(ident); + assert(len(ident) == 3); + assert(ident[0] == "baz" && ident[1] == "bar" + && ident[2] == "foo"); assert(lex::lex(&lexer) is io::EOF); }; @@ -61,15 +44,9 @@ use fmt; let buf = bufio::fixed(strings::to_utf8(in)); let lexer = lex::lexer_init(buf, "<test>"); let ident = ident(&lexer) as ast::ident; - defer ast::ident_finish(&ident); - assert(ident.name == "foo"); - match (ident.ns) { - null => abort(), - ns: *ast::ident => { - assert(ns.name == "bar"); - assert(ns.ns == null); - }, - }; + defer ast::ident_free(ident); + assert(len(ident) == 2); + assert(ident[0] == "bar" && ident[1] == "foo"); let tok = lex::lex(&lexer) as (lex::token, lex::location); assert(tok.0 as lex::btoken == hare::lex::btoken::SEMICOLON); }; @@ -84,7 +61,7 @@ use fmt; assert(len(mods) == 1); assert(mods[0] is ast::import_module); let mod = mods[0] as ast::import_module; - assert(mod.name == "foo"); + assert(len(mod) == 1 && mod[0] == "foo"); assert(lex::lex(&lexer) is io::EOF); }; @@ -99,12 +76,15 @@ use fmt; let mods = imports(&lexer) as []ast::import; assert(len(mods) == 3); - let expected = ["foo", "bar", "baz"]; + let expected: [_][]str = [["foo"], ["bar"], ["bat", "baz"]]; for (let i = 0z; i < len(mods); i += 1) { assert(mods[i] is ast::import_module); let mod = mods[i] as ast::import_module; - assert(mod.name == expected[i]); + assert(len(mod) == len(expected[i])); + for (let j = 0z; j < len(expected[i]); j += 1z) { + assert(mod[j] == expected[i][j]); + }; }; let tok = lex::lex(&lexer) as (lex::token, lex::location); diff --git a/hare/parse/parse.ha b/hare/parse/parse.ha @@ -1,26 +1,25 @@ use hare::ast; use hare::lex; +use slice; // Parses a single identifier, i.e. foo::bar::baz export fn ident(lexer: *lex::lexer) (ast::ident | error) = { - // TODO: This is actually wrong, it builds the idents backwards. Whoops - let ident = ast::ident { ... }, cur = &ident; + let ident: []str = []; for (true) { - cur.name = match (want_name(lexer)) { + let name = match (want_name(lexer)) { err: error => return err, n: lex::name => n: str, }; + append(ident, name); + match (try_btoken(lexer, hare::lex::btoken::DOUBLE_COLON)) { err: error => return err, void => break, * => void, // Grab the next ident }; - - let new = alloc(*ast::ident, ast::ident { ... }); - cur.ns = new; - cur = new; }; + slice::reverse(ident, size(ast::ident)); return ident; }; diff --git a/slice/reverse.ha b/slice/reverse.ha @@ -0,0 +1,23 @@ +// Reverses a slice. +export fn reverse(b: []void, membsz: size) void = { + if (len(b) == 0) { + return; + }; + let a = b: *[*]u8; + for (let s = 0z, e = len(b) - 1; s < e) { + for (let i = 0z; i < membsz; i += 1z) { + // XOR swap + a[s * membsz + i] ^= a[e * membsz + i]; + a[e * membsz + i] ^= a[s * membsz + i]; + a[s * membsz + i] ^= a[e * membsz + i]; + }; + s += 1; + e -= 1; + }; +}; + +@test fn reverse() void = { + let a: []int = [1, 2, 3, 4]; + reverse(a, size(int)); + assert(a[0] == 4 && a[1] == 3 && a[2] == 2 && a[3] == 1); +};