commit a6e0ba6a4a067a88ff4e3c0a5ded65045c74b85b
parent c6fbfa5519948400676271027e801400732d7bdd
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 5 Apr 2021 19:02:00 -0400
hare::parse: implement cast-expression
Diffstat:
3 files changed, 59 insertions(+), 32 deletions(-)
diff --git a/hare/parse/+test.ha b/hare/parse/+test.ha
@@ -168,16 +168,8 @@ use strio;
};
};
-@test fn decls() void = {
- const in = "export type foo::bar = *int, baz = const void;\n"
- "type foo = ...bar;\n"
- "type foo = nullable *fn(x: rune, _: int) void;\n"
- "export let @symbol(\"_\") foo::bar: int = void, baz: int = void;\n"
- "def foo::bar: int = void;\n"
- "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n"
- "@test fn foo(_: int, ...) void;\n"
- "export fn main() void = void;\n";
- let buf = bufio::fixed(strings::toutf8(in), mode::READ);
+fn roundtrip(src: str) void = {
+ let buf = bufio::fixed(strings::toutf8(src), mode::READ);
let lexer = lex::init(buf, "<test>");
let u = ast::subunit {
imports = [],
@@ -186,23 +178,28 @@ use strio;
defer ast::subunit_free(u);
let out = strio::dynamic();
unparse::subunit(out, u) as size;
- let s = strio::finish(out);
- defer free(s);
- assert(s == in);
+ let unsrc = strio::finish(out);
+ defer free(unsrc);
+ assert(unsrc == src);
+};
+
+@test fn decls() void = {
+ roundtrip("export type foo::bar = *int, baz = const void;\n"
+ "type foo = ...bar;\n"
+ "type foo = nullable *fn(x: rune, _: int) void;\n"
+ "export let @symbol(\"_\") foo::bar: int = void, baz: int = void;\n"
+ "def foo::bar: int = void;\n"
+ "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n"
+ "@test fn foo(_: int, ...) void;\n"
+ "export fn main() void = void;\n");
};
@test fn binarithm() void = {
- const in = "export fn main() void = void + void * void / void;\n";
- let buf = bufio::fixed(strings::toutf8(in), mode::READ);
- let lexer = lex::init(buf, "<test>");
- let u = ast::subunit {
- imports = [],
- decls = decls(&lexer) as []ast::decl,
- };
- defer ast::subunit_free(u);
- let out = strio::dynamic();
- unparse::subunit(out, u) as size;
- let s = strio::finish(out);
- defer free(s);
- assert(s == in);
+ roundtrip("export fn main() void = void + void * void / void;\n");
+};
+
+@test fn cast() void = {
+ roundtrip("export fn main() void = void: int;\n"
+ "export fn main() void = void as int;\n"
+ "export fn main() void = void is int;\n");
};
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -2,11 +2,6 @@ use hare::ast;
use hare::lex;
use hare::lex::{btoken};
-fn cast(lexer: *lex::lexer) (ast::expr | error) = {
- want_btoken(lexer, btoken::VOID)?; // TODO
- return void;
-};
-
fn binarithm(
lexer: *lex::lexer,
lvalue: (ast::expr | void),
@@ -59,6 +54,31 @@ fn binarithm(
return lvalue;
};
+fn cast(lexer: *lex::lexer) (ast::expr | error) = {
+ let lvalue = unarithm(lexer)?;
+ const tok = match (try_btoken(lexer, btoken::COLON,
+ btoken::AS, btoken::IS)?) {
+ void => return lvalue,
+ tok: btoken => tok,
+ };
+ const kind = switch (tok) {
+ btoken::COLON => ast::cast_kind::CAST,
+ btoken::AS => ast::cast_kind::ASSERTION,
+ btoken::IS => ast::cast_kind::TEST,
+ * => abort(),
+ };
+ return ast::cast_expr {
+ kind = kind,
+ value = alloc(lvalue),
+ _type = alloc(_type(lexer)?),
+ };
+};
+
+fn unarithm(lexer: *lex::lexer) (ast::expr | error) = {
+ want_btoken(lexer, btoken::VOID)?; // TODO
+ return void;
+};
+
fn binop_for_tok(tok: (lex::token, lex::location)) ast::binarithm_op = {
let tok = match (tok.0) {
b: btoken => b,
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -43,7 +43,17 @@ export fn expr(
e: []ast::binding_expr => abort(),
e: ast::break_expr => abort(),
e: ast::call_expr => abort(),
- e: ast::cast_expr => abort(),
+ e: ast::cast_expr => {
+ let z = expr(out, indent, *e.value)?;
+ const op = switch (e.kind) {
+ ast::cast_kind::CAST => ": ",
+ ast::cast_kind::ASSERTION => " as ",
+ ast::cast_kind::TEST => " is ",
+ };
+ z += fmt::fprintf(out, "{}", op)?;
+ z += _type(out, indent, *e._type)?;
+ z;
+ },
e: ast::constant_expr => {
assert(e is void);
fmt::fprint(out, "void")?;