hare

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

commit abbddbb92bc983a79d9f23396d6cff90e1f5ceba
parent d5c8418cc83900114ef139ea3d9e24989c371460
Author: Sebastian <sebastian@sebsite.pw>
Date:   Tue, 17 Oct 2023 21:07:21 -0400

hare::*: implement local constant definitions

Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mhare/ast/expr.ha | 9++++++++-
Mhare/parse/+test/expr_test.ha | 1+
Mhare/parse/expr.ha | 31++++++++++++++++++++++++++-----
Mhare/unit/process.ha | 2+-
Mhare/unparse/expr.ha | 10++++++++--
5 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha @@ -144,12 +144,19 @@ export type binding = struct { // (foo, _, bar) export type binding_unpack = [](str | void); +// The kind of binding expression being used. +export type binding_kind = enum { + CONST, + DEF, + LET, +}; + // A variable binding expression. // // let foo: int = bar, ... export type binding_expr = struct { is_static: bool, - is_const: bool, + kind: binding_kind, bindings: []binding, }; diff --git a/hare/parse/+test/expr_test.ha b/hare/parse/+test/expr_test.ha @@ -40,6 +40,7 @@ const z: int = 42, q: int = 24; const (foo, bar): (int, bool) = (42, true); const (foo, _, bar): (int, uint, bool) = (42, 12u, true); + def X: int = 1337, y = 7331; static let p: int = 62893, o = 39826; static const w: int = 62893, t = 39826; }; diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -320,7 +320,17 @@ fn binding_unpack(lexer: *lex::lexer) (ast::binding_unpack | error) = { fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { const loc = lex::mkloc(lexer); - const is_const = want(lexer, ltok::LET, ltok::CONST)?.0 == ltok::CONST; + const tok = want(lexer, ltok::DEF, ltok::CONST, ltok::LET)?.0; + const kind = switch (tok) { + case ltok::DEF => + assert(!is_static); + yield ast::binding_kind::DEF; + case ltok::CONST => + yield ast::binding_kind::CONST; + case ltok::LET => + yield ast::binding_kind::LET; + case => abort(); // unreachable + }; let bindings: []ast::binding = []; for (true) { @@ -329,6 +339,10 @@ fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { case ltok::NAME => yield value as str; case ltok::LPAREN => + if (kind == ast::binding_kind::DEF) { + return syntaxerr(lex::mkloc(lexer), + "Can't use tuple unpacking with def"); + }; yield binding_unpack(lexer)?; case => abort(); }; @@ -354,7 +368,7 @@ fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { end = lex::prevloc(lexer), expr = ast::binding_expr { is_static = is_static, - is_const = is_const, + kind = kind, bindings = bindings, }, }; @@ -631,7 +645,7 @@ fn compound_expr(lexer: *lex::lexer) (ast::expr | error) = { }; fn stmt(lexer: *lex::lexer) (ast::expr | error) = { - const expr = match (try(lexer, ltok::DEFER, + const expr = match (try(lexer, ltok::DEFER, ltok::DEF, ltok::LET, ltok::CONST, ltok::STATIC)?) { case let tok: lex::token => yield switch (tok.0) { @@ -642,7 +656,7 @@ fn stmt(lexer: *lex::lexer) (ast::expr | error) = { end = lex::prevloc(lexer), expr = expr: ast::defer_expr, }; - case ltok::LET, ltok::CONST => + case ltok::DEF, ltok::CONST, ltok::LET => lex::unlex(lexer, tok); yield binding(lexer, false)?; case ltok::STATIC => @@ -667,12 +681,19 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { want(lexer, ltok::LPAREN)?; const bindings: nullable *ast::expr = - match (peek(lexer, ltok::LET, ltok::CONST, ltok::STATIC)?) { + match (peek(lexer, ltok::DEF, ltok::LET, ltok::CONST, + ltok::STATIC)?) { case void => yield null; case let tok: lex::token => let is_static = if (tok.0 == ltok::STATIC) { want(lexer, ltok::STATIC)?; + match (peek(lexer, ltok::LET, ltok::CONST)?) { + case lex::token => void; + case void => + want(lexer, ltok::LET, ltok::CONST)?; + abort(); // unreachable + }; yield true; } else false; const bindings = alloc(binding(lexer, is_static)?); diff --git a/hare/unit/process.ha b/hare/unit/process.ha @@ -174,7 +174,7 @@ fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = { fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const bind = aexpr.expr as ast::binding_expr; - assert(!bind.is_static && !bind.is_const); // TODO + assert(!bind.is_static && bind.kind == ast::binding_kind::LET); let bindings: bindings = []; for (let i = 0z; i < len(bind.bindings); i += 1) { diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -235,8 +235,14 @@ fn _expr(ctx: *context, syn: *synfunc, e: ast::expr) (size | io::error) = { z += syn(ctx, "static", synkind::KEYWORD)?; z += space(ctx)?; }; - z += syn(ctx, if (e.is_const) "const" else "let", - synkind::KEYWORD)?; + switch (e.kind) { + case ast::binding_kind::DEF => + z += syn(ctx, "def", synkind::KEYWORD)?; + case ast::binding_kind::CONST => + z += syn(ctx, "const", synkind::KEYWORD)?; + case ast::binding_kind::LET => + z += syn(ctx, "let", synkind::KEYWORD)?; + }; z += space(ctx)?; for (let i = 0z; i < len(e.bindings); i += 1) { let binding = e.bindings[i];