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:
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)?;