diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 95338b2a26..8b28607e0f 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -344,14 +344,14 @@ class BlockExpr : public Expr { /// `decls e` or `e .where decls` if @p where is `true`. class DeclExpr : public Expr { public: - DeclExpr(Loc loc, Ptrs&& decls, Ptr&& expr, bool where) + DeclExpr(Loc loc, Ptrs&& decls, Ptr&& expr, bool is_where) : Expr(loc) , decls_(std::move(decls)) , expr_(std::move(expr)) - , where_(where) {} + , is_where_(is_where) {} const auto& decls() const { return decls_; } - bool where() const { return where_; } + bool is_where() const { return is_where_; } const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; @@ -362,7 +362,7 @@ class DeclExpr : public Expr { Ptrs decls_; Ptr expr_; - bool where_; + bool is_where_; }; /// `.Type level` diff --git a/lit/regex/match_manual.thorin b/lit/regex/match_manual.thorin index 5716b989be..15d79967a0 100644 --- a/lit/regex/match_manual.thorin +++ b/lit/regex/match_manual.thorin @@ -17,11 +17,6 @@ .con .extern main[mem: %mem.M, argc: .I32, argv: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), exit : .Cn [%mem.M, .I32]] = (exit, match_argument) # (%core.icmp.ug (argc, 1I32)) (mem, 0I32) .where - .con error(mem: %mem.M, i : .I32) = - reject (mem, 0I32) - .where - .con reject[mem: %mem.M, .Idx Top] = exit (mem, 0I32); - .end .con match_argument[mem: %mem.M, .I32] = .let arg1 = %mem.lea (Top, ‹Top; %mem.Ptr («⊤:.Nat; .I8», 0)›, 0) (argv, 1I32); .let (`mem, to_match) = %mem.load (mem, arg1); @@ -45,10 +40,6 @@ .let is_end = %core.icmp.e (c, '\0'); (not_end, error)#is_end (mem, new_i) .where - .con not_a(mem: %mem.M, i: .I32) = - .let is_match_b = %core.icmp.e (c, 'b'); - (error, state1)#is_match_b (mem, i); - .con not_end(mem: %mem.M, i: .I32) = .let is_match_a = %core.icmp.e (c, 'a'); (not_a, state2)#is_match_a (mem, i) @@ -60,22 +51,30 @@ .let is_end = %core.icmp.e (c, '\0'); (not_end, accept)#is_end (mem, new_i) .where - .con not_a(mem: %mem.M, i: .I32) = - .let is_match_b = %core.icmp.e (c, 'b'); - (error, state1)#is_match_b (mem, i); - .con not_end(mem: %mem.M, i: .I32) = .let is_match_a = %core.icmp.e (c, 'a'); (not_a, state2)#is_match_a (mem, i); .con accept[mem: %mem.M, .I32] = exit (mem, 1I32); + + .con not_a(mem: %mem.M, i: .I32) = + .let is_match_b = %core.icmp.e (c, 'b'); + (error, state1)#is_match_b (mem, i); .end - .end + .end; + .con not_a(mem: %mem.M, i: .I32) = + .let is_match_b = %core.icmp.e (c, 'b'); + (error, state1)#is_match_b (mem, i); .end .end .end - .end + .end; + .con error(mem: %mem.M, i : .I32) = + reject (mem, 0I32) + .where + .con reject[mem: %mem.M, .Idx Top] = exit (mem, 0I32); + .end; .end // CHECK-NOT: %regex. diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 2c1f5464b3..6a345391f8 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -125,7 +125,10 @@ void LitExpr::bind(Scopes& s) const { } void DeclExpr::bind(Scopes& s) const { - for (const auto& decl : decls()) decl->bind(s); + if (is_where()) + for (const auto& decl : decls() | std::ranges::views::reverse) decl->bind(s); + else + for (const auto& decl : decls()) decl->bind(s); expr()->bind(s); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index d25e63703f..4007fdeeef 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -179,7 +179,10 @@ Ref LitExpr::emit_(Emitter& e) const { } Ref DeclExpr::emit_(Emitter& e) const { - for (const auto& decl : decls()) decl->emit(e); + if (is_where()) + for (const auto& decl : decls() | std::ranges::views::reverse) decl->emit(e); + else + for (const auto& decl : decls()) decl->emit(e); return expr()->emit(e); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index b981747bf0..a8220673fa 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -242,7 +242,12 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre lex(); auto decls = parse_decls(); lhs = ptr(track, std::move(decls), std::move(lhs), true); + + bool where = ahead().tag() == Tag::K_where; expect(Tag::K_end, "end of a .where declaration block"); + if (where) + ast().note(lhs->loc().anew_finis(), + "did you accidentally end your declaration expression with a ';'?"); return lhs; } default: return lhs; diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 5167278547..58b43b5e24 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -90,7 +90,7 @@ std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& DeclExpr::stream(Tab& tab, std::ostream& os) const { - if (where()) { + if (is_where()) { tab.println(os, "{} .where", S(tab, expr())); ++tab; for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get()));