commit c5b1b81064efd567b4adcb442e29b7426f2cd173
parent 6da2a3fec8f5732e85df7e9050c3090c903a1c08
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 17 Apr 2021 11:12:38 -0400
hare::parse: implement bindings
Diffstat:
4 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -83,14 +83,20 @@ export type binarithm_expr = struct {
rvalue: *expr,
};
-// let foo: int = bar
-export type binding_expr = struct {
+// foo: int = bar
+export type binding = struct {
name: str,
_type: nullable *_type,
- is_static: bool,
init: *expr,
};
+// let foo: int = bar, ...
+export type binding_expr = struct {
+ is_static: bool,
+ is_const: bool,
+ bindings: []binding,
+};
+
// break :label
export type break_expr = label;
@@ -243,7 +249,7 @@ export type unarithm_expr = struct {
// An expression
export type expr = (access_expr | alloc_expr | append_expr | assert_expr |
- assign_expr | binarithm_expr | []binding_expr | break_expr | call_expr |
+ assign_expr | binarithm_expr | binding_expr | break_expr | call_expr |
cast_expr | constant_expr | continue_expr | defer_expr | delete_expr |
for_expr | free_expr | if_expr | list_expr | match_expr | len_expr |
size_expr | offset_expr | propagate_expr | return_expr | slice_expr |
@@ -300,13 +306,13 @@ export fn expr_free(e: (expr | nullable *expr)) void = match (e) {
expr_free(b.lvalue);
expr_free(b.rvalue);
},
- b: []binding_expr => {
- for (let i = 0z; i < len(b); i += 1) {
- free(b[i].name);
- type_free(b[i]._type);
- expr_free(b[i].init);
+ b: binding_expr => {
+ for (let i = 0z; i < len(b.bindings); i += 1) {
+ free(b.bindings[i].name);
+ type_free(b.bindings[i]._type);
+ expr_free(b.bindings[i].init);
};
- free(b);
+ free(b.bindings);
},
b: break_expr => free(b),
c: call_expr => {
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -2,6 +2,16 @@
roundtrip("export fn main() void = void + void * void / void;\n");
};
+@test fn binding() void = {
+ roundtrip("export fn main() void = {
+ let x: int = 1337, y = 7331;
+ const z: int = 42, q: int = 24;
+ static let p: int = 62893, o = 39826;
+ static const w: int = 62893, t = 39826;
+};
+");
+};
+
@test fn call() void = {
roundtrip("export fn main() void = test();\n"
"export fn main() void = test(void, void, void);\n"
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -18,7 +18,7 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
ltok::IF => if_expr(lexer),
ltok::FOR => abort(), // TODO
ltok::BREAK, ltok::CONTINUE, ltok::RETURN => control(lexer),
- ltok::LET, ltok::CONST => binding(lexer),
+ ltok::LET, ltok::CONST => binding(lexer, false),
* => abort(), // Invariant
};
};
@@ -61,8 +61,37 @@ fn binarithm(
return lvalue;
};
-fn binding(lexer: *lex::lexer) (ast::expr | error) = {
- abort(); // TODO
+fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
+ const is_const = switch (want(lexer, ltok::LET, ltok::CONST)?.0) {
+ ltok::LET => false,
+ ltok::CONST => true,
+ };
+
+ let bindings: []ast::binding = [];
+ for (true) {
+ const name = want(lexer, ltok::NAME)?.1 as str;
+ const btype: nullable *ast::_type =
+ if (try(lexer, ltok::COLON)? is lex::token) {
+ alloc(_type(lexer)?);
+ } else null;
+ want(lexer, ltok::EQUAL)?;
+ const init = alloc(expression(lexer)?);
+ append(bindings, ast::binding {
+ name = name,
+ _type = btype,
+ init = init,
+ });
+ match (try(lexer, ltok::COMMA)?) {
+ void => break,
+ lex::token => void,
+ };
+ };
+
+ return ast::binding_expr {
+ is_static = is_static,
+ is_const = is_const,
+ bindings = bindings,
+ };
};
fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
@@ -78,7 +107,21 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
ltok::DELETE => abort(),
ltok::FREE => abort(),
ltok::ASSERT => abort(),
- ltok::STATIC => abort(),
+ ltok::STATIC => {
+ want(lexer, ltok::STATIC)?;
+ let tok = match (peek(lexer, ltok::LET, ltok::CONST,
+ ltok::ASSERT)?) {
+ tok: lex::token => tok,
+ // TODO: The following is lame
+ void => return syntaxerr(tok.2,
+ "Expected let, const, or assert"),
+ };
+ switch (tok.0) {
+ ltok::LET, ltok::CONST => binding(lexer, true),
+ ltok::ASSERT => abort(), // TODO
+ * => abort(),
+ };
+ },
ltok::SIZE, ltok::LEN, ltok::OFFSET => abort(),
ltok::DEFER => abort(),
* => abort(), // Invariant
@@ -389,7 +432,7 @@ fn unarithm(lexer: *lex::lexer) (ast::expr | error) = {
const tok = match (try(lexer,
ltok::PLUS, ltok::MINUS, ltok::BNOT,
ltok::LNOT, ltok::TIMES, ltok::BAND)) {
- void => return postfix(lexer, void),
+ void => return builtin(lexer),
tok: lex::token => tok.0,
};
const op = switch (tok) {
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -58,7 +58,28 @@ export fn expr(
z += expr(out, indent, *e.rvalue)?;
z;
},
- e: []ast::binding_expr => abort(),
+ e: ast::binding_expr => {
+ let z = fmt::fprintf(out, "{}{}",
+ if (e.is_static) "static " else "",
+ if (e.is_const) "const " else "let ")?;
+ for (let i = 0z; i < len(e.bindings); i += 1) {
+ let binding = e.bindings[i];
+ z += match (binding._type) {
+ null => fmt::fprint(out, binding.name)?,
+ t: *ast::_type => {
+ fmt::fprintf(out, "{}: ",
+ binding.name)?
+ + _type(out, indent, *t)?;
+ },
+ };
+ z += fmt::fprint(out, " = ")?;
+ z += expr(out, indent, *binding.init)?;
+ if (i + 1 < len(e.bindings)) {
+ z += fmt::fprint(out, ", ")?;
+ };
+ };
+ z;
+ },
e: ast::break_expr => {
let z = fmt::fprint(out, "break")?;
// TODO: https://todo.sr.ht/~sircmpwn/hare/380