commit 99edd27a4cbefdab5debe6745c4672bb1575d428
parent de30fe2fcf07c7aa7921af384adf1aeb929c1de8
Author: Sebastian <sebastian@sebsite.pw>
Date: Sat, 9 Dec 2023 21:11:30 -0500
hare::*: support for/switch/match labels
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
4 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -281,6 +281,7 @@ export type for_expr = struct {
cond: *expr,
afterthought: nullable *expr,
body: *expr,
+ label: label,
};
// A free expression.
@@ -328,6 +329,7 @@ export type match_case = struct {
export type match_expr = struct {
value: *expr,
cases: []match_case,
+ label: label,
};
// An offset expression.
@@ -378,6 +380,7 @@ export type switch_case = struct {
export type switch_expr = struct {
value: *expr,
cases: []switch_case,
+ label: label,
};
// A unary operator
@@ -595,6 +598,7 @@ case let e: *expr =>
expr_finish(l);
free(l);
case let m: match_expr =>
+ free(m.label);
expr_finish(m.value);
free(m.value);
for (let i = 0z; i < len(m.cases); i += 1) {
@@ -629,6 +633,7 @@ case let e: *expr =>
expr_finish(s.end);
free(s.end);
case let s: switch_expr =>
+ free(s.label);
expr_finish(s.value);
free(s.value);
for (let i = 0z; i < len(s.cases); i += 1) {
diff --git a/hare/parse/+test/expr_test.ha b/hare/parse/+test/expr_test.ha
@@ -197,7 +197,7 @@
for (true) {
x;
};
- for (true) :label {
+ for :label (true) {
x;
};
for (let x = 0; x < 10) {
@@ -268,6 +268,9 @@
case =>
defer x;
};
+ switch :label (x) {
+ case => void;
+ };
};
");
};
@@ -286,7 +289,7 @@
case null => void;
case => abort();
};
- match (x) {
+ match :label (x) {
case let s: matchdata =>
return y;
case str =>
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -678,6 +678,10 @@ fn stmt(lexer: *lex::lexer) (ast::expr | error) = {
fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
const tok = want(lexer, ltok::FOR)?;
+ const label = if (try(lexer, ltok::COLON)? is lex::token) {
+ const tok = want(lexer, ltok::NAME)?;
+ yield tok.1 as str;
+ } else "";
want(lexer, ltok::LPAREN)?;
const bindings: nullable *ast::expr =
@@ -721,6 +725,7 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
cond = cond,
afterthought = afterthought,
body = body,
+ label = label,
},
};
};
@@ -1109,6 +1114,11 @@ fn static_expr(lexer: *lex::lexer) (ast::expr | error) = {
fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = {
const start = want(lexer, ltok::SWITCH)?;
+ const label = if (try(lexer, ltok::COLON)? is lex::token) {
+ const tok = want(lexer, ltok::NAME)?;
+ yield tok.1 as str;
+ } else "";
+
want(lexer, ltok::LPAREN)?;
const value = expr(lexer)?;
want(lexer, ltok::RPAREN)?;
@@ -1159,6 +1169,7 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = {
expr = ast::switch_expr {
value = alloc(value),
cases = cases,
+ label = label,
},
};
};
@@ -1204,6 +1215,10 @@ fn match_case(lexer: *lex::lexer) (ast::match_case | error) = {
fn match_expr(lexer: *lex::lexer) (ast::expr | error) = {
const start = want(lexer, ltok::MATCH)?;
+ const label = if (try(lexer, ltok::COLON)? is lex::token) {
+ const tok = want(lexer, ltok::NAME)?;
+ yield tok.1 as str;
+ } else "";
want(lexer, ltok::LPAREN)?;
const value = expr(lexer)?;
want(lexer, ltok::RPAREN)?;
@@ -1221,8 +1236,9 @@ fn match_expr(lexer: *lex::lexer) (ast::expr | error) = {
start = start.2,
end = lex::prevloc(lexer),
expr = ast::match_expr {
- value = alloc(value),
- cases = cases,
+ value = alloc(value),
+ cases = cases,
+ label = label,
},
};
};
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -743,6 +743,11 @@ fn for_expr(
) (size | io::error) = {
let z = syn(ctx, "for", synkind::KEYWORD)?;
z += space(ctx)?;
+ if (e.label != "") {
+ z += syn(ctx, ":", synkind::LABEL)?;
+ z += syn(ctx, e.label, synkind::LABEL)?;
+ z += space(ctx)?;
+ };
z += syn(ctx, "(", synkind::PUNCTUATION)?;
match (e.bindings) {
case null => void;
@@ -775,6 +780,11 @@ fn switch_expr(
) (size | io::error) = {
let z = syn(ctx, "switch", synkind::KEYWORD)?;
z += space(ctx)?;
+ if (e.label != "") {
+ z += syn(ctx, ":", synkind::LABEL)?;
+ z += syn(ctx, e.label, synkind::LABEL)?;
+ z += space(ctx)?;
+ };
z += syn(ctx, "(", synkind::PUNCTUATION)?;
z += _expr(ctx, syn, e.value)?;
z += syn(ctx, ")", synkind::PUNCTUATION)?;
@@ -816,6 +826,11 @@ fn match_expr(
) (size | io::error) = {
let z = syn(ctx, "match", synkind::KEYWORD)?;
z += space(ctx)?;
+ if (e.label != "") {
+ z += syn(ctx, ":", synkind::LABEL)?;
+ z += syn(ctx, e.label, synkind::LABEL)?;
+ z += space(ctx)?;
+ };
z += syn(ctx, "(", synkind::PUNCTUATION)?;
z += _expr(ctx, syn, e.value)?;
z += syn(ctx, ")", synkind::PUNCTUATION)?;