hare

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

commit 01aaa1c2b5f5d91db545095b22b22f4d352fc83d
parent 259c1176016fafb3384a785156763c38c99ceb0a
Author: Alexey Yerin <yyp@disroot.org>
Date:   Sat, 11 Jun 2022 00:19:10 +0300

hare::parse: add tuple unpacking

Signed-off-by: Alexey Yerin <yyp@disroot.org>

Diffstat:
Mhare/ast/expr.ha | 22++++++++++++++++++++--
Mhare/parse/+test/expr.ha | 2++
Mhare/parse/expr.ha | 32+++++++++++++++++++++++++++++++-
Mhare/unit/process.ha | 5+++--
Mhare/unparse/expr.ha | 25+++++++++++++++++++++----
5 files changed, 77 insertions(+), 9 deletions(-)

diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha @@ -126,12 +126,18 @@ export type binarithm_expr = struct { // A single variable biding. // // foo: int = bar +// (foo, foo2): int = bar export type binding = struct { - name: str, + name: (str | binding_unpack), _type: nullable *_type, init: *expr, }; +// Tuple unpacking binding. +// +// (foo, _, bar) +export type binding_unpack = [](str | void); + // A variable binding expression. // // let foo: int = bar, ... @@ -473,7 +479,19 @@ case let e: expr => expr_finish(b.rvalue); case let b: binding_expr => for (let i = 0z; i < len(b.bindings); i += 1) { - free(b.bindings[i].name); + match (b.bindings[i].name) { + case let s: str => + free(s); + case let u: binding_unpack => + for (let i = 0z; i < len(u); i += 1) { + match (u[i]) { + case let s: str => + free(s); + case => void; + }; + }; + free(u); + }; type_finish(b.bindings[i]._type); expr_finish(b.bindings[i].init); }; diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha @@ -36,6 +36,8 @@ roundtrip("export fn main() void = { let x: int = 1337, y = 7331; const z: int = 42, q: int = 24; + const (foo, bar): (int, bool) = (42, true); + const (foo, _, bar): (int, uint, bool) = (42, 12u, true); 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 @@ -316,13 +316,43 @@ fn binarithm( return lvalue; }; +fn binding_unpack(lexer: *lex::lexer) (ast::binding_unpack | error) = { + let fields: ast::binding_unpack = []; + for (true) { + const (tok, value, _) = want(lexer, ltok::NAME, + ltok::UNDERSCORE)?; + if (tok == ltok::UNDERSCORE) { + append(fields, void); + } else { + append(fields, value as str); + }; + if (len(fields) == 1) { + want(lexer, ltok::COMMA)?; + } else { + match (try(lexer, ltok::COMMA)?) { + case void => break; + case lex::token => void; + }; + }; + }; + want(lexer, ltok::RPAREN)?; + return fields; +}; + 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; let bindings: []ast::binding = []; for (true) { - const name = want(lexer, ltok::NAME)?.1 as str; + const (tok, value, _) = want(lexer, ltok::NAME, ltok::LPAREN)?; + const name = switch (tok) { + case ltok::NAME => + yield value as str; + case ltok::LPAREN => + yield binding_unpack(lexer)?; + case => abort(); + }; const btype: nullable *ast::_type = if (try(lexer, ltok::COLON)? is lex::token) { yield alloc(_type(lexer)?); diff --git a/hare/unit/process.ha b/hare/unit/process.ha @@ -209,8 +209,9 @@ fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { }; const object = scope_insert(ctx, object { kind = object_kind::BIND, - ident = ast::ident_dup([item.name]), - name = ast::ident_dup([item.name]), + // TODO: tuple unpacking + ident = ast::ident_dup([item.name as str]), + name = ast::ident_dup([item.name as str]), _type = _type, ... }); diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -194,15 +194,32 @@ export fn expr( if (e.is_const) "const " else "let ")?; for (let i = 0z; i < len(e.bindings); i += 1) { let binding = e.bindings[i]; + match (binding.name) { + case let s: str => + z += fmt::fprint(out, s)?; + case let u: ast::binding_unpack => + z += fmt::fprint(out, "(")?; + for (let i = 0z; i < len(u); i += 1) { + match (u[i]) { + case let s: str => + z += fmt::fprint(out, s)?; + case void => + z += fmt::fprint(out, "_")?; + }; + if (i + 1 < len(u)) { + z += fmt::fprint(out, ", ")?; + }; + }; + z += fmt::fprint(out, ")")?; + }; z += match (binding._type) { - case null => - yield fmt::fprint(out, binding.name)?; case let t: *ast::_type => let z = 0z; - z += fmt::fprintf(out, "{}: ", - binding.name)?; + z += fmt::fprintf(out, ": ")?; z += _type(out, indent, *t)?; yield z; + case null => + yield 0z; }; z += fmt::fprint(out, " = ")?; z += expr(out, indent, *binding.init)?;