commit 8fd2614695b0d216e0e773b9e6bbd61b3026c4d8
parent 4b064c0a701a7139b6e883327d959ce2d5b38fd1
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 18 Apr 2021 08:10:27 -0400
hare::parse: implement for loops
Diffstat:
3 files changed, 94 insertions(+), 4 deletions(-)
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -54,6 +54,27 @@
");
};
+@test fn for_expr() void = {
+ roundtrip("export fn main() void = {
+ for (true) {
+ x;
+ };
+ :label for (true) {
+ x;
+ };
+ for (let x = 0; x < 10) {
+ x;
+ };
+ for (x < 10; x) {
+ x;
+ };
+ for (let x = 10; x < 10; x) {
+ x;
+ };
+};
+");
+};
+
@test fn if_expr() void = {
roundtrip("export fn main() void = {
if (x == y) {
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -6,8 +6,8 @@ use fmt;
// Parses an expression.
export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
const tok = match (peek(lexer, ltok::LBRACE, ltok::MATCH, ltok::SWITCH,
- ltok::IF, ltok::FOR, ltok::BREAK, ltok::CONTINUE,
- ltok::RETURN, ltok::LET, ltok::CONST)?) {
+ ltok::IF, ltok::LABEL, ltok::FOR, ltok::BREAK,
+ ltok::CONTINUE, ltok::RETURN, ltok::LET, ltok::CONST)?) {
void => return binarithm(lexer, void, 0),
tok: lex::token => tok,
};
@@ -16,7 +16,7 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
ltok::MATCH => abort(), // TODO
ltok::SWITCH => abort(), // TODO
ltok::IF => if_expr(lexer),
- ltok::FOR => abort(), // TODO
+ ltok::LABEL, ltok::FOR => for_expr(lexer),
ltok::BREAK, ltok::CONTINUE, ltok::RETURN => control(lexer),
ltok::LET, ltok::CONST => binding(lexer, false),
* => abort(), // Invariant
@@ -237,6 +237,50 @@ fn expression_list(lexer: *lex::lexer) (ast::expr | error) = {
return items;
};
+fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
+ let tok = want(lexer, ltok::FOR, ltok::LABEL)?;
+ let label: ast::label = switch (tok.0) {
+ ltok::LABEL => {
+ want(lexer, ltok::FOR)?;
+ tok.1 as str;
+ },
+ * => "",
+ };
+
+ want(lexer, ltok::LPAREN)?;
+
+ let bindings: nullable *ast::expr = match (peek(
+ lexer, ltok::LET, ltok::CONST)?) {
+ void => null,
+ lex::token => {
+ let bindings = alloc(binding(lexer, false)?);
+ want(lexer, ltok::SEMICOLON)?;
+ bindings;
+ },
+ };
+
+ let cond = alloc(expression(lexer)?);
+
+ let afterthought: nullable *ast::expr = match (peek(
+ lexer, ltok::SEMICOLON)) {
+ void => null,
+ lex::token => {
+ want(lexer, ltok::SEMICOLON)?;
+ alloc(expression(lexer)?);
+ },
+ };
+
+ want(lexer, ltok::RPAREN)?;
+
+ return ast::for_expr {
+ label = label,
+ bindings = bindings,
+ cond = cond,
+ afterthought = afterthought,
+ body = alloc(expression(lexer)?),
+ };
+};
+
fn if_expr(lexer: *lex::lexer) (ast::expr | error) = {
want(lexer, ltok::IF)?;
want(lexer, ltok::LPAREN)?;
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -123,7 +123,7 @@ export fn expr(
},
e: ast::defer_expr => abort(),
e: ast::delete_expr => abort(),
- e: ast::for_expr => abort(),
+ e: ast::for_expr => for_expr(out, indent, e)?,
e: ast::free_expr => abort(),
e: ast::if_expr => {
let z = fmt::fprint(out, "if (")?;
@@ -240,3 +240,28 @@ fn constant(
},
};
};
+
+fn for_expr(
+ out: *io::stream,
+ indent: size,
+ e: ast::for_expr,
+) (size | io::error) = {
+ let z = 0z;
+ if (e.label != "") {
+ z += fmt::fprintf(out, ":{} ", e.label)?;
+ };
+ z += fmt::fprintf(out, "for (")?;
+ z += match (e.bindings) {
+ null => 0z,
+ e: *ast::expr => expr(out, indent, *e)?
+ + fmt::fprint(out, "; ")?,
+ };
+ z += expr(out, indent, *e.cond)?;
+ z += match (e.afterthought) {
+ null => 0z,
+ e: *ast::expr => fmt::fprint(out, "; ")?
+ + expr(out, indent, *e)?,
+ };
+ z += fmt::fprintf(out, ") ")?;
+ return z + expr(out, indent, *e.body)?;
+};