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:
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);
+};