hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mhare/ast/expr.ha | 5+++++
Mhare/parse/+test/expr_test.ha | 7+++++--
Mhare/parse/expr.ha | 20++++++++++++++++++--
Mhare/unparse/expr.ha | 15+++++++++++++++
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)?;