From eaa470df8a6496dcc99c0f43bd18ca3dba71f0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 8 Mar 2024 02:39:22 +0100 Subject: [PATCH 01/95] thorin/fe -> thorin/ast Also puts this stuff in thorin::ast --- examples/hello.cpp | 4 ++-- gtest/automaton.cpp | 12 +++++------ gtest/lexer.cpp | 3 ++- gtest/restricted_dep_types.cpp | 6 +++--- gtest/test.cpp | 6 +++--- include/thorin/{fe => ast}/ast.h | 33 ++++++++++++++++++++++------- include/thorin/{fe => ast}/lexer.h | 6 +++++- include/thorin/{fe => ast}/parser.h | 10 ++++----- include/thorin/{fe => ast}/scopes.h | 4 ++++ include/thorin/{fe => ast}/tok.h | 3 +++ src/thorin/CMakeLists.txt | 10 ++++----- src/thorin/{fe => ast}/ast.cpp | 8 +++---- src/thorin/{fe => ast}/lexer.cpp | 6 +++--- src/thorin/{fe => ast}/parser.cpp | 6 +++--- src/thorin/{fe => ast}/scopes.cpp | 6 +++--- src/thorin/{fe => ast}/tok.cpp | 6 +++--- src/thorin/cli/main.cpp | 4 ++-- src/thorin/dump.cpp | 8 ++++--- 18 files changed, 86 insertions(+), 55 deletions(-) rename include/thorin/{fe => ast}/ast.h (86%) rename include/thorin/{fe => ast}/lexer.h (96%) rename include/thorin/{fe => ast}/parser.h (97%) rename include/thorin/{fe => ast}/scopes.h (95%) rename include/thorin/{fe => ast}/tok.h (99%) rename src/thorin/{fe => ast}/ast.cpp (95%) rename src/thorin/{fe => ast}/lexer.cpp (99%) rename src/thorin/{fe => ast}/parser.cpp (99%) rename src/thorin/{fe => ast}/scopes.cpp (92%) rename src/thorin/{fe => ast}/tok.cpp (92%) diff --git a/examples/hello.cpp b/examples/hello.cpp index 51870900ad..d1f3312fde 100644 --- a/examples/hello.cpp +++ b/examples/hello.cpp @@ -2,7 +2,7 @@ #include -#include +#include #include #include @@ -17,7 +17,7 @@ int main(int, char**) { auto& world = driver.world(); driver.log().set(&std::cerr).set(Log::Level::Debug); - auto parser = Parser(world); + auto parser = ast::Parser(world); for (auto plugin : {"compile", "core"}) parser.plugin(plugin); // .Cn [%mem.M, I32, %mem.Ptr (I32, 0) .Cn [%mem.M, I32]] diff --git a/gtest/automaton.cpp b/gtest/automaton.cpp index c37bd4009e..f7461dfbfb 100644 --- a/gtest/automaton.cpp +++ b/gtest/automaton.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include #include @@ -156,7 +156,7 @@ TEST(Automaton, NFAAorBplusA) { TEST(Automaton, Regex2NFA) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); auto pattern = w.call( @@ -169,7 +169,7 @@ TEST(Automaton, Regex2NFA) { TEST(Automaton, Regex2NFAAorBplusA) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); auto pattern = w.call( @@ -189,7 +189,7 @@ TEST(Automaton, Regex2NFAAorBplusA) { TEST(Automaton, Regex2NFA1or5or9) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); // %regex.disj 2 (%regex.disj 2 (%regex.range ‹2; 49:(.Idx 256)›, %regex.range ‹2; 53:(.Idx 256)›), %regex.range ‹2; @@ -210,7 +210,7 @@ TEST(Automaton, Regex2NFA1or5or9) { TEST(Automaton, Regex2NFANot1or5or9) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); // %regex.not_ (%regex.disj 2 (%regex.disj 2 (%regex.range ‹2; 49:(.Idx 256)›, %regex.range ‹2; 53:(.Idx 256)›), @@ -231,7 +231,7 @@ TEST(Automaton, Regex2NFANot1or5or9) { TEST(Automaton, Regex2NFANotwds) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); // %regex.not_ (%regex.conj 3 (%regex.cls.w, %regex.cls.d, %regex.cls.s)) diff --git a/gtest/lexer.cpp b/gtest/lexer.cpp index ea6de7bedb..8d1c7ec91a 100644 --- a/gtest/lexer.cpp +++ b/gtest/lexer.cpp @@ -5,10 +5,11 @@ #include -#include +#include using namespace std::literals; using namespace thorin; +using namespace thorin::ast; TEST(Lexer, Toks) { Driver driver; diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index 7bb770a380..c8be966791 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include @@ -28,7 +28,7 @@ TEST(RestrictedDependentTypes, join_singleton) { auto test_on_world = [](auto test) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math"}) parser.plugin(plugin); auto i32_t = w.type_int(32); @@ -221,7 +221,7 @@ TEST(RestrictedDependentTypes, join_singleton) { TEST(RestrictedDependentTypes, ll) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "mem", "core", "math"}) parser.plugin(plugin); auto mem_t = w.annex(); diff --git a/gtest/test.cpp b/gtest/test.cpp index a7e2c62585..4a984bede5 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include @@ -19,7 +19,7 @@ using namespace thorin::plug; TEST(Zip, fold) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); std::istringstream iss(".plugin core;" ".let _32 = 4294967296;" @@ -89,7 +89,7 @@ TEST(Annex, split) { TEST(trait, idx) { Driver driver; World& w = driver.world(); - auto parser = Parser(w); + auto parser = ast::Parser(w); parser.plugin("core"); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'00FF_n))), 1); diff --git a/include/thorin/fe/ast.h b/include/thorin/ast/ast.h similarity index 86% rename from include/thorin/fe/ast.h rename to include/thorin/ast/ast.h index a559dd4646..a97daa59f6 100644 --- a/include/thorin/fe/ast.h +++ b/include/thorin/ast/ast.h @@ -5,7 +5,9 @@ #include "thorin/def.h" -#include "thorin/fe/tok.h" +#include "thorin/ast/tok.h" + +#include "fe/cast.h" namespace thorin { @@ -13,31 +15,45 @@ class Infer; class Sigma; class World; -class Scopes; using Def2Fields = DefMap>; +namespace ast { + +class Scopes; + +class Node : public fe::RuntimeCast { +protected: + Node(Dbg dbg) + : dbg_(dbg) {} + virtual ~Node() {} + +public: + Dbg dbg() const { return dbg_; } + Loc loc() const { return dbg_.loc; } + Sym sym() const { return dbg_.sym; } + +private: + Dbg dbg_; +}; + /* * Pattern */ -class Ptrn { +class Ptrn : public Node { public: Ptrn(Dbg dbg, bool rebind, const Def* type) - : dbg_(dbg) + : Node(dbg) , rebind_(rebind) , type_(type) {} virtual ~Ptrn() {} - Dbg dbg() const { return dbg_; } - Loc loc() const { return dbg_.loc; } - Sym sym() const { return dbg_.sym; } bool rebind() const { return rebind_; } bool is_anonymous() const { return sym() == '_'; } virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; virtual const Def* type(World&, Def2Fields&) const = 0; protected: - Dbg dbg_; bool rebind_; mutable const Def* type_; }; @@ -74,4 +90,5 @@ class TuplePtrn : public Ptrn { Def* decl_ = nullptr; }; +} // namespace ast } // namespace thorin diff --git a/include/thorin/fe/lexer.h b/include/thorin/ast/lexer.h similarity index 96% rename from include/thorin/fe/lexer.h rename to include/thorin/ast/lexer.h index d5bec5b556..9133a9d054 100644 --- a/include/thorin/fe/lexer.h +++ b/include/thorin/ast/lexer.h @@ -5,11 +5,14 @@ #include #include -#include "thorin/fe/tok.h" +#include "thorin/ast/tok.h" namespace thorin { + class World; +namespace ast { + class Lexer : public fe::Lexer<3, Lexer> { using Super = fe::Lexer<3, Lexer>; @@ -62,4 +65,5 @@ class Lexer : public fe::Lexer<3, Lexer> { friend class fe::Lexer<3, Lexer>; }; +} // namespace ast } // namespace thorin diff --git a/include/thorin/fe/parser.h b/include/thorin/ast/parser.h similarity index 97% rename from include/thorin/fe/parser.h rename to include/thorin/ast/parser.h index cde7d0e5be..29f74c200c 100644 --- a/include/thorin/fe/parser.h +++ b/include/thorin/ast/parser.h @@ -4,11 +4,11 @@ #include "thorin/driver.h" -#include "thorin/fe/ast.h" -#include "thorin/fe/lexer.h" -#include "thorin/fe/scopes.h" +#include "thorin/ast/ast.h" +#include "thorin/ast/lexer.h" +#include "thorin/ast/scopes.h" -namespace thorin { +namespace thorin::ast { constexpr size_t Look_Ahead = 2; @@ -143,4 +143,4 @@ class Parser : public fe::Parser { friend class fe::Parser; }; -} // namespace thorin +} // namespace thorin::ast diff --git a/include/thorin/fe/scopes.h b/include/thorin/ast/scopes.h similarity index 95% rename from include/thorin/fe/scopes.h rename to include/thorin/ast/scopes.h index 43c7d70be1..b90481476d 100644 --- a/include/thorin/fe/scopes.h +++ b/include/thorin/ast/scopes.h @@ -7,6 +7,9 @@ namespace thorin { class Def; + +namespace ast { + class Ptrn; class Scopes { @@ -28,4 +31,5 @@ class Scopes { std::deque scopes_; }; +} // namespace ast } // namespace thorin diff --git a/include/thorin/fe/tok.h b/include/thorin/ast/tok.h similarity index 99% rename from include/thorin/fe/tok.h rename to include/thorin/ast/tok.h index bc82fab7c5..17698e81fc 100644 --- a/include/thorin/fe/tok.h +++ b/include/thorin/ast/tok.h @@ -10,6 +10,8 @@ namespace thorin { class Def; class Lit; +namespace ast { + // clang-format off #define THORIN_KEY(m) \ m(K_module, ".module") \ @@ -194,4 +196,5 @@ class Tok { }; }; +} // namespace ast } // namespace thorin diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index dc37aeca2e..5329576968 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -21,11 +21,11 @@ target_sources(libthorin analyses/scope.cpp be/dot/dot.cpp be/h/bootstrap.cpp - fe/ast.cpp - fe/lexer.cpp - fe/parser.cpp - fe/scopes.cpp - fe/tok.cpp + ast/ast.cpp + ast/lexer.cpp + ast/parser.cpp + ast/scopes.cpp + ast/tok.cpp pass/beta_red.cpp pass/eta_exp.cpp pass/eta_red.cpp diff --git a/src/thorin/fe/ast.cpp b/src/thorin/ast/ast.cpp similarity index 95% rename from src/thorin/fe/ast.cpp rename to src/thorin/ast/ast.cpp index 584657edbd..22ab39d1f0 100644 --- a/src/thorin/fe/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -1,13 +1,13 @@ -#include "thorin/fe/ast.h" +#include "thorin/ast/ast.h" #include "thorin/check.h" #include "thorin/def.h" #include "thorin/rewrite.h" #include "thorin/world.h" -#include "thorin/fe/scopes.h" +#include "thorin/ast/scopes.h" -namespace thorin { +namespace thorin::ast { /* * bind @@ -87,4 +87,4 @@ const Def* TuplePtrn::type(World& world, Def2Fields& def2fields) const { return type_ = sigma; } -} // namespace thorin +} // namespace thorin::ast diff --git a/src/thorin/fe/lexer.cpp b/src/thorin/ast/lexer.cpp similarity index 99% rename from src/thorin/fe/lexer.cpp rename to src/thorin/ast/lexer.cpp index bc85aee217..fbe9f39cbc 100644 --- a/src/thorin/fe/lexer.cpp +++ b/src/thorin/ast/lexer.cpp @@ -1,10 +1,10 @@ -#include "thorin/fe/lexer.h" +#include "thorin/ast/lexer.h" #include "thorin/world.h" using namespace std::literals; -namespace thorin { +namespace thorin::ast { namespace utf8 = fe::utf8; using Tag = Tok::Tag; @@ -348,4 +348,4 @@ void Lexer::emit_md(bool start_of_file) { Sym Lexer::sym() { return world().sym(str_); } -} // namespace thorin +} // namespace thorin::ast diff --git a/src/thorin/fe/parser.cpp b/src/thorin/ast/parser.cpp similarity index 99% rename from src/thorin/fe/parser.cpp rename to src/thorin/ast/parser.cpp index 0dd946f226..bd15f89329 100644 --- a/src/thorin/fe/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -1,4 +1,4 @@ -#include "thorin/fe/parser.h" +#include "thorin/ast/parser.h" #include #include @@ -15,7 +15,7 @@ using namespace std::string_literals; -namespace thorin { +namespace thorin::ast { using Tag = Tok::Tag; @@ -981,4 +981,4 @@ void Parser::parse_pi_decl() { expect(Tag::T_semicolon, "end of a pi declaration"); } -} // namespace thorin +} // namespace thorin::ast diff --git a/src/thorin/fe/scopes.cpp b/src/thorin/ast/scopes.cpp similarity index 92% rename from src/thorin/fe/scopes.cpp rename to src/thorin/ast/scopes.cpp index db76e27d80..50a7ca6792 100644 --- a/src/thorin/fe/scopes.cpp +++ b/src/thorin/ast/scopes.cpp @@ -1,8 +1,8 @@ -#include "thorin/fe/scopes.h" +#include "thorin/ast/scopes.h" #include "thorin/world.h" -namespace thorin { +namespace thorin::ast { void Scopes::pop() { assert(!scopes_.empty()); @@ -36,4 +36,4 @@ void Scopes::bind(Scope* scope, Dbg dbg, const Def* def, bool rebind) { } } -} // namespace thorin +} // namespace thorin::ast diff --git a/src/thorin/fe/tok.cpp b/src/thorin/ast/tok.cpp similarity index 92% rename from src/thorin/fe/tok.cpp rename to src/thorin/ast/tok.cpp index 501165a34c..70e2bd7918 100644 --- a/src/thorin/fe/tok.cpp +++ b/src/thorin/ast/tok.cpp @@ -1,11 +1,11 @@ -#include "thorin/fe/tok.h" +#include "thorin/ast/tok.h" #include #include "thorin/lam.h" #include "thorin/tuple.h" -namespace thorin { +namespace thorin::ast { std::string_view Tok::tag2str(Tok::Tag tag) { switch (tag) { @@ -37,4 +37,4 @@ Tok::Prec Tok::prec(const Def* def) { } // clang-format on -} // namespace thorin +} // namespace thorin::ast diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index d656cd3d8e..e36e05bbdc 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -9,9 +9,9 @@ #include "thorin/config.h" #include "thorin/driver.h" +#include "thorin/ast/parser.h" #include "thorin/be/dot/dot.h" #include "thorin/be/h/bootstrap.h" -#include "thorin/fe/parser.h" #include "thorin/pass/optimize.h" #include "thorin/pass/pass.h" #include "thorin/pass/pipelinebuilder.h" @@ -132,7 +132,7 @@ int main(int argc, char** argv) { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); - auto parser = Parser(world); + auto parser = ast::Parser(world); parser.import(driver.sym(input), os[Md]); if (auto dep = os[D]) { diff --git a/src/thorin/dump.cpp b/src/thorin/dump.cpp index af61f2459d..4dcda2d172 100644 --- a/src/thorin/dump.cpp +++ b/src/thorin/dump.cpp @@ -5,7 +5,7 @@ #include "thorin/driver.h" #include "thorin/analyses/deptree.h" -#include "thorin/fe/tok.h" +#include "thorin/ast/tok.h" #include "thorin/util/util.h" using namespace std::literals; @@ -90,10 +90,12 @@ template struct LRPrec { friend std::ostream& operator<<(std::ostream& os, const LRPrec& p) { if constexpr (L) { - if (Inline(p.l) && Tok::prec(Tok::prec(p.r))[0] > Tok::prec(p.r)) return print(os, "({})", p.l); + if (Inline(p.l) && ast::Tok::prec(ast::Tok::prec(p.r))[0] > ast::Tok::prec(p.r)) + return print(os, "({})", p.l); return print(os, "{}", p.l); } else { - if (Inline(p.r) && Tok::prec(p.l) > Tok::prec(Tok::prec(p.l))[1]) return print(os, "({})", p.r); + if (Inline(p.r) && ast::Tok::prec(p.l) > ast::Tok::prec(ast::Tok::prec(p.l))[1]) + return print(os, "({})", p.r); return print(os, "{}", p.r); } } From 27351b8d675cd915cd6470630b7b3f57ef1908ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 8 Mar 2024 02:54:12 +0100 Subject: [PATCH 02/95] stubbing ast --- include/thorin/ast/ast.h | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index a97daa59f6..c759342e53 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -90,5 +90,81 @@ class TuplePtrn : public Ptrn { Def* decl_ = nullptr; }; +/* + * Expr + */ + +#if 0 + +class Expr : public Node { +protected: + Expr(Dbg dbg) + : Node(dbg) {} +}; + +// lam + +class Pi : public Expr { +public: +private: +}; + +class Lam : public Expr { +public: + Lam(Dbg dbg, Tok::Tag tag, Ptrns&& domains, Expr* codom, Expr* filter, Expr* body) + : Expr(dbg) + , tag_(tag) + , domains_(std::move(domains)) + , codom_(std::move(codom)) + , filter_(std::move(filter)) + , body_(std::move(body)) {} + + Tok::Tag tag() const { return tag_; } + const auto& domains() const { return domains_; } + Expr* codom() const { return codom_; } + Expr* filter() const { return filter_; } + Expr* body() const { return body_; } + +private: + Tok::Tag tag_; + Ptrns domains_; + Expr* codom_; + Expr* filter_; + Expr* body_; +}; + +class App : public Expr { +public: + App(Dbg dbg, Expr* callee, Expr* arg) + : Expr(dbg) + , callee_(callee) + , arg_(arg) {} + + Expr* callee() const { return callee_; } + Expr* arg() const { return arg_; } + +private: + Expr* callee_; + Expr* arg_;; +}; + +// tuple + +class Sigma : public Expr { +public: +private: +}; + +class Tuple : public Expr { +public: +private: +}; + +class Extract : public Expr { +public: +private: +}; +#endif + } // namespace ast } // namespace thorin From 3e7efa150b46cf985db77cd721391abd8b89d788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 25 Mar 2024 02:51:46 +0100 Subject: [PATCH 03/95] wip: AST --- examples/hello.cpp | 2 +- include/thorin/ast/ast.h | 68 +++++++++++++++++++++++-------- include/thorin/ast/parser.h | 6 ++- include/thorin/plug/regex/regex.h | 7 ---- src/thorin/ast/ast.cpp | 6 +++ src/thorin/ast/parser.cpp | 41 ++++++++++--------- 6 files changed, 83 insertions(+), 47 deletions(-) diff --git a/examples/hello.cpp b/examples/hello.cpp index c84c6e3a2f..5daea14a1d 100644 --- a/examples/hello.cpp +++ b/examples/hello.cpp @@ -17,7 +17,7 @@ int main(int, char**) { auto& w = driver.world(); driver.log().set(&std::cerr).set(Log::Level::Debug); - auto parser = ast::Parser(world); + auto parser = ast::Parser(w); for (auto plugin : {"compile", "core"}) parser.plugin(plugin); // .Cn [%mem.M, I32, %mem.Ptr (I32, 0) .Cn [%mem.M, I32]] diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index c759342e53..ba035e5b20 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -7,10 +7,12 @@ #include "thorin/ast/tok.h" +#include "fe/arena.h" #include "fe/cast.h" namespace thorin { +class Driver; class Infer; class Sigma; class World; @@ -19,20 +21,52 @@ using Def2Fields = DefMap>; namespace ast { +namespace ir = thorin; + +template using Ptr = fe::Arena::Ptr; +template using Ptrs = std::deque>; + +class AST { +public: + AST(World& world) + : world_(world) {} + + World& world() { return world_; } + Driver& driver(); + + /// @name Sym + ///@{ + Sym sym(std::string_view); + Sym sym(const char*); + Sym sym(const std::string&); + ///@} + + template auto ptr(Args&&... args) { + return arena_.mk(std::forward(args)...); + } + +private: + World& world_; + fe::Arena arena_; +}; + class Scopes; class Node : public fe::RuntimeCast { protected: - Node(Dbg dbg) - : dbg_(dbg) {} + Node(AST& ast, Dbg dbg) + : ast_(ast) + , dbg_(dbg) {} virtual ~Node() {} public: + AST& ast() const { return ast_; } Dbg dbg() const { return dbg_; } Loc loc() const { return dbg_.loc; } Sym sym() const { return dbg_.sym; } private: + AST& ast_; Dbg dbg_; }; @@ -42,8 +76,8 @@ class Node : public fe::RuntimeCast { class Ptrn : public Node { public: - Ptrn(Dbg dbg, bool rebind, const Def* type) - : Node(dbg) + Ptrn(AST& ast, Dbg dbg, bool rebind, const Def* type) + : Node(ast, dbg) , rebind_(rebind) , type_(type) {} virtual ~Ptrn() {} @@ -62,8 +96,8 @@ using Ptrns = std::deque>; class IdPtrn : public Ptrn { public: - IdPtrn(Dbg dbg, bool rebind, const Def* type) - : Ptrn(dbg, rebind, type) {} + IdPtrn(AST& ast, Dbg dbg, bool rebind, const Def* type) + : Ptrn(ast, dbg, rebind, type) {} void bind(Scopes&, const Def*, bool rebind = false) const override; const Def* type(World&, Def2Fields&) const override; @@ -71,8 +105,8 @@ class IdPtrn : public Ptrn { class TuplePtrn : public Ptrn { public: - TuplePtrn(Dbg dbg, bool rebind, Ptrns&& ptrns, const Def* type, std::vector&& infers, Def* decl) - : Ptrn(dbg, rebind, type) + TuplePtrn(AST& ast, Dbg dbg, bool rebind, Ptrns&& ptrns, const Def* type, std::vector&& infers, Def* decl) + : Ptrn(ast, dbg, rebind, type) , ptrns_(std::move(ptrns)) , infers_(std::move(infers)) , decl_(decl) {} @@ -94,12 +128,10 @@ class TuplePtrn : public Ptrn { * Expr */ -#if 0 - class Expr : public Node { protected: - Expr(Dbg dbg) - : Node(dbg) {} + Expr(AST& ast, Dbg dbg) + : Node(ast, dbg) {} }; // lam @@ -111,8 +143,8 @@ class Pi : public Expr { class Lam : public Expr { public: - Lam(Dbg dbg, Tok::Tag tag, Ptrns&& domains, Expr* codom, Expr* filter, Expr* body) - : Expr(dbg) + Lam(AST& ast, Dbg dbg, Tok::Tag tag, Ptrns&& domains, Expr* codom, Expr* filter, Expr* body) + : Expr(ast, dbg) , tag_(tag) , domains_(std::move(domains)) , codom_(std::move(codom)) @@ -135,8 +167,8 @@ class Lam : public Expr { class App : public Expr { public: - App(Dbg dbg, Expr* callee, Expr* arg) - : Expr(dbg) + App(AST& ast, Dbg dbg, Expr* callee, Expr* arg) + : Expr(ast, dbg) , callee_(callee) , arg_(arg) {} @@ -145,11 +177,13 @@ class App : public Expr { private: Expr* callee_; - Expr* arg_;; + Expr* arg_; + ; }; // tuple +#if 0 class Sigma : public Expr { public: private: diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 29f74c200c..708fbf21e8 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -34,6 +34,7 @@ class Parser : public fe::Parser { public: Parser(World& world) : world_(world) + , ast_(world) , anonymous_(world.sym("_")) , return_(world.sym("return")) {} @@ -87,11 +88,11 @@ class Parser : public fe::Parser { Ref parse_sigma_expr(); Ref parse_tuple_expr(); Ref parse_type_expr(); - Pi* parse_pi_expr(Pi* = nullptr); + ir::Pi* parse_pi_expr(ir::Pi* = nullptr); Ref parse_lit_expr(); Ref parse_insert_expr(); Ref parse_ret_expr(); - Lam* parse_lam(bool decl = false); + ir::Lam* parse_lam(bool decl = false); ///@} /// @name parse ptrns @@ -134,6 +135,7 @@ class Parser : public fe::Parser { ///@} World& world_; + AST ast_; Lexer* lexer_ = nullptr; Scopes scopes_; Def2Fields def2fields_; diff --git a/include/thorin/plug/regex/regex.h b/include/thorin/plug/regex/regex.h index 4e33a228c3..2fedc11cad 100644 --- a/include/thorin/plug/regex/regex.h +++ b/include/thorin/plug/regex/regex.h @@ -1,10 +1,3 @@ #pragma once #include "thorin/plug/regex/autogen.h" - -namespace thorin { -template<> struct Axiom::Match { - using type = Axiom; -}; - -} // namespace thorin diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 1eec96dd50..d15fd5713e 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -2,6 +2,7 @@ #include "thorin/check.h" #include "thorin/def.h" +#include "thorin/driver.h" #include "thorin/rewrite.h" #include "thorin/world.h" @@ -9,6 +10,11 @@ namespace thorin::ast { +Driver& AST::driver() { return world().driver(); } +Sym AST::sym(const char* s) { return driver().sym(s); } +Sym AST::sym(std::string_view s) { return driver().sym(s); } +Sym AST::sym(const std::string& s) { return driver().sym(s); } + /* * bind */ diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 00ec48cab2..e4753d3c62 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -351,7 +351,7 @@ Ref Parser::parse_type_expr() { return world().type(level)->set(track.loc()); } -Pi* Parser::parse_pi_expr(Pi* outer) { +ir::Pi* Parser::parse_pi_expr(ir::Pi* outer) { auto track = tracker(); auto tok = lex(); @@ -363,8 +363,8 @@ Pi* Parser::parse_pi_expr(Pi* outer) { default: fe::unreachable(); } - Pi* first = nullptr; - std::deque pis; + ir::Pi* first = nullptr; + std::deque pis; scopes_.push(); do { auto implicit = (bool)accept(Tag::T_dot); @@ -410,7 +410,7 @@ Pi* Parser::parse_pi_expr(Pi* outer) { return first; } -Lam* Parser::parse_lam(bool is_decl) { +ir::Lam* Parser::parse_lam(bool is_decl) { auto track = tracker(); auto tok = lex(); auto prec = tok.isa(Tag::K_cn) || tok.isa(Tag::K_con) ? Tok::Prec::Bot : Tok::Prec::Pi; @@ -431,10 +431,10 @@ Lam* Parser::parse_lam(bool is_decl) { auto [dbg, anx] = is_decl ? parse_name(entity) : std::pair(Dbg{prev_, anonymous_}, false); auto outer = scopes_.curr(); - Lam* decl = nullptr; + ir::Lam* decl = nullptr; if (auto def = scopes_.query(dbg)) { - if (auto lam = def->isa_mut()) + if (auto lam = def->isa_mut()) decl = lam; else error(dbg.loc, "'{}' has not been declared as a function", dbg.sym); @@ -442,7 +442,7 @@ Lam* Parser::parse_lam(bool is_decl) { std::unique_ptr dom_p; scopes_.push(); - std::deque> funs; + std::deque> funs; do { const Def* filter = accept(Tag::T_bang) ? world().lit_tt() : nullptr; bool implicit = (bool)accept(Tag::T_dot); @@ -561,7 +561,7 @@ Ref Parser::parse_ret_expr() { auto cn = parse_expr("continuation expression of a ret expression"); expect(Tag::T_dollar, "separator of a ret expression"); - if (auto ret_pi = Pi::ret_pi(cn->type())) { + if (auto ret_pi = ir::Pi::ret_pi(cn->type())) { auto arg = parse_expr("argument of ret expression"); expect(Tag::T_semicolon, "let expression"); auto lam = world().mut_lam(ret_pi); @@ -663,7 +663,7 @@ std::unique_ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok sym = eat(Tag::M_id).sym(); eat(Tag::T_colon); auto type = parse_expr(ctxt, prec); - return std::make_unique(dbg(track, sym), rebind, type); + return std::make_unique(ast_, dbg(track, sym), rebind, type); } else { // p -> s b -> e where e == id // p -> 's @@ -671,18 +671,18 @@ std::unique_ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok // p -> s // p -> 's sym = eat(Tag::M_id).sym(); - return std::make_unique(dbg(track, sym), rebind, nullptr); + return std::make_unique(ast_, dbg(track, sym), rebind, nullptr); } else { // b -> e where e == id auto type = parse_expr(ctxt, prec); - return std::make_unique(dbg(track, sym), rebind, type); + return std::make_unique(ast_, dbg(track, sym), rebind, type); } } } else if (b) { // b -> e where e != id if (backtick) error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding"); auto type = parse_expr(ctxt, prec); - return std::make_unique(dbg(track, sym), rebind, type); + return std::make_unique(ast_, dbg(track, sym), rebind, type); } else if (!ctxt.empty()) { // p -> ↯ syntax_err("pattern", ctxt); @@ -719,7 +719,7 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, auto tok = sym_toks[i]; infers.emplace_back(world().mut_infer(type)->set(tok.dbg())); ops.emplace_back(type); - auto ptrn = std::make_unique(tok.dbg(), false, type); + auto ptrn = std::make_unique(ast_, tok.dbg(), false, type); if (i != e - 1) ptrn->bind(scopes_, infers.back()); // last element will be bound above ptrns.emplace_back(std::move(ptrn)); } @@ -734,14 +734,14 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, } auto [_, r] = Tok::prec(Tok::Prec::App); auto expr = parse_infix_expr(track, lhs, r); - ptrn = std::make_unique(dbg(track, anonymous_), false, expr); + ptrn = std::make_unique(ast_, dbg(track, anonymous_), false, expr); } else { ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); auto type = ptrn->type(world(), def2fields_); if (b) { // If we are able to parse more stuff, we got an expression instead of just a binder. if (auto expr = parse_infix_expr(track, type); expr != type) - ptrn = std::make_unique(dbg(track, anonymous_), false, expr); + ptrn = std::make_unique(ast_, dbg(track, anonymous_), false, expr); } } @@ -753,7 +753,8 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, scopes_.pop(); // TODO parse type - return std::make_unique(dbg(track, sym), rebind, std::move(ptrns), nullptr, std::move(infers), decl); + return std::make_unique(ast_, dbg(track, sym), rebind, std::move(ptrns), nullptr, std::move(infers), + decl); } /* @@ -807,9 +808,9 @@ void Parser::parse_ax_decl() { error(dbg.loc, "cannot extend subs of axiom '{}' because it was declared as a subless axiom", dbg.sym); auto type = parse_type_ascr("type ascription of an axiom"); - if (!is_new && annex.pi != (type->isa() != nullptr)) + if (!is_new && annex.pi != (type->isa() != nullptr)) error(dbg.loc, "all declarations of annex '{}' have to be function types if any is", dbg.sym); - annex.pi = type->isa() != nullptr; + annex.pi = type->isa() != nullptr; Sym normalizer; if (ahead().isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) { @@ -946,9 +947,9 @@ void Parser::parse_pi_decl() { auto type = accept(Tag::T_colon) ? parse_expr("type of a pi declaration") : world().type(); if (accept(Tag::T_assign)) { - Pi* pi; + ir::Pi* pi; if (auto def = scopes_.query(dbg)) { - if (auto mut = def->isa_mut()) { + if (auto mut = def->isa_mut()) { if (!Check::alpha(mut->type(), type)) error(dbg.loc, "'{}' of type '{}' has been redeclared with a different type '{}'; here: {}", dbg.sym, mut->type(), type, mut->loc()); From 2e357b692fa8a0dd517d6b511b9d8048811b838a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 25 Mar 2024 11:35:27 +0100 Subject: [PATCH 04/95] wip: more AST --- include/thorin/ast/ast.h | 168 ++++++++++++++++++++++++++++++------ include/thorin/ast/parser.h | 4 +- src/thorin/ast/ast.cpp | 4 +- src/thorin/ast/parser.cpp | 39 ++++----- 4 files changed, 164 insertions(+), 51 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index ba035e5b20..1728695151 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -92,8 +92,6 @@ class Ptrn : public Node { mutable const Def* type_; }; -using Ptrns = std::deque>; - class IdPtrn : public Ptrn { public: IdPtrn(AST& ast, Dbg dbg, bool rebind, const Def* type) @@ -105,13 +103,19 @@ class IdPtrn : public Ptrn { class TuplePtrn : public Ptrn { public: - TuplePtrn(AST& ast, Dbg dbg, bool rebind, Ptrns&& ptrns, const Def* type, std::vector&& infers, Def* decl) + TuplePtrn(AST& ast, + Dbg dbg, + bool rebind, + Ptrs&& ptrns, + const Def* type, + std::vector&& infers, + Def* decl) : Ptrn(ast, dbg, rebind, type) , ptrns_(std::move(ptrns)) , infers_(std::move(infers)) , decl_(decl) {} - const Ptrns& ptrns() const { return ptrns_; } + const auto& ptrns() const { return ptrns_; } const Ptrn* ptrn(size_t i) const { return ptrns_[i].get(); } size_t num_ptrns() const { return ptrns().size(); } @@ -119,7 +123,7 @@ class TuplePtrn : public Ptrn { const Def* type(World&, Def2Fields&) const override; private: - Ptrns ptrns_; + Ptrs ptrns_; std::vector infers_; Def* decl_ = nullptr; }; @@ -134,17 +138,66 @@ class Expr : public Node { : Node(ast, dbg) {} }; +class IdExpr : public Node { +protected: + IdExpr(AST& ast, Dbg dbg, Sym) + : Node(ast, dbg) {} + +public: + Sym sym() const { return sym_; } + +private: + Sym sym_; +}; + +class Decl : public Expr { +protected: + Decl(AST& ast, Dbg dbg) + : Expr(ast, dbg) {} +}; + +class Let : public Decl { +public: + Let(AST& ast, Dbg dbg, Ptr&& type, Ptr&& init) + : Decl(ast, dbg) + , type_(std::move(type)) + , init_(std::move(init)) {} + + const Expr* type() const { return type_.get(); } + const Expr* init() const { return init_.get(); } + +private: + Ptr type_; + Ptr init_; +}; + +class Axiom : public Decl {}; + // lam -class Pi : public Expr { +class Pi : public Decl { public: + Pi(AST& ast, Dbg dbg, Tok::Tag tag, Ptrs&& domains, Ptr&& codom) + : Decl(ast, dbg) + , tag_(tag) + , domains_(std::move(domains)) + , codom_(std::move(codom)) {} + +private: + Tok::Tag tag() const { return tag_; } + const auto& domains() const { return domains_; } + const Expr* codom() const { return codom_.get(); } + private: + Tok::Tag tag_; + Ptrs domains_; + Ptr codom_; }; -class Lam : public Expr { +class Lam : public Decl { public: - Lam(AST& ast, Dbg dbg, Tok::Tag tag, Ptrns&& domains, Expr* codom, Expr* filter, Expr* body) - : Expr(ast, dbg) + Lam(AST& ast, Dbg dbg, Tok::Tag tag, Ptrs&& domains, Ptr&& codom, Ptr&& filter, Ptr&& body) + : Decl(ast, dbg) , tag_(tag) , domains_(std::move(domains)) , codom_(std::move(codom)) @@ -153,52 +206,113 @@ class Lam : public Expr { Tok::Tag tag() const { return tag_; } const auto& domains() const { return domains_; } - Expr* codom() const { return codom_; } - Expr* filter() const { return filter_; } - Expr* body() const { return body_; } + const Expr* codom() const { return codom_.get(); } + const Expr* filter() const { return filter_.get(); } + const Expr* body() const { return body_.get(); } private: Tok::Tag tag_; - Ptrns domains_; - Expr* codom_; - Expr* filter_; - Expr* body_; + Ptrs domains_; + Ptr codom_; + Ptr filter_; + Ptr body_; }; class App : public Expr { public: - App(AST& ast, Dbg dbg, Expr* callee, Expr* arg) + App(AST& ast, Dbg dbg, Ptr&& callee, Ptr&& arg) : Expr(ast, dbg) - , callee_(callee) - , arg_(arg) {} + , callee_(std::move(callee)) + , arg_(std::move(arg)) {} - Expr* callee() const { return callee_; } - Expr* arg() const { return arg_; } + const Expr* callee() const { return callee_.get(); } + const Expr* arg() const { return arg_.get(); } private: - Expr* callee_; - Expr* arg_; - ; + Ptr callee_; + Ptr arg_; }; // tuple -#if 0 -class Sigma : public Expr { +class Sigma : public Decl { public: + Sigma(AST& ast, Dbg dbg, Ptrs&& elems) + : Decl(ast, dbg) + , elems_(std::move(elems)) {} + + const auto& elems() const { return elems_; } + const Ptrn* elem(size_t i) const { return elems_[i].get(); } + size_t num_elems() const { return elems().size(); } + private: + Ptrs elems_; }; class Tuple : public Expr { public: + Tuple(AST& ast, Dbg dbg, Ptrs&& elems) + : Expr(ast, dbg) + , elems_(std::move(elems)) {} + + const auto& elems() const { return elems_; } + const Expr* elem(size_t i) const { return elems_[i].get(); } + size_t num_elems() const { return elems().size(); } + private: + Ptrs elems_; }; class Extract : public Expr { public: + Extract(AST& ast, Dbg dbg, Ptr&& tuple, Ptr&& index) + : Expr(ast, dbg) + , tuple_(std::move(tuple)) + , index_(std::move(index)) {} + + const Expr* tuple() const { return tuple_.get(); } + const Expr* index() const { return index_.get(); } + +private: + Ptr tuple_; + Ptr index_; +}; + +class Insert : public Expr { +public: + Insert(AST& ast, Dbg dbg, Ptr&& tuple, Ptr&& index, Ptr&& value) + : Expr(ast, dbg) + , tuple_(std::move(tuple)) + , index_(std::move(index)) + , value_(std::move(value)) {} + + const Expr* tuple() const { return tuple_.get(); } + const Expr* index() const { return index_.get(); } + const Expr* value() const { return value_.get(); } + +private: + Ptr tuple_; + Ptr index_; + Ptr value_; +}; + +/* + * Module + */ + +class Module : public Node { +public: + Module(AST& ast, Dbg dbg, Ptrs&& decls) + : Node(ast, dbg) + , decls_(std::move(decls)) {} + + const auto& decls() const { return decls_; } + const Decl* decl(size_t i) const { return decls_[i].get(); } + size_t num_decls() const { return decls_.size(); } + private: + Ptrs decls_; }; -#endif } // namespace ast } // namespace thorin diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 708fbf21e8..97d9c99b70 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -99,8 +99,8 @@ class Parser : public fe::Parser { ///@{ /// Depending on @p tag, this parses a `()`-style (Tok::Tag::D_paren_l) or `[]`-style (Tok::Tag::D_brckt_l) Ptrn. - std::unique_ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); - std::unique_ptr parse_tuple_ptrn(Tracker, bool rebind, Sym, Def* = nullptr); + Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); + Ptr parse_tuple_ptrn(Tracker, bool rebind, Sym, Def* = nullptr); ///@} /// @name parse decls diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index d15fd5713e..258d61f656 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -54,9 +54,9 @@ const Def* TuplePtrn::type(World& world, Def2Fields& def2fields) const { assert(n > 0); auto type = world.umax(ops); - Sigma* sigma; + ir::Sigma* sigma; if (decl_) { - if (auto s = decl_->isa_mut()) + if (auto s = decl_->isa_mut()) sigma = s; else { sigma = world.mut_sigma(type, n)->set(loc(), sym()); diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index e4753d3c62..5d9bdf71c6 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -174,7 +174,7 @@ Ref Parser::parse_extract_expr(Tracker track, const Def* lhs, Tok::Prec p) { lex(); if (ahead().isa(Tag::M_id)) { - if (auto sigma = lhs->type()->isa_mut()) { + if (auto sigma = lhs->type()->isa_mut()) { auto tok = eat(Tag::M_id); if (tok.sym() == '_') error(tok.loc(), "you cannot use special symbol '_' as field access"); @@ -440,7 +440,7 @@ ir::Lam* Parser::parse_lam(bool is_decl) { error(dbg.loc, "'{}' has not been declared as a function", dbg.sym); } - std::unique_ptr dom_p; + Ptr dom_p; scopes_.push(); std::deque> funs; do { @@ -607,7 +607,7 @@ Ref Parser::parse_lit_expr() { * ptrns */ -std::unique_ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) { +Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) { auto track = tracker(); auto sym = anonymous_; bool p = delim_l == Tag::D_paren_l; @@ -663,7 +663,7 @@ std::unique_ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok sym = eat(Tag::M_id).sym(); eat(Tag::T_colon); auto type = parse_expr(ctxt, prec); - return std::make_unique(ast_, dbg(track, sym), rebind, type); + return ast_.ptr(ast_, dbg(track, sym), rebind, type); } else { // p -> s b -> e where e == id // p -> 's @@ -671,18 +671,18 @@ std::unique_ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok // p -> s // p -> 's sym = eat(Tag::M_id).sym(); - return std::make_unique(ast_, dbg(track, sym), rebind, nullptr); + return ast_.ptr(ast_, dbg(track, sym), rebind, nullptr); } else { // b -> e where e == id auto type = parse_expr(ctxt, prec); - return std::make_unique(ast_, dbg(track, sym), rebind, type); + return ast_.ptr(ast_, dbg(track, sym), rebind, type); } } } else if (b) { // b -> e where e != id if (backtick) error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding"); auto type = parse_expr(ctxt, prec); - return std::make_unique(ast_, dbg(track, sym), rebind, type); + return ast_.ptr(ast_, dbg(track, sym), rebind, type); } else if (!ctxt.empty()) { // p -> ↯ syntax_err("pattern", ctxt); @@ -691,13 +691,13 @@ std::unique_ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok return nullptr; } -std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, Sym sym, Def* decl) { +Ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, Sym sym, Def* decl) { auto delim_l = ahead().tag(); bool p = delim_l == Tag::D_paren_l; bool b = delim_l == Tag::D_brckt_l; assert(p ^ b); - std::deque> ptrns; + Ptrs ptrns; std::vector infers; DefVec ops; @@ -706,7 +706,7 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, parse_decls({}); auto track = tracker(); if (!ptrns.empty()) ptrns.back()->bind(scopes_, infers.back()); - std::unique_ptr ptrn; + Ptr ptrn; if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) { std::vector sym_toks; @@ -719,7 +719,7 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, auto tok = sym_toks[i]; infers.emplace_back(world().mut_infer(type)->set(tok.dbg())); ops.emplace_back(type); - auto ptrn = std::make_unique(ast_, tok.dbg(), false, type); + auto ptrn = ast_.ptr(ast_, tok.dbg(), false, type); if (i != e - 1) ptrn->bind(scopes_, infers.back()); // last element will be bound above ptrns.emplace_back(std::move(ptrn)); } @@ -734,14 +734,14 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, } auto [_, r] = Tok::prec(Tok::Prec::App); auto expr = parse_infix_expr(track, lhs, r); - ptrn = std::make_unique(ast_, dbg(track, anonymous_), false, expr); + ptrn = ast_.ptr(ast_, dbg(track, anonymous_), false, expr); } else { ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); auto type = ptrn->type(world(), def2fields_); if (b) { // If we are able to parse more stuff, we got an expression instead of just a binder. if (auto expr = parse_infix_expr(track, type); expr != type) - ptrn = std::make_unique(ast_, dbg(track, anonymous_), false, expr); + ptrn = ast_.ptr(ast_, dbg(track, anonymous_), false, expr); } } @@ -753,8 +753,7 @@ std::unique_ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, scopes_.pop(); // TODO parse type - return std::make_unique(ast_, dbg(track, sym), rebind, std::move(ptrns), nullptr, std::move(infers), - decl); + return ast_.ptr(ast_, dbg(track, sym), rebind, std::move(ptrns), nullptr, std::move(infers), decl); } /* @@ -822,7 +821,7 @@ void Parser::parse_ax_decl() { error(dbg.loc, "all declarations of axiom '{}' must use the same normalizer name", dbg.sym); annex.normalizer = normalizer; - auto [curry, trip] = Axiom::infer_curry_and_trip(type); + auto [curry, trip] = ir::Axiom::infer_curry_and_trip(type); if (accept(Tag::T_comma)) { auto c = expect(Tag::L_u, "curry counter for axiom"); @@ -861,7 +860,7 @@ void Parser::parse_let_decl() { auto track = tracker(); eat(Tag::K_let); - std::variant, Dbg> name; + std::variant, Dbg> name; Ref type; if (auto tok = accept(Tag::M_anx)) { name = tok.dbg(); @@ -883,7 +882,7 @@ void Parser::parse_let_decl() { scopes_.bind(*dbg, value); register_annex(*dbg, value); } else { - std::get>(name)->bind(scopes_, value); + std::get>(name)->bind(scopes_, value); } expect(Tag::T_semicolon, "let declaration"); @@ -900,7 +899,7 @@ void Parser::parse_sigma_decl() { if (accept(Tag::T_assign)) { Def* decl; if (auto def = scopes_.query(dbg)) { - if ((!def->isa_mut() && !def->isa()) || !def->isa_lit_arity()) + if ((!def->isa_mut() && !def->isa()) || !def->isa_lit_arity()) error(dbg.loc, "'{}' has not been declared as a sigma", dbg.sym); if (!Check::alpha(def->type(), type)) error(dbg.loc, "'{}' of type '{}' has been redeclared with a different type '{}'; here: {}", dbg.sym, @@ -921,7 +920,7 @@ void Parser::parse_sigma_decl() { auto ptrn = parse_tuple_ptrn(track, false, dbg.sym, decl); auto t = ptrn->type(world(), def2fields_); - assert(t->isa_mut()); + assert(t->isa_mut()); t->set(track.loc()); if (anx) register_annex(dbg, t); From 866ddbaa3e675477b3d114bd7ff5a3dfb907d08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 27 Mar 2024 17:16:26 +0100 Subject: [PATCH 05/95] it compiles but doesn't link yet --- include/thorin/ast/ast.h | 382 +++++++++++++++------ include/thorin/ast/parser.h | 62 ++-- include/thorin/util/dbg.h | 9 + src/thorin/ast/ast.cpp | 25 +- src/thorin/ast/parser.cpp | 656 +++++++++++------------------------- 5 files changed, 536 insertions(+), 598 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 1728695151..848e176469 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -21,18 +21,16 @@ using Def2Fields = DefMap>; namespace ast { -namespace ir = thorin; - template using Ptr = fe::Arena::Ptr; template using Ptrs = std::deque>; class AST { public: - AST(World& world) - : world_(world) {} + AST(World& world); World& world() { return world_; } Driver& driver(); + Sym anonymous() const { return anonymous_; } /// @name Sym ///@{ @@ -42,217 +40,309 @@ class AST { ///@} template auto ptr(Args&&... args) { - return arena_.mk(std::forward(args)...); + return arena_.mk(*this, std::forward(args)...); } private: World& world_; fe::Arena arena_; + Sym anonymous_; }; class Scopes; class Node : public fe::RuntimeCast { protected: - Node(AST& ast, Dbg dbg) + Node(AST& ast, Loc loc) : ast_(ast) - , dbg_(dbg) {} + , loc_(loc) {} virtual ~Node() {} public: AST& ast() const { return ast_; } - Dbg dbg() const { return dbg_; } - Loc loc() const { return dbg_.loc; } - Sym sym() const { return dbg_.sym; } + Loc loc() const { return loc_; } private: AST& ast_; - Dbg dbg_; + Loc loc_; +}; + +class Expr : public Node { +protected: + Expr(AST& ast, Loc loc) + : Node(ast, loc) {} +}; + +class Decl : public Node { +protected: + Decl(AST& ast, Loc loc, Sym sym) + : Node(ast, loc) + , sym_(sym) {} + +public: + Sym sym() const { return sym_; } + +private: + Sym sym_; }; /* - * Pattern + * Ptrn */ class Ptrn : public Node { public: - Ptrn(AST& ast, Dbg dbg, bool rebind, const Def* type) - : Node(ast, dbg) + Ptrn(AST& ast, Loc loc, bool rebind, Sym sym, Ptr&& type) + : Node(ast, loc) , rebind_(rebind) - , type_(type) {} - virtual ~Ptrn() {} + , sym_(sym) + , type_(std::move(type)) {} bool rebind() const { return rebind_; } + Sym sym() const { return sym_; } + Dbg dbg() const { return {loc(), sym()}; } bool is_anonymous() const { return sym() == '_'; } - virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; - virtual const Def* type(World&, Def2Fields&) const = 0; + + [[nodiscard]] static Ptr expr(AST& ast, Ptr&&); + + virtual Ptr expr() const = 0; + // virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; + // virtual const Def* type(World&, Def2Fields&) const = 0; protected: bool rebind_; - mutable const Def* type_; + Sym sym_; + Ptr type_; }; class IdPtrn : public Ptrn { public: - IdPtrn(AST& ast, Dbg dbg, bool rebind, const Def* type) - : Ptrn(ast, dbg, rebind, type) {} - - void bind(Scopes&, const Def*, bool rebind = false) const override; - const Def* type(World&, Def2Fields&) const override; + IdPtrn(AST& ast, Loc loc, bool rebind, Sym sym, Ptr&& type) + : Ptrn(ast, loc, rebind, sym, std::move(type)) {} + IdPtrn(AST& ast, Ptr&& type) + : Ptrn(ast, type->loc(), false, ast.anonymous(), std::move(type)) {} + + Ptr expr() const override; + // void bind(Scopes&, const Def*, bool rebind = false) const override {} + // const Def* type(World&, Def2Fields&) const override {} }; class TuplePtrn : public Ptrn { public: - TuplePtrn(AST& ast, - Dbg dbg, - bool rebind, - Ptrs&& ptrns, - const Def* type, - std::vector&& infers, - Def* decl) - : Ptrn(ast, dbg, rebind, type) - , ptrns_(std::move(ptrns)) - , infers_(std::move(infers)) - , decl_(decl) {} + TuplePtrn(AST& ast, Loc loc, bool rebind, Sym sym, Tok::Tag tag, Ptrs&& ptrns, Ptr&& type) + : Ptrn(ast, loc, rebind, sym, std::move(type)) + , tag_(tag) + , ptrns_(std::move(ptrns)) {} + Tok::Tag tag() const { return tag_; } const auto& ptrns() const { return ptrns_; } const Ptrn* ptrn(size_t i) const { return ptrns_[i].get(); } size_t num_ptrns() const { return ptrns().size(); } - void bind(Scopes&, const Def*, bool rebind = false) const override; - const Def* type(World&, Def2Fields&) const override; + Ptr expr() const override; + // void bind(Scopes&, const Def*, bool rebind = false) const override {} + // const Def* type(World&, Def2Fields&) const override {} private: + Tok::Tag tag_; Ptrs ptrns_; - std::vector infers_; - Def* decl_ = nullptr; }; /* * Expr */ -class Expr : public Node { -protected: - Expr(AST& ast, Dbg dbg) - : Node(ast, dbg) {} -}; - -class IdExpr : public Node { -protected: - IdExpr(AST& ast, Dbg dbg, Sym) - : Node(ast, dbg) {} - +class IdExpr : public Expr { public: + IdExpr(AST& ast, Loc loc, Sym sym) + : Expr(ast, loc) + , sym_(sym) {} + IdExpr(AST& ast, Tok tok) + : IdExpr(ast, tok.loc(), tok.sym()) {} + Sym sym() const { return sym_; } private: Sym sym_; }; -class Decl : public Expr { -protected: - Decl(AST& ast, Dbg dbg) - : Expr(ast, dbg) {} +class PrimaryExpr : public Expr { +public: + PrimaryExpr(AST& ast, Tok tok) + : Expr(ast, tok.loc()) + , tag_(tok.tag()) {} + + Tok::Tag tag() const { return tag_; } + +private: + Tok::Tag tag_; }; -class Let : public Decl { +class BlockExpr : public Expr { public: - Let(AST& ast, Dbg dbg, Ptr&& type, Ptr&& init) - : Decl(ast, dbg) - , type_(std::move(type)) - , init_(std::move(init)) {} + BlockExpr(AST& ast, Loc loc, Ptrs&& decls, Ptr&& expr) + : Expr(ast, loc) + , decls_(std::move(decls)) + , expr_(std::move(expr)) {} - const Expr* type() const { return type_.get(); } - const Expr* init() const { return init_.get(); } + const auto& decls() const { return decls_; } + const Decl* decl(size_t i) const { return decls_[i].get(); } + size_t num_decls() const { return decls_.size(); } + const Expr* expr() const { return expr_.get(); } private: - Ptr type_; - Ptr init_; + Ptrs decls_; + Ptr expr_; }; -class Axiom : public Decl {}; - // lam -class Pi : public Decl { +class SimplePiExpr : public Expr { public: - Pi(AST& ast, Dbg dbg, Tok::Tag tag, Ptrs&& domains, Ptr&& codom) - : Decl(ast, dbg) + SimplePiExpr(AST& ast, Loc loc, Ptr&& dom, Ptr&& codom) + : Expr(ast, loc) + , dom_(std::move(dom)) + , codom_(std::move(codom)) {} + +private: + const Expr* dom() const { return dom_.get(); } + const Expr* codom() const { return codom_.get(); } + +private: + Ptr dom_; + Ptr codom_; +}; + +class PiExpr : public Expr { +public: + class Dom : public Node { + public: + Dom(AST& ast, Loc loc, bool implicit, Ptr&& ptrn) + : Node(ast, loc) + , implicit_(implicit) + , ptrn_(std::move(ptrn)) {} + + bool implicit() const { return implicit_; } + const Ptrn* ptrn() const { return ptrn_.get(); } + + private: + bool implicit_; + Ptr ptrn_; + }; + + PiExpr(AST& ast, Loc loc, Tok::Tag tag, Ptrs&& doms, Ptr&& codom) + : Expr(ast, loc) , tag_(tag) - , domains_(std::move(domains)) + , doms_(std::move(doms)) , codom_(std::move(codom)) {} private: Tok::Tag tag() const { return tag_; } - const auto& domains() const { return domains_; } + const auto& doms() const { return doms_; } + const Dom* dom(size_t i) const { return doms_[i].get(); } + size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } private: Tok::Tag tag_; - Ptrs domains_; + Ptrs doms_; Ptr codom_; }; -class Lam : public Decl { +class LamExpr : public Expr { public: - Lam(AST& ast, Dbg dbg, Tok::Tag tag, Ptrs&& domains, Ptr&& codom, Ptr&& filter, Ptr&& body) - : Decl(ast, dbg) + class Dom : public PiExpr::Dom { + public: + Dom(AST& ast, Loc loc, bool implicit, Ptr&& ptrn, Ptr&& filter) + : PiExpr::Dom(ast, loc, implicit, std::move(ptrn)) + , filter_(std::move(filter)) {} + + const Expr* filter() const { return filter_.get(); } + + private: + Ptr filter_; + }; + + LamExpr(AST& ast, Loc loc, Tok::Tag tag, Sym sym, Ptrs&& doms, Ptr&& codom, Ptr&& body) + : Expr(ast, loc) , tag_(tag) - , domains_(std::move(domains)) + , sym_(sym) + , doms_(std::move(doms)) , codom_(std::move(codom)) - , filter_(std::move(filter)) , body_(std::move(body)) {} Tok::Tag tag() const { return tag_; } - const auto& domains() const { return domains_; } + Sym sym() const { return sym_; } + const auto& doms() const { return doms_; } + const Dom* dom(size_t i) const { return doms_[i].get(); } const Expr* codom() const { return codom_.get(); } - const Expr* filter() const { return filter_.get(); } const Expr* body() const { return body_.get(); } private: Tok::Tag tag_; - Ptrs domains_; + Sym sym_; + Ptrs doms_; Ptr codom_; - Ptr filter_; Ptr body_; + ; }; -class App : public Expr { +class AppExpr : public Expr { public: - App(AST& ast, Dbg dbg, Ptr&& callee, Ptr&& arg) - : Expr(ast, dbg) + AppExpr(AST& ast, Loc loc, bool is_explicit, Ptr&& callee, Ptr&& arg) + : Expr(ast, loc) + , is_explicit_(is_explicit) , callee_(std::move(callee)) , arg_(std::move(arg)) {} + bool is_explicit() const { return is_explicit_; } const Expr* callee() const { return callee_.get(); } const Expr* arg() const { return arg_.get(); } private: + bool is_explicit_; Ptr callee_; Ptr arg_; }; +class RetExpr : public Expr { +public: + RetExpr(AST& ast, Loc loc, Ptr&& ptrn, Ptr&& callee, Ptr&& arg, Ptr body) + : Expr(ast, loc) + , ptrn_(std::move(ptrn)) + , callee_(std::move(callee)) + , arg_(std::move(arg)) + , body_(std::move(body)) {} + + const Ptrn* ptrn() const { return ptrn_.get(); } + const Expr* callee() const { return callee_.get(); } + const Expr* arg() const { return arg_.get(); } + const Expr* body() const { return body_.get(); } + +private: + Ptr ptrn_; + Ptr callee_; + Ptr arg_; + Ptr body_; +}; // tuple -class Sigma : public Decl { +class SigmaExpr : public Expr { public: - Sigma(AST& ast, Dbg dbg, Ptrs&& elems) - : Decl(ast, dbg) - , elems_(std::move(elems)) {} + SigmaExpr(AST& ast, Ptr&& ptrn) + : Expr(ast, ptrn->loc()) + , ptrn_(std::move(ptrn)) {} - const auto& elems() const { return elems_; } - const Ptrn* elem(size_t i) const { return elems_[i].get(); } - size_t num_elems() const { return elems().size(); } + const Ptrn* ptrn() const { return ptrn_.get(); } private: - Ptrs elems_; + Ptr ptrn_; }; -class Tuple : public Expr { +class TupleExpr : public Expr { public: - Tuple(AST& ast, Dbg dbg, Ptrs&& elems) - : Expr(ast, dbg) + TupleExpr(AST& ast, Loc loc, Ptrs&& elems) + : Expr(ast, loc) , elems_(std::move(elems)) {} const auto& elems() const { return elems_; } @@ -263,10 +353,31 @@ class Tuple : public Expr { Ptrs elems_; }; -class Extract : public Expr { +template class ArrOrPackExpr : public Expr { public: - Extract(AST& ast, Dbg dbg, Ptr&& tuple, Ptr&& index) - : Expr(ast, dbg) + ArrOrPackExpr(AST& ast, Loc loc, Sym sym, Ptr&& shape, Ptr&& body) + : Expr(ast, loc) + , sym_(sym) + , shape_(std::move(shape)) + , body_(std::move(body)) {} + + Sym sym() const { return sym_; } + const Expr* shape() const { return shape_.get(); } + const Expr* body() const { return body_.get(); } + +private: + Sym sym_; + Ptr shape_; + Ptr body_; +}; + +using ArrExpr = ArrOrPackExpr; +using PackExpr = ArrOrPackExpr; + +class ExtractExpr : public Expr { +public: + ExtractExpr(AST& ast, Loc loc, Ptr&& tuple, Ptr&& index) + : Expr(ast, loc) , tuple_(std::move(tuple)) , index_(std::move(index)) {} @@ -278,10 +389,10 @@ class Extract : public Expr { Ptr index_; }; -class Insert : public Expr { +class InsertExpr : public Expr { public: - Insert(AST& ast, Dbg dbg, Ptr&& tuple, Ptr&& index, Ptr&& value) - : Expr(ast, dbg) + InsertExpr(AST& ast, Loc loc, Ptr&& tuple, Ptr&& index, Ptr&& value) + : Expr(ast, loc) , tuple_(std::move(tuple)) , index_(std::move(index)) , value_(std::move(value)) {} @@ -296,14 +407,81 @@ class Insert : public Expr { Ptr value_; }; +/* + * Further Decls + */ + +class LetDecl : public Decl { +public: + LetDecl(AST& ast, Loc loc, Ptr&& ptrn, Ptr&& value) + : Decl(ast, loc, ptrn->sym()) + , ptrn_(std::move(ptrn)) + , value_(std::move(value)) {} + + const Ptrn* ptrn() const { return ptrn_.get(); } + const Expr* value() const { return value_.get(); } + +private: + Ptr ptrn_; + Ptr value_; +}; + +class AxiomDecl : public Decl { +public: + AxiomDecl(AST& ast, Loc loc, Sym sym) + : Decl(ast, loc, sym) {} +}; + +class PiDecl : public Decl { +public: + PiDecl(AST& ast, Loc loc, Sym sym, Ptr&& type, Ptr&& body) + : Decl(ast, loc, sym) + , type_(std::move(type)) + , body_(std::move(body)) {} + + const Expr* type() const { return type_.get(); } + const Expr* body() const { return body_.get(); } + +private: + Ptr type_; + Ptr body_; +}; + +class LamDecl : public Decl { +public: + LamDecl(AST& ast, Ptr&& lam) + : Decl(ast, lam->loc(), lam->sym()) + , lam_(std::move(lam)) {} + + const LamExpr* lam() const { return lam_.get(); } + +private: + Ptr lam_; +}; + +class SigmaDecl : public Decl { +public: + SigmaDecl(AST& ast, Loc loc, Sym sym, Ptr&& type, Ptr&& body) + : Decl(ast, loc, sym) + , type_(std::move(type)) + , body_(std::move(body)) {} + + const Expr* type() const { return type_.get(); } + const Expr* body() const { return body_.get(); } + +private: + Ptr type_; + Ptr body_; +}; + /* * Module */ class Module : public Node { public: - Module(AST& ast, Dbg dbg, Ptrs&& decls) - : Node(ast, dbg) + Module(AST& ast, Loc loc, Ptrs&& decls) + : Node(ast, loc) , decls_(std::move(decls)) {} const auto& decls() const { return decls_; } diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 97d9c99b70..f5355e1a79 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -34,10 +34,9 @@ class Parser : public fe::Parser { public: Parser(World& world) : world_(world) - , ast_(world) - , anonymous_(world.sym("_")) - , return_(world.sym("return")) {} + , ast_(world) {} + AST& ast() { return ast_; } World& world() { return world_; } Driver& driver() { return world().driver(); } void import(std::string_view sv) { return import(driver().sym(sv)); } @@ -45,21 +44,24 @@ class Parser : public fe::Parser { void import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); void plugin(Sym); void plugin(const char* name) { return plugin(driver().sym(name)); } - const Scopes& scopes() const { return scopes_; } private: + template auto ptr(Args&&... args) { + return ast_.ptr(std::forward(args)...); + } + Dbg dbg(const Tracker& tracker, Sym sym) const { return {tracker.loc(), sym}; } Lexer& lexer() { return *lexer_; } /// @name parse misc ///@{ - void parse_module(); + Ptr parse_module(); Dbg parse_id(std::string_view ctxt = {}); std::pair parse_annex(std::string_view ctxt = {}); - std::pair parse_name(std::string_view ctxt = {}); + Sym parse_name(std::string_view ctxt = {}); void parse_import(); void parse_plugin(); - Ref parse_type_ascr(std::string_view ctxt = {}); + Ptr parse_type_ascr(std::string_view ctxt = {}); void register_annex(Dbg, Ref); template void parse_list(std::string ctxt, Tok::Tag delim_l, F f, Tok::Tag sep = Tok::Tag::T_comma) { @@ -74,25 +76,24 @@ class Parser : public fe::Parser { /// @name parse exprs ///@{ - Ref parse_expr(std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); - Ref parse_primary_expr(std::string_view ctxt); - Ref parse_infix_expr(Tracker, const Def* lhs, Tok::Prec = Tok::Prec::Bot); - Ref parse_extract_expr(Tracker, const Def*, Tok::Prec); + Ptr parse_expr(std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); + Ptr parse_primary_expr(std::string_view ctxt); + Ptr parse_infix_expr(Tracker, Ptr&& lhs, Tok::Prec = Tok::Prec::Bot); + Ptr parse_extract_expr(Tracker, Ptr&&, Tok::Prec); ///@} /// @name parse primary exprs ///@{ - Ref parse_arr_expr(); - Ref parse_pack_expr(); - Ref parse_block_expr(); - Ref parse_sigma_expr(); - Ref parse_tuple_expr(); - Ref parse_type_expr(); - ir::Pi* parse_pi_expr(ir::Pi* = nullptr); - Ref parse_lit_expr(); - Ref parse_insert_expr(); - Ref parse_ret_expr(); - ir::Lam* parse_lam(bool decl = false); + template Ptr parse_arr_or_pack_expr(); + Ptr parse_block_expr(std::string_view ctxt); ///< Empty @p ctxt means an explicit BlockExpr `{ d* e }`. + Ptr parse_type_expr(); + Ptr parse_lit_expr(); + Ptr parse_ret_expr(); + Ptr parse_pi_expr(); + Ptr parse_lam_expr(); + Ptr parse_sigma_expr(); + Ptr parse_tuple_expr(); + Ptr parse_insert_expr(); ///@} /// @name parse ptrns @@ -100,7 +101,7 @@ class Parser : public fe::Parser { /// Depending on @p tag, this parses a `()`-style (Tok::Tag::D_paren_l) or `[]`-style (Tok::Tag::D_brckt_l) Ptrn. Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); - Ptr parse_tuple_ptrn(Tracker, bool rebind, Sym, Def* = nullptr); + Ptr parse_tuple_ptrn(bool rebind, Sym); ///@} /// @name parse decls @@ -109,11 +110,12 @@ class Parser : public fe::Parser { /// If @p ctxt ... /// * ... empty: **Only** decls are parsed. @returns `nullptr` /// * ... **non**-empty: Decls are parsed, then an expression. @returns expression. - Ref parse_decls(std::string_view ctxt); - void parse_ax_decl(); - void parse_let_decl(); - void parse_sigma_decl(); - void parse_pi_decl(); + Ptrs parse_decls(std::string_view ctxt); + Ptr parse_axiom_decl(); + Ptr parse_let_decl(); + Ptr parse_pi_decl(); + Ptr parse_lam_decl(); + Ptr parse_sigma_decl(); ///@} /// @name error messages @@ -137,10 +139,6 @@ class Parser : public fe::Parser { World& world_; AST ast_; Lexer* lexer_ = nullptr; - Scopes scopes_; - Def2Fields def2fields_; - Sym anonymous_; - Sym return_; friend class fe::Parser; }; diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index ae6449bffc..8727cd0766 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -29,6 +29,15 @@ template [[noreturn]] void error(Loc ///@} struct Dbg { + constexpr Dbg() noexcept = default; + constexpr Dbg(const Dbg&) noexcept = default; + constexpr Dbg(Loc loc, Sym sym) noexcept + : loc(loc) + , sym(sym) {} + constexpr Dbg(Loc loc) noexcept + : Dbg(loc, {}) {} + Dbg& operator=(const Dbg&) noexcept = default; + Loc loc; Sym sym; }; diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 258d61f656..3096e08fee 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -10,11 +10,31 @@ namespace thorin::ast { +AST::AST(World& world) + : world_(world) + , anonymous_(world.sym("_")) {} + Driver& AST::driver() { return world().driver(); } Sym AST::sym(const char* s) { return driver().sym(s); } Sym AST::sym(std::string_view s) { return driver().sym(s); } Sym AST::sym(const std::string& s) { return driver().sym(s); } +/* + * Ptrn::expr + */ + +Ptr Ptrn::expr(AST& ast, Ptr&& ptrn) { + if (auto id_ptrn = ptrn->isa()) { + return ast.ptr(id_ptrn->loc(), id_ptrn->sym()); + } else if (auto tuple_ptrn = ptrn->isa(); tuple_ptrn && tuple_ptrn->tag() == Tok::Tag::D_brckt_r) { + (void)ptrn.release(); + return ast.ptr(Ptr(tuple_ptrn)); + } + // ptrn.get_deleter()(ptrn.release()); + return {}; +} + +#if 0 /* * bind */ @@ -54,9 +74,9 @@ const Def* TuplePtrn::type(World& world, Def2Fields& def2fields) const { assert(n > 0); auto type = world.umax(ops); - ir::Sigma* sigma; + Sigma* sigma; if (decl_) { - if (auto s = decl_->isa_mut()) + if (auto s = decl_->isa_mut()) sigma = s; else { sigma = world.mut_sigma(type, n)->set(loc(), sym()); @@ -92,5 +112,6 @@ const Def* TuplePtrn::type(World& world, Def2Fields& def2fields) const { return type_ = sigma; } +#endif } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 5d9bdf71c6..43251ac66d 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,8 @@ using Tag = Tok::Tag; * entry points */ -void Parser::parse_module() { +Ptr Parser::parse_module() { + auto track = tracker(); while (true) if (ahead().tag() == Tag::K_import) parse_import(); @@ -32,8 +34,9 @@ void Parser::parse_module() { else break; - parse_decls({}); + auto decls = parse_decls({}); expect(Tag::EoF, "module"); + return ptr(track, std::move(decls)); } void Parser::import(Sym name, std::ostream* md) { @@ -98,14 +101,11 @@ Dbg Parser::parse_id(std::string_view ctxt) { return {prev_, world().sym("")}; } -std::pair Parser::parse_name(std::string_view ctxt) { - if (auto tok = accept(Tag::M_anx)) return {tok.dbg(), true}; - if (auto tok = accept(Tag::M_id)) return {tok.dbg(), false}; +Sym Parser::parse_name(std::string_view ctxt) { + if (auto tok = accept(Tag::M_anx)) return tok.sym(); + if (auto tok = accept(Tag::M_id)) return tok.sym(); syntax_err("identifier or annex name", ctxt); - return { - {prev_, world().sym("")}, - false - }; + return ast().sym(""); } void Parser::register_annex(Dbg dbg, Ref def) { @@ -124,7 +124,7 @@ void Parser::register_annex(Dbg dbg, Ref def) { world().register_annex(p | (t << 8) | s, def); } -Ref Parser::parse_type_ascr(std::string_view ctxt) { +Ptr Parser::parse_type_ascr(std::string_view ctxt) { if (accept(Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot); if (ctxt.empty()) return nullptr; syntax_err("':'", ctxt); @@ -134,18 +134,18 @@ Ref Parser::parse_type_ascr(std::string_view ctxt) { * exprs */ -Ref Parser::parse_expr(std::string_view ctxt, Tok::Prec p) { +Ptr Parser::parse_expr(std::string_view ctxt, Tok::Prec p) { auto track = tracker(); auto lhs = parse_primary_expr(ctxt); - return parse_infix_expr(track, lhs, p); + return parse_infix_expr(track, std::move(lhs), p); } -Ref Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p) { +Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec p) { while (true) { // If operator in ahead has less left precedence: reduce (break). if (ahead().isa(Tag::T_extract)) { - if (auto extract = parse_extract_expr(track, lhs, p)) - lhs = extract; + if (auto extract = parse_extract_expr(track, std::move(lhs), p)) + lhs = std::move(extract); else break; } else if (ahead().isa(Tag::T_arrow)) { @@ -153,13 +153,13 @@ Ref Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p) { if (l < p) break; lex(); auto rhs = parse_expr("right-hand side of an function type", r); - lhs = world().pi(lhs, rhs)->set(track.loc()); + lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); } else { auto [l, r] = Tok::prec(Tok::Prec::App); if (l < p) break; bool is_explicit = (bool)accept(Tag::T_at); if (auto rhs = parse_expr({}, r)) // if we can parse an expression, it's an App - lhs = (is_explicit ? world().app(lhs, rhs) : world().iapp(lhs, rhs))->set(track.loc()); + lhs = ptr(track.loc(), is_explicit, std::move(lhs), std::move(rhs)); else return lhs; } @@ -168,31 +168,15 @@ Ref Parser::parse_infix_expr(Tracker track, const Def* lhs, Tok::Prec p) { return lhs; } -Ref Parser::parse_extract_expr(Tracker track, const Def* lhs, Tok::Prec p) { +Ptr Parser::parse_extract_expr(Tracker track, Ptr&& lhs, Tok::Prec p) { auto [l, r] = Tok::prec(Tok::Prec::Extract); if (l < p) return nullptr; lex(); - - if (ahead().isa(Tag::M_id)) { - if (auto sigma = lhs->type()->isa_mut()) { - auto tok = eat(Tag::M_id); - if (tok.sym() == '_') error(tok.loc(), "you cannot use special symbol '_' as field access"); - - if (auto i = def2fields_.find(sigma); i != def2fields_.end()) { - if (auto& fields = i->second; fields.size() == sigma->num_ops()) { - for (size_t i = 0, n = sigma->num_ops(); i != n; ++i) - if (fields[i] == tok.sym()) return world().extract(lhs, n, i)->set(track.loc()); - } - } - error(tok.loc(), "could not find elemement '{}' to extract from '{}' of type '{}'", tok.sym(), lhs, sigma); - } - } - auto rhs = parse_expr("right-hand side of an extract", r); - return world().extract(lhs, rhs)->set(track.loc()); + return ptr(track.loc(), std::move(lhs), std::move(rhs)); } -Ref Parser::parse_insert_expr() { +Ptr Parser::parse_insert_expr() { eat(Tag::K_ins); auto track = tracker(); @@ -204,54 +188,58 @@ Ref Parser::parse_insert_expr() { auto value = parse_expr("insert value"); expect(Tag::D_paren_r, "closing paren for insert arguments"); - return world().insert(tuple, index, value)->set(track.loc()); + return ptr(track.loc(), std::move(tuple), std::move(index), std::move(value)); } -Ref Parser::parse_primary_expr(std::string_view ctxt) { +Ptr Parser::parse_primary_expr(std::string_view ctxt) { // clang-format off switch (ahead().tag()) { - case Tag::D_quote_l: return parse_arr_expr(); - case Tag::D_angle_l: return parse_pack_expr(); - case Tag::D_brace_l: return parse_block_expr(); - case Tag::D_brckt_l: return parse_sigma_expr(); - case Tag::D_paren_l: return parse_tuple_expr(); - case Tag::K_Type: return parse_type_expr(); - case Tag::K_Univ: lex(); return world().univ(); - case Tag::K_Idx: lex(); return world().type_idx(); - case Tag::K_Nat: lex(); return world().type_nat(); - case Tag::K_ff: lex(); return world().lit_ff(); - case Tag::K_tt: lex(); return world().lit_tt(); - case Tag::K_i1: lex(); return world().lit_i1(); - case Tag::K_i8: lex(); return world().lit_i8(); - case Tag::K_i16: lex(); return world().lit_i16(); - case Tag::K_i32: lex(); return world().lit_i32(); - case Tag::K_i64: lex(); return world().lit_i64(); - case Tag::K_Bool: - case Tag::K_I1: lex(); return world().type_i1(); - case Tag::K_I8: lex(); return world().type_i8(); - case Tag::K_I16: lex(); return world().type_i16(); - case Tag::K_I32: lex(); return world().type_i32(); - case Tag::K_I64: lex(); return world().type_i64(); case Tag::K_Cn: case Tag::K_Fn: case Tag::T_Pi: return parse_pi_expr(); case Tag::K_cn: case Tag::K_fn: - case Tag::T_lm: return parse_lam(); - case Tag::T_star: lex(); return world().type(); - case Tag::T_box: lex(); return world().type<1>(); + case Tag::T_lm: return parse_lam_expr(); + case Tag::K_ins: return parse_insert_expr(); + case Tag::K_ret: return parse_ret_expr(); + case Tag::D_quote_l: return parse_arr_or_pack_expr(); + case Tag::D_angle_l: return parse_arr_or_pack_expr(); + case Tag::D_brckt_l: return parse_sigma_expr(); + case Tag::D_paren_l: return parse_tuple_expr(); + case Tag::D_brace_l: return parse_block_expr({}); + case Tag::K_Type: return parse_type_expr(); + + case Tag::K_Univ: + case Tag::K_Idx: + case Tag::K_Nat: + case Tag::K_ff: + case Tag::K_tt: + case Tag::K_i1: + case Tag::K_i8: + case Tag::K_i16: + case Tag::K_i32: + case Tag::K_i64: + case Tag::K_Bool: + case Tag::K_I1: + case Tag::K_I8: + case Tag::K_I16: + case Tag::K_I32: + case Tag::K_I64: + case Tag::T_star: + case Tag::T_box: { + auto tok = lex(); + return ptr(tok); + } case Tag::T_bot: case Tag::T_top: case Tag::L_s: case Tag::L_u: case Tag::L_f: return parse_lit_expr(); - case Tag::L_c: return world().lit_i8(lex().lit_c()); - case Tag::L_i: return lex().lit_i(); - case Tag::K_ins: return parse_insert_expr(); - case Tag::K_ret: return parse_ret_expr(); + //case Tag::L_c: return world().lit_i8(lex().lit_c()); + //case Tag::L_i: return lex().lit_i(); case Tag::M_anx: - case Tag::M_id: return scopes_.find(lex().dbg()); - case Tag::M_str: return world().tuple(lex().sym())->set(prev_); + case Tag::M_id: return ptr(lex()); + //case Tag::M_str: return world().tuple(lex().sym())->set(prev_); default: if (ctxt.empty()) return nullptr; syntax_err("primary expression", ctxt); @@ -260,198 +248,107 @@ Ref Parser::parse_primary_expr(std::string_view ctxt) { return nullptr; } -Ref Parser::parse_arr_expr() { +template Ptr Parser::parse_arr_or_pack_expr() { auto track = tracker(); - scopes_.push(); - eat(Tag::D_quote_l); + eat(arr ? Tag::D_quote_l : Tag::D_angle_l); - const Def* shape = nullptr; - Arr* arr = nullptr; + Sym sym; if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) { - auto id = eat(Tag::M_id); + sym = eat(Tag::M_id).sym(); eat(Tag::T_colon); - - auto shape = parse_expr("shape of an array"); - auto type = world().mut_infer_univ(); - arr = world().mut_arr(type)->set_shape(shape); - scopes_.bind(id.dbg(), arr->var()->set(id.dbg())); - } else { - shape = parse_expr("shape of an array"); } - expect(Tag::T_semicolon, "array"); - auto body = parse_expr("body of an array"); - expect(Tag::D_quote_r, "closing delimiter of an array"); - scopes_.pop(); + auto shape = parse_expr(arr ? "shape of an array" : "shape of a pack"); + expect(Tag::T_semicolon, arr ? "array" : "pack"); + auto body = parse_expr(arr ? "body of an array" : "body of a pack"); + expect(arr ? Tag::D_quote_r : Tag::D_angle_r, + arr ? "closing delimiter of an array" : "closing delimiter of a pack"); - if (arr) return arr->set_body(body); - return world().arr(shape, body)->set(track.loc()); + return ptr>(track, sym, std::move(shape), std::move(body)); } -Ref Parser::parse_pack_expr() { +Ptr Parser::parse_block_expr(std::string_view ctxt) { auto track = tracker(); - scopes_.push(); - eat(Tag::D_angle_l); - - if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) { - auto id = eat(Tag::M_id); - eat(Tag::T_colon); - - auto shape = parse_expr("shape of a pack"); - auto infer = world().mut_infer(world().type_idx(shape))->set(id.sym()); - scopes_.bind(id.dbg(), infer); - - expect(Tag::T_semicolon, "pack"); - auto body = parse_expr("body of a pack"); - expect(Tag::D_angle_r, "closing delimiter of a pack"); - scopes_.pop(); - - auto arr = world().arr(shape, body->type()); - auto pack = world().mut_pack(arr)->set(body); - auto var = pack->var(); - infer->set(var); - return pack->reset(pack->reduce(var)); // get rid of infer - } - - auto shape = parse_expr("shape of a pack"); - expect(Tag::T_semicolon, "pack"); - auto body = parse_expr("body of a pack"); - expect(Tag::D_angle_r, "closing delimiter of a pack"); - scopes_.pop(); - return world().pack(shape, body)->set(track.loc()); -} - -Ref Parser::parse_block_expr() { - scopes_.push(); - eat(Tag::D_brace_l); - auto res = parse_decls("block expression"); - expect(Tag::D_brace_r, "block expression"); - scopes_.pop(); - return res; + if (ctxt.empty()) eat(Tag::D_brace_l); + auto decls = parse_decls(ctxt.empty() ? "block expression" : ctxt); + auto expr = parse_expr("final expression in a "s + (ctxt.empty() ? "block expressoin"s : std::string(ctxt))); + if (ctxt.empty()) expect(Tag::D_brace_r, "block expression"); + return ptr(track, std::move(decls), std::move(expr)); } -Ref Parser::parse_sigma_expr() { - auto track = tracker(); - auto ptrn = parse_tuple_ptrn(track, false, anonymous_); - return ptrn->type(world(), def2fields_); -} +Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, ast().anonymous())); } -Ref Parser::parse_tuple_expr() { +Ptr Parser::parse_tuple_expr() { auto track = tracker(); - DefVec ops; - parse_list("tuple", Tag::D_paren_l, [&]() { ops.emplace_back(parse_expr("tuple element")); }); - return world().tuple(ops)->set(track.loc()); + Ptrs elems; + parse_list("tuple", Tag::D_paren_l, [&]() { elems.emplace_back(parse_expr("tuple element")); }); + return ptr(track, std::move(elems)); } -Ref Parser::parse_type_expr() { - auto track = tracker(); - eat(Tag::K_Type); - auto [l, r] = Tok::prec(Tok::Prec::App); - auto level = parse_expr("type level", r); - return world().type(level)->set(track.loc()); -} +// Ptr Parser::parse_type_expr() { +// auto track = tracker(); +// eat(Tag::K_Type); +// auto [l, r] = Tok::prec(Tok::Prec::App); +// auto level = parse_expr("type level", r); +// return world().type(level)->set(track.loc()); +// } -ir::Pi* Parser::parse_pi_expr(ir::Pi* outer) { +Ptr Parser::parse_pi_expr() { auto track = tracker(); - auto tok = lex(); + auto tag = lex().tag(); std::string entity; - switch (tok.tag()) { + switch (tag) { case Tag::T_Pi: entity = "dependent function type"; break; case Tag::K_Cn: entity = "continuation type"; break; case Tag::K_Fn: entity = "returning continuation type"; break; default: fe::unreachable(); } - ir::Pi* first = nullptr; - std::deque pis; - scopes_.push(); + Ptrs doms; do { + auto track = tracker(); auto implicit = (bool)accept(Tag::T_dot); - auto prec = tok.isa(Tag::K_Cn) ? Tok::Prec::Bot : Tok::Prec::App; - auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec); - auto dom_t = dom->type(world(), def2fields_); - auto pi = (outer ? outer : world().mut_pi(world().type_infer_univ()))->set_dom(dom_t)->set(dom->dbg()); - auto var = pi->var()->set(dom->sym()); - first = first ? first : pi; - - if (implicit) pi->make_implicit(); - dom->bind(scopes_, var); - pis.emplace_back(pi); + auto prec = tag == Tag::K_Cn ? Tok::Prec::Bot : Tok::Prec::App; + auto ptrn = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec); + doms.emplace_back(ptr(track, implicit, std::move(ptrn))); } while (ahead().isa(Tag::T_dot) || ahead().isa(Tag::D_brckt_l) || ahead().isa(Tag::T_backtick) || (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon_colon))); - Ref codom; - switch (tok.tag()) { - case Tag::T_Pi: - expect(Tag::T_arrow, entity); - codom = parse_expr("codomain of a dependent function type", Tok::Prec::Arrow); - break; - case Tag::K_Cn: codom = world().Bot(); break; - case Tag::K_Fn: { - expect(Tag::T_arrow, entity); - codom = world().Bot(); - auto ret = parse_expr("domain of return continuation", Tok::Prec::Arrow); - auto pi = pis.back(); - auto last = world().sigma({pi->dom(), world().cn(ret)}); - pi->unset()->set_dom(last); - break; - } - default: fe::unreachable(); - } - - for (auto pi : pis | std::ranges::views::reverse) { - pi->set_codom(codom); - codom = pi; - } + auto codom = tag != Tag::K_Cn + ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) + : nullptr; - first->set(track.loc()); - scopes_.pop(); - return first; + return ptr(track.loc(), tag, std::move(doms), std::move(codom)); } -ir::Lam* Parser::parse_lam(bool is_decl) { - auto track = tracker(); - auto tok = lex(); - auto prec = tok.isa(Tag::K_cn) || tok.isa(Tag::K_con) ? Tok::Prec::Bot : Tok::Prec::Pi; - bool external = is_decl && (bool)accept(Tag::K_extern); +Ptr Parser::parse_lam_expr() { + auto track = tracker(); + auto tag = lex().tag(); + auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Tok::Prec::Bot : Tok::Prec::Pi; + bool decl; std::string entity; // clang-format off - switch (tok.tag()) { - case Tag::T_lm: entity = "function expression"; break; - case Tag::K_cn: entity = "continuation expression"; break; - case Tag::K_fn: entity = "returning continuation expression"; break; - case Tag::K_lam: entity = "function declaration"; break; - case Tag::K_con: entity = "continuation declaration"; break; - case Tag::K_fun: entity = "returning continuation declaration"; break; + switch (tag) { + case Tag::T_lm: decl = false; entity = "function expression"; break; + case Tag::K_cn: decl = false; entity = "continuation expression"; break; + case Tag::K_fn: decl = false; entity = "returning continuation expression"; break; + case Tag::K_lam: decl = true ; entity = "function declaration"; break; + case Tag::K_con: decl = true ; entity = "continuation declaration"; break; + case Tag::K_fun: decl = true ; entity = "returning continuation declaration"; break; default: fe::unreachable(); } // clang-format on - auto [dbg, anx] = is_decl ? parse_name(entity) : std::pair(Dbg{prev_, anonymous_}, false); - auto outer = scopes_.curr(); - ir::Lam* decl = nullptr; - - if (auto def = scopes_.query(dbg)) { - if (auto lam = def->isa_mut()) - decl = lam; - else - error(dbg.loc, "'{}' has not been declared as a function", dbg.sym); - } - - Ptr dom_p; - scopes_.push(); - std::deque> funs; + auto sym = decl ? parse_name(entity) : Sym(); + Ptrs doms; do { - const Def* filter = accept(Tag::T_bang) ? world().lit_tt() : nullptr; - bool implicit = (bool)accept(Tag::T_dot); - dom_p = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); - auto dom_t = dom_p->type(world(), def2fields_); - auto pi = world().mut_pi(world().type_infer_univ(), implicit)->set_dom(dom_t); - auto lam = (funs.empty() && decl) ? decl : world().mut_lam(pi); - auto var = lam->var()->set(dom_p->loc(), dom_p->sym()); - dom_p->bind(scopes_, var); + auto track = tracker(); + auto bang = accept(Tag::T_bang); + auto filter = bang ? ptr(bang) : Ptr(); + bool implicit = (bool)accept(Tag::T_dot); + auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); if (auto tok = accept(Tag::T_at)) { if (filter) error(tok.loc(), "filter already specified via '!'"); @@ -460,121 +357,41 @@ ir::Lam* Parser::parse_lam(bool is_decl) { expect(Tag::D_paren_r, "closing parenthesis of a filter"); } - funs.emplace_back(std::tuple(pi, lam, filter)); + doms.emplace_back(ptr(track, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); - Ref codom; - switch (tok.tag()) { - case Tag::T_lm: - case Tag::K_lam: { - codom = accept(Tag::T_colon) ? parse_expr("return type of a "s + entity) : world().mut_infer_type(); - break; - } - case Tag::K_cn: - case Tag::K_con: codom = world().Bot(); break; - case Tag::K_fn: - case Tag::K_fun: { - auto& [pi, lam, filter] = funs.back(); - - codom = world().Bot(); - auto track = tracker(); - auto ret = accept(Tag::T_colon) ? parse_expr("return type of a "s + entity) : world().mut_infer_type(); - auto ret_loc = dom_p->loc() + track.loc(); - auto sigma = world().mut_sigma(2)->set(0, pi->dom()); - - // Fix wrong dependencies: - // Connect old filter to lam and ret to pi. Otherwise, scope will not find it. - // 1. ret depends on lam->var() instead of sigma->var(2, 0) - pi->set_codom(ret); - if (filter) lam->set_filter(filter); - auto old_var = lam->var()->as(); - auto rw = VarRewriter(old_var, sigma->var(2, 0)); - sigma->set(1, world().cn({rw.rewrite(ret)})); - - auto new_pi = world().mut_pi(pi->type(), pi->is_implicit())->set(ret_loc)->set_dom(sigma); - auto new_lam = world().mut_lam(new_pi); - auto new_var = new_lam->var()->set(ret_loc); - - // 2. filter depends on lam->var() instead of new_lam->var(2, 0) - if (filter) filter = rewrite(filter, lam, new_lam->var(2, 0)->set(lam->var()->dbg())); - - pi->unset(); - pi = new_pi; - lam->unset(); - lam = new_lam; - - dom_p->bind(scopes_, new_var->proj(2, 0), true); - scopes_.bind({ret_loc, return_}, new_var->proj(2, 1)->set(Dbg{ret_loc, return_})); - break; - } - default: fe::unreachable(); - } - - auto [_, first, __] = funs.front(); - first->set(dbg.sym); - - for (auto [pi, lam, _] : funs | std::ranges::views::reverse) { - // First, connect old codom to lam. Otherwise, scope will not find it. Then, rewrite. - pi->set_codom(codom); - auto rw = VarRewriter(lam->var()->as(), pi->var()->set(lam->var()->dbg())); - auto dom = pi->dom(); - codom = rw.rewrite(codom); - pi->reset({dom, codom}); - codom = pi; - } - - if (!decl) { - scopes_.bind(outer, dbg, first); - if (external) first->make_external(); - } + auto codom = (tag != Tag::K_cn && tag != Tag::K_con) + ? (expect(Tag::T_colon, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) + : nullptr; - auto body = accept(Tag::T_assign) ? parse_decls("body of a "s + entity) : nullptr; + auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : Ptr(); +#if 0 if (!body) { if (!is_decl) error(prev_, "body of a {}", entity); if (auto [_, __, filter] = funs.back(); filter) error(prev_, "cannot specify filter of a {}", entity); } +#endif - // filter defaults to .tt for everything except the actual continuation of con/cn/fun/fn; here we use .ff as default - bool last = true; - for (auto [_, lam, filter] : funs | std::ranges::views::reverse) { - bool is_cn - = last - && (tok.tag() == Tag::K_con || tok.tag() == Tag::K_cn || tok.tag() == Tag::K_fun || tok.tag() == Tag::K_fn); - if (body) lam->set(filter ? filter : is_cn ? world().lit_ff() : world().lit_tt(), body); - body = lam; - last = false; - } - - if (is_decl) expect(Tag::T_semicolon, "end of "s + entity); - if (anx) register_annex(dbg, first); - - first->set(track.loc()); + // if (is_decl) expect(Tag::T_semicolon, "end of "s + entity); - scopes_.pop(); - return first; + return ptr(track, tag, sym, std::move(doms), std::move(codom), std::move(body)); } -Ref Parser::parse_ret_expr() { +Ptr Parser::parse_ret_expr() { + auto track = tracker(); eat(Tag::K_ret); auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a ret expression"); expect(Tag::T_assign, "let expression"); - - auto cn = parse_expr("continuation expression of a ret expression"); + auto callee = parse_expr("continuation expression of a ret expression"); expect(Tag::T_dollar, "separator of a ret expression"); - if (auto ret_pi = ir::Pi::ret_pi(cn->type())) { - auto arg = parse_expr("argument of ret expression"); - expect(Tag::T_semicolon, "let expression"); - auto lam = world().mut_lam(ret_pi); - ptrn->bind(scopes_, lam->var()); - auto body = parse_decls("body of a ret expression"); - lam->set(false, body); - return world().app(cn, {arg, lam}); - } - - error(prev_, "continuation of the ret expression is not a returning continuation but has type '{}'", cn->type()); + auto arg = parse_expr("argument of ret expression"); + expect(Tag::T_semicolon, "let expression"); + auto decls = parse_block_expr("body of a ret expression"); + return ptr(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(decls)); } -Ref Parser::parse_lit_expr() { +#if 0 +Ptr Parser::parse_lit_expr() { auto track = tracker(); auto tok = lex(); auto [_, r] = Tok::prec(Tok::Prec::Lit); @@ -602,6 +419,7 @@ Ref Parser::parse_lit_expr() { return world().lit_nat(tok.lit_u())->set(track.loc()); } +#endif /* * ptrns @@ -609,7 +427,7 @@ Ref Parser::parse_lit_expr() { Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) { auto track = tracker(); - auto sym = anonymous_; + auto sym = ast().anonymous(); bool p = delim_l == Tag::D_paren_l; bool b = delim_l == Tag::D_brckt_l; assert((p ^ b) && "left delimiter must either be '(' or '['"); @@ -626,10 +444,10 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec if (p && ahead().isa(Tag::D_paren_l)) { // p -> (p, ..., p) - return parse_tuple_ptrn(track, false, sym); + return parse_tuple_ptrn(false, sym); } else if (ahead().isa(Tag::D_brckt_l)) { // p -> [b, ..., b] b -> [b, ..., b] - return parse_tuple_ptrn(track, false, sym); + return parse_tuple_ptrn(false, sym); } auto backtick = accept(Tag::T_backtick); @@ -654,7 +472,7 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec // b -> 's::(p, ..., p) // b -> 's::[b, ..., b] b -> 's::[b, ..., b] if (ahead().isa(Tag::D_paren_l) || ahead().isa(Tag::D_brckt_l)) - return parse_tuple_ptrn(track, rebind, sym); + return parse_tuple_ptrn(rebind, sym); else syntax_err("tuple pattern after '" + sym.str() + "::'", ctxt); } else if (ahead(1).isa(Tag::T_colon)) { @@ -663,7 +481,7 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec sym = eat(Tag::M_id).sym(); eat(Tag::T_colon); auto type = parse_expr(ctxt, prec); - return ast_.ptr(ast_, dbg(track, sym), rebind, type); + return ptr(track, rebind, sym, std::move(type)); } else { // p -> s b -> e where e == id // p -> 's @@ -671,18 +489,18 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec // p -> s // p -> 's sym = eat(Tag::M_id).sym(); - return ast_.ptr(ast_, dbg(track, sym), rebind, nullptr); + return ptr(track, rebind, sym, nullptr); } else { // b -> e where e == id auto type = parse_expr(ctxt, prec); - return ast_.ptr(ast_, dbg(track, sym), rebind, type); + return ptr(track, rebind, sym, std::move(type)); } } } else if (b) { // b -> e where e != id if (backtick) error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding"); auto type = parse_expr(ctxt, prec); - return ast_.ptr(ast_, dbg(track, sym), rebind, type); + return ptr(track, rebind, sym, std::move(type)); } else if (!ctxt.empty()) { // p -> ↯ syntax_err("pattern", ctxt); @@ -691,21 +509,16 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec return nullptr; } -Ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, Sym sym, Def* decl) { +Ptr Parser::parse_tuple_ptrn(bool rebind, Sym sym) { + auto track = tracker(); auto delim_l = ahead().tag(); bool p = delim_l == Tag::D_paren_l; bool b = delim_l == Tag::D_brckt_l; assert(p ^ b); Ptrs ptrns; - std::vector infers; - DefVec ops; - - scopes_.push(); parse_list("tuple pattern", delim_l, [&]() { - parse_decls({}); auto track = tracker(); - if (!ptrns.empty()) ptrns.back()->bind(scopes_, infers.back()); Ptr ptrn; if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) { @@ -716,62 +529,59 @@ Ptr Parser::parse_tuple_ptrn(Tracker track, bool rebind, Sym sym, Def auto type = parse_expr("type of an identifier group within a tuple pattern"); for (size_t i = 0, e = sym_toks.size(); i != e; ++i) { - auto tok = sym_toks[i]; - infers.emplace_back(world().mut_infer(type)->set(tok.dbg())); - ops.emplace_back(type); - auto ptrn = ast_.ptr(ast_, tok.dbg(), false, type); - if (i != e - 1) ptrn->bind(scopes_, infers.back()); // last element will be bound above + auto tok = sym_toks[i]; + auto ptrn = ptr(tok.loc(), false, tok.sym(), std::move(type)); ptrns.emplace_back(std::move(ptrn)); } return; } // "x y z" is a curried app and maybe the prefix of a longer type expression - auto lhs = scopes_.find(sym_toks.front().dbg()); + Ptr lhs = ptr(sym_toks.front()); for (auto sym_tok : sym_toks | std::views::drop(1)) { - auto rhs = scopes_.find(sym_tok.dbg()); - lhs = world().iapp(lhs, rhs)->set(lhs->loc() + sym_tok.loc()); + auto rhs = ptr(sym_tok); + lhs = ptr(track, false, std::move(lhs), std::move(rhs)); } auto [_, r] = Tok::prec(Tok::Prec::App); - auto expr = parse_infix_expr(track, lhs, r); - ptrn = ast_.ptr(ast_, dbg(track, anonymous_), false, expr); + auto expr = parse_infix_expr(track, std::move(lhs), r); + ptrn = ptr(std::move(expr)); } else { - ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); - auto type = ptrn->type(world(), def2fields_); - - if (b) { // If we are able to parse more stuff, we got an expression instead of just a binder. - if (auto expr = parse_infix_expr(track, type); expr != type) - ptrn = ast_.ptr(ast_, dbg(track, anonymous_), false, expr); - } + ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); + + if (b) + // If we are able to parse more stuff, we got an expr instead of a binder: + // [..., [.Nat, .Nat] -> .Nat, ...] ==> [..., _: [.Nat, .Nat] -> .Nat, ...] +#if 0 + if (auto new_expr = parse_infix_expr(track, std::move(expr)); new_expr != expr) + ptrn = ptr(expr); +#endif + assert(false && "TODO"); } - auto type = ptrn->type(world(), def2fields_); - infers.emplace_back(world().mut_infer(type)->set(ptrn->sym())); - ops.emplace_back(type); ptrns.emplace_back(std::move(ptrn)); }); - scopes_.pop(); // TODO parse type - return ast_.ptr(ast_, dbg(track, sym), rebind, std::move(ptrns), nullptr, std::move(infers), decl); + return ptr(track, rebind, sym, delim_l, std::move(ptrns), nullptr); } /* * decls */ -Ref Parser::parse_decls(std::string_view ctxt) { +#if 0 +Ptrs Parser::parse_decls(std::string_view ctxt) { while (true) { // clang-format off switch (ahead().tag()) { case Tag::T_semicolon: lex(); break; // eat up stray semicolons - case Tag::K_ax: parse_ax_decl(); break; + //case Tag::K_ax: parse_ax_decl(); break; case Tag::K_let: parse_let_decl(); break; case Tag::K_Sigma: parse_sigma_decl(); break; case Tag::K_Pi: parse_pi_decl(); break; case Tag::K_con: case Tag::K_fun: - case Tag::K_lam: parse_lam(true); break; + case Tag::K_lam: parse_lam_decl(); break; default: return ctxt.empty() ? nullptr : parse_expr(ctxt); } // clang-format on @@ -856,126 +666,48 @@ void Parser::parse_ax_decl() { expect(Tag::T_semicolon, "end of an axiom"); } -void Parser::parse_let_decl() { +#endif + +Ptr Parser::parse_let_decl() { auto track = tracker(); eat(Tag::K_let); - std::variant, Dbg> name; - Ref type; - if (auto tok = accept(Tag::M_anx)) { - name = tok.dbg(); - type = parse_type_ascr(); - } else { - auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration"); - type = ptrn->type(world(), def2fields_); - name = std::move(ptrn); - } + // Ptr ptrn; + // TODO annex + // if (auto tok = accept(Tag::M_anx)) { + // ptrn = ptr( + //} else { + auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration"); expect(Tag::T_assign, "let"); + auto type = parse_type_ascr(); auto value = parse_expr("value of a let declaration"); - - if (type && !Check::assignable(type, value)) - error(track.loc(), "cannot assign value `{}` of type `{}` to its declared type `{}` in a let declaration", - value, value->type(), type); - - if (auto dbg = std::get_if(&name)) { - scopes_.bind(*dbg, value); - register_annex(*dbg, value); - } else { - std::get>(name)->bind(scopes_, value); - } - expect(Tag::T_semicolon, "let declaration"); + return ptr(track, std::move(ptrn), std::move(value)); } -void Parser::parse_sigma_decl() { +Ptr Parser::parse_pi_decl() { auto track = tracker(); - eat(Tag::K_Sigma); - auto [dbg, anx] = parse_name("sigma declaration"); - auto type = accept(Tag::T_colon) ? parse_expr("type of a sigma declaration") : world().type(); - auto arity = std::optional{}; - if (accept(Tag::T_comma)) arity = expect(Tag::L_u, "arity of a sigma").lit_u(); - - if (accept(Tag::T_assign)) { - Def* decl; - if (auto def = scopes_.query(dbg)) { - if ((!def->isa_mut() && !def->isa()) || !def->isa_lit_arity()) - error(dbg.loc, "'{}' has not been declared as a sigma", dbg.sym); - if (!Check::alpha(def->type(), type)) - error(dbg.loc, "'{}' of type '{}' has been redeclared with a different type '{}'; here: {}", dbg.sym, - def->type(), type, def->loc()); - if (arity && *arity != def->as_lit_arity()) - error(dbg.loc, "sigma '{}' redeclared with a different arity '{}'; previous arity was '{}' here: {}", - dbg.sym, *arity, def->arity(), def->loc()); - decl = def->as_mut(); - if (decl->is_set()) - error(dbg.loc, "redefinition of '{}'; previous definition here: '{}'", dbg.sym, decl->loc()); - } else { - decl = (arity ? (Def*)world().mut_sigma(type, *arity) : (Def*)world().mut_infer(type))->set(dbg); - scopes_.bind(dbg, decl); - } - - if (!ahead().isa(Tag::D_brckt_l)) syntax_err("sigma expression", "definition of a sigma declaration"); - - auto ptrn = parse_tuple_ptrn(track, false, dbg.sym, decl); - auto t = ptrn->type(world(), def2fields_); - - assert(t->isa_mut()); - t->set(track.loc()); - if (anx) register_annex(dbg, t); - - if (auto infer = decl->isa()) { - assert(infer->op() == t); - infer->set(track.loc()); - scopes_.bind(dbg, t, true); // rebind dbg to point to sigma instead of infer - } else { - assert(t == decl); - } - } else { - auto decl = (arity ? (Def*)world().mut_sigma(type, *arity) : (Def*)world().mut_infer(type))->set(dbg); - scopes_.bind(dbg, decl); - } + eat(Tag::K_Pi); + auto sym = parse_name("pi declaration"); + auto type = accept(Tag::T_colon) ? parse_expr("type of a pi declaration") : Ptr(); + auto body = accept(Tag::T_assign) ? parse_expr("body of a pi declaration") : Ptr(); + expect(Tag::T_semicolon, "end of a pi declaration"); - expect(Tag::T_semicolon, "end of a sigma declaration"); + return ptr(track, sym, std::move(type), std::move(body)); } -void Parser::parse_pi_decl() { - auto track = tracker(); - eat(Tag::K_Pi); - auto [dbg, anx] = parse_name("pi declaration"); - auto type = accept(Tag::T_colon) ? parse_expr("type of a pi declaration") : world().type(); - - if (accept(Tag::T_assign)) { - ir::Pi* pi; - if (auto def = scopes_.query(dbg)) { - if (auto mut = def->isa_mut()) { - if (!Check::alpha(mut->type(), type)) - error(dbg.loc, "'{}' of type '{}' has been redeclared with a different type '{}'; here: {}", - dbg.sym, mut->type(), type, mut->loc()); - if (mut->is_set()) - error(dbg.loc, "redefinition of '{}'; previous definition here: '{}'", dbg.sym, mut->loc()); - pi = mut; - } else { - error(dbg.loc, "'{}' has not been declared as a pi", dbg.sym); - } - } else { - pi = world().mut_pi(type)->set(dbg); - scopes_.bind(dbg, pi); - } - if (anx) register_annex(dbg, pi); - - if (!ahead().isa(Tag::T_Pi) && !ahead().isa(Tag::K_Cn) && !ahead().isa(Tag::K_Fn)) - syntax_err("pi expression", "definition of a pi declaration"); +Ptr Parser::parse_lam_decl() { return ptr(parse_lam_expr()); } - auto other = parse_pi_expr(pi); - assert_unused(other == pi); - pi->set(track.loc()); - } else { - auto pi = world().mut_pi(type)->set(dbg); - scopes_.bind(dbg, pi); - } +Ptr Parser::parse_sigma_decl() { + auto track = tracker(); + eat(Tag::K_Sigma); + auto sym = parse_name("sigma declaration"); + auto type = accept(Tag::T_colon) ? parse_expr("type of a sigma declaration") : Ptr(); + auto body = accept(Tag::T_assign) ? parse_expr("body of a sigma declaration") : Ptr(); + expect(Tag::T_semicolon, "end of a sigma declaration"); - expect(Tag::T_semicolon, "end of a pi declaration"); + return ptr(track, sym, std::move(type), std::move(body)); } } // namespace thorin::ast From 9c0533faf52cce672d5c3862ef219830890c5fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 29 Mar 2024 02:44:44 +0100 Subject: [PATCH 06/95] first ast dumps working --- include/thorin/ast/ast.h | 231 +++++++++++++++++++++++++----------- include/thorin/ast/parser.h | 10 +- include/thorin/ast/tok.h | 1 + src/thorin/CMakeLists.txt | 1 + src/thorin/ast/parser.cpp | 78 ++++++------ src/thorin/ast/stream.cpp | 139 ++++++++++++++++++++++ src/thorin/cli/main.cpp | 10 +- 7 files changed, 359 insertions(+), 111 deletions(-) create mode 100644 src/thorin/ast/stream.cpp diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 848e176469..aa4f361442 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -40,7 +40,7 @@ class AST { ///@} template auto ptr(Args&&... args) { - return arena_.mk(*this, std::forward(args)...); + return arena_.mk(std::forward(args)...); } private: @@ -53,30 +53,29 @@ class Scopes; class Node : public fe::RuntimeCast { protected: - Node(AST& ast, Loc loc) - : ast_(ast) - , loc_(loc) {} + Node(Loc loc) + : loc_(loc) {} virtual ~Node() {} public: - AST& ast() const { return ast_; } Loc loc() const { return loc_; } + virtual std::ostream& stream(Tab&, std::ostream&) const = 0; + private: - AST& ast_; Loc loc_; }; class Expr : public Node { protected: - Expr(AST& ast, Loc loc) - : Node(ast, loc) {} + Expr(Loc loc) + : Node(loc) {} }; class Decl : public Node { protected: - Decl(AST& ast, Loc loc, Sym sym) - : Node(ast, loc) + Decl(Loc loc, Sym sym) + : Node(loc) , sym_(sym) {} public: @@ -92,20 +91,16 @@ class Decl : public Node { class Ptrn : public Node { public: - Ptrn(AST& ast, Loc loc, bool rebind, Sym sym, Ptr&& type) - : Node(ast, loc) - , rebind_(rebind) - , sym_(sym) - , type_(std::move(type)) {} + Ptrn(Loc loc) + : Node(loc) {} bool rebind() const { return rebind_; } Sym sym() const { return sym_; } Dbg dbg() const { return {loc(), sym()}; } bool is_anonymous() const { return sym() == '_'; } + const Expr* type() const { return type_.get(); } - [[nodiscard]] static Ptr expr(AST& ast, Ptr&&); - - virtual Ptr expr() const = 0; + [[nodiscard]] static Ptr expr(AST&, Ptr&&); // virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; // virtual const Def* type(World&, Def2Fields&) const = 0; @@ -117,33 +112,76 @@ class Ptrn : public Node { class IdPtrn : public Ptrn { public: - IdPtrn(AST& ast, Loc loc, bool rebind, Sym sym, Ptr&& type) - : Ptrn(ast, loc, rebind, sym, std::move(type)) {} - IdPtrn(AST& ast, Ptr&& type) - : Ptrn(ast, type->loc(), false, ast.anonymous(), std::move(type)) {} + IdPtrn(Loc loc, bool rebind, Sym sym, Ptr&& type) + : Ptrn(loc) + , rebind_(rebind) + , sym_(sym) + , type_(std::move(type)) {} + + bool rebind() const { return rebind_; } + Sym sym() const { return sym_; } + + static Ptr mk_type(AST& ast, Ptr&& type) { + return ast.ptr(type->loc(), false, ast.anonymous(), std::move(type)); + } + + // void bind(Scopes&, const Def*, bool rebind = false) const override {} + // const Def* type(World&, Def2Fields&) const override {} + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + bool rebind_; + Sym sym_; + Ptr type_; +}; + +/// `sym_0 ... sym_n-1 : type` +class GroupPtrn : public Ptrn { +public: + GroupPtrn(Loc loc, std::deque&& syms, Ptr&& type) + : Ptrn(loc) + , syms_(std::move(syms)) + , type_(std::move(type)) {} + + const auto& syms() const { return syms_; } + const Expr* type() const { return type_.get(); } + + static Ptr mk_type(AST& ast, Ptr&& type) { + return ast.ptr(type->loc(), false, ast.anonymous(), std::move(type)); + } - Ptr expr() const override; // void bind(Scopes&, const Def*, bool rebind = false) const override {} // const Def* type(World&, Def2Fields&) const override {} + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + std::deque syms_; + Ptr type_; }; class TuplePtrn : public Ptrn { public: - TuplePtrn(AST& ast, Loc loc, bool rebind, Sym sym, Tok::Tag tag, Ptrs&& ptrns, Ptr&& type) - : Ptrn(ast, loc, rebind, sym, std::move(type)) + TuplePtrn(Loc loc, bool rebind, Sym sym, Tok::Tag tag, Ptrs&& ptrns) + : Ptrn(loc) + , rebind_(rebind) + , sym_(sym) , tag_(tag) , ptrns_(std::move(ptrns)) {} + bool rebind() const { return rebind_; } + Sym sym() const { return sym_; } Tok::Tag tag() const { return tag_; } const auto& ptrns() const { return ptrns_; } const Ptrn* ptrn(size_t i) const { return ptrns_[i].get(); } size_t num_ptrns() const { return ptrns().size(); } - Ptr expr() const override; // void bind(Scopes&, const Def*, bool rebind = false) const override {} // const Def* type(World&, Def2Fields&) const override {} + std::ostream& stream(Tab&, std::ostream&) const override; private: + bool rebind_; + Sym sym_; Tok::Tag tag_; Ptrs ptrns_; }; @@ -152,36 +190,57 @@ class TuplePtrn : public Ptrn { * Expr */ +/// `sym` class IdExpr : public Expr { public: - IdExpr(AST& ast, Loc loc, Sym sym) - : Expr(ast, loc) + IdExpr(Loc loc, Sym sym) + : Expr(loc) , sym_(sym) {} - IdExpr(AST& ast, Tok tok) - : IdExpr(ast, tok.loc(), tok.sym()) {} + IdExpr(Tok tok) + : IdExpr(tok.loc(), tok.sym()) {} Sym sym() const { return sym_; } + std::ostream& stream(Tab&, std::ostream&) const override; private: Sym sym_; }; +/// `tag` class PrimaryExpr : public Expr { public: - PrimaryExpr(AST& ast, Tok tok) - : Expr(ast, tok.loc()) + PrimaryExpr(Tok tok) + : Expr(tok.loc()) , tag_(tok.tag()) {} Tok::Tag tag() const { return tag_; } + std::ostream& stream(Tab&, std::ostream&) const override; private: Tok::Tag tag_; }; +/// `tag:type` +class LitExpr : public Expr { +public: + LitExpr(Loc loc, Tok value, Ptr&& type) + : Expr(loc) + , value_(value) + , type_(std::move(type)) {} + + Tok value() const { return value_; } + const Expr* type() const { return type_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Tok value_; + Ptr type_; +}; + class BlockExpr : public Expr { public: - BlockExpr(AST& ast, Loc loc, Ptrs&& decls, Ptr&& expr) - : Expr(ast, loc) + BlockExpr(Loc loc, Ptrs&& decls, Ptr&& expr) + : Expr(loc) , decls_(std::move(decls)) , expr_(std::move(expr)) {} @@ -189,24 +248,39 @@ class BlockExpr : public Expr { const Decl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } const Expr* expr() const { return expr_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptrs decls_; Ptr expr_; }; +class TypeExpr : public Expr { +public: + TypeExpr(Loc loc, Ptr&& level) + : Expr(loc) + , level_(std::move(level)) {} + + const Expr* level() const { return level_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Ptr level_; +}; + // lam class SimplePiExpr : public Expr { public: - SimplePiExpr(AST& ast, Loc loc, Ptr&& dom, Ptr&& codom) - : Expr(ast, loc) + SimplePiExpr(Loc loc, Ptr&& dom, Ptr&& codom) + : Expr(loc) , dom_(std::move(dom)) , codom_(std::move(codom)) {} private: const Expr* dom() const { return dom_.get(); } const Expr* codom() const { return codom_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr dom_; @@ -217,21 +291,22 @@ class PiExpr : public Expr { public: class Dom : public Node { public: - Dom(AST& ast, Loc loc, bool implicit, Ptr&& ptrn) - : Node(ast, loc) + Dom(Loc loc, bool implicit, Ptr&& ptrn) + : Node(loc) , implicit_(implicit) , ptrn_(std::move(ptrn)) {} bool implicit() const { return implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: bool implicit_; Ptr ptrn_; }; - PiExpr(AST& ast, Loc loc, Tok::Tag tag, Ptrs&& doms, Ptr&& codom) - : Expr(ast, loc) + PiExpr(Loc loc, Tok::Tag tag, Ptrs&& doms, Ptr&& codom) + : Expr(loc) , tag_(tag) , doms_(std::move(doms)) , codom_(std::move(codom)) {} @@ -242,6 +317,7 @@ class PiExpr : public Expr { const Dom* dom(size_t i) const { return doms_[i].get(); } size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Tok::Tag tag_; @@ -253,18 +329,19 @@ class LamExpr : public Expr { public: class Dom : public PiExpr::Dom { public: - Dom(AST& ast, Loc loc, bool implicit, Ptr&& ptrn, Ptr&& filter) - : PiExpr::Dom(ast, loc, implicit, std::move(ptrn)) + Dom(Loc loc, bool implicit, Ptr&& ptrn, Ptr&& filter) + : PiExpr::Dom(loc, implicit, std::move(ptrn)) , filter_(std::move(filter)) {} const Expr* filter() const { return filter_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr filter_; }; - LamExpr(AST& ast, Loc loc, Tok::Tag tag, Sym sym, Ptrs&& doms, Ptr&& codom, Ptr&& body) - : Expr(ast, loc) + LamExpr(Loc loc, Tok::Tag tag, Sym sym, Ptrs&& doms, Ptr&& codom, Ptr&& body) + : Expr(loc) , tag_(tag) , sym_(sym) , doms_(std::move(doms)) @@ -277,6 +354,7 @@ class LamExpr : public Expr { const Dom* dom(size_t i) const { return doms_[i].get(); } const Expr* codom() const { return codom_.get(); } const Expr* body() const { return body_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Tok::Tag tag_; @@ -284,13 +362,12 @@ class LamExpr : public Expr { Ptrs doms_; Ptr codom_; Ptr body_; - ; }; class AppExpr : public Expr { public: - AppExpr(AST& ast, Loc loc, bool is_explicit, Ptr&& callee, Ptr&& arg) - : Expr(ast, loc) + AppExpr(Loc loc, bool is_explicit, Ptr&& callee, Ptr&& arg) + : Expr(loc) , is_explicit_(is_explicit) , callee_(std::move(callee)) , arg_(std::move(arg)) {} @@ -298,6 +375,7 @@ class AppExpr : public Expr { bool is_explicit() const { return is_explicit_; } const Expr* callee() const { return callee_.get(); } const Expr* arg() const { return arg_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: bool is_explicit_; @@ -307,8 +385,8 @@ class AppExpr : public Expr { class RetExpr : public Expr { public: - RetExpr(AST& ast, Loc loc, Ptr&& ptrn, Ptr&& callee, Ptr&& arg, Ptr body) - : Expr(ast, loc) + RetExpr(Loc loc, Ptr&& ptrn, Ptr&& callee, Ptr&& arg, Ptr body) + : Expr(loc) , ptrn_(std::move(ptrn)) , callee_(std::move(callee)) , arg_(std::move(arg)) @@ -318,6 +396,7 @@ class RetExpr : public Expr { const Expr* callee() const { return callee_.get(); } const Expr* arg() const { return arg_.get(); } const Expr* body() const { return body_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr ptrn_; @@ -329,11 +408,12 @@ class RetExpr : public Expr { class SigmaExpr : public Expr { public: - SigmaExpr(AST& ast, Ptr&& ptrn) - : Expr(ast, ptrn->loc()) + SigmaExpr(Ptr&& ptrn) + : Expr(ptrn->loc()) , ptrn_(std::move(ptrn)) {} const Ptrn* ptrn() const { return ptrn_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr ptrn_; @@ -341,13 +421,14 @@ class SigmaExpr : public Expr { class TupleExpr : public Expr { public: - TupleExpr(AST& ast, Loc loc, Ptrs&& elems) - : Expr(ast, loc) + TupleExpr(Loc loc, Ptrs&& elems) + : Expr(loc) , elems_(std::move(elems)) {} const auto& elems() const { return elems_; } const Expr* elem(size_t i) const { return elems_[i].get(); } size_t num_elems() const { return elems().size(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptrs elems_; @@ -355,8 +436,8 @@ class TupleExpr : public Expr { template class ArrOrPackExpr : public Expr { public: - ArrOrPackExpr(AST& ast, Loc loc, Sym sym, Ptr&& shape, Ptr&& body) - : Expr(ast, loc) + ArrOrPackExpr(Loc loc, Sym sym, Ptr&& shape, Ptr&& body) + : Expr(loc) , sym_(sym) , shape_(std::move(shape)) , body_(std::move(body)) {} @@ -364,6 +445,7 @@ template class ArrOrPackExpr : public Expr { Sym sym() const { return sym_; } const Expr* shape() const { return shape_.get(); } const Expr* body() const { return body_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Sym sym_; @@ -376,13 +458,14 @@ using PackExpr = ArrOrPackExpr; class ExtractExpr : public Expr { public: - ExtractExpr(AST& ast, Loc loc, Ptr&& tuple, Ptr&& index) - : Expr(ast, loc) + ExtractExpr(Loc loc, Ptr&& tuple, Ptr&& index) + : Expr(loc) , tuple_(std::move(tuple)) , index_(std::move(index)) {} const Expr* tuple() const { return tuple_.get(); } const Expr* index() const { return index_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr tuple_; @@ -391,8 +474,8 @@ class ExtractExpr : public Expr { class InsertExpr : public Expr { public: - InsertExpr(AST& ast, Loc loc, Ptr&& tuple, Ptr&& index, Ptr&& value) - : Expr(ast, loc) + InsertExpr(Loc loc, Ptr&& tuple, Ptr&& index, Ptr&& value) + : Expr(loc) , tuple_(std::move(tuple)) , index_(std::move(index)) , value_(std::move(value)) {} @@ -400,6 +483,7 @@ class InsertExpr : public Expr { const Expr* tuple() const { return tuple_.get(); } const Expr* index() const { return index_.get(); } const Expr* value() const { return value_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr tuple_; @@ -413,13 +497,14 @@ class InsertExpr : public Expr { class LetDecl : public Decl { public: - LetDecl(AST& ast, Loc loc, Ptr&& ptrn, Ptr&& value) - : Decl(ast, loc, ptrn->sym()) + LetDecl(Loc loc, Ptr&& ptrn, Ptr&& value) + : Decl(loc, ptrn->sym()) , ptrn_(std::move(ptrn)) , value_(std::move(value)) {} const Ptrn* ptrn() const { return ptrn_.get(); } const Expr* value() const { return value_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr ptrn_; @@ -428,19 +513,20 @@ class LetDecl : public Decl { class AxiomDecl : public Decl { public: - AxiomDecl(AST& ast, Loc loc, Sym sym) - : Decl(ast, loc, sym) {} + AxiomDecl(Loc loc, Sym sym) + : Decl(loc, sym) {} }; class PiDecl : public Decl { public: - PiDecl(AST& ast, Loc loc, Sym sym, Ptr&& type, Ptr&& body) - : Decl(ast, loc, sym) + PiDecl(Loc loc, Sym sym, Ptr&& type, Ptr&& body) + : Decl(loc, sym) , type_(std::move(type)) , body_(std::move(body)) {} const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr type_; @@ -449,11 +535,12 @@ class PiDecl : public Decl { class LamDecl : public Decl { public: - LamDecl(AST& ast, Ptr&& lam) - : Decl(ast, lam->loc(), lam->sym()) + LamDecl(Ptr&& lam) + : Decl(lam->loc(), lam->sym()) , lam_(std::move(lam)) {} const LamExpr* lam() const { return lam_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr lam_; @@ -461,13 +548,14 @@ class LamDecl : public Decl { class SigmaDecl : public Decl { public: - SigmaDecl(AST& ast, Loc loc, Sym sym, Ptr&& type, Ptr&& body) - : Decl(ast, loc, sym) + SigmaDecl(Loc loc, Sym sym, Ptr&& type, Ptr&& body) + : Decl(loc, sym) , type_(std::move(type)) , body_(std::move(body)) {} const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr type_; @@ -480,13 +568,14 @@ class SigmaDecl : public Decl { class Module : public Node { public: - Module(AST& ast, Loc loc, Ptrs&& decls) - : Node(ast, loc) + Module(Loc loc, Ptrs&& decls) + : Node(loc) , decls_(std::move(decls)) {} const auto& decls() const { return decls_; } const Decl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } + std::ostream& stream(Tab&, std::ostream&) const override; private: Ptrs decls_; diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index f5355e1a79..ff76625647 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -39,9 +39,9 @@ class Parser : public fe::Parser { AST& ast() { return ast_; } World& world() { return world_; } Driver& driver() { return world().driver(); } - void import(std::string_view sv) { return import(driver().sym(sv)); } - void import(Sym, std::ostream* md = nullptr); - void import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); + Ptr import(std::string_view sv) { return import(driver().sym(sv)); } + Ptr import(Sym, std::ostream* md = nullptr); + Ptr import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); void plugin(Sym); void plugin(const char* name) { return plugin(driver().sym(name)); } @@ -86,8 +86,8 @@ class Parser : public fe::Parser { ///@{ template Ptr parse_arr_or_pack_expr(); Ptr parse_block_expr(std::string_view ctxt); ///< Empty @p ctxt means an explicit BlockExpr `{ d* e }`. - Ptr parse_type_expr(); Ptr parse_lit_expr(); + Ptr parse_type_expr(); Ptr parse_ret_expr(); Ptr parse_pi_expr(); Ptr parse_lam_expr(); @@ -110,7 +110,7 @@ class Parser : public fe::Parser { /// If @p ctxt ... /// * ... empty: **Only** decls are parsed. @returns `nullptr` /// * ... **non**-empty: Decls are parsed, then an expression. @returns expression. - Ptrs parse_decls(std::string_view ctxt); + Ptrs parse_decls(); Ptr parse_axiom_decl(); Ptr parse_let_decl(); Ptr parse_pi_decl(); diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 33c5441f21..4f189091ba 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -194,6 +194,7 @@ class Tok { Sym sym() const { assert(isa(Tag::M_anx) || isa(Tag::M_id) || isa(Tag::M_str)); return sym_; } // clang-format on friend std::ostream& operator<<(std::ostream&, Tok); + friend std::ostream& operator<<(std::ostream& os, Tok::Tag tag) { return os << tag2str(tag); } private: Loc loc_; diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index 6274e27c42..1e35e724d6 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(libthorin ast/lexer.cpp ast/parser.cpp ast/scopes.cpp + ast/stream.cpp ast/tok.cpp pass/beta_red.cpp pass/eta_exp.cpp diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 43251ac66d..867c2f2263 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -34,12 +34,12 @@ Ptr Parser::parse_module() { else break; - auto decls = parse_decls({}); + auto decls = parse_decls(); expect(Tag::EoF, "module"); return ptr(track, std::move(decls)); } -void Parser::import(Sym name, std::ostream* md) { +Ptr Parser::import(Sym name, std::ostream* md) { world().VLOG("import: {}", name); auto filename = fs::path(name.view()); @@ -56,11 +56,12 @@ void Parser::import(Sym name, std::ostream* md) { if (auto path = driver().add_import(std::move(rel_path), name)) { auto ifs = std::ifstream(*path); - import(ifs, path, md); + return import(ifs, path, md); } + return {}; } -void Parser::import(std::istream& is, const fs::path* path, std::ostream* md) { +Ptr Parser::import(std::istream& is, const fs::path* path, std::ostream* md) { world().VLOG("reading: {}", path ? path->string() : ""s); if (!is) error("cannot read file '{}'", *path); @@ -68,8 +69,9 @@ void Parser::import(std::istream& is, const fs::path* path, std::ostream* md) { auto lexer = Lexer(world(), is, path, md); lexer_ = &lexer; init(path); - parse_module(); + auto mod = parse_module(); std::tie(prev_, ahead_, lexer_) = state; + return mod; } void Parser::plugin(Sym name) { @@ -270,12 +272,20 @@ template Ptr Parser::parse_arr_or_pack_expr() { Ptr Parser::parse_block_expr(std::string_view ctxt) { auto track = tracker(); if (ctxt.empty()) eat(Tag::D_brace_l); - auto decls = parse_decls(ctxt.empty() ? "block expression" : ctxt); + auto decls = parse_decls(); auto expr = parse_expr("final expression in a "s + (ctxt.empty() ? "block expressoin"s : std::string(ctxt))); if (ctxt.empty()) expect(Tag::D_brace_r, "block expression"); return ptr(track, std::move(decls), std::move(expr)); } +Ptr Parser::parse_lit_expr() { + auto track = tracker(); + auto value = lex(); + auto [_, r] = Tok::prec(Tok::Prec::Lit); + auto type = accept(Tag::T_colon) ? parse_expr("literal", r) : Ptr(); + return ptr(track, value, std::move(type)); +} + Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, ast().anonymous())); } Ptr Parser::parse_tuple_expr() { @@ -285,13 +295,13 @@ Ptr Parser::parse_tuple_expr() { return ptr(track, std::move(elems)); } -// Ptr Parser::parse_type_expr() { -// auto track = tracker(); -// eat(Tag::K_Type); -// auto [l, r] = Tok::prec(Tok::Prec::App); -// auto level = parse_expr("type level", r); -// return world().type(level)->set(track.loc()); -// } +Ptr Parser::parse_type_expr() { + auto track = tracker(); + eat(Tag::K_Type); + auto [l, r] = Tok::prec(Tok::Prec::App); + auto level = parse_expr("type level", r); + return ptr(track, std::move(level)); +} Ptr Parser::parse_pi_expr() { auto track = tracker(); @@ -522,29 +532,28 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Sym sym) { Ptr ptrn; if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) { - std::vector sym_toks; - while (auto tok = accept(Tag::M_id)) sym_toks.emplace_back(tok); + std::deque toks; + std::deque syms; + while (auto tok = accept(Tag::M_id)) { + toks.emplace_back(tok); + syms.emplace_back(tok.sym()); + } if (accept(Tag::T_colon)) { // identifier group: x y x: T auto type = parse_expr("type of an identifier group within a tuple pattern"); - - for (size_t i = 0, e = sym_toks.size(); i != e; ++i) { - auto tok = sym_toks[i]; - auto ptrn = ptr(tok.loc(), false, tok.sym(), std::move(type)); - ptrns.emplace_back(std::move(ptrn)); - } + ptrns.emplace_back(ptr(track, std::move(syms), std::move(type))); return; } // "x y z" is a curried app and maybe the prefix of a longer type expression - Ptr lhs = ptr(sym_toks.front()); - for (auto sym_tok : sym_toks | std::views::drop(1)) { - auto rhs = ptr(sym_tok); + Ptr lhs = ptr(toks.front()); + for (auto tok : toks | std::views::drop(1)) { + auto rhs = ptr(tok); lhs = ptr(track, false, std::move(lhs), std::move(rhs)); } auto [_, r] = Tok::prec(Tok::Prec::App); auto expr = parse_infix_expr(track, std::move(lhs), r); - ptrn = ptr(std::move(expr)); + ptrn = IdPtrn::mk_type(ast(), std::move(expr)); } else { ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); @@ -562,32 +571,33 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Sym sym) { }); // TODO parse type - return ptr(track, rebind, sym, delim_l, std::move(ptrns), nullptr); + return ptr(track, rebind, sym, delim_l, std::move(ptrns)); } /* * decls */ -#if 0 -Ptrs Parser::parse_decls(std::string_view ctxt) { +Ptrs Parser::parse_decls() { + Ptrs decls; while (true) { // clang-format off switch (ahead().tag()) { - case Tag::T_semicolon: lex(); break; // eat up stray semicolons + case Tag::T_semicolon: lex(); break; // eat up stray semicolons //case Tag::K_ax: parse_ax_decl(); break; - case Tag::K_let: parse_let_decl(); break; - case Tag::K_Sigma: parse_sigma_decl(); break; - case Tag::K_Pi: parse_pi_decl(); break; + case Tag::K_let: decls.emplace_back(parse_let_decl()); break; + case Tag::K_Sigma: decls.emplace_back(parse_sigma_decl()); break; + case Tag::K_Pi: decls.emplace_back(parse_pi_decl()); break; case Tag::K_con: case Tag::K_fun: - case Tag::K_lam: parse_lam_decl(); break; - default: return ctxt.empty() ? nullptr : parse_expr(ctxt); + case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break; + default: return decls; } // clang-format on } } +#if 0 void Parser::parse_ax_decl() { auto track = tracker(); eat(Tag::K_ax); diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp new file mode 100644 index 0000000000..df0f5055c5 --- /dev/null +++ b/src/thorin/ast/stream.cpp @@ -0,0 +1,139 @@ +#include + +#include "thorin/ast/ast.h" +#include "thorin/util/print.h" + +namespace thorin::ast { + +struct S { + S(Tab& tab, const Node* node) + : tab(tab) + , node(node) {} + + Tab& tab; + const Node* node; + + friend std::ostream& operator<<(std::ostream& os, const S& s) { return s.node->stream(s.tab, os); } +}; + +template struct R { + R(Tab& tab, const Ptrs& range) + : tab(tab) + , range(range) + , f([&tab](std::ostream& os, const Ptr& ptr) { ptr->stream(tab, os); }) {} + + Tab& tab; + const Ptrs& range; + std::function&)> f; +}; + +/* + * Ptrn + */ + +std::ostream& IdPtrn::stream(Tab& tab, std::ostream& os) const { + os << sym(); + if (type()) print(os, ": {}", S(tab, type())); + return os; +} + +std::ostream& GroupPtrn::stream(Tab& tab, std::ostream& os) const { + return print(os, "{ }: {}", syms(), S(tab, type())); +} + +std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { + return print(os, "{}::{}{, }{}", sym(), tag(), R(tab, ptrns()), Tok::delim_l2r(tag())); +} + +/* + * Ptrn + */ + +std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", sym()); } +std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } + +std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { + os << value().lit_u(); + if (type()) print(os, ": {}", S(tab, type())); + return os; +} + +std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { + tab++.println(os, "{{"); + for (auto sep = ""; const auto& decl : decls()) { + decl->stream(tab, os << sep); + sep = "\n"; + } + if (expr()) expr()->stream(tab, os); + return tab--.println(os, "}}"); +} + +std::ostream& TypeExpr ::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } +std::ostream& SimplePiExpr::stream(Tab& tab, std::ostream& os) const { + return print(os, "{} -> {}", S(tab, dom()), S(tab, codom())); +} +std::ostream& PiExpr::Dom ::stream(Tab& tab, std::ostream& os) const { + return print(os, "{}{}", implicit() ? "." : "", S(tab, ptrn())); +} +std::ostream& PiExpr ::stream(Tab& tab, std::ostream& os) const { + return print(os, "{}{} -> {}", tag(), R(tab, doms()), S(tab, codom())); +} + +std::ostream& LamExpr::Dom ::stream(Tab& tab, std::ostream& os) const { + return print(PiExpr::Dom::stream(tab, os), "@({})", filter()); +} +std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { + return print(os, "{}{} -> {} = {}", tag(), R(tab, doms()), S(tab, codom()), S(tab, body())); +} + +std::ostream& AppExpr::stream(Tab& tab, std::ostream& os) const { + return print(os, "{} {}", S(tab, callee()), S(tab, arg())); +} + +std::ostream& RetExpr::stream(Tab& tab, std::ostream& os) const { + println(os, ".ret {} = {} $ {};", S(tab, ptrn()), S(tab, callee()), S(tab, arg())); + return tab.print(os, "{}", S(tab, body())); +} + +std::ostream& SigmaExpr::stream(Tab& tab, std::ostream& os) const { return ptrn()->stream(tab, os); } +std::ostream& TupleExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "({, }", R(tab, elems())); } + +template std::ostream& ArrOrPackExpr::stream(Tab& tab, std::ostream& os) const { + return print(os, "{}{}; {}{}", arr ? "«" : "‹", S(tab, shape()), S(tab, body()), arr ? "»" : "›"); +} + +template std::ostream& ArrOrPackExpr::stream(Tab&, std::ostream&) const; +template std::ostream& ArrOrPackExpr::stream(Tab&, std::ostream&) const; + +std::ostream& ExtractExpr::stream(Tab& tab, std::ostream& os) const { + return print(os, "{}#{}", S(tab, tuple()), S(tab, index())); +} +std::ostream& InsertExpr::stream(Tab& tab, std::ostream& os) const { + return print(os, ".ins({}, {}, {})", S(tab, tuple()), S(tab, index()), S(tab, value())); +} + +/* + * Decl + */ + +std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { + return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); +} + +std::ostream& PiDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".Pi"); } +std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return lam()->stream(tab, os); } +std::ostream& SigmaDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".Sigma"); } + +/* + * Module + */ + +std::ostream& Module::stream(Tab& tab, std::ostream& os) const { + for (auto sep = ""; const auto& decl : decls()) { + tab.print(os, "{}{}", S(tab, decl.get()), sep); + sep = "\n"; + } + return os; +} + +} // namespace thorin::ast diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 4084b1b573..fe974625b6 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -22,7 +22,7 @@ using namespace thorin; using namespace std::literals; int main(int argc, char** argv) { - enum Backends { D, Dot, H, LL, Md, Thorin, Num_Backends }; + enum Backends { AST, D, Dot, H, LL, Md, Thorin, Num_Backends }; try { static const auto version = "thorin command-line utility version " THORIN_VER "\n"; @@ -55,6 +55,7 @@ int main(int argc, char** argv) { | lyra::opt(search_paths, "path" )["-P"]["--plugin-path" ]("Path to search for plugins.") | lyra::opt(inc_verbose )["-V"]["--verbose" ]("Verbose mode. Multiple -V options increase the verbosity. The maximum is 4.").cardinality(0, 4) | lyra::opt(opt, "level" )["-O"]["--optimize" ]("Optimization level (default: 2).") + | lyra::opt(output[AST ], "file" ) ["--output-ast" ]("Directly emits AST represntation of input.") | lyra::opt(output[D ], "file" ) ["--output-d" ]("Emits dependency file containing a rule suitable for 'make' describing the dependencies of the source file (requires --output-h).") | lyra::opt(output[Dot ], "file" ) ["--output-dot" ]("Emits the Thorin program as a graph using Graphviz' DOT language.") | lyra::opt(output[H ], "file" ) ["--output-h" ]("Emits a header file to be used to interface with a plugin in C++.") @@ -138,6 +139,7 @@ int main(int argc, char** argv) { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); auto parser = ast::Parser(world); +#if 0 parser.import(driver.sym(input), os[Md]); if (auto dep = os[D]) { @@ -169,7 +171,13 @@ int main(int argc, char** argv) { break; default: error("illegal optimization level '{}'", opt); } +#endif + if (os[AST]) { + auto mod = parser.import(driver.sym(input), os[Md]); + Tab tab; + mod->stream(tab, *os[AST]); + } if (os[Thorin]) world.dump(*os[Thorin]); if (os[Dot]) world.dot(*os[Dot], dot_all_annexes, dot_follow_types); From 7ae73d7be43acb5ef0aadd1e4d477af776896baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 29 Mar 2024 23:26:16 +0100 Subject: [PATCH 07/95] use Dbg instead of Sym for identifiers --- include/thorin/ast/ast.h | 165 ++++++++++++++++++++++-------------- include/thorin/ast/parser.h | 6 +- include/thorin/util/dbg.h | 4 + src/thorin/ast/ast.cpp | 6 +- src/thorin/ast/parser.cpp | 165 ++++++++++-------------------------- src/thorin/ast/stream.cpp | 28 +++--- 6 files changed, 170 insertions(+), 204 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index aa4f361442..7af3972971 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -8,6 +8,7 @@ #include "thorin/ast/tok.h" #include "fe/arena.h" +#include "fe/assert.h" #include "fe/cast.h" namespace thorin { @@ -23,6 +24,7 @@ namespace ast { template using Ptr = fe::Arena::Ptr; template using Ptrs = std::deque>; +/* */ using Dbgs = std::deque; class AST { public: @@ -30,7 +32,7 @@ class AST { World& world() { return world_; } Driver& driver(); - Sym anonymous() const { return anonymous_; } + Sym anon() const { return anon_; } /// @name Sym ///@{ @@ -46,7 +48,7 @@ class AST { private: World& world_; fe::Arena arena_; - Sym anonymous_; + Sym anon_; }; class Scopes; @@ -60,6 +62,7 @@ class Node : public fe::RuntimeCast { public: Loc loc() const { return loc_; } + void dump() const; virtual std::ostream& stream(Tab&, std::ostream&) const = 0; private: @@ -74,15 +77,8 @@ class Expr : public Node { class Decl : public Node { protected: - Decl(Loc loc, Sym sym) - : Node(loc) - , sym_(sym) {} - -public: - Sym sym() const { return sym_; } - -private: - Sym sym_; + Decl(Loc loc) + : Node(loc) {} }; /* @@ -94,35 +90,27 @@ class Ptrn : public Node { Ptrn(Loc loc) : Node(loc) {} - bool rebind() const { return rebind_; } - Sym sym() const { return sym_; } - Dbg dbg() const { return {loc(), sym()}; } - bool is_anonymous() const { return sym() == '_'; } - const Expr* type() const { return type_.get(); } - [[nodiscard]] static Ptr expr(AST&, Ptr&&); // virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; // virtual const Def* type(World&, Def2Fields&) const = 0; - -protected: - bool rebind_; - Sym sym_; - Ptr type_; }; +/// `dbg: type` class IdPtrn : public Ptrn { public: - IdPtrn(Loc loc, bool rebind, Sym sym, Ptr&& type) + IdPtrn(Loc loc, bool rebind, Dbg dbg, Ptr&& type) : Ptrn(loc) , rebind_(rebind) - , sym_(sym) + , dbg_(dbg) , type_(std::move(type)) {} bool rebind() const { return rebind_; } - Sym sym() const { return sym_; } + Dbg dbg() const { return dbg_; } + const Expr* type() const { return type_.get(); } static Ptr mk_type(AST& ast, Ptr&& type) { - return ast.ptr(type->loc(), false, ast.anonymous(), std::move(type)); + auto loc = type->loc(); + return ast.ptr(loc, false, Dbg(loc, ast.anon()), std::move(type)); } // void bind(Scopes&, const Def*, bool rebind = false) const override {} @@ -131,23 +119,26 @@ class IdPtrn : public Ptrn { private: bool rebind_; - Sym sym_; + Dbg dbg_; Ptr type_; }; -/// `sym_0 ... sym_n-1 : type` +/// `dbg_0 ... dbg_n-1: type` class GroupPtrn : public Ptrn { public: - GroupPtrn(Loc loc, std::deque&& syms, Ptr&& type) + GroupPtrn(Loc loc, Dbgs&& dbgs, Ptr&& type) : Ptrn(loc) - , syms_(std::move(syms)) + , dbgs_(std::move(dbgs)) , type_(std::move(type)) {} - const auto& syms() const { return syms_; } + const auto& dbgs() const { return dbgs_; } + Dbg dbg(size_t i) const { return dbgs_[i]; } + size_t num_dbgs() const { return dbgs_.size(); } const Expr* type() const { return type_.get(); } static Ptr mk_type(AST& ast, Ptr&& type) { - return ast.ptr(type->loc(), false, ast.anonymous(), std::move(type)); + auto loc = type->loc(); + return ast.ptr(loc, false, Dbg(loc, ast.anon()), std::move(type)); } // void bind(Scopes&, const Def*, bool rebind = false) const override {} @@ -155,22 +146,27 @@ class GroupPtrn : public Ptrn { std::ostream& stream(Tab&, std::ostream&) const override; private: - std::deque syms_; + Dbgs dbgs_; Ptr type_; }; +/// `dbg::(ptrn_0, ..., ptrn_n-1)` or `dbg::[ptrn_0, ..., ptrn_n-1]` class TuplePtrn : public Ptrn { public: - TuplePtrn(Loc loc, bool rebind, Sym sym, Tok::Tag tag, Ptrs&& ptrns) + TuplePtrn(Loc loc, bool rebind, Dbg dbg, Tok::Tag delim_l, Ptrs&& ptrns) : Ptrn(loc) , rebind_(rebind) - , sym_(sym) - , tag_(tag) + , dbg_(dbg) + , delim_l_(delim_l) , ptrns_(std::move(ptrns)) {} bool rebind() const { return rebind_; } - Sym sym() const { return sym_; } - Tok::Tag tag() const { return tag_; } + Dbg dbg() const { return dbg_; } + Tok::Tag delim_l() const { return delim_l_; } + Tok::Tag delim_r() const { return Tok::delim_l2r(delim_l()); } + bool is_paren() const { return delim_l() == Tok::Tag::D_paren_l; } + bool is_brckt() const { return delim_l() == Tok::Tag::D_brckt_l; } + const auto& ptrns() const { return ptrns_; } const Ptrn* ptrn(size_t i) const { return ptrns_[i].get(); } size_t num_ptrns() const { return ptrns().size(); } @@ -181,8 +177,8 @@ class TuplePtrn : public Ptrn { private: bool rebind_; - Sym sym_; - Tok::Tag tag_; + Dbg dbg_; + Tok::Tag delim_l_; Ptrs ptrns_; }; @@ -193,17 +189,15 @@ class TuplePtrn : public Ptrn { /// `sym` class IdExpr : public Expr { public: - IdExpr(Loc loc, Sym sym) - : Expr(loc) - , sym_(sym) {} - IdExpr(Tok tok) - : IdExpr(tok.loc(), tok.sym()) {} + IdExpr(Dbg dbg) + : Expr(dbg.loc) + , dbg_(dbg) {} - Sym sym() const { return sym_; } + Dbg dbg() const { return dbg_; } std::ostream& stream(Tab&, std::ostream&) const override; private: - Sym sym_; + Dbg dbg_; }; /// `tag` @@ -237,6 +231,7 @@ class LitExpr : public Expr { Ptr type_; }; +/// `{ decl_0 ... decl_n-1 e }` or `decl_0 ... decl_n-1` (used internaly) class BlockExpr : public Expr { public: BlockExpr(Loc loc, Ptrs&& decls, Ptr&& expr) @@ -255,6 +250,7 @@ class BlockExpr : public Expr { Ptr expr_; }; +/// `.Type level` class TypeExpr : public Expr { public: TypeExpr(Loc loc, Ptr&& level) @@ -270,6 +266,7 @@ class TypeExpr : public Expr { // lam +/// `dom -> codom` class SimplePiExpr : public Expr { public: SimplePiExpr(Loc loc, Ptr&& dom, Ptr&& codom) @@ -287,6 +284,10 @@ class SimplePiExpr : public Expr { Ptr codom_; }; +/// One of: +/// * `Π dom_0 ... dom_n-1 -> codom` +/// * `.Cn dom_0 ... dom_n-1` +/// * `.Fn dom_0 ... dom_n-1 -> codom` class PiExpr : public Expr { public: class Dom : public Node { @@ -325,6 +326,13 @@ class PiExpr : public Expr { Ptr codom_; }; +/// One of: +/// * `λ dom_0 ... dom_n-1 -> codom` +/// * `.cn dom_0 ... dom_n-1` +/// * `.fn dom_0 ... dom_n-1 -> codom` +/// * `.lam dbg dom_0 ... dom_n-1 -> codom` +/// * `.con dbg dom_0 ... dom_n-1` +/// * `.fun dbg dom_0 ... dom_n-1 -> codom` class LamExpr : public Expr { public: class Dom : public PiExpr::Dom { @@ -340,16 +348,16 @@ class LamExpr : public Expr { Ptr filter_; }; - LamExpr(Loc loc, Tok::Tag tag, Sym sym, Ptrs&& doms, Ptr&& codom, Ptr&& body) + LamExpr(Loc loc, Tok::Tag tag, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) : Expr(loc) , tag_(tag) - , sym_(sym) + , dbg_(dbg) , doms_(std::move(doms)) , codom_(std::move(codom)) , body_(std::move(body)) {} Tok::Tag tag() const { return tag_; } - Sym sym() const { return sym_; } + Dbg dbg() const { return dbg_; } const auto& doms() const { return doms_; } const Dom* dom(size_t i) const { return doms_[i].get(); } const Expr* codom() const { return codom_.get(); } @@ -358,12 +366,13 @@ class LamExpr : public Expr { private: Tok::Tag tag_; - Sym sym_; + Dbg dbg_; Ptrs doms_; Ptr codom_; Ptr body_; }; +/// `callee arg` class AppExpr : public Expr { public: AppExpr(Loc loc, bool is_explicit, Ptr&& callee, Ptr&& arg) @@ -383,6 +392,7 @@ class AppExpr : public Expr { Ptr arg_; }; +/// `.ret ptrn = callee $ arg; body` class RetExpr : public Expr { public: RetExpr(Loc loc, Ptr&& ptrn, Ptr&& callee, Ptr&& arg, Ptr body) @@ -406,6 +416,7 @@ class RetExpr : public Expr { }; // tuple +/// Just wraps TuplePtrn as Expr. class SigmaExpr : public Expr { public: SigmaExpr(Ptr&& ptrn) @@ -419,6 +430,7 @@ class SigmaExpr : public Expr { Ptr ptrn_; }; +/// `(elem_0, ..., elem_n-1)` class TupleExpr : public Expr { public: TupleExpr(Loc loc, Ptrs&& elems) @@ -434,21 +446,22 @@ class TupleExpr : public Expr { Ptrs elems_; }; +/// `«dbg: shape; body»` or `‹dbg: shape; body›` template class ArrOrPackExpr : public Expr { public: - ArrOrPackExpr(Loc loc, Sym sym, Ptr&& shape, Ptr&& body) + ArrOrPackExpr(Loc loc, Dbg dbg, Ptr&& shape, Ptr&& body) : Expr(loc) - , sym_(sym) + , dbg_(dbg) , shape_(std::move(shape)) , body_(std::move(body)) {} - Sym sym() const { return sym_; } + Dbg dbg() const { return dbg_; } const Expr* shape() const { return shape_.get(); } const Expr* body() const { return body_.get(); } std::ostream& stream(Tab&, std::ostream&) const override; private: - Sym sym_; + Dbg dbg_; Ptr shape_; Ptr body_; }; @@ -456,22 +469,28 @@ template class ArrOrPackExpr : public Expr { using ArrExpr = ArrOrPackExpr; using PackExpr = ArrOrPackExpr; +/// `tuple#index` class ExtractExpr : public Expr { public: ExtractExpr(Loc loc, Ptr&& tuple, Ptr&& index) : Expr(loc) , tuple_(std::move(tuple)) , index_(std::move(index)) {} + ExtractExpr(Loc loc, Ptr&& tuple, Dbg index) + : Expr(loc) + , tuple_(std::move(tuple)) + , index_(index) {} const Expr* tuple() const { return tuple_.get(); } - const Expr* index() const { return index_.get(); } + const auto& index() const { return index_; } std::ostream& stream(Tab&, std::ostream&) const override; private: Ptr tuple_; - Ptr index_; + std::variant, Dbg> index_; }; +/// `.ins(tuple, index, value)` class InsertExpr : public Expr { public: InsertExpr(Loc loc, Ptr&& tuple, Ptr&& index, Ptr&& value) @@ -495,10 +514,11 @@ class InsertExpr : public Expr { * Further Decls */ +/// `.let ptrn: type = value;` class LetDecl : public Decl { public: LetDecl(Loc loc, Ptr&& ptrn, Ptr&& value) - : Decl(loc, ptrn->sym()) + : Decl(loc) , ptrn_(std::move(ptrn)) , value_(std::move(value)) {} @@ -511,32 +531,44 @@ class LetDecl : public Decl { Ptr value_; }; +/// `.let ptrn: type = value;` class AxiomDecl : public Decl { public: - AxiomDecl(Loc loc, Sym sym) - : Decl(loc, sym) {} + AxiomDecl(Loc loc, Dbg dbg) + : Decl(loc) + , dbg_(dbg) {} + + Dbg dbg() const { return dbg_; } + +private: + Dbg dbg_; }; +/// `.Pi dbg: type = body´ class PiDecl : public Decl { public: - PiDecl(Loc loc, Sym sym, Ptr&& type, Ptr&& body) - : Decl(loc, sym) + PiDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) + : Decl(loc) + , dbg_(dbg) , type_(std::move(type)) , body_(std::move(body)) {} + Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } std::ostream& stream(Tab&, std::ostream&) const override; private: + Dbg dbg_; Ptr type_; Ptr body_; }; +/// Just wraps a LamDecl as Expr. class LamDecl : public Decl { public: LamDecl(Ptr&& lam) - : Decl(lam->loc(), lam->sym()) + : Decl(lam->loc()) , lam_(std::move(lam)) {} const LamExpr* lam() const { return lam_.get(); } @@ -546,10 +578,12 @@ class LamDecl : public Decl { Ptr lam_; }; +/// `.Sigma dbg: type = body` class SigmaDecl : public Decl { public: - SigmaDecl(Loc loc, Sym sym, Ptr&& type, Ptr&& body) - : Decl(loc, sym) + SigmaDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) + : Decl(loc) + , dbg_(dbg) , type_(std::move(type)) , body_(std::move(body)) {} @@ -558,6 +592,7 @@ class SigmaDecl : public Decl { std::ostream& stream(Tab&, std::ostream&) const override; private: + Dbg dbg_; Ptr type_; Ptr body_; }; diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index ff76625647..3262d8237f 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -58,7 +58,7 @@ class Parser : public fe::Parser { Ptr parse_module(); Dbg parse_id(std::string_view ctxt = {}); std::pair parse_annex(std::string_view ctxt = {}); - Sym parse_name(std::string_view ctxt = {}); + Dbg parse_name(std::string_view ctxt = {}); void parse_import(); void parse_plugin(); Ptr parse_type_ascr(std::string_view ctxt = {}); @@ -101,7 +101,7 @@ class Parser : public fe::Parser { /// Depending on @p tag, this parses a `()`-style (Tok::Tag::D_paren_l) or `[]`-style (Tok::Tag::D_brckt_l) Ptrn. Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); - Ptr parse_tuple_ptrn(bool rebind, Sym); + Ptr parse_tuple_ptrn(bool rebind, Dbg); ///@} /// @name parse decls @@ -111,7 +111,7 @@ class Parser : public fe::Parser { /// * ... empty: **Only** decls are parsed. @returns `nullptr` /// * ... **non**-empty: Decls are parsed, then an expression. @returns expression. Ptrs parse_decls(); - Ptr parse_axiom_decl(); + // Ptr parse_axiom_decl(); Ptr parse_let_decl(); Ptr parse_pi_decl(); Ptr parse_lam_decl(); diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 8727cd0766..0c37c5b260 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -40,6 +40,10 @@ struct Dbg { Loc loc; Sym sym; + + explicit operator bool() const { return sym.operator bool(); } + + friend std::ostream& operator<<(std::ostream& os, const Dbg& dbg) { return os << dbg.sym; } }; } // namespace thorin diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 3096e08fee..a75628f0e7 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -12,7 +12,7 @@ namespace thorin::ast { AST::AST(World& world) : world_(world) - , anonymous_(world.sym("_")) {} + , anon_(sym("_")) {} Driver& AST::driver() { return world().driver(); } Sym AST::sym(const char* s) { return driver().sym(s); } @@ -25,8 +25,8 @@ Sym AST::sym(const std::string& s) { return driver().sym(s); } Ptr Ptrn::expr(AST& ast, Ptr&& ptrn) { if (auto id_ptrn = ptrn->isa()) { - return ast.ptr(id_ptrn->loc(), id_ptrn->sym()); - } else if (auto tuple_ptrn = ptrn->isa(); tuple_ptrn && tuple_ptrn->tag() == Tok::Tag::D_brckt_r) { + return ast.ptr(id_ptrn->dbg()); + } else if (auto tuple_ptrn = ptrn->isa(); tuple_ptrn && tuple_ptrn->is_brckt()) { (void)ptrn.release(); return ast.ptr(Ptr(tuple_ptrn)); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 867c2f2263..0518fe11d4 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -103,11 +103,11 @@ Dbg Parser::parse_id(std::string_view ctxt) { return {prev_, world().sym("")}; } -Sym Parser::parse_name(std::string_view ctxt) { - if (auto tok = accept(Tag::M_anx)) return tok.sym(); - if (auto tok = accept(Tag::M_id)) return tok.sym(); +Dbg Parser::parse_name(std::string_view ctxt) { + if (auto tok = accept(Tag::M_anx)) return tok.dbg(); + if (auto tok = accept(Tag::M_id)) return tok.dbg(); syntax_err("identifier or annex name", ctxt); - return ast().sym(""); + return Dbg(prev_, ast().sym("")); } void Parser::register_annex(Dbg dbg, Ref def) { @@ -174,6 +174,7 @@ Ptr Parser::parse_extract_expr(Tracker track, Ptr&& lhs, Tok::Prec p auto [l, r] = Tok::prec(Tok::Prec::Extract); if (l < p) return nullptr; lex(); + if (auto tok = accept(Tag::M_id)) return ptr(track.loc(), std::move(lhs), tok.dbg()); auto rhs = parse_expr("right-hand side of an extract", r); return ptr(track.loc(), std::move(lhs), std::move(rhs)); } @@ -181,7 +182,6 @@ Ptr Parser::parse_extract_expr(Tracker track, Ptr&& lhs, Tok::Prec p Ptr Parser::parse_insert_expr() { eat(Tag::K_ins); auto track = tracker(); - expect(Tag::D_paren_l, "opening paren for insert arguments"); auto tuple = parse_expr("the tuple to insert into"); expect(Tag::T_comma, "comma after tuple to insert into"); @@ -189,7 +189,6 @@ Ptr Parser::parse_insert_expr() { expect(Tag::T_comma, "comma after insert index"); auto value = parse_expr("insert value"); expect(Tag::D_paren_r, "closing paren for insert arguments"); - return ptr(track.loc(), std::move(tuple), std::move(index), std::move(value)); } @@ -212,8 +211,9 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::K_Type: return parse_type_expr(); case Tag::K_Univ: - case Tag::K_Idx: case Tag::K_Nat: + case Tag::K_Idx: + case Tag::K_Bool: case Tag::K_ff: case Tag::K_tt: case Tag::K_i1: @@ -221,7 +221,6 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::K_i16: case Tag::K_i32: case Tag::K_i64: - case Tag::K_Bool: case Tag::K_I1: case Tag::K_I8: case Tag::K_I16: @@ -240,7 +239,7 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { //case Tag::L_c: return world().lit_i8(lex().lit_c()); //case Tag::L_i: return lex().lit_i(); case Tag::M_anx: - case Tag::M_id: return ptr(lex()); + case Tag::M_id: return ptr(lex().dbg()); //case Tag::M_str: return world().tuple(lex().sym())->set(prev_); default: if (ctxt.empty()) return nullptr; @@ -254,9 +253,9 @@ template Ptr Parser::parse_arr_or_pack_expr() { auto track = tracker(); eat(arr ? Tag::D_quote_l : Tag::D_angle_l); - Sym sym; + Dbg dbg; if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon)) { - sym = eat(Tag::M_id).sym(); + dbg = eat(Tag::M_id).dbg(); eat(Tag::T_colon); } @@ -266,7 +265,7 @@ template Ptr Parser::parse_arr_or_pack_expr() { expect(arr ? Tag::D_quote_r : Tag::D_angle_r, arr ? "closing delimiter of an array" : "closing delimiter of a pack"); - return ptr>(track, sym, std::move(shape), std::move(body)); + return ptr>(track, dbg, std::move(shape), std::move(body)); } Ptr Parser::parse_block_expr(std::string_view ctxt) { @@ -286,7 +285,7 @@ Ptr Parser::parse_lit_expr() { return ptr(track, value, std::move(type)); } -Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, ast().anonymous())); } +Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, Dbg(ahead().loc(), Sym()))); } Ptr Parser::parse_tuple_expr() { auto track = tracker(); @@ -351,7 +350,7 @@ Ptr Parser::parse_lam_expr() { } // clang-format on - auto sym = decl ? parse_name(entity) : Sym(); + auto dbg = decl ? parse_name(entity) : Dbg(); Ptrs doms; do { auto track = tracker(); @@ -384,7 +383,7 @@ Ptr Parser::parse_lam_expr() { // if (is_decl) expect(Tag::T_semicolon, "end of "s + entity); - return ptr(track, tag, sym, std::move(doms), std::move(codom), std::move(body)); + return ptr(track, tag, dbg, std::move(doms), std::move(codom), std::move(body)); } Ptr Parser::parse_ret_expr() { @@ -400,44 +399,13 @@ Ptr Parser::parse_ret_expr() { return ptr(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(decls)); } -#if 0 -Ptr Parser::parse_lit_expr() { - auto track = tracker(); - auto tok = lex(); - auto [_, r] = Tok::prec(Tok::Prec::Lit); - - if (accept(Tag::T_colon)) { - auto type = parse_expr("literal", r); - - // clang-format off - switch (tok.tag()) { - case Tag::L_s: - case Tag::L_u: - case Tag::L_f: break; - case Tag::T_bot: return world().bot(type)->set(track.loc()); - case Tag::T_top: return world().top(type)->set(track.loc()); - default: fe::unreachable(); - } - // clang-format on - return world().lit(type, tok.lit_u())->set(track.loc()); - } - - if (tok.tag() == Tag::T_bot) return world().bot(world().type())->set(track.loc()); - if (tok.tag() == Tag::T_top) return world().top(world().type())->set(track.loc()); - if (tok.tag() == Tag::L_s) error(prev_, ".Nat literal specified as signed but must be unsigned"); - if (tok.tag() == Tag::L_f) error(prev_, ".Nat literal specified as floating-point but must be unsigned"); - - return world().lit_nat(tok.lit_u())->set(track.loc()); -} -#endif - /* * ptrns */ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) { auto track = tracker(); - auto sym = ast().anonymous(); + auto dbg = Dbg(ahead().loc(), Sym()); bool p = delim_l == Tag::D_paren_l; bool b = delim_l == Tag::D_brckt_l; assert((p ^ b) && "left delimiter must either be '(' or '['"); @@ -454,10 +422,10 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec if (p && ahead().isa(Tag::D_paren_l)) { // p -> (p, ..., p) - return parse_tuple_ptrn(false, sym); + return parse_tuple_ptrn(false, dbg); } else if (ahead().isa(Tag::D_brckt_l)) { // p -> [b, ..., b] b -> [b, ..., b] - return parse_tuple_ptrn(false, sym); + return parse_tuple_ptrn(false, dbg); } auto backtick = accept(Tag::T_backtick); @@ -467,13 +435,13 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec // p -> s::(p, ..., p) // p -> s::[b, ..., b] b -> s::[b, ..., b] // p -> s: e b -> s: e - // p -> s b -> e where e == id + // p -> s b -> e where e == id // p -> 's::(p, ..., p) // p -> 's::[b, ..., b] b -> 's::[b, ..., b] // p -> 's: e b -> 's: e // p -> 's if (ahead(1).isa(Tag::T_colon_colon)) { - sym = eat(Tag::M_id).sym(); + dbg = eat(Tag::M_id).dbg(); eat(Tag::T_colon_colon); if (b && ahead().isa(Tag::D_paren_l)) error(ahead().loc(), "switching from []-style patterns to ()-style patterns is not allowed"); @@ -482,35 +450,35 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec // b -> 's::(p, ..., p) // b -> 's::[b, ..., b] b -> 's::[b, ..., b] if (ahead().isa(Tag::D_paren_l) || ahead().isa(Tag::D_brckt_l)) - return parse_tuple_ptrn(rebind, sym); + return parse_tuple_ptrn(rebind, dbg); else - syntax_err("tuple pattern after '" + sym.str() + "::'", ctxt); + syntax_err("tuple pattern after '" + dbg.sym.str() + "::'", ctxt); } else if (ahead(1).isa(Tag::T_colon)) { // p -> s: e b -> s: e // p -> 's: e b -> 's: e - sym = eat(Tag::M_id).sym(); + dbg = eat(Tag::M_id).dbg(); eat(Tag::T_colon); auto type = parse_expr(ctxt, prec); - return ptr(track, rebind, sym, std::move(type)); + return ptr(track, rebind, dbg, std::move(type)); } else { // p -> s b -> e where e == id // p -> 's if (p) { // p -> s // p -> 's - sym = eat(Tag::M_id).sym(); - return ptr(track, rebind, sym, nullptr); + dbg = eat(Tag::M_id).dbg(); + return ptr(track, rebind, dbg, nullptr); } else { // b -> e where e == id auto type = parse_expr(ctxt, prec); - return ptr(track, rebind, sym, std::move(type)); + return ptr(track, rebind, dbg, std::move(type)); } } } else if (b) { // b -> e where e != id if (backtick) error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding"); auto type = parse_expr(ctxt, prec); - return ptr(track, rebind, sym, std::move(type)); + return ptr(track, rebind, dbg, std::move(type)); } else if (!ctxt.empty()) { // p -> ↯ syntax_err("pattern", ctxt); @@ -519,7 +487,7 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec return nullptr; } -Ptr Parser::parse_tuple_ptrn(bool rebind, Sym sym) { +Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { auto track = tracker(); auto delim_l = ahead().tag(); bool p = delim_l == Tag::D_paren_l; @@ -532,23 +500,19 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Sym sym) { Ptr ptrn; if (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::M_id)) { - std::deque toks; - std::deque syms; - while (auto tok = accept(Tag::M_id)) { - toks.emplace_back(tok); - syms.emplace_back(tok.sym()); - } + Dbgs dbgs; + while (auto tok = accept(Tag::M_id)) dbgs.emplace_back(tok.dbg()); if (accept(Tag::T_colon)) { // identifier group: x y x: T auto type = parse_expr("type of an identifier group within a tuple pattern"); - ptrns.emplace_back(ptr(track, std::move(syms), std::move(type))); + ptrns.emplace_back(ptr(track, std::move(dbgs), std::move(type))); return; } // "x y z" is a curried app and maybe the prefix of a longer type expression - Ptr lhs = ptr(toks.front()); - for (auto tok : toks | std::views::drop(1)) { - auto rhs = ptr(tok); + Ptr lhs = ptr(dbgs.front()); + for (auto dbg : dbgs | std::views::drop(1)) { + auto rhs = ptr(dbg); lhs = ptr(track, false, std::move(lhs), std::move(rhs)); } auto [_, r] = Tok::prec(Tok::Prec::App); @@ -571,7 +535,7 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Sym sym) { }); // TODO parse type - return ptr(track, rebind, sym, delim_l, std::move(ptrns)); + return ptr(track, rebind, dbg, delim_l, std::move(ptrns)); } /* @@ -598,17 +562,12 @@ Ptrs Parser::parse_decls() { } #if 0 -void Parser::parse_ax_decl() { +Ptr Parser::parse_axiom_decl() { auto track = tracker(); eat(Tag::K_ax); - auto dbg = expect(Tag::M_anx, "annex name of an axiom").dbg(); - auto [plugin, tag, sub] = Annex::split(world(), dbg.sym); - auto&& [annex, is_new] = driver().name2annex(dbg.sym, plugin, tag, dbg.loc); - - if (!plugin) error(dbg.loc, "invalid axiom name '{}'", dbg.sym); - if (sub) error(dbg.loc, "axiom '{}' must not have a subtag", dbg.sym); + auto dbg = expect(Tag::M_anx, "annex name of an axiom").dbg(); - std::deque> new_subs; + std::deque> new_subs; if (ahead().isa(Tag::D_paren_l)) { parse_list("tag list of an axiom", Tag::D_paren_l, [&]() { auto& aliases = new_subs.emplace_back(); @@ -621,61 +580,23 @@ void Parser::parse_ax_decl() { }); } - if (!is_new && new_subs.empty() && !annex.subs.empty()) - error(dbg.loc, "redeclaration of axiom '{}' without specifying new subs", dbg.sym); - else if (!is_new && !new_subs.empty() && annex.subs.empty()) - error(dbg.loc, "cannot extend subs of axiom '{}' because it was declared as a subless axiom", dbg.sym); - auto type = parse_type_ascr("type ascription of an axiom"); - if (!is_new && annex.pi != (type->isa() != nullptr)) - error(dbg.loc, "all declarations of annex '{}' have to be function types if any is", dbg.sym); - annex.pi = type->isa() != nullptr; - Sym normalizer; + Dbg normalizer; if (ahead().isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) { lex(); normalizer = parse_id("normalizer of an axiom").sym; } - if (!is_new && (annex.normalizer && normalizer) && annex.normalizer != normalizer) - error(dbg.loc, "all declarations of axiom '{}' must use the same normalizer name", dbg.sym); - annex.normalizer = normalizer; - - auto [curry, trip] = ir::Axiom::infer_curry_and_trip(type); - if (accept(Tag::T_comma)) { auto c = expect(Tag::L_u, "curry counter for axiom"); - if (c.lit_u() > curry) error(c.loc(), "curry counter cannot be greater than {}", curry); curry = c.lit_u(); } if (accept(Tag::T_comma)) trip = expect(Tag::L_u, "trip count for axiom").lit_u(); - plugin_t p = *Annex::mangle(plugin); - tag_t t = annex.tag_id; - sub_t s = annex.subs.size(); - if (new_subs.empty()) { - auto norm = driver().normalizer(p, t, 0); - auto axiom = world().axiom(norm, curry, trip, type, p, t, 0)->set(dbg); - world().register_annex(p | (flags_t(t) << 8_u64), axiom); - scopes_.bind(dbg, axiom); - } else { - for (const auto& sub : new_subs) { - auto name = world().sym(dbg.sym.str() + "."s + sub.front().str()); - auto norm = driver().normalizer(p, t, s); - auto axiom = world().axiom(norm, curry, trip, type, p, t, s)->set(track.loc(), name); - world().register_annex(p | (flags_t(t) << 8_u64) | flags_t(s), axiom); - for (auto& alias : sub) { - auto sym = world().sym(dbg.sym.str() + "."s + alias.str()); - scopes_.bind({prev_, sym}, axiom); - } - ++s; - } - annex.subs.insert(annex.subs.end(), new_subs.begin(), new_subs.end()); - } expect(Tag::T_semicolon, "end of an axiom"); } - #endif Ptr Parser::parse_let_decl() { @@ -699,12 +620,12 @@ Ptr Parser::parse_let_decl() { Ptr Parser::parse_pi_decl() { auto track = tracker(); eat(Tag::K_Pi); - auto sym = parse_name("pi declaration"); + auto dbg = parse_name("pi declaration"); auto type = accept(Tag::T_colon) ? parse_expr("type of a pi declaration") : Ptr(); auto body = accept(Tag::T_assign) ? parse_expr("body of a pi declaration") : Ptr(); expect(Tag::T_semicolon, "end of a pi declaration"); - return ptr(track, sym, std::move(type), std::move(body)); + return ptr(track, dbg, std::move(type), std::move(body)); } Ptr Parser::parse_lam_decl() { return ptr(parse_lam_expr()); } @@ -712,12 +633,12 @@ Ptr Parser::parse_lam_decl() { return ptr(parse_lam_expr()); } Ptr Parser::parse_sigma_decl() { auto track = tracker(); eat(Tag::K_Sigma); - auto sym = parse_name("sigma declaration"); + auto dbg = parse_name("sigma declaration"); auto type = accept(Tag::T_colon) ? parse_expr("type of a sigma declaration") : Ptr(); auto body = accept(Tag::T_assign) ? parse_expr("body of a sigma declaration") : Ptr(); expect(Tag::T_semicolon, "end of a sigma declaration"); - return ptr(track, sym, std::move(type), std::move(body)); + return ptr(track, dbg, std::move(type), std::move(body)); } } // namespace thorin::ast diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index df0f5055c5..e53ab3b81c 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -27,29 +27,36 @@ template struct R { std::function&)> f; }; +void Node::dump() const { + Tab tab; + stream(tab, std::cout) << std::endl; + ; +} + /* * Ptrn */ std::ostream& IdPtrn::stream(Tab& tab, std::ostream& os) const { - os << sym(); + os << dbg(); if (type()) print(os, ": {}", S(tab, type())); return os; } std::ostream& GroupPtrn::stream(Tab& tab, std::ostream& os) const { - return print(os, "{ }: {}", syms(), S(tab, type())); + return print(os, "{ }: {}", dbgs(), S(tab, type())); } std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { - return print(os, "{}::{}{, }{}", sym(), tag(), R(tab, ptrns()), Tok::delim_l2r(tag())); + if (dbg()) print(os, "{}::", dbg()); + return print(os, "{}{, }{}", delim_l(), R(tab, ptrns()), delim_r()); } /* * Ptrn */ -std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", sym()); } +std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", dbg()); } std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { @@ -106,8 +113,10 @@ template std::ostream& ArrOrPackExpr::stream(Tab&, std::ostream&) const; template std::ostream& ArrOrPackExpr::stream(Tab&, std::ostream&) const; std::ostream& ExtractExpr::stream(Tab& tab, std::ostream& os) const { - return print(os, "{}#{}", S(tab, tuple()), S(tab, index())); + if (auto expr = std::get_if>(&index())) return print(os, "{}#{}", S(tab, tuple()), S(tab, expr->get())); + return print(os, "{}#{}", S(tab, tuple()), std::get(index())); } + std::ostream& InsertExpr::stream(Tab& tab, std::ostream& os) const { return print(os, ".ins({}, {}, {})", S(tab, tuple()), S(tab, index()), S(tab, value())); } @@ -120,19 +129,16 @@ std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); } -std::ostream& PiDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".Pi"); } +std::ostream& PiDecl::stream(Tab& /*tab*/, std::ostream& os) const { return print(os, ".Pi"); } std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return lam()->stream(tab, os); } -std::ostream& SigmaDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".Sigma"); } +std::ostream& SigmaDecl::stream(Tab& /*tab*/, std::ostream& os) const { return print(os, ".Sigma"); } /* * Module */ std::ostream& Module::stream(Tab& tab, std::ostream& os) const { - for (auto sep = ""; const auto& decl : decls()) { - tab.print(os, "{}{}", S(tab, decl.get()), sep); - sep = "\n"; - } + for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); return os; } From 5cfe1f6e898961bfe276d212242fe6c5629838c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 30 Mar 2024 01:26:14 +0100 Subject: [PATCH 08/95] parsing of axioms and more AST streaming + bug fixes --- include/thorin/ast/ast.h | 56 ++++++++++++++++++++++++------ include/thorin/ast/parser.h | 2 +- src/thorin/ast/ast.cpp | 25 +++++++++----- src/thorin/ast/parser.cpp | 68 +++++++++++++++++++------------------ src/thorin/ast/stream.cpp | 54 ++++++++++++++++++++++------- 5 files changed, 139 insertions(+), 66 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 7af3972971..88544300e4 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -2,6 +2,7 @@ #include #include +#include #include "thorin/def.h" @@ -90,7 +91,8 @@ class Ptrn : public Node { Ptrn(Loc loc) : Node(loc) {} - [[nodiscard]] static Ptr expr(AST&, Ptr&&); + [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); + [[nodiscard]] static Ptr to_ptrn(AST&, Ptr&&); // virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; // virtual const Def* type(World&, Def2Fields&) const = 0; }; @@ -234,11 +236,13 @@ class LitExpr : public Expr { /// `{ decl_0 ... decl_n-1 e }` or `decl_0 ... decl_n-1` (used internaly) class BlockExpr : public Expr { public: - BlockExpr(Loc loc, Ptrs&& decls, Ptr&& expr) + BlockExpr(Loc loc, bool has_braces, Ptrs&& decls, Ptr&& expr) : Expr(loc) + , has_braces_(has_braces) , decls_(std::move(decls)) , expr_(std::move(expr)) {} + bool has_braces() const { return has_braces_; } const auto& decls() const { return decls_; } const Decl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } @@ -246,6 +250,7 @@ class BlockExpr : public Expr { std::ostream& stream(Tab&, std::ostream&) const override; private: + bool has_braces_; Ptrs decls_; Ptr expr_; }; @@ -292,17 +297,17 @@ class PiExpr : public Expr { public: class Dom : public Node { public: - Dom(Loc loc, bool implicit, Ptr&& ptrn) + Dom(Loc loc, bool is_implicit, Ptr&& ptrn) : Node(loc) - , implicit_(implicit) + , is_implicit_(is_implicit) , ptrn_(std::move(ptrn)) {} - bool implicit() const { return implicit_; } + bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } std::ostream& stream(Tab&, std::ostream&) const override; private: - bool implicit_; + bool is_implicit_; Ptr ptrn_; }; @@ -337,14 +342,17 @@ class LamExpr : public Expr { public: class Dom : public PiExpr::Dom { public: - Dom(Loc loc, bool implicit, Ptr&& ptrn, Ptr&& filter) - : PiExpr::Dom(loc, implicit, std::move(ptrn)) + Dom(Loc loc, bool has_bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) + : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) + , has_bang_(has_bang) , filter_(std::move(filter)) {} + bool has_bang() const { return has_bang_; } const Expr* filter() const { return filter_.get(); } std::ostream& stream(Tab&, std::ostream&) const override; private: + bool has_bang_; Ptr filter_; }; @@ -360,6 +368,7 @@ class LamExpr : public Expr { Dbg dbg() const { return dbg_; } const auto& doms() const { return doms_; } const Dom* dom(size_t i) const { return doms_[i].get(); } + size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } const Expr* body() const { return body_.get(); } std::ostream& stream(Tab&, std::ostream&) const override; @@ -428,6 +437,8 @@ class SigmaExpr : public Expr { private: Ptr ptrn_; + + friend Ptr Ptrn::to_ptrn(AST&, Ptr&&); }; /// `(elem_0, ..., elem_n-1)` @@ -531,17 +542,40 @@ class LetDecl : public Decl { Ptr value_; }; -/// `.let ptrn: type = value;` +/// `.ax ptrn: type = value;` class AxiomDecl : public Decl { public: - AxiomDecl(Loc loc, Dbg dbg) + AxiomDecl(Loc loc, + Dbg dbg, + std::deque&& subs, + Ptr&& type, + Dbg normalizer, + std::optional curry, + std::optional trip) : Decl(loc) - , dbg_(dbg) {} + , dbg_(dbg) + , subs_(std::move(subs)) + , type_(std::move(type)) + , normalizer_(normalizer) + , curry_(curry) + , trip_(trip) {} Dbg dbg() const { return dbg_; } + const auto& subs() const { return subs_; } + size_t num_subs() const { return subs_.size(); } + const auto& sub(size_t i) const { return subs_[i]; } + const Expr* type() const { return type_.get(); } + Dbg normalizer() const { return normalizer_; } + std::optional curry() const { return curry_; } + std::optional trip() const { return trip_; } + std::ostream& stream(Tab&, std::ostream&) const override; private: Dbg dbg_; + std::deque subs_; + Ptr type_; + Dbg normalizer_; + std::optional curry_, trip_; }; /// `.Pi dbg: type = body´ diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 3262d8237f..cca82624c5 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -111,7 +111,7 @@ class Parser : public fe::Parser { /// * ... empty: **Only** decls are parsed. @returns `nullptr` /// * ... **non**-empty: Decls are parsed, then an expression. @returns expression. Ptrs parse_decls(); - // Ptr parse_axiom_decl(); + Ptr parse_axiom_decl(); Ptr parse_let_decl(); Ptr parse_pi_decl(); Ptr parse_lam_decl(); diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index a75628f0e7..90bcb36650 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -8,6 +8,8 @@ #include "thorin/ast/scopes.h" +#include "fe/assert.h" + namespace thorin::ast { AST::AST(World& world) @@ -20,18 +22,25 @@ Sym AST::sym(std::string_view s) { return driver().sym(s); } Sym AST::sym(const std::string& s) { return driver().sym(s); } /* - * Ptrn::expr + * Ptrn::to_expr/to_ptrn */ -Ptr Ptrn::expr(AST& ast, Ptr&& ptrn) { - if (auto id_ptrn = ptrn->isa()) { - return ast.ptr(id_ptrn->dbg()); - } else if (auto tuple_ptrn = ptrn->isa(); tuple_ptrn && tuple_ptrn->is_brckt()) { +Ptr Ptrn::to_expr(AST& ast, Ptr&& ptrn) { + if (auto id = ptrn->isa()) { + return ast.ptr(id->dbg()); + } else if (auto tuple = ptrn->isa(); tuple && tuple->is_brckt()) { (void)ptrn.release(); - return ast.ptr(Ptr(tuple_ptrn)); + return ast.ptr(Ptr(tuple)); } - // ptrn.get_deleter()(ptrn.release()); - return {}; + fe::unreachable(); +} + +Ptr Ptrn::to_ptrn(AST& ast, Ptr&& expr) { + if (auto id = expr->isa()) + return ast.ptr(id->loc(), false, id->dbg(), Ptr()); + else if (auto sigma = expr->isa()) + return std::move(const_cast(sigma)->ptrn_); // TODO get rid off const_cast + fe::unreachable(); } #if 0 diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 0518fe11d4..f8d09fe46a 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -274,7 +274,7 @@ Ptr Parser::parse_block_expr(std::string_view ctxt) { auto decls = parse_decls(); auto expr = parse_expr("final expression in a "s + (ctxt.empty() ? "block expressoin"s : std::string(ctxt))); if (ctxt.empty()) expect(Tag::D_brace_r, "block expression"); - return ptr(track, std::move(decls), std::move(expr)); + return ptr(track, /*has_braces*/ ctxt.empty(), std::move(decls), std::move(expr)); } Ptr Parser::parse_lit_expr() { @@ -354,19 +354,18 @@ Ptr Parser::parse_lam_expr() { Ptrs doms; do { auto track = tracker(); - auto bang = accept(Tag::T_bang); - auto filter = bang ? ptr(bang) : Ptr(); + bool bang = (bool)accept(Tag::T_bang); bool implicit = (bool)accept(Tag::T_dot); auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); + Ptr filter; if (auto tok = accept(Tag::T_at)) { - if (filter) error(tok.loc(), "filter already specified via '!'"); expect(Tag::D_paren_l, "opening parenthesis of a filter"); filter = parse_expr("filter"); expect(Tag::D_paren_r, "closing parenthesis of a filter"); } - doms.emplace_back(ptr(track, implicit, std::move(ptrn), std::move(filter))); + doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); auto codom = (tag != Tag::K_cn && tag != Tag::K_con) @@ -521,14 +520,19 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { } else { ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); - if (b) - // If we are able to parse more stuff, we got an expr instead of a binder: - // [..., [.Nat, .Nat] -> .Nat, ...] ==> [..., _: [.Nat, .Nat] -> .Nat, ...] -#if 0 - if (auto new_expr = parse_infix_expr(track, std::move(expr)); new_expr != expr) - ptrn = ptr(expr); -#endif - assert(false && "TODO"); + if (b) { + // If we are able to parse more stuff, we got an expr instead of a binder: + // [..., [.Nat, .Nat] -> .Nat, ...] ==> [..., _: [.Nat, .Nat] -> .Nat, ...] + auto expr = Ptrn::to_expr(ast(), std::move(ptrn)); + auto addr = expr.get(); + expr = parse_infix_expr(track, std::move(expr)); + if (expr.get() != addr) { + auto loc = expr->loc(); + ptrn = ptr(loc, false, Dbg(loc.anew_begin(), Sym()), std::move(expr)); + } else { + ptrn = Ptrn::to_ptrn(ast(), std::move(expr)); + } + } } ptrns.emplace_back(std::move(ptrn)); @@ -548,7 +552,7 @@ Ptrs Parser::parse_decls() { // clang-format off switch (ahead().tag()) { case Tag::T_semicolon: lex(); break; // eat up stray semicolons - //case Tag::K_ax: parse_ax_decl(); break; + case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break; case Tag::K_let: decls.emplace_back(parse_let_decl()); break; case Tag::K_Sigma: decls.emplace_back(parse_sigma_decl()); break; case Tag::K_Pi: decls.emplace_back(parse_pi_decl()); break; @@ -561,43 +565,41 @@ Ptrs Parser::parse_decls() { } } -#if 0 Ptr Parser::parse_axiom_decl() { auto track = tracker(); eat(Tag::K_ax); - auto dbg = expect(Tag::M_anx, "annex name of an axiom").dbg(); + Dbg dbg, normalizer; + if (auto name = expect(Tag::M_anx, "annex name of an axiom")) + dbg = name.dbg(); + else + dbg = Dbg(prev_, ast().sym("")); - std::deque> new_subs; + std::deque subs; if (ahead().isa(Tag::D_paren_l)) { parse_list("tag list of an axiom", Tag::D_paren_l, [&]() { - auto& aliases = new_subs.emplace_back(); - auto [_, tag] = parse_id("tag of an axiom"); - aliases.emplace_back(tag); - while (accept(Tag::T_assign)) { - auto [_, alias] = parse_id("alias of an axiom tag"); - aliases.emplace_back(alias); - } + auto& aliases = subs.emplace_back(); + aliases.emplace_back(parse_id("tag of an axiom")); + while (accept(Tag::T_assign)) aliases.emplace_back(parse_id("alias of an axiom tag")); }); } auto type = parse_type_ascr("type ascription of an axiom"); - Dbg normalizer; - if (ahead().isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) { - lex(); - normalizer = parse_id("normalizer of an axiom").sym; + if (accept(Tag::T_comma)) { + if (auto tok = expect(Tag::M_id, "normalizer of an axiom")) normalizer = tok.dbg(); } + std::optional curry, trip; if (accept(Tag::T_comma)) { - auto c = expect(Tag::L_u, "curry counter for axiom"); - curry = c.lit_u(); + if (auto c = expect(Tag::L_u, "curry counter for axiom")) curry = c.lit_u(); + if (accept(Tag::T_comma)) { + if (auto t = expect(Tag::L_u, "trip count for axiom")) trip = t.lit_u(); + } } - if (accept(Tag::T_comma)) trip = expect(Tag::L_u, "trip count for axiom").lit_u(); - expect(Tag::T_semicolon, "end of an axiom"); + return ptr(track, dbg, std::move(subs), std::move(type), normalizer, curry, trip); } -#endif Ptr Parser::parse_let_decl() { auto track = tracker(); diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index e53ab3b81c..3d2be90a88 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -30,7 +30,6 @@ template struct R { void Node::dump() const { Tab tab; stream(tab, std::cout) << std::endl; - ; } /* @@ -66,13 +65,17 @@ std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { - tab++.println(os, "{{"); - for (auto sep = ""; const auto& decl : decls()) { - decl->stream(tab, os << sep); - sep = "\n"; + if (!has_braces() && num_decls() == 0) { + if (expr()) return expr()->stream(tab, os); + return os << ""; } - if (expr()) expr()->stream(tab, os); - return tab--.println(os, "}}"); + + if (has_braces()) println(os, "{{"); + ++tab; + for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); + if (expr()) tab.println(os, "{}", S(tab, expr())); + if (has_braces()) (--tab).print(os, "}}"); + return os; } std::ostream& TypeExpr ::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } @@ -80,17 +83,25 @@ std::ostream& SimplePiExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{} -> {}", S(tab, dom()), S(tab, codom())); } std::ostream& PiExpr::Dom ::stream(Tab& tab, std::ostream& os) const { - return print(os, "{}{}", implicit() ? "." : "", S(tab, ptrn())); + return print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); } -std::ostream& PiExpr ::stream(Tab& tab, std::ostream& os) const { +std::ostream& PiExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{} -> {}", tag(), R(tab, doms()), S(tab, codom())); } -std::ostream& LamExpr::Dom ::stream(Tab& tab, std::ostream& os) const { - return print(PiExpr::Dom::stream(tab, os), "@({})", filter()); +std::ostream& LamExpr::Dom::stream(Tab& tab, std::ostream& os) const { + if (has_bang()) os << '!'; + PiExpr::Dom::stream(tab, os); + if (filter()) print(os, "@({})", filter()); + return os; } std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { - return print(os, "{}{} -> {} = {}", tag(), R(tab, doms()), S(tab, codom()), S(tab, body())); + os << tag() << ' '; + if (dbg()) os << dbg(); + print(os, "{}", R(tab, doms())); + if (codom()) print(os, ": {}", S(tab, codom())); + if (body()) print(os, " = {}", S(tab, body())); + return os; } std::ostream& AppExpr::stream(Tab& tab, std::ostream& os) const { @@ -129,8 +140,25 @@ std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); } +std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { + print(os, ".ax {}", dbg()); + if (num_subs() != 0) { + os << '('; + for (auto sep = ""; const auto& aliases : subs()) { + print(os, "{}{ = }", sep, aliases); + sep = ", "; + } + os << ')'; + } + print(os, ": {}", S(tab, type())); + if (normalizer()) print(os, ", {}", normalizer()); + if (curry()) print(os, ", {}", *curry()); + if (trip()) print(os, ", {}", *trip()); + return os << ";"; +} + std::ostream& PiDecl::stream(Tab& /*tab*/, std::ostream& os) const { return print(os, ".Pi"); } -std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return lam()->stream(tab, os); } +std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return print(os, "{};", S(tab, lam())); } std::ostream& SigmaDecl::stream(Tab& /*tab*/, std::ostream& os) const { return print(os, ".Sigma"); } /* From 6bbe54a7ec58519f1791f9757ca48bd11537640d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 30 Mar 2024 01:42:29 +0100 Subject: [PATCH 09/95] Lambda: parse .extern --- include/thorin/ast/ast.h | 5 ++++- src/thorin/ast/parser.cpp | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 88544300e4..5a6be0d64b 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -356,15 +356,17 @@ class LamExpr : public Expr { Ptr filter_; }; - LamExpr(Loc loc, Tok::Tag tag, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) + LamExpr(Loc loc, Tok::Tag tag, bool is_external, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) : Expr(loc) , tag_(tag) + , is_external_(is_external) , dbg_(dbg) , doms_(std::move(doms)) , codom_(std::move(codom)) , body_(std::move(body)) {} Tok::Tag tag() const { return tag_; } + bool is_external() const { return is_external_; } Dbg dbg() const { return dbg_; } const auto& doms() const { return doms_; } const Dom* dom(size_t i) const { return doms_[i].get(); } @@ -375,6 +377,7 @@ class LamExpr : public Expr { private: Tok::Tag tag_; + bool is_external_; Dbg dbg_; Ptrs doms_; Ptr codom_; diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index f8d09fe46a..c3c0d5fba3 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -332,9 +332,10 @@ Ptr Parser::parse_pi_expr() { } Ptr Parser::parse_lam_expr() { - auto track = tracker(); - auto tag = lex().tag(); - auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Tok::Prec::Bot : Tok::Prec::Pi; + auto track = tracker(); + auto tag = lex().tag(); + auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Tok::Prec::Bot : Tok::Prec::Pi; + bool external = (bool)accept(Tag::K_extern); bool decl; std::string entity; @@ -382,7 +383,7 @@ Ptr Parser::parse_lam_expr() { // if (is_decl) expect(Tag::T_semicolon, "end of "s + entity); - return ptr(track, tag, dbg, std::move(doms), std::move(codom), std::move(body)); + return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } Ptr Parser::parse_ret_expr() { From d36db5d805b2e2ed014a1a4aa54ef427197c6cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 30 Mar 2024 17:03:09 +0100 Subject: [PATCH 10/95] LetDecl: allow annex again --- include/thorin/ast/parser.h | 2 +- src/thorin/ast/parser.cpp | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index cca82624c5..ae446bd47c 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -100,7 +100,7 @@ class Parser : public fe::Parser { ///@{ /// Depending on @p tag, this parses a `()`-style (Tok::Tag::D_paren_l) or `[]`-style (Tok::Tag::D_brckt_l) Ptrn. - Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); + Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot, bool allow_annex = false); Ptr parse_tuple_ptrn(bool rebind, Dbg); ///@} diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index c3c0d5fba3..cf1301c456 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -403,12 +403,23 @@ Ptr Parser::parse_ret_expr() { * ptrns */ -Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec /*= Tok::Prec::Bot*/) { +Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec, bool allow_annex) { auto track = tracker(); auto dbg = Dbg(ahead().loc(), Sym()); bool p = delim_l == Tag::D_paren_l; bool b = delim_l == Tag::D_brckt_l; assert((p ^ b) && "left delimiter must either be '(' or '['"); + + if (allow_annex) { + assert(p); + // p -> anx + // p -> anx: e + if (auto anx = accept(Tok::Tag::M_anx)) { + auto type = parse_type_ascr(); + return ptr(track, false, anx.dbg(), std::move(type)); + } + } + // p -> (p, ..., p) // p -> [b, ..., b] b -> [b, ..., b] // p -> s::(p, ..., p) @@ -605,14 +616,7 @@ Ptr Parser::parse_axiom_decl() { Ptr Parser::parse_let_decl() { auto track = tracker(); eat(Tag::K_let); - - // Ptr ptrn; - // TODO annex - // if (auto tok = accept(Tag::M_anx)) { - // ptrn = ptr( - //} else { - - auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration"); + auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration", Tok::Prec::Bot, true); expect(Tag::T_assign, "let"); auto type = parse_type_ascr(); auto value = parse_expr("value of a let declaration"); From 8fe65269a7680a5ca20518829be077bc19a72485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 31 Mar 2024 00:54:01 +0100 Subject: [PATCH 11/95] remove thorin IR dependencies from thorin::ast --- include/thorin/ast/ast.h | 70 ++++++++++++++++++++----------------- include/thorin/ast/lexer.h | 17 ++++----- include/thorin/ast/parser.h | 15 +++----- include/thorin/ast/tok.h | 57 ++++++++++-------------------- src/thorin/ast/ast.cpp | 9 ----- src/thorin/ast/lexer.cpp | 70 ++++++++++++++----------------------- src/thorin/ast/parser.cpp | 46 ++++++++++-------------- src/thorin/ast/stream.cpp | 12 +++++-- src/thorin/ast/tok.cpp | 8 ++++- src/thorin/cli/main.cpp | 2 +- 10 files changed, 131 insertions(+), 175 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 5a6be0d64b..7cb489ebf3 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -4,23 +4,16 @@ #include #include -#include "thorin/def.h" +#include +#include +#include -#include "thorin/ast/tok.h" +#include "thorin/driver.h" -#include "fe/arena.h" -#include "fe/assert.h" -#include "fe/cast.h" +#include "thorin/ast/tok.h" namespace thorin { -class Driver; -class Infer; -class Sigma; -class World; - -using Def2Fields = DefMap>; - namespace ast { template using Ptr = fe::Arena::Ptr; @@ -29,17 +22,18 @@ template using Ptrs = std::deque>; class AST { public: - AST(World& world); + AST(Driver& driver) + : driver_(driver) + , anon_(sym("_")) {} - World& world() { return world_; } - Driver& driver(); + Driver& driver() { return driver_; } Sym anon() const { return anon_; } /// @name Sym ///@{ - Sym sym(std::string_view); - Sym sym(const char*); - Sym sym(const std::string&); + Sym sym(const char* s) { return driver().sym(s); } + Sym sym(std::string_view s) { return driver().sym(s); } + Sym sym(const std::string& s) { return driver().sym(s); } ///@} template auto ptr(Args&&... args) { @@ -47,7 +41,7 @@ class AST { } private: - World& world_; + Driver& driver_; fe::Arena arena_; Sym anon_; }; @@ -219,17 +213,35 @@ class PrimaryExpr : public Expr { /// `tag:type` class LitExpr : public Expr { public: - LitExpr(Loc loc, Tok value, Ptr&& type) + LitExpr(Loc loc, Dbg value, Ptr&& type) : Expr(loc) , value_(value) , type_(std::move(type)) {} - Tok value() const { return value_; } + Dbg value() const { return value_; } const Expr* type() const { return type_.get(); } std::ostream& stream(Tab&, std::ostream&) const override; private: - Tok value_; + Dbg value_; + Ptr type_; +}; + +/// `tag:type` +class ExtremumExpr : public Expr { +public: + ExtremumExpr(Loc loc, Tok::Tag tag, Ptr&& type) + : Expr(loc) + , tag_(tag) + , type_(std::move(type)) {} + + Tok::Tag tag() const { return tag_; } + const Expr* type() const { return type_.get(); } + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Tok::Tag tag_; + ; Ptr type_; }; @@ -548,13 +560,7 @@ class LetDecl : public Decl { /// `.ax ptrn: type = value;` class AxiomDecl : public Decl { public: - AxiomDecl(Loc loc, - Dbg dbg, - std::deque&& subs, - Ptr&& type, - Dbg normalizer, - std::optional curry, - std::optional trip) + AxiomDecl(Loc loc, Dbg dbg, std::deque&& subs, Ptr&& type, Dbg normalizer, Dbg curry, Dbg trip) : Decl(loc) , dbg_(dbg) , subs_(std::move(subs)) @@ -569,8 +575,8 @@ class AxiomDecl : public Decl { const auto& sub(size_t i) const { return subs_[i]; } const Expr* type() const { return type_.get(); } Dbg normalizer() const { return normalizer_; } - std::optional curry() const { return curry_; } - std::optional trip() const { return trip_; } + Dbg curry() const { return curry_; } + Dbg trip() const { return trip_; } std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -578,7 +584,7 @@ class AxiomDecl : public Decl { std::deque subs_; Ptr type_; Dbg normalizer_; - std::optional curry_, trip_; + Dbg curry_, trip_; }; /// `.Pi dbg: type = body´ diff --git a/include/thorin/ast/lexer.h b/include/thorin/ast/lexer.h index 9133a9d054..6c68910ce5 100644 --- a/include/thorin/ast/lexer.h +++ b/include/thorin/ast/lexer.h @@ -5,13 +5,11 @@ #include #include -#include "thorin/ast/tok.h" - -namespace thorin { +#include "thorin/driver.h" -class World; +#include "thorin/ast/tok.h" -namespace ast { +namespace thorin::ast { class Lexer : public fe::Lexer<3, Lexer> { using Super = fe::Lexer<3, Lexer>; @@ -19,9 +17,9 @@ class Lexer : public fe::Lexer<3, Lexer> { public: /// Creates a lexer to read Thorin files (see [Lexical Structure](@ref lex)). /// If @p md is not `nullptr`, a Markdown output will be generated. - Lexer(World& world, std::istream& istream, const fs::path* path = nullptr, std::ostream* md = nullptr); + Lexer(Driver& driver, std::istream& istream, const fs::path* path = nullptr, std::ostream* md = nullptr); - World& world() { return world_; } + Driver& driver() { return driver_; } const fs::path* path() const { return loc_.path; } Loc loc() const { return loc_; } Tok lex(); @@ -56,7 +54,7 @@ class Lexer : public fe::Lexer<3, Lexer> { if (md_) *md_ << "```\n"; } - World& world_; + Driver& driver_; std::ostream* md_; bool out_ = true; fe::SymMap keywords_; @@ -65,5 +63,4 @@ class Lexer : public fe::Lexer<3, Lexer> { friend class fe::Lexer<3, Lexer>; }; -} // namespace ast -} // namespace thorin +} // namespace thorin::ast diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index ae446bd47c..bbe237601a 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -2,8 +2,6 @@ #include -#include "thorin/driver.h" - #include "thorin/ast/ast.h" #include "thorin/ast/lexer.h" #include "thorin/ast/scopes.h" @@ -12,7 +10,7 @@ namespace thorin::ast { constexpr size_t Look_Ahead = 2; -/// Parses Thorin code into the provided World. +/// Parses Thorin code as AST. /// /// The logic behind the various parse methods is as follows: /// 1. The `parse_*` method does **not** have a `std::string_view ctxt` parameter: @@ -32,13 +30,11 @@ constexpr size_t Look_Ahead = 2; /// * If default argument is **provided** we have the same behavior as in 2. class Parser : public fe::Parser { public: - Parser(World& world) - : world_(world) - , ast_(world) {} + Parser(Driver& driver) + : ast_(driver) {} AST& ast() { return ast_; } - World& world() { return world_; } - Driver& driver() { return world().driver(); } + Driver& driver() { return ast().driver(); } Ptr import(std::string_view sv) { return import(driver().sym(sv)); } Ptr import(Sym, std::ostream* md = nullptr); Ptr import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); @@ -62,7 +58,6 @@ class Parser : public fe::Parser { void parse_import(); void parse_plugin(); Ptr parse_type_ascr(std::string_view ctxt = {}); - void register_annex(Dbg, Ref); template void parse_list(std::string ctxt, Tok::Tag delim_l, F f, Tok::Tag sep = Tok::Tag::T_comma) { expect(delim_l, ctxt); @@ -87,6 +82,7 @@ class Parser : public fe::Parser { template Ptr parse_arr_or_pack_expr(); Ptr parse_block_expr(std::string_view ctxt); ///< Empty @p ctxt means an explicit BlockExpr `{ d* e }`. Ptr parse_lit_expr(); + Ptr parse_extremum_expr(); Ptr parse_type_expr(); Ptr parse_ret_expr(); Ptr parse_pi_expr(); @@ -136,7 +132,6 @@ class Parser : public fe::Parser { } ///@} - World& world_; AST ast_; Lexer* lexer_ = nullptr; diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 4f189091ba..9a87b2553d 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -55,17 +55,14 @@ constexpr auto Num_Keys = size_t(0) THORIN_KEY(CODE); #undef CODE #define THORIN_TOK(m) \ - m(EoF, "") \ + m(EoF, "" ) \ /* literals */ \ - m(L_s, "") \ - m(L_u, "" ) \ - m(L_i, "" ) \ - m(L_f, "") \ - m(L_c, "" ) \ /* misc */ \ - m(M_id, "") \ - m(M_anx, "") \ - m(M_str, "" ) \ + m(M_id, "" ) \ + m(M_anx, "" ) \ + m(M_str, "" ) \ + m(M_lit, "" ) \ + m(M_char, "") \ /* delimiters */ \ m(D_angle_l, "‹") \ m(D_angle_r, "›") \ @@ -145,7 +142,7 @@ class Tok { #undef CODE }; - static std::string_view tag2str(Tok::Tag); + static const char* tag2str(Tok::Tag); static constexpr Tok::Tag delim_l2r(Tag tag) { return Tok::Tag(int(tag) + 1); } ///@} @@ -157,42 +154,28 @@ class Tok { , tag_(tag) {} Tok(Loc loc, char8_t c) : loc_(loc) - , tag_(Tag::L_c) + , tag_(Tag::M_char) , c_(c) {} - Tok(Loc loc, u64 u) - : loc_(loc) - , tag_(Tag::L_u) - , u_(u) {} - Tok(Loc loc, s64 s) - : loc_(loc) - , tag_(Tag::L_s) - , u_(std::bit_cast(s)) {} - Tok(Loc loc, f64 f) - : loc_(loc) - , tag_(Tag::L_f) - , u_(std::bit_cast(f)) {} - Tok(Loc loc, const Lit* i) - : loc_(loc) - , tag_(Tag::L_i) - , i_(i) {} Tok(Loc loc, Tag tag, Sym sym) : loc_(loc) , tag_(tag) - , sym_(sym) { - assert(tag == Tag::M_id || tag == Tag::M_anx || tag == Tag::M_str); - } + , sym_(sym) {} bool isa(Tag tag) const { return tag == tag_; } Tag tag() const { return tag_; } Dbg dbg() const { return {loc(), sym()}; } Loc loc() const { return loc_; } explicit operator bool() const { return tag_ != Tag::Nil; } - // clang-format off - const Lit* lit_i() const { assert(isa(Tag::L_i)); return i_; } - char8_t lit_c() const { assert(isa(Tag::L_c)); return c_; } - u64 lit_u() const { assert(isa(Tag::L_u ) || isa(Tag::L_s ) || isa(Tag::L_f )); return u_; } - Sym sym() const { assert(isa(Tag::M_anx) || isa(Tag::M_id) || isa(Tag::M_str)); return sym_; } - // clang-format on + char8_t chr() const { + assert(isa(Tag::M_char)); + return c_; + } + Sym sym() const { + assert(isa(Tag::M_anx) || isa(Tag::M_id) || isa(Tag::M_str) || isa(Tag::M_lit)); + return sym_; + } + std::string str() const; + friend std::ostream& operator<<(std::ostream&, Tok); friend std::ostream& operator<<(std::ostream& os, Tok::Tag tag) { return os << tag2str(tag); } @@ -201,9 +184,7 @@ class Tok { Tag tag_ = Tag::Nil; union { Sym sym_; - u64 u_; char8_t c_; - const Lit* i_; }; }; diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 90bcb36650..fbc3a60057 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -12,15 +12,6 @@ namespace thorin::ast { -AST::AST(World& world) - : world_(world) - , anon_(sym("_")) {} - -Driver& AST::driver() { return world().driver(); } -Sym AST::sym(const char* s) { return driver().sym(s); } -Sym AST::sym(std::string_view s) { return driver().sym(s); } -Sym AST::sym(const std::string& s) { return driver().sym(s); } - /* * Ptrn::to_expr/to_ptrn */ diff --git a/src/thorin/ast/lexer.cpp b/src/thorin/ast/lexer.cpp index f98fab1870..dc05f12564 100644 --- a/src/thorin/ast/lexer.cpp +++ b/src/thorin/ast/lexer.cpp @@ -1,6 +1,6 @@ #include "thorin/ast/lexer.h" -#include "thorin/world.h" +#include "thorin/ast/ast.h" using namespace std::literals; @@ -9,16 +9,16 @@ namespace thorin::ast { namespace utf8 = fe::utf8; using Tag = Tok::Tag; -Lexer::Lexer(World& world, std::istream& istream, const fs::path* path /*= nullptr*/, std::ostream* md /*= nullptr*/) +Lexer::Lexer(Driver& driver, std::istream& istream, const fs::path* path /*= nullptr*/, std::ostream* md /*= nullptr*/) : Super(istream, path) - , world_(world) + , driver_(driver) , md_(md) { -#define CODE(t, str) keywords_[world.sym(str)] = Tag::t; +#define CODE(t, str) keywords_[driver.sym(str)] = Tag::t; THORIN_KEY(CODE) #undef CODE #define CODE(str, t) \ - if (Tag::t != Tag::Nil) keywords_[world.sym(str)] = Tag::t; + if (Tag::t != Tag::Nil) keywords_[driver.sym(str)] = Tag::t; THORIN_SUBST(CODE) #undef CODE @@ -110,14 +110,14 @@ Tok Lexer::lex() { assert(!cache_.has_value()); auto id_loc = loc(); ++id_loc.begin.col; - cache_.emplace(id_loc, Tag::M_id, world().sym(str_.substr(1))); + cache_.emplace(id_loc, Tag::M_id, driver().sym(str_.substr(1))); return {loc().anew_begin(), Tag::T_dot}; } if (accept(utf8::isdigit)) { parse_digits(); parse_exp(); - return {loc_, f64(std::strtod(str_.c_str(), nullptr))}; + return {loc_, Tag::M_str, sym()}; } return tok(Tag::T_dot); @@ -196,52 +196,41 @@ std::optional Lexer::parse_lit() { int base = 10; std::optional sign; - if (accept('+')) { + if (accept('+')) { sign = false; - } else if (accept('-')) { + } else if (accept('-')) { if (accept('>')) return tok(Tag::T_arrow); sign = true; } // prefix starting with '0' - if (accept('0')) { - if (accept('b')) base = 2; - else if (accept('B')) base = 2; - else if (accept('o')) base = 8; - else if (accept('O')) base = 8; - else if (accept('x')) base = 16; - else if (accept('X')) base = 16; + if (accept('0')) { + if (accept('b')) base = 2; + else if (accept('B')) base = 2; + else if (accept('o')) base = 8; + else if (accept('O')) base = 8; + else if (accept('x')) base = 16; + else if (accept('X')) base = 16; } parse_digits(base); - if (accept('I')) { - if (sign) str_.insert(0, "-"sv); - auto val = std::strtoull(str_.c_str(), nullptr, base); - str_.clear(); + if (accept(utf8::any('i', 'I'))) { parse_digits(); - auto width = std::strtoull(str_.c_str(), nullptr, 10); - return Tok{loc_, world().lit_int(width, val)}; + return Tok{loc_, Tag::M_lit, sym()}; } if (!sign && base == 10) { if (utf8::isrange(ahead(), U'₀', U'₉')) { - auto i = std::strtoull(str_.c_str(), nullptr, 10); - std::string mod; - while (utf8::isrange(ahead(), U'₀', U'₉')) mod += next() - U'₀' + '0'; - auto m = std::strtoull(mod.c_str(), nullptr, 10); - return Tok{loc_, world().lit_idx_mod(m, i)}; - } else if (accept('_')) { - auto i = std::strtoull(str_.c_str(), nullptr, 10); - str_.clear(); + while (accept(utf8::isrange(U'₀', U'₉'))) {} + return Tok{loc_, Tag::M_lit, sym()}; + } else if (accept('_')) { if (accept(utf8::isdigit)) { - parse_digits(10); - auto m = std::strtoull(str_.c_str(), nullptr, 10); - return Tok{loc_, world().lit_idx_mod(m, i)}; + parse_digits(); + return Tok{loc_, Tag::M_lit, sym()}; } else { - error(loc_, "stray underscore in unsigned literal"); - auto i = std::strtoull(str_.c_str(), nullptr, 10); - return Tok{loc_, u64(i)}; + error(loc_, "stray underscore in .Idx literal; size is missing"); + return {}; } } } @@ -264,12 +253,7 @@ std::optional Lexer::parse_lit() { return {}; } - if (is_float && base == 16) str_.insert(0, "0x"sv); - if (sign && *sign) str_.insert(0, "-"sv); - - if (is_float) return Tok{loc_, f64(std::strtod (str_.c_str(), nullptr ))}; - if (sign) return Tok{loc_, u64(std::strtoll (str_.c_str(), nullptr, base))}; - else return Tok{loc_, u64(std::strtoull(str_.c_str(), nullptr, base))}; + return Tok{loc_, Tag::M_lit, sym()}; } void Lexer::parse_digits(int base /*= 10*/) { @@ -351,6 +335,6 @@ void Lexer::emit_md(bool start_of_file) { md_fence(); } -Sym Lexer::sym() { return world().sym(str_); } +Sym Lexer::sym() { return driver().sym(str_); } } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index cf1301c456..06dd47bd5f 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -40,7 +40,7 @@ Ptr Parser::parse_module() { } Ptr Parser::import(Sym name, std::ostream* md) { - world().VLOG("import: {}", name); + driver().VLOG("import: {}", name); auto filename = fs::path(name.view()); if (!filename.has_extension()) filename.replace_extension("thorin"); // TODO error cases @@ -62,11 +62,11 @@ Ptr Parser::import(Sym name, std::ostream* md) { } Ptr Parser::import(std::istream& is, const fs::path* path, std::ostream* md) { - world().VLOG("reading: {}", path ? path->string() : ""s); + driver().VLOG("reading: {}", path ? path->string() : ""s); if (!is) error("cannot read file '{}'", *path); auto state = std::tuple(prev_, ahead_, lexer_); - auto lexer = Lexer(world(), is, path, md); + auto lexer = Lexer(driver(), is, path, md); lexer_ = &lexer; init(path); auto mod = parse_module(); @@ -100,7 +100,7 @@ void Parser::parse_plugin() { Dbg Parser::parse_id(std::string_view ctxt) { if (auto id = accept(Tag::M_id)) return id.dbg(); syntax_err("identifier", ctxt); - return {prev_, world().sym("")}; + return {prev_, driver().sym("")}; } Dbg Parser::parse_name(std::string_view ctxt) { @@ -110,22 +110,6 @@ Dbg Parser::parse_name(std::string_view ctxt) { return Dbg(prev_, ast().sym("")); } -void Parser::register_annex(Dbg dbg, Ref def) { - auto [plugin, tag, sub] = Annex::split(world(), dbg.sym); - auto name = world().sym("%"s + plugin.str() + "."s + tag.str()); - auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc); - plugin_t p = *Annex::mangle(plugin); - tag_t t = annex.tag_id; - sub_t s = annex.subs.size(); - - if (sub) { - auto& aliases = annex.subs.emplace_back(); - aliases.emplace_back(sub); - } - - world().register_annex(p | (t << 8) | s, def); -} - Ptr Parser::parse_type_ascr(std::string_view ctxt) { if (accept(Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot); if (ctxt.empty()) return nullptr; @@ -231,11 +215,9 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { auto tok = lex(); return ptr(tok); } + case Tag::M_lit: return parse_lit_expr(); case Tag::T_bot: - case Tag::T_top: - case Tag::L_s: - case Tag::L_u: - case Tag::L_f: return parse_lit_expr(); + case Tag::T_top: return parse_extremum_expr(); //case Tag::L_c: return world().lit_i8(lex().lit_c()); //case Tag::L_i: return lex().lit_i(); case Tag::M_anx: @@ -277,12 +259,20 @@ Ptr Parser::parse_block_expr(std::string_view ctxt) { return ptr(track, /*has_braces*/ ctxt.empty(), std::move(decls), std::move(expr)); } +Ptr Parser::parse_extremum_expr() { + auto track = tracker(); + auto tag = lex().tag(); + auto [_, r] = Tok::prec(Tok::Prec::Lit); + auto type = accept(Tag::T_colon) ? parse_expr("type of "s + Tok::tag2str(tag), r) : Ptr(); + return ptr(track, tag, std::move(type)); +} + Ptr Parser::parse_lit_expr() { auto track = tracker(); auto value = lex(); auto [_, r] = Tok::prec(Tok::Prec::Lit); auto type = accept(Tag::T_colon) ? parse_expr("literal", r) : Ptr(); - return ptr(track, value, std::move(type)); + return ptr(track, value.dbg(), std::move(type)); } Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, Dbg(ahead().loc(), Sym()))); } @@ -601,11 +591,11 @@ Ptr Parser::parse_axiom_decl() { if (auto tok = expect(Tag::M_id, "normalizer of an axiom")) normalizer = tok.dbg(); } - std::optional curry, trip; + Dbg curry, trip; if (accept(Tag::T_comma)) { - if (auto c = expect(Tag::L_u, "curry counter for axiom")) curry = c.lit_u(); + if (auto c = expect(Tag::M_lit, "curry counter for axiom")) curry = c.dbg(); if (accept(Tag::T_comma)) { - if (auto t = expect(Tag::L_u, "trip count for axiom")) trip = t.lit_u(); + if (auto t = expect(Tag::M_lit, "trip count for axiom")) trip = t.dbg(); } } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 3d2be90a88..8aaff171e8 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -59,7 +59,13 @@ std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{ std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { - os << value().lit_u(); + os << value(); + if (type()) print(os, ": {}", S(tab, type())); + return os; +} + +std::ostream& ExtremumExpr::stream(Tab& tab, std::ostream& os) const { + os << tag(); if (type()) print(os, ": {}", S(tab, type())); return os; } @@ -152,8 +158,8 @@ std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { } print(os, ": {}", S(tab, type())); if (normalizer()) print(os, ", {}", normalizer()); - if (curry()) print(os, ", {}", *curry()); - if (trip()) print(os, ", {}", *trip()); + if (curry()) print(os, ", {}", curry()); + if (trip()) print(os, ", {}", trip()); return os << ";"; } diff --git a/src/thorin/ast/tok.cpp b/src/thorin/ast/tok.cpp index 70e2bd7918..83abf09c83 100644 --- a/src/thorin/ast/tok.cpp +++ b/src/thorin/ast/tok.cpp @@ -7,7 +7,7 @@ namespace thorin::ast { -std::string_view Tok::tag2str(Tok::Tag tag) { +const char* Tok::tag2str(Tok::Tag tag) { switch (tag) { #define CODE(t, str) \ case Tok::Tag::t: return str; @@ -19,6 +19,12 @@ std::string_view Tok::tag2str(Tok::Tag tag) { fe::unreachable(); } +std::string Tok::str() const { + std::ostringstream oss; + oss << *this; + return oss.str(); +} + /// @name std::ostream operator ///@{ std::ostream& operator<<(std::ostream& os, Tok tok) { diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index fe974625b6..ee2ecc070c 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -138,7 +138,7 @@ int main(int argc, char** argv) { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); - auto parser = ast::Parser(world); + auto parser = ast::Parser(driver); #if 0 parser.import(driver.sym(input), os[Md]); From ed6ba354e74a18b72de20300c0e1dc6b5314b39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 31 Mar 2024 01:41:06 +0100 Subject: [PATCH 12/95] bug fixes + tune AST output --- include/thorin/ast/ast.h | 4 ++-- src/thorin/ast/ast.cpp | 14 ++++++-------- src/thorin/ast/parser.cpp | 17 +++++++++-------- src/thorin/ast/stream.cpp | 20 +++++++++++++------- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 7cb489ebf3..87e5eff9aa 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -86,7 +86,7 @@ class Ptrn : public Node { : Node(loc) {} [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); - [[nodiscard]] static Ptr to_ptrn(AST&, Ptr&&); + [[nodiscard]] static Ptr to_ptrn(Ptr&&); // virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; // virtual const Def* type(World&, Def2Fields&) const = 0; }; @@ -453,7 +453,7 @@ class SigmaExpr : public Expr { private: Ptr ptrn_; - friend Ptr Ptrn::to_ptrn(AST&, Ptr&&); + friend Ptr Ptrn::to_ptrn(Ptr&&); }; /// `(elem_0, ..., elem_n-1)` diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index fbc3a60057..b2ce5440a1 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -17,21 +17,19 @@ namespace thorin::ast { */ Ptr Ptrn::to_expr(AST& ast, Ptr&& ptrn) { - if (auto id = ptrn->isa()) { - return ast.ptr(id->dbg()); + if (auto idp = ptrn->isa(); idp && !idp->dbg() && idp->type()) { + if (auto ide = idp->type()->isa()) return ast.ptr(ide->dbg()); } else if (auto tuple = ptrn->isa(); tuple && tuple->is_brckt()) { (void)ptrn.release(); return ast.ptr(Ptr(tuple)); } - fe::unreachable(); + return {}; } -Ptr Ptrn::to_ptrn(AST& ast, Ptr&& expr) { - if (auto id = expr->isa()) - return ast.ptr(id->loc(), false, id->dbg(), Ptr()); - else if (auto sigma = expr->isa()) +Ptr Ptrn::to_ptrn(Ptr&& expr) { + if (auto sigma = expr->isa()) return std::move(const_cast(sigma)->ptrn_); // TODO get rid off const_cast - fe::unreachable(); + return {}; } #if 0 diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 06dd47bd5f..6a6df71da1 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -525,14 +525,15 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { if (b) { // If we are able to parse more stuff, we got an expr instead of a binder: // [..., [.Nat, .Nat] -> .Nat, ...] ==> [..., _: [.Nat, .Nat] -> .Nat, ...] - auto expr = Ptrn::to_expr(ast(), std::move(ptrn)); - auto addr = expr.get(); - expr = parse_infix_expr(track, std::move(expr)); - if (expr.get() != addr) { - auto loc = expr->loc(); - ptrn = ptr(loc, false, Dbg(loc.anew_begin(), Sym()), std::move(expr)); - } else { - ptrn = Ptrn::to_ptrn(ast(), std::move(expr)); + if (auto expr = Ptrn::to_expr(ast(), std::move(ptrn))) { + auto addr = expr.get(); + expr = parse_infix_expr(track, std::move(expr)); + if (expr.get() != addr) { + auto loc = expr->loc(); + ptrn = ptr(loc, false, Dbg(loc.anew_begin(), Sym()), std::move(expr)); + } else { + if (!ptrn) ptrn = Ptrn::to_ptrn(std::move(expr)); + } } } } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 8aaff171e8..d177cfc3f0 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -37,9 +37,12 @@ void Node::dump() const { */ std::ostream& IdPtrn::stream(Tab& tab, std::ostream& os) const { - os << dbg(); - if (type()) print(os, ": {}", S(tab, type())); - return os; + // clang-format off + if ( dbg() && type()) return print(os, "{}: {}", dbg(), S(tab, type())); + if ( dbg() && !type()) return print(os, "{}", dbg()); + if (!dbg() && type()) return print(os, "{}", S(tab, type())); + // clang-format on + return os << ""; } std::ostream& GroupPtrn::stream(Tab& tab, std::ostream& os) const { @@ -76,11 +79,13 @@ std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { return os << ""; } - if (has_braces()) println(os, "{{"); + if (has_braces()) os << '{'; + os << std::endl; ++tab; for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); - if (expr()) tab.println(os, "{}", S(tab, expr())); - if (has_braces()) (--tab).print(os, "}}"); + if (expr()) tab.print(os, "{}", S(tab, expr())); + --tab; + if (has_braces()) tab.print(os << std::endl, "}}"); return os; } @@ -104,6 +109,7 @@ std::ostream& LamExpr::Dom::stream(Tab& tab, std::ostream& os) const { std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { os << tag() << ' '; if (dbg()) os << dbg(); + if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; print(os, "{}", R(tab, doms())); if (codom()) print(os, ": {}", S(tab, codom())); if (body()) print(os, " = {}", S(tab, body())); @@ -120,7 +126,7 @@ std::ostream& RetExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& SigmaExpr::stream(Tab& tab, std::ostream& os) const { return ptrn()->stream(tab, os); } -std::ostream& TupleExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "({, }", R(tab, elems())); } +std::ostream& TupleExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "({, })", R(tab, elems())); } template std::ostream& ArrOrPackExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{}; {}{}", arr ? "«" : "‹", S(tab, shape()), S(tab, body()), arr ? "»" : "›"); From 8398987c89be1ccbf91317777337eecc430df5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 31 Mar 2024 03:59:09 +0200 Subject: [PATCH 13/95] wip: ast bind --- include/thorin/ast/ast.h | 74 +++++++++++-- include/thorin/ast/parser.h | 1 - include/thorin/ast/scopes.h | 35 ------ lit/main_loop.thorin | 2 +- src/thorin/CMakeLists.txt | 2 +- src/thorin/ast/ast.cpp | 22 +--- src/thorin/ast/bind.cpp | 205 ++++++++++++++++++++++++++++++++++++ src/thorin/ast/scopes.cpp | 39 ------- src/thorin/ast/stream.cpp | 2 +- src/thorin/cli/main.cpp | 1 + 10 files changed, 275 insertions(+), 108 deletions(-) delete mode 100644 include/thorin/ast/scopes.h create mode 100644 src/thorin/ast/bind.cpp delete mode 100644 src/thorin/ast/scopes.cpp diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 87e5eff9aa..5b567a8cef 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -12,9 +12,9 @@ #include "thorin/ast/tok.h" -namespace thorin { +namespace thorin::ast { -namespace ast { +class Scopes; template using Ptr = fe::Arena::Ptr; template using Ptrs = std::deque>; @@ -57,8 +57,9 @@ class Node : public fe::RuntimeCast { public: Loc loc() const { return loc_; } - void dump() const; + virtual void bind(Scopes&) const = 0; virtual std::ostream& stream(Tab&, std::ostream&) const = 0; + void dump() const; private: Loc loc_; @@ -80,15 +81,14 @@ class Decl : public Node { * Ptrn */ -class Ptrn : public Node { +class Ptrn : public Decl { public: Ptrn(Loc loc) - : Node(loc) {} + : Decl(loc) {} + // virtual const Def* type(World&, Def2Fields&) const = 0; [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); - // virtual void bind(Scopes&, const Def*, bool rebind = false) const = 0; - // virtual const Def* type(World&, Def2Fields&) const = 0; }; /// `dbg: type` @@ -111,6 +111,7 @@ class IdPtrn : public Ptrn { // void bind(Scopes&, const Def*, bool rebind = false) const override {} // const Def* type(World&, Def2Fields&) const override {} + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -139,6 +140,7 @@ class GroupPtrn : public Ptrn { // void bind(Scopes&, const Def*, bool rebind = false) const override {} // const Def* type(World&, Def2Fields&) const override {} + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -169,6 +171,7 @@ class TuplePtrn : public Ptrn { // void bind(Scopes&, const Def*, bool rebind = false) const override {} // const Def* type(World&, Def2Fields&) const override {} + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -190,10 +193,14 @@ class IdExpr : public Expr { , dbg_(dbg) {} Dbg dbg() const { return dbg_; } + const Decl* decl() const { return decl_; } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: Dbg dbg_; + mutable const Decl* decl_ = nullptr; }; /// `tag` @@ -204,6 +211,8 @@ class PrimaryExpr : public Expr { , tag_(tok.tag()) {} Tok::Tag tag() const { return tag_; } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -220,6 +229,8 @@ class LitExpr : public Expr { Dbg value() const { return value_; } const Expr* type() const { return type_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -237,11 +248,12 @@ class ExtremumExpr : public Expr { Tok::Tag tag() const { return tag_; } const Expr* type() const { return type_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: Tok::Tag tag_; - ; Ptr type_; }; @@ -259,6 +271,8 @@ class BlockExpr : public Expr { const Decl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } const Expr* expr() const { return expr_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -275,6 +289,8 @@ class TypeExpr : public Expr { , level_(std::move(level)) {} const Expr* level() const { return level_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -294,6 +310,8 @@ class SimplePiExpr : public Expr { private: const Expr* dom() const { return dom_.get(); } const Expr* codom() const { return codom_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -316,6 +334,8 @@ class PiExpr : public Expr { bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -335,6 +355,8 @@ class PiExpr : public Expr { const Dom* dom(size_t i) const { return doms_[i].get(); } size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -361,6 +383,8 @@ class LamExpr : public Expr { bool has_bang() const { return has_bang_; } const Expr* filter() const { return filter_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -385,6 +409,8 @@ class LamExpr : public Expr { size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } const Expr* body() const { return body_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -408,6 +434,8 @@ class AppExpr : public Expr { bool is_explicit() const { return is_explicit_; } const Expr* callee() const { return callee_.get(); } const Expr* arg() const { return arg_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -430,6 +458,8 @@ class RetExpr : public Expr { const Expr* callee() const { return callee_.get(); } const Expr* arg() const { return arg_.get(); } const Expr* body() const { return body_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -448,6 +478,8 @@ class SigmaExpr : public Expr { , ptrn_(std::move(ptrn)) {} const Ptrn* ptrn() const { return ptrn_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -466,6 +498,8 @@ class TupleExpr : public Expr { const auto& elems() const { return elems_; } const Expr* elem(size_t i) const { return elems_[i].get(); } size_t num_elems() const { return elems().size(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -484,6 +518,8 @@ template class ArrOrPackExpr : public Expr { Dbg dbg() const { return dbg_; } const Expr* shape() const { return shape_.get(); } const Expr* body() const { return body_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -509,6 +545,8 @@ class ExtractExpr : public Expr { const Expr* tuple() const { return tuple_.get(); } const auto& index() const { return index_; } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -528,6 +566,8 @@ class InsertExpr : public Expr { const Expr* tuple() const { return tuple_.get(); } const Expr* index() const { return index_.get(); } const Expr* value() const { return value_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -550,6 +590,8 @@ class LetDecl : public Decl { const Ptrn* ptrn() const { return ptrn_.get(); } const Expr* value() const { return value_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -577,6 +619,8 @@ class AxiomDecl : public Decl { Dbg normalizer() const { return normalizer_; } Dbg curry() const { return curry_; } Dbg trip() const { return trip_; } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -599,6 +643,8 @@ class PiDecl : public Decl { Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -615,6 +661,8 @@ class LamDecl : public Decl { , lam_(std::move(lam)) {} const LamExpr* lam() const { return lam_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -632,6 +680,8 @@ class SigmaDecl : public Decl { const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -653,11 +703,15 @@ class Module : public Node { const auto& decls() const { return decls_; } const Decl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } + + void compile() const; + void bind() const; + + void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: Ptrs decls_; }; -} // namespace ast -} // namespace thorin +} // namespace thorin::ast diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index bbe237601a..72b683410c 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -4,7 +4,6 @@ #include "thorin/ast/ast.h" #include "thorin/ast/lexer.h" -#include "thorin/ast/scopes.h" namespace thorin::ast { diff --git a/include/thorin/ast/scopes.h b/include/thorin/ast/scopes.h deleted file mode 100644 index b90481476d..0000000000 --- a/include/thorin/ast/scopes.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include "thorin/util/dbg.h" - -namespace thorin { - -class Def; - -namespace ast { - -class Ptrn; - -class Scopes { -public: - using Scope = fe::SymMap>; - - Scopes() { push(); /* root scope */ } - - void push() { scopes_.emplace_back(); } - void pop(); - Scope* curr() { return &scopes_.back(); } - const Def* query(Dbg) const; - const Def* find(Dbg) const; ///< Same as Scopes::query but potentially raises an error. - void bind(Scope*, Dbg, const Def*, bool rebind = false); - void bind(Dbg dbg, const Def* def, bool rebind = false) { bind(&scopes_.back(), dbg, def, rebind); } - void swap(Scope& other) { std::swap(scopes_.back(), other); } - -private: - std::deque scopes_; -}; - -} // namespace ast -} // namespace thorin diff --git a/lit/main_loop.thorin b/lit/main_loop.thorin index ba728680d2..4794244498 100644 --- a/lit/main_loop.thorin +++ b/lit/main_loop.thorin @@ -12,7 +12,7 @@ .con body m: %mem.M = .let inc = %core.wrap.add 0 (1I32, i); .let acci = %core.wrap.add 0 (i, acc); - loop (m, inc, acci); + loopi (m, inc, acci); (.cn m: %mem.M = return (m, acc), body)#cond mem; loop (mem, 0I32, 0I32); diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index 1e35e724d6..c3dff2087f 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -22,9 +22,9 @@ target_sources(libthorin analyses/scope.cpp be/h/bootstrap.cpp ast/ast.cpp + ast/bind.cpp ast/lexer.cpp ast/parser.cpp - ast/scopes.cpp ast/stream.cpp ast/tok.cpp pass/beta_red.cpp diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index b2ce5440a1..4b0c82ebe2 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -6,10 +6,6 @@ #include "thorin/rewrite.h" #include "thorin/world.h" -#include "thorin/ast/scopes.h" - -#include "fe/assert.h" - namespace thorin::ast { /* @@ -32,23 +28,9 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { return {}; } -#if 0 -/* - * bind - */ - -void IdPtrn::bind(Scopes& scopes, const Def* def, bool rebind) const { - scopes.bind(dbg(), def, rebind || this->rebind()); -} - -void TuplePtrn::bind(Scopes& scopes, const Def* def, bool rebind) const { - scopes.bind(dbg(), def, rebind || this->rebind()); - for (size_t i = 0, e = num_ptrns(); i != e; ++i) { - auto proj = def->proj(e, i)->set(ptrn(i)->loc(), ptrn(i)->sym()); - ptrn(i)->bind(scopes, proj, rebind); - } -} +void Module::compile() const { bind(); } +#if 0 /* * type */ diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp new file mode 100644 index 0000000000..b4a881bcb4 --- /dev/null +++ b/src/thorin/ast/bind.cpp @@ -0,0 +1,205 @@ +#include "thorin/ast/ast.h" + +namespace thorin::ast { + +class Scopes { +public: + using Scope = fe::SymMap>; + + Scopes() { push(); /* root scope */ } + + void push() { scopes_.emplace_back(); } + void pop(); + Scope* curr() { return &scopes_.back(); } + const Decl* query(Dbg) const; + const Decl* find(Dbg) const; ///< Same as Scopes::query but potentially raises an error. + void bind(Scope*, Dbg, const Decl*, bool rebind = false); + void bind(Dbg dbg, const Decl* decl, bool rebind = false) { bind(&scopes_.back(), dbg, decl, rebind); } + void swap(Scope& other) { std::swap(scopes_.back(), other); } + +private: + std::deque scopes_; +}; + +void Scopes::pop() { + assert(!scopes_.empty()); + scopes_.pop_back(); +} + +const Decl* Scopes::query(Dbg dbg) const { + if (dbg.sym == '_') return nullptr; + + for (auto& scope : scopes_ | std::ranges::views::reverse) + if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; + + return nullptr; +} + +const Decl* Scopes::find(Dbg dbg) const { + if (dbg.sym == '_') error(dbg.loc, "the symbol '_' is special and never binds to anything"); + if (auto res = query(dbg)) return res; + error(dbg.loc, "'{}' not found", dbg.sym); +} + +void Scopes::bind(Scope* scope, Dbg dbg, const Decl* decl, bool rebind) { + assert(dbg); + auto [loc, sym] = dbg; + if (sym == '_') return; // don't do anything with '_' + + if (rebind) { + (*scope)[sym] = std::pair(loc, decl); + } else if (auto [i, ins] = scope->emplace(sym, std::pair(loc, decl)); !ins) { + auto prev = i->second.first; + error(loc, "redeclaration of '{}'; previous declaration here: {}", sym, prev); + } +} + +/* + * AST + */ + +void Module::bind() const { + Scopes scopes; + bind(scopes); +} + +void Module::bind(Scopes& s) const { + for (const auto& decl : decls()) decl->bind(s); +} + +/* + * Ptrn + */ + +void IdPtrn::bind(Scopes& s) const { + if (type()) type()->bind(s); + if (dbg()) s.bind(dbg(), nullptr, rebind()); +} + +void TuplePtrn::bind(Scopes& s) const { + if (dbg()) s.bind(dbg(), nullptr, rebind()); + s.push(); + for (const auto& ptrn : ptrns()) ptrn->bind(s); + s.pop(); +} + +void GroupPtrn::bind(Scopes& s) const { + type()->bind(s); + for (auto dbg : dbgs()) s.bind(dbg, nullptr, false); +} + +/* + * Expr + */ + +void IdExpr::bind(Scopes& s) const { decl_ = s.find(dbg()); } + +void PrimaryExpr::bind(Scopes&) const {} + +void LitExpr ::bind(Scopes& s) const { + if (type()) type()->bind(s); +} +void ExtremumExpr::bind(Scopes& s) const { + if (type()) type()->bind(s); +} +void TypeExpr ::bind(Scopes& s) const { + if (level()) level()->bind(s); +} + +void BlockExpr::bind(Scopes& s) const { + s.push(); + for (const auto& decl : decls()) decl->bind(s); + if (expr()) expr()->bind(s); + s.pop(); +} + +void SimplePiExpr::bind(Scopes& s) const { + dom()->bind(s); + codom()->bind(s); +} + +void PiExpr::Dom::bind(Scopes& s) const { ptrn()->bind(s); } + +void PiExpr::bind(Scopes& s) const { + s.push(); + for (const auto& dom : doms()) dom->bind(s); + if (codom()) codom()->bind(s); + s.pop(); +} + +void LamExpr::Dom::bind(Scopes& s) const { ptrn()->bind(s); } + +void LamExpr::bind(Scopes& s) const { + s.push(); + for (const auto& dom : doms()) dom->bind(s); + if (codom()) codom()->bind(s); + body()->bind(s); + s.pop(); +} + +void AppExpr::bind(Scopes& s) const { + callee()->bind(s); + arg()->bind(s); +} + +void RetExpr::bind(Scopes& s) const { + ptrn()->bind(s); + callee()->bind(s); + arg()->bind(s); +} + +void SigmaExpr::bind(Scopes& s) const { ptrn()->bind(s); } + +void TupleExpr::bind(Scopes& s) const { + for (const auto& elem : elems()) elem->bind(s); +} + +template void ArrOrPackExpr::bind(Scopes& s) const { + s.push(); + shape()->bind(s); + body()->bind(s); + s.pop(); +} + +template void ArrOrPackExpr::bind(Scopes&) const; +template void ArrOrPackExpr::bind(Scopes&) const; + +void ExtractExpr::bind(Scopes& s) const { + tuple()->bind(s); + if (auto expr = std::get_if>(&index())) (*expr)->bind(s); + // We check for Dbg case during "emit" as we need full type info. +} + +void InsertExpr::bind(Scopes& s) const { + tuple()->bind(s); + index()->bind(s); + value()->bind(s); +} + +/* + * Decl + */ + +void LetDecl::bind(Scopes& s) const { + value()->bind(s); + ptrn()->bind(s); +} + +void AxiomDecl::bind(Scopes& s) const { type()->bind(s); } + +void PiDecl::bind(Scopes& s) const { + if (type()) type()->bind(s); + body()->bind(s); +} + +void LamDecl::bind(Scopes& s) const { + s.bind(lam()->dbg(), this); + lam()->bind(s); +} + +void SigmaDecl::bind(Scopes& s) const { + if (type()) type()->bind(s); + body()->bind(s); +} + +} // namespace thorin::ast diff --git a/src/thorin/ast/scopes.cpp b/src/thorin/ast/scopes.cpp deleted file mode 100644 index 50a7ca6792..0000000000 --- a/src/thorin/ast/scopes.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "thorin/ast/scopes.h" - -#include "thorin/world.h" - -namespace thorin::ast { - -void Scopes::pop() { - assert(!scopes_.empty()); - scopes_.pop_back(); -} - -const Def* Scopes::query(Dbg dbg) const { - if (dbg.sym == '_') return nullptr; - - for (auto& scope : scopes_ | std::ranges::views::reverse) - if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; - - return nullptr; -} - -const Def* Scopes::find(Dbg dbg) const { - if (dbg.sym == '_') error(dbg.loc, "the symbol '_' is special and never binds to anything"); - if (auto res = query(dbg)) return res; - error(dbg.loc, "'{}' not found", dbg.sym); -} - -void Scopes::bind(Scope* scope, Dbg dbg, const Def* def, bool rebind) { - auto [loc, sym] = dbg; - if (sym == '_') return; // don't do anything with '_' - - if (rebind) { - (*scope)[sym] = std::pair(loc, def); - } else if (auto [i, ins] = scope->emplace(sym, std::pair(loc, def)); !ins) { - auto prev = i->second.first; - error(loc, "redeclaration of '{}'; previous declaration here: {}", sym, prev); - } -} - -} // namespace thorin::ast diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index d177cfc3f0..bd9b623836 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -55,7 +55,7 @@ std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { } /* - * Ptrn + * Expr */ std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", dbg()); } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index ee2ecc070c..93467e1f28 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -175,6 +175,7 @@ int main(int argc, char** argv) { if (os[AST]) { auto mod = parser.import(driver.sym(input), os[Md]); + mod->compile(); Tab tab; mod->stream(tab, *os[AST]); } From 1971158318751de14160a01a08ff99672fbee890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 1 Apr 2024 16:04:22 +0200 Subject: [PATCH 14/95] AST wip: bind names --- include/thorin/ast/ast.h | 73 +++++++++++++++++++++++++++++++------ include/thorin/ast/lexer.h | 10 ++--- include/thorin/ast/parser.h | 14 +++---- include/thorin/util/dbg.h | 3 +- src/thorin/ast/ast.cpp | 2 +- src/thorin/ast/bind.cpp | 72 ++++++++++++++++++++---------------- src/thorin/ast/lexer.cpp | 39 ++++++++++---------- src/thorin/ast/parser.cpp | 9 +++-- src/thorin/ast/stream.cpp | 5 +++ src/thorin/cli/main.cpp | 5 ++- 10 files changed, 149 insertions(+), 83 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 5b567a8cef..d05127bb0e 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -27,20 +27,41 @@ class AST { , anon_(sym("_")) {} Driver& driver() { return driver_; } - Sym anon() const { return anon_; } /// @name Sym ///@{ Sym sym(const char* s) { return driver().sym(s); } Sym sym(std::string_view s) { return driver().sym(s); } Sym sym(const std::string& s) { return driver().sym(s); } + Sym anon() const { return anon_; } ///< `"_"`. ///@} template auto ptr(Args&&... args) { return arena_.mk(std::forward(args)...); } + /// @name Formatted Output + ///@{ + /// Prefixes error message with `: error: `. + template void error(Loc loc, const char* fmt, Args&&... args) const { + ++num_errors_; + print(std::cerr, "{}{}: {}error: {}", rang::fg::yellow, loc, rang::fg::red, rang::fg::reset); + println(std::cerr, fmt, std::forward(args)...); + } + template void warn(Loc loc, const char* fmt, Args&&... args) const { + ++num_warnings_; + print(std::cerr, "{}{}: {}warning: {}", rang::fg::yellow, loc, rang::fg::magenta, rang::fg::reset); + println(std::cerr, fmt, std::forward(args)...); + } + template void note(Loc loc, const char* fmt, Args&&... args) const { + print(std::cerr, "{}{}: {}note: {}", rang::fg::yellow, loc, rang::fg::green, rang::fg::reset); + println(std::cerr, fmt, std::forward(args)...); + } + ///@} + private: + mutable int num_errors_ = 0; + mutable int num_warnings_ = 0; Driver& driver_; fe::Arena arena_; Sym anon_; @@ -77,6 +98,16 @@ class Decl : public Node { : Node(loc) {} }; +class RecDecl : public Decl { +protected: + RecDecl(Loc loc) + : Decl(loc) {} + +public: + void bind_rec(Scopes&) const; + virtual const Expr* body() const = 0; +}; + /* * Ptrn */ @@ -206,6 +237,9 @@ class IdExpr : public Expr { /// `tag` class PrimaryExpr : public Expr { public: + PrimaryExpr(Loc loc, Tok::Tag tag) + : Expr(loc) + , tag_(tag) {} PrimaryExpr(Tok tok) : Expr(tok.loc()) , tag_(tok.tag()) {} @@ -576,6 +610,21 @@ class InsertExpr : public Expr { Ptr value_; }; +class ErrorExpr : public Expr { +public: + ErrorExpr(Loc loc, Ptr&& type) + : Expr(loc) + , type_(std::move(type)) {} + + const Expr* type() const { return type_.get(); } + + void bind(Scopes&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Ptr type_; +}; + /* * Further Decls */ @@ -632,17 +681,17 @@ class AxiomDecl : public Decl { }; /// `.Pi dbg: type = body´ -class PiDecl : public Decl { +class PiDecl : public RecDecl { public: PiDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) - : Decl(loc) + : RecDecl(loc) , dbg_(dbg) , type_(std::move(type)) , body_(std::move(body)) {} Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } - const Expr* body() const { return body_.get(); } + const Expr* body() const override { return body_.get(); } void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -654,13 +703,14 @@ class PiDecl : public Decl { }; /// Just wraps a LamDecl as Expr. -class LamDecl : public Decl { +class LamDecl : public RecDecl { public: LamDecl(Ptr&& lam) - : Decl(lam->loc()) + : RecDecl(lam->loc()) , lam_(std::move(lam)) {} const LamExpr* lam() const { return lam_.get(); } + const Expr* body() const override { return lam()->body(); } void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -670,16 +720,16 @@ class LamDecl : public Decl { }; /// `.Sigma dbg: type = body` -class SigmaDecl : public Decl { +class SigmaDecl : public RecDecl { public: SigmaDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) - : Decl(loc) + : RecDecl(loc) , dbg_(dbg) , type_(std::move(type)) , body_(std::move(body)) {} const Expr* type() const { return type_.get(); } - const Expr* body() const { return body_.get(); } + const Expr* body() const override { return body_.get(); } void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -704,9 +754,8 @@ class Module : public Node { const Decl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } - void compile() const; - void bind() const; - + void compile(AST&) const; + void bind(AST&) const; void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; diff --git a/include/thorin/ast/lexer.h b/include/thorin/ast/lexer.h index 6c68910ce5..1b8f34cc8b 100644 --- a/include/thorin/ast/lexer.h +++ b/include/thorin/ast/lexer.h @@ -5,21 +5,21 @@ #include #include -#include "thorin/driver.h" - #include "thorin/ast/tok.h" namespace thorin::ast { +class AST; + class Lexer : public fe::Lexer<3, Lexer> { using Super = fe::Lexer<3, Lexer>; public: /// Creates a lexer to read Thorin files (see [Lexical Structure](@ref lex)). /// If @p md is not `nullptr`, a Markdown output will be generated. - Lexer(Driver& driver, std::istream& istream, const fs::path* path = nullptr, std::ostream* md = nullptr); + Lexer(AST&, std::istream&, const fs::path* path = nullptr, std::ostream* md = nullptr); - Driver& driver() { return driver_; } + AST& ast() { return ast_; } const fs::path* path() const { return loc_.path; } Loc loc() const { return loc_; } Tok lex(); @@ -54,7 +54,7 @@ class Lexer : public fe::Lexer<3, Lexer> { if (md_) *md_ << "```\n"; } - Driver& driver_; + AST& ast_; std::ostream* md_; bool out_ = true; fe::SymMap keywords_; diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 72b683410c..5add2302da 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -29,8 +29,8 @@ constexpr size_t Look_Ahead = 2; /// * If default argument is **provided** we have the same behavior as in 2. class Parser : public fe::Parser { public: - Parser(Driver& driver) - : ast_(driver) {} + Parser(AST& ast) + : ast_(ast) {} AST& ast() { return ast_; } Driver& driver() { return ast().driver(); } @@ -117,21 +117,21 @@ class Parser : public fe::Parser { ///@{ /// Issue an error message of the form: /// "expected \, got '\\' while parsing \" - [[noreturn]] void syntax_err(std::string_view what, const Tok& tok, std::string_view ctxt) { - error(tok.loc(), "expected {}, got '{}' while parsing {}", what, tok, ctxt); + void syntax_err(std::string_view what, const Tok& tok, std::string_view ctxt) { + ast().error(tok.loc(), "expected {}, got '{}' while parsing {}", what, tok, ctxt); } /// Same above but uses @p ahead() as @p tok. - [[noreturn]] void syntax_err(std::string_view what, std::string_view ctxt) { syntax_err(what, ahead(), ctxt); } + void syntax_err(std::string_view what, std::string_view ctxt) { syntax_err(what, ahead(), ctxt); } - [[noreturn]] void syntax_err(Tok::Tag tag, std::string_view ctxt) { + void syntax_err(Tok::Tag tag, std::string_view ctxt) { std::string msg("'"); msg.append(Tok::tag2str(tag)).append("'"); syntax_err(msg, ctxt); } ///@} - AST ast_; + AST& ast_; Lexer* lexer_ = nullptr; friend class fe::Parser; diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 0c37c5b260..fd65ecc997 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "thorin/util/print.h" @@ -22,7 +23,7 @@ using fe::Sym; /// Prefixes error message with `: error: `. template [[noreturn]] void error(Loc loc, const char* fmt, Args&&... args) { std::ostringstream o; - print(o, "{}: error: ", loc); + print(o, "{}{}: {}error: {}", rang::fg::yellow, loc, rang::fg::red, rang::fg::reset); print(o, fmt, std::forward(args)...); throw T(o.str()); } diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 4b0c82ebe2..4f55fae6a0 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -28,7 +28,7 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { return {}; } -void Module::compile() const { bind(); } +void Module::compile(AST& ast) const { bind(ast); } #if 0 /* diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index b4a881bcb4..f16bf38a71 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -6,8 +6,12 @@ class Scopes { public: using Scope = fe::SymMap>; - Scopes() { push(); /* root scope */ } + Scopes(AST& ast) + : ast_(ast) { + push(); // root scope + } + AST& ast() const { return ast_; } void push() { scopes_.emplace_back(); } void pop(); Scope* curr() { return &scopes_.back(); } @@ -18,6 +22,7 @@ class Scopes { void swap(Scope& other) { std::swap(scopes_.back(), other); } private: + AST& ast_; std::deque scopes_; }; @@ -36,9 +41,10 @@ const Decl* Scopes::query(Dbg dbg) const { } const Decl* Scopes::find(Dbg dbg) const { - if (dbg.sym == '_') error(dbg.loc, "the symbol '_' is special and never binds to anything"); + if (dbg.sym == '_') ast().error(dbg.loc, "the symbol '_' is special and never binds to anything"); if (auto res = query(dbg)) return res; - error(dbg.loc, "'{}' not found", dbg.sym); + ast().error(dbg.loc, "'{}' not found", dbg.sym); + return nullptr; } void Scopes::bind(Scope* scope, Dbg dbg, const Decl* decl, bool rebind) { @@ -50,7 +56,8 @@ void Scopes::bind(Scope* scope, Dbg dbg, const Decl* decl, bool rebind) { (*scope)[sym] = std::pair(loc, decl); } else if (auto [i, ins] = scope->emplace(sym, std::pair(loc, decl)); !ins) { auto prev = i->second.first; - error(loc, "redeclaration of '{}'; previous declaration here: {}", sym, prev); + ast().error(loc, "redeclaration of '{}'", sym); + ast().note(prev, "previous declaration here"); } } @@ -58,13 +65,35 @@ void Scopes::bind(Scope* scope, Dbg dbg, const Decl* decl, bool rebind) { * AST */ -void Module::bind() const { - Scopes scopes; +// clang-format off +void ExtremumExpr::bind(Scopes& s) const { if ( type()) type()->bind(s); } +void LitExpr ::bind(Scopes& s) const { if ( type()) type()->bind(s); } +void PiDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } +void SigmaDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } +void TypeExpr ::bind(Scopes& s) const { if (level()) level()->bind(s); } +void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } +void ErrorExpr ::bind(Scopes&) const {} +void PrimaryExpr ::bind(Scopes&) const {} +void RecDecl ::bind_rec(Scopes& s) const { body()->bind(s); } +// clang-format on + +void Module::bind(AST& ast) const { + auto scopes = Scopes(ast); bind(scopes); } void Module::bind(Scopes& s) const { - for (const auto& decl : decls()) decl->bind(s); + for (size_t i = 0, e = num_decls(), r = 0; true; ++i) { + if (decl(i)->isa()) { + if (!decl(r)->isa()) r = i; + } else if (decl(r)->isa()) { + for (size_t j = r; j != i; ++j) decl(j)->as()->bind_rec(s); + r = i; + } + + if (i == e) break; + decl(i)->bind(s); + } } /* @@ -92,20 +121,6 @@ void GroupPtrn::bind(Scopes& s) const { * Expr */ -void IdExpr::bind(Scopes& s) const { decl_ = s.find(dbg()); } - -void PrimaryExpr::bind(Scopes&) const {} - -void LitExpr ::bind(Scopes& s) const { - if (type()) type()->bind(s); -} -void ExtremumExpr::bind(Scopes& s) const { - if (type()) type()->bind(s); -} -void TypeExpr ::bind(Scopes& s) const { - if (level()) level()->bind(s); -} - void BlockExpr::bind(Scopes& s) const { s.push(); for (const auto& decl : decls()) decl->bind(s); @@ -187,19 +202,12 @@ void LetDecl::bind(Scopes& s) const { void AxiomDecl::bind(Scopes& s) const { type()->bind(s); } -void PiDecl::bind(Scopes& s) const { - if (type()) type()->bind(s); - body()->bind(s); -} - void LamDecl::bind(Scopes& s) const { + s.push(); + for (const auto& dom : lam()->doms()) dom->bind(s); + if (auto codom = lam()->codom()) codom->bind(s); + s.pop(); s.bind(lam()->dbg(), this); - lam()->bind(s); -} - -void SigmaDecl::bind(Scopes& s) const { - if (type()) type()->bind(s); - body()->bind(s); } } // namespace thorin::ast diff --git a/src/thorin/ast/lexer.cpp b/src/thorin/ast/lexer.cpp index dc05f12564..4e389aeb80 100644 --- a/src/thorin/ast/lexer.cpp +++ b/src/thorin/ast/lexer.cpp @@ -9,16 +9,16 @@ namespace thorin::ast { namespace utf8 = fe::utf8; using Tag = Tok::Tag; -Lexer::Lexer(Driver& driver, std::istream& istream, const fs::path* path /*= nullptr*/, std::ostream* md /*= nullptr*/) +Lexer::Lexer(AST& ast, std::istream& istream, const fs::path* path /*= nullptr*/, std::ostream* md /*= nullptr*/) : Super(istream, path) - , driver_(driver) + , ast_(ast) , md_(md) { -#define CODE(t, str) keywords_[driver.sym(str)] = Tag::t; +#define CODE(t, str) keywords_[ast.sym(str)] = Tag::t; THORIN_KEY(CODE) #undef CODE #define CODE(str, t) \ - if (Tag::t != Tag::Nil) keywords_[driver.sym(str)] = Tag::t; + if (Tag::t != Tag::Nil) keywords_[ast.sym(str)] = Tag::t; THORIN_SUBST(CODE) #undef CODE @@ -39,7 +39,7 @@ Tok Lexer::lex() { if (accept(utf8::EoF)) return tok(Tag::EoF); if (accept(utf8::isspace)) continue; - if (accept(utf8::Null)) error(loc_, "invalid UTF-8 character"); + if (accept(utf8::Null)) ast().error(loc_, "invalid UTF-8 character"); // clang-format off // delimiters @@ -90,7 +90,7 @@ Tok Lexer::lex() { if (accept('~')) { if (accept('|')) return tok(Tag::T_Pi); } - error(loc_, "invalid input char '{}'; maybe you wanted to use '|~|'?", str_); + ast().error(loc_, "invalid input char '{}'; maybe you wanted to use '|~|'?", str_); continue; } // clang-format on @@ -100,7 +100,7 @@ Tok Lexer::lex() { auto loc = cache_trailing_dot(); return {loc, Tag::M_anx, sym()}; } - error(loc_, "invalid axiom name '{}'", str_); + ast().error(loc_, "invalid axiom name '{}'", str_); } if (accept('.')) { @@ -110,7 +110,7 @@ Tok Lexer::lex() { assert(!cache_.has_value()); auto id_loc = loc(); ++id_loc.begin.col; - cache_.emplace(id_loc, Tag::M_id, driver().sym(str_.substr(1))); + cache_.emplace(id_loc, Tag::M_id, ast().sym(str_.substr(1))); return {loc().anew_begin(), Tag::T_dot}; } @@ -126,7 +126,7 @@ Tok Lexer::lex() { if (accept('\'')) { auto c = lex_char(); if (accept('\'')) return {loc(), c}; - error(loc_, "invalid character literal {}", str_); + ast().error(loc_, "invalid character literal {}", str_); continue; } @@ -162,11 +162,11 @@ Tok Lexer::lex() { continue; } - error({loc_.path, peek_}, "invalid input char '/'; maybe you wanted to start a comment?"); + ast().error({loc_.path, peek_}, "invalid input char '/'; maybe you wanted to start a comment?"); continue; } - error({loc_.path, peek_}, "invalid input char '{}'", utf8::Char32(ahead())); + ast().error({loc_.path, peek_}, "invalid input char '{}'", utf8::Char32(ahead())); next(); } } @@ -229,7 +229,7 @@ std::optional Lexer::parse_lit() { parse_digits(); return Tok{loc_, Tag::M_lit, sym()}; } else { - error(loc_, "stray underscore in .Idx literal; size is missing"); + ast().error(loc_, "stray underscore in .Idx literal; size is missing"); return {}; } } @@ -244,12 +244,12 @@ std::optional Lexer::parse_lit() { } bool has_exp = parse_exp(base); - if (base == 16 && is_float && !has_exp) error(loc_, "hexadecimal floating constants require an exponent"); + if (base == 16 && is_float && !has_exp) ast().error(loc_, "hexadecimal floating constants require an exponent"); is_float |= has_exp; } if (sign && str_.empty()) { - error(loc_, "stray '{}'", *sign ? "-" : "+"); + ast().error(loc_, "stray '{}'", *sign ? "-" : "+"); return {}; } @@ -271,7 +271,7 @@ void Lexer::parse_digits(int base /*= 10*/) { bool Lexer::parse_exp(int base /*= 10*/) { if (accept(base == 10 ? utf8::any('e', 'E') : utf8::any('p', 'P'))) { accept(utf8::any('+', '-')); - if (!utf8::isdigit(ahead())) error(loc_, "exponent has no digits"); + if (!utf8::isdigit(ahead())) ast().error(loc_, "exponent has no digits"); parse_digits(); return true; } @@ -294,21 +294,22 @@ char8_t Lexer::lex_char() { else if (accept( 'r')) str_ += '\r'; else if (accept( 't')) str_ += '\t'; else if (accept( 'v')) str_ += '\v'; - else error(loc_.anew_finis(), "invalid escape character '\\{}'", (char)ahead()); + else ast().error(loc_.anew_finis(), "invalid escape character '\\{}'", (char)ahead()); // clang-format on return str_.back(); } auto c = next(); str_ += c; if (utf8::isascii(c)) return c; - error(loc_, "invalid character '{}'", (char)c); + ast().error(loc_, "invalid character '{}'", (char)c); + return '\0'; } void Lexer::eat_comments() { while (true) { while (ahead() != utf8::EoF && ahead() != '*') next(); if (accept(utf8::EoF)) { - error(loc_, "non-terminated multiline comment"); + ast().error(loc_, "non-terminated multiline comment"); return; } next(); @@ -335,6 +336,6 @@ void Lexer::emit_md(bool start_of_file) { md_fence(); } -Sym Lexer::sym() { return driver().sym(str_); } +Sym Lexer::sym() { return ast().sym(str_); } } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 6a6df71da1..10170c1e90 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -63,10 +63,10 @@ Ptr Parser::import(Sym name, std::ostream* md) { Ptr Parser::import(std::istream& is, const fs::path* path, std::ostream* md) { driver().VLOG("reading: {}", path ? path->string() : ""s); - if (!is) error("cannot read file '{}'", *path); + if (!is) return {}; auto state = std::tuple(prev_, ahead_, lexer_); - auto lexer = Lexer(driver(), is, path, md); + auto lexer = Lexer(ast(), is, path, md); lexer_ = &lexer; init(path); auto mod = parse_module(); @@ -114,6 +114,7 @@ Ptr Parser::parse_type_ascr(std::string_view ctxt) { if (accept(Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot); if (ctxt.empty()) return nullptr; syntax_err("':'", ctxt); + return ptr(prev_, ptr(prev_, Tag::T_star)); } /* @@ -445,7 +446,7 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec, dbg = eat(Tag::M_id).dbg(); eat(Tag::T_colon_colon); if (b && ahead().isa(Tag::D_paren_l)) - error(ahead().loc(), "switching from []-style patterns to ()-style patterns is not allowed"); + ast().error(ahead().loc(), "switching from []-style patterns to ()-style patterns is not allowed"); // b -> s::(p, ..., p) // b -> s::[b, ..., b] b -> s::[b, ..., b] // b -> 's::(p, ..., p) @@ -477,7 +478,7 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec, } } else if (b) { // b -> e where e != id - if (backtick) error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding"); + if (backtick) ast().error(backtick.loc(), "you can only prefix identifiers with backtick for rebinding"); auto type = parse_expr(ctxt, prec); return ptr(track, rebind, dbg, std::move(type)); } else if (!ctxt.empty()) { diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index bd9b623836..0a469c555a 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -144,6 +144,11 @@ std::ostream& InsertExpr::stream(Tab& tab, std::ostream& os) const { return print(os, ".ins({}, {}, {})", S(tab, tuple()), S(tab, index()), S(tab, value())); } +std::ostream& ErrorExpr::stream(Tab& tab, std::ostream& os) const { + if (type()) return print(os, "", S(tab, type())); + return os << ""; +} + /* * Decl */ diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 93467e1f28..45ae222773 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -138,7 +138,8 @@ int main(int argc, char** argv) { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); - auto parser = ast::Parser(driver); + auto ast = ast::AST(driver); + auto parser = ast::Parser(ast); #if 0 parser.import(driver.sym(input), os[Md]); @@ -175,7 +176,7 @@ int main(int argc, char** argv) { if (os[AST]) { auto mod = parser.import(driver.sym(input), os[Md]); - mod->compile(); + mod->compile(ast); Tab tab; mod->stream(tab, *os[AST]); } From a7afbd221180c86273a837b2cbd16f7cae344ae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 00:12:38 +0200 Subject: [PATCH 15/95] wip: bind names --- include/thorin/ast/ast.h | 80 +++++++++++++----- include/thorin/ast/parser.h | 1 + lit/main_loop.thorin | 2 +- src/thorin/ast/bind.cpp | 160 +++++++++++++++++++++--------------- src/thorin/ast/parser.cpp | 2 +- src/thorin/ast/stream.cpp | 22 +++-- 6 files changed, 171 insertions(+), 96 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index d05127bb0e..ce9947ec17 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -24,7 +24,8 @@ class AST { public: AST(Driver& driver) : driver_(driver) - , anon_(sym("_")) {} + , sym_anon_(sym("_")) + , sym_return_(sym("return")) {} Driver& driver() { return driver_; } @@ -33,7 +34,8 @@ class AST { Sym sym(const char* s) { return driver().sym(s); } Sym sym(std::string_view s) { return driver().sym(s); } Sym sym(const std::string& s) { return driver().sym(s); } - Sym anon() const { return anon_; } ///< `"_"`. + Sym sym_anon() const { return sym_anon_; } ///< `"_"`. + Sym sym_return() const { return sym_return_; } ///< `"return"`. ///@} template auto ptr(Args&&... args) { @@ -64,7 +66,8 @@ class AST { mutable int num_warnings_ = 0; Driver& driver_; fe::Arena arena_; - Sym anon_; + Sym sym_anon_; + Sym sym_return_; }; class Scopes; @@ -104,8 +107,23 @@ class RecDecl : public Decl { : Decl(loc) {} public: - void bind_rec(Scopes&) const; - virtual const Expr* body() const = 0; + virtual void bind_rec(Scopes&) const = 0; +}; + +class DeclsBlock { +public: + DeclsBlock(Ptrs&& decls) + : decls_(std::move(decls)) {} + + const auto& decls() const { return decls_; } + const Decl* decl(size_t i) const { return decls_[i].get(); } + size_t num_decls() const { return decls_.size(); } + + std::ostream& stream(Tab&, std::ostream&) const; + void bind(Scopes&) const; + +private: + Ptrs decls_; }; /* @@ -137,7 +155,7 @@ class IdPtrn : public Ptrn { static Ptr mk_type(AST& ast, Ptr&& type) { auto loc = type->loc(); - return ast.ptr(loc, false, Dbg(loc, ast.anon()), std::move(type)); + return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } // void bind(Scopes&, const Def*, bool rebind = false) const override {} @@ -166,7 +184,7 @@ class GroupPtrn : public Ptrn { static Ptr mk_type(AST& ast, Ptr&& type) { auto loc = type->loc(); - return ast.ptr(loc, false, Dbg(loc, ast.anon()), std::move(type)); + return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } // void bind(Scopes&, const Def*, bool rebind = false) const override {} @@ -212,6 +230,28 @@ class TuplePtrn : public Ptrn { Ptrs ptrns_; }; +/// Dummy Ptrn to introduce `return: type`. +/// @note ReturnPtrn::type is **not** owned. +class ReturnPtrn : public Ptrn { +public: + ReturnPtrn(AST& ast, const Expr* type) + : Ptrn(type->loc()) + , dbg_(type->loc(), ast.sym_return()) + , type_(type) {} + + Dbg dbg() const { return dbg_; } + const Expr* type() const { return type_; } + + // void bind(Scopes&, const Def*, bool rebind = false) const override {} + // const Def* type(World&, Def2Fields&) const override {} + void bind(Scopes&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Dbg dbg_; + const Expr* type_; +}; + /* * Expr */ @@ -301,9 +341,6 @@ class BlockExpr : public Expr { , expr_(std::move(expr)) {} bool has_braces() const { return has_braces_; } - const auto& decls() const { return decls_; } - const Decl* decl(size_t i) const { return decls_[i].get(); } - size_t num_decls() const { return decls_.size(); } const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; @@ -311,7 +348,7 @@ class BlockExpr : public Expr { private: bool has_braces_; - Ptrs decls_; + DeclsBlock decls_; Ptr expr_; }; @@ -334,9 +371,9 @@ class TypeExpr : public Expr { // lam /// `dom -> codom` -class SimplePiExpr : public Expr { +class ArrowExpr : public Expr { public: - SimplePiExpr(Loc loc, Ptr&& dom, Ptr&& codom) + ArrowExpr(Loc loc, Ptr&& dom, Ptr&& codom) : Expr(loc) , dom_(std::move(dom)) , codom_(std::move(codom)) {} @@ -442,6 +479,7 @@ class LamExpr : public Expr { const Dom* dom(size_t i) const { return doms_[i].get(); } size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } + const ReturnPtrn* ret() const { return ret_.get(); } const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; @@ -454,6 +492,7 @@ class LamExpr : public Expr { Ptrs doms_; Ptr codom_; Ptr body_; + mutable Ptr ret_; }; /// `callee arg` @@ -691,9 +730,10 @@ class PiDecl : public RecDecl { Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } - const Expr* body() const override { return body_.get(); } + const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; + void bind_rec(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -710,9 +750,10 @@ class LamDecl : public RecDecl { , lam_(std::move(lam)) {} const LamExpr* lam() const { return lam_.get(); } - const Expr* body() const override { return lam()->body(); } + const Expr* body() const { return lam()->body(); } void bind(Scopes&) const override; + void bind_rec(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -729,9 +770,10 @@ class SigmaDecl : public RecDecl { , body_(std::move(body)) {} const Expr* type() const { return type_.get(); } - const Expr* body() const override { return body_.get(); } + const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; + void bind_rec(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -750,17 +792,13 @@ class Module : public Node { : Node(loc) , decls_(std::move(decls)) {} - const auto& decls() const { return decls_; } - const Decl* decl(size_t i) const { return decls_[i].get(); } - size_t num_decls() const { return decls_.size(); } - void compile(AST&) const; void bind(AST&) const; void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Ptrs decls_; + DeclsBlock decls_; }; } // namespace thorin::ast diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 5add2302da..ee776188c7 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -45,6 +45,7 @@ class Parser : public fe::Parser { return ast_.ptr(std::forward(args)...); } + Dbg anon() const { return {ahead().loc().anew_begin(), ast_.sym_anon()}; } Dbg dbg(const Tracker& tracker, Sym sym) const { return {tracker.loc(), sym}; } Lexer& lexer() { return *lexer_; } diff --git a/lit/main_loop.thorin b/lit/main_loop.thorin index 4794244498..b04ce1631f 100644 --- a/lit/main_loop.thorin +++ b/lit/main_loop.thorin @@ -13,7 +13,7 @@ .let inc = %core.wrap.add 0 (1I32, i); .let acci = %core.wrap.add 0 (i, acc); loopi (m, inc, acci); - (.cn m: %mem.M = return (m, acc), body)#cond mem; + (.cn m: %mem.M = returnx (m, acc), body)#cond mem; loop (mem, 0I32, 0I32); // CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[_{{[0-9]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .I32, %mem.Ptr (%mem.Ptr (.I8, 0), 0)], return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index f16bf38a71..1c44c43721 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -1,65 +1,73 @@ #include "thorin/ast/ast.h" +#include "fe/assert.h" + namespace thorin::ast { +using Tag = Tok::Tag; + +class DummyDecl : public Decl { +public: + DummyDecl() + : Decl(Loc()) {} + + std::ostream& stream(Tab&, std::ostream& os) const override { return os << ""; } + void bind(Scopes&) const override { fe::unreachable(); } +}; + class Scopes { public: using Scope = fe::SymMap>; Scopes(AST& ast) - : ast_(ast) { + : ast_(ast) + , dummy_(ast.ptr()) { push(); // root scope } AST& ast() const { return ast_; } - void push() { scopes_.emplace_back(); } - void pop(); - Scope* curr() { return &scopes_.back(); } - const Decl* query(Dbg) const; - const Decl* find(Dbg) const; ///< Same as Scopes::query but potentially raises an error. - void bind(Scope*, Dbg, const Decl*, bool rebind = false); - void bind(Dbg dbg, const Decl* decl, bool rebind = false) { bind(&scopes_.back(), dbg, decl, rebind); } - void swap(Scope& other) { std::swap(scopes_.back(), other); } - -private: - AST& ast_; - std::deque scopes_; -}; - -void Scopes::pop() { - assert(!scopes_.empty()); - scopes_.pop_back(); -} + Scope& top() { return scopes_.back(); } + const Decl* dummy() const { return dummy_.get(); } -const Decl* Scopes::query(Dbg dbg) const { - if (dbg.sym == '_') return nullptr; + void push() { scopes_.emplace_back(); } - for (auto& scope : scopes_ | std::ranges::views::reverse) - if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; + void pop() { + assert(!scopes_.empty()); + scopes_.pop_back(); + } - return nullptr; -} + const Decl* find(Dbg dbg) { + if (dbg.sym == '_') return nullptr; -const Decl* Scopes::find(Dbg dbg) const { - if (dbg.sym == '_') ast().error(dbg.loc, "the symbol '_' is special and never binds to anything"); - if (auto res = query(dbg)) return res; - ast().error(dbg.loc, "'{}' not found", dbg.sym); - return nullptr; -} + for (auto& scope : scopes_ | std::ranges::views::reverse) + if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; -void Scopes::bind(Scope* scope, Dbg dbg, const Decl* decl, bool rebind) { - assert(dbg); - auto [loc, sym] = dbg; - if (sym == '_') return; // don't do anything with '_' + ast().error(dbg.loc, "'{}' not found", dbg.sym); + bind(dbg, dummy_.get()); // put into scope to prevent further errors + return nullptr; + } - if (rebind) { - (*scope)[sym] = std::pair(loc, decl); - } else if (auto [i, ins] = scope->emplace(sym, std::pair(loc, decl)); !ins) { - auto prev = i->second.first; - ast().error(loc, "redeclaration of '{}'", sym); - ast().note(prev, "previous declaration here"); + void bind(Dbg dbg, const Decl* decl, bool rebind = false) { + assert(dbg); + auto [loc, sym] = dbg; + if (sym == '_') return; // don't do anything with '_' + + if (rebind) { + top()[sym] = std::pair(loc, decl); + } else if (auto [i, ins] = top().emplace(sym, std::pair(loc, decl)); !ins) { + auto [prev_loc, prev_decl] = i->second; + if (!prev_decl->isa()) { // if prev_decl stems from an error - don't complain + ast().error(loc, "redeclaration of '{}'", sym); + ast().note(prev_loc, "previous declaration here"); + } + } } -} + +private: + AST& ast_; + Ptr dummy_; + std::deque scopes_; +}; /* * AST @@ -68,13 +76,14 @@ void Scopes::bind(Scope* scope, Dbg dbg, const Decl* decl, bool rebind) { // clang-format off void ExtremumExpr::bind(Scopes& s) const { if ( type()) type()->bind(s); } void LitExpr ::bind(Scopes& s) const { if ( type()) type()->bind(s); } -void PiDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } -void SigmaDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } +void PiDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } +void SigmaDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } void TypeExpr ::bind(Scopes& s) const { if (level()) level()->bind(s); } void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } void ErrorExpr ::bind(Scopes&) const {} void PrimaryExpr ::bind(Scopes&) const {} -void RecDecl ::bind_rec(Scopes& s) const { body()->bind(s); } +void SigmaDecl ::bind_rec(Scopes& s) const { body()->bind(s); } +void PiDecl ::bind_rec(Scopes& s) const { body()->bind(s); } // clang-format on void Module::bind(AST& ast) const { @@ -82,19 +91,7 @@ void Module::bind(AST& ast) const { bind(scopes); } -void Module::bind(Scopes& s) const { - for (size_t i = 0, e = num_decls(), r = 0; true; ++i) { - if (decl(i)->isa()) { - if (!decl(r)->isa()) r = i; - } else if (decl(r)->isa()) { - for (size_t j = r; j != i; ++j) decl(j)->as()->bind_rec(s); - r = i; - } - - if (i == e) break; - decl(i)->bind(s); - } -} +void Module::bind(Scopes& s) const { decls_.bind(s); } /* * Ptrn @@ -117,18 +114,23 @@ void GroupPtrn::bind(Scopes& s) const { for (auto dbg : dbgs()) s.bind(dbg, nullptr, false); } +void ReturnPtrn::bind(Scopes& s) const { + s.bind(dbg(), this); + // No need to check this->type(); it's shared and has already been checked. +} + /* * Expr */ void BlockExpr::bind(Scopes& s) const { s.push(); - for (const auto& decl : decls()) decl->bind(s); + decls_.bind(s); if (expr()) expr()->bind(s); s.pop(); } -void SimplePiExpr::bind(Scopes& s) const { +void ArrowExpr::bind(Scopes& s) const { dom()->bind(s); codom()->bind(s); } @@ -148,6 +150,26 @@ void LamExpr::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); if (codom()) codom()->bind(s); + if (tag() == Tok::Tag::K_fn) { + ret_ = s.ast().ptr(s.ast(), codom()); + ret_->bind(s); + } + body()->bind(s); + s.pop(); +} + +void LamDecl::bind(Scopes& s) const { + s.push(); + for (const auto& dom : lam()->doms()) dom->bind(s); + if (auto codom = lam()->codom()) codom->bind(s); + s.pop(); + s.bind(lam()->dbg(), this); +} + +void LamDecl::bind_rec(Scopes& s) const { + s.push(); + for (const auto& dom : lam()->doms()) dom->bind(s); + if (auto codom = lam()->codom()) codom->bind(s); body()->bind(s); s.pop(); } @@ -202,12 +224,18 @@ void LetDecl::bind(Scopes& s) const { void AxiomDecl::bind(Scopes& s) const { type()->bind(s); } -void LamDecl::bind(Scopes& s) const { - s.push(); - for (const auto& dom : lam()->doms()) dom->bind(s); - if (auto codom = lam()->codom()) codom->bind(s); - s.pop(); - s.bind(lam()->dbg(), this); +void DeclsBlock::bind(Scopes& s) const { + for (size_t i = 0, e = num_decls(), r = 0; true; ++i) { + if (i < e && decl(i)->isa()) { + if (!decl(r)->isa()) r = i; + } else if (r < e && decl(r)->isa()) { + for (size_t j = r; j != i; ++j) decl(j)->as()->bind_rec(s); + r = i; + } + + if (i == e) break; + decl(i)->bind(s); + } } } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 10170c1e90..f249b88abf 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -140,7 +140,7 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec p) if (l < p) break; lex(); auto rhs = parse_expr("right-hand side of an function type", r); - lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); + lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); } else { auto [l, r] = Tok::prec(Tok::Prec::App); if (l < p) break; diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 0a469c555a..ff9a5ee393 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -54,6 +54,12 @@ std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{, }{}", delim_l(), R(tab, ptrns()), delim_r()); } +std::ostream& ReturnPtrn::stream(Tab& tab, std::ostream& os) const { + os << dbg(); + if (type()) print(os, ": {}", S(tab, type())); + return os; +} + /* * Expr */ @@ -74,7 +80,7 @@ std::ostream& ExtremumExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { - if (!has_braces() && num_decls() == 0) { + if (!has_braces() && decls_.num_decls() == 0) { if (expr()) return expr()->stream(tab, os); return os << ""; } @@ -82,7 +88,7 @@ std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { if (has_braces()) os << '{'; os << std::endl; ++tab; - for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); + decls_.stream(tab, os); if (expr()) tab.print(os, "{}", S(tab, expr())); --tab; if (has_braces()) tab.print(os << std::endl, "}}"); @@ -90,7 +96,7 @@ std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& TypeExpr ::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } -std::ostream& SimplePiExpr::stream(Tab& tab, std::ostream& os) const { +std::ostream& ArrowExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{} -> {}", S(tab, dom()), S(tab, codom())); } std::ostream& PiExpr::Dom ::stream(Tab& tab, std::ostream& os) const { @@ -153,6 +159,11 @@ std::ostream& ErrorExpr::stream(Tab& tab, std::ostream& os) const { * Decl */ +std::ostream& DeclsBlock::stream(Tab& tab, std::ostream& os) const { + for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); + return os; +} + std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); } @@ -182,9 +193,6 @@ std::ostream& SigmaDecl::stream(Tab& /*tab*/, std::ostream& os) const { return p * Module */ -std::ostream& Module::stream(Tab& tab, std::ostream& os) const { - for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); - return os; -} +std::ostream& Module::stream(Tab& tab, std::ostream& os) const { return decls_.stream(tab, os); } } // namespace thorin::ast From 7ae89df496e316de74c6aa26bc5f43ee3e6871de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 00:58:33 +0200 Subject: [PATCH 16/95] fiddling around with ErrorExpr --- include/thorin/ast/ast.h | 11 +++-------- lit/main_loop.thorin | 4 ++-- src/thorin/ast/bind.cpp | 15 +++++++++------ src/thorin/ast/parser.cpp | 4 ++-- src/thorin/ast/stream.cpp | 21 ++++++++------------- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index ce9947ec17..7578bca032 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -493,6 +493,7 @@ class LamExpr : public Expr { Ptr codom_; Ptr body_; mutable Ptr ret_; + friend class LamDecl; }; /// `callee arg` @@ -651,17 +652,11 @@ class InsertExpr : public Expr { class ErrorExpr : public Expr { public: - ErrorExpr(Loc loc, Ptr&& type) - : Expr(loc) - , type_(std::move(type)) {} - - const Expr* type() const { return type_.get(); } + ErrorExpr(Loc loc) + : Expr(loc) {} void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; - -private: - Ptr type_; }; /* diff --git a/lit/main_loop.thorin b/lit/main_loop.thorin index b04ce1631f..ba728680d2 100644 --- a/lit/main_loop.thorin +++ b/lit/main_loop.thorin @@ -12,8 +12,8 @@ .con body m: %mem.M = .let inc = %core.wrap.add 0 (1I32, i); .let acci = %core.wrap.add 0 (i, acc); - loopi (m, inc, acci); - (.cn m: %mem.M = returnx (m, acc), body)#cond mem; + loop (m, inc, acci); + (.cn m: %mem.M = return (m, acc), body)#cond mem; loop (mem, 0I32, 0I32); // CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[_{{[0-9]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .I32, %mem.Ptr (%mem.Ptr (.I8, 0), 0)], return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 1c44c43721..c850c214bb 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -37,7 +37,7 @@ class Scopes { } const Decl* find(Dbg dbg) { - if (dbg.sym == '_') return nullptr; + if (!dbg || dbg.sym == '_') return nullptr; for (auto& scope : scopes_ | std::ranges::views::reverse) if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; @@ -48,9 +48,8 @@ class Scopes { } void bind(Dbg dbg, const Decl* decl, bool rebind = false) { - assert(dbg); auto [loc, sym] = dbg; - if (sym == '_') return; // don't do anything with '_' + if (!sym || sym == '_') return; // don't do anything with '_' if (rebind) { top()[sym] = std::pair(loc, decl); @@ -99,11 +98,11 @@ void Module::bind(Scopes& s) const { decls_.bind(s); } void IdPtrn::bind(Scopes& s) const { if (type()) type()->bind(s); - if (dbg()) s.bind(dbg(), nullptr, rebind()); + s.bind(dbg(), nullptr, rebind()); } void TuplePtrn::bind(Scopes& s) const { - if (dbg()) s.bind(dbg(), nullptr, rebind()); + s.bind(dbg(), nullptr, rebind()); s.push(); for (const auto& ptrn : ptrns()) ptrn->bind(s); s.pop(); @@ -162,6 +161,10 @@ void LamDecl::bind(Scopes& s) const { s.push(); for (const auto& dom : lam()->doms()) dom->bind(s); if (auto codom = lam()->codom()) codom->bind(s); + if (lam()->tag() == Tok::Tag::K_fun) { + lam()->ret_ = s.ast().ptr(s.ast(), lam()->codom()); + lam()->ret_->bind(s); + } s.pop(); s.bind(lam()->dbg(), this); } @@ -169,7 +172,7 @@ void LamDecl::bind(Scopes& s) const { void LamDecl::bind_rec(Scopes& s) const { s.push(); for (const auto& dom : lam()->doms()) dom->bind(s); - if (auto codom = lam()->codom()) codom->bind(s); + if (auto ret = lam()->ret()) ret->bind(s); body()->bind(s); s.pop(); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index f249b88abf..6a82be58c3 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -114,7 +114,7 @@ Ptr Parser::parse_type_ascr(std::string_view ctxt) { if (accept(Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot); if (ctxt.empty()) return nullptr; syntax_err("':'", ctxt); - return ptr(prev_, ptr(prev_, Tag::T_star)); + return ptr(prev_); } /* @@ -229,7 +229,7 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { syntax_err("primary expression", ctxt); } // clang-format on - return nullptr; + return ptr(prev_); } template Ptr Parser::parse_arr_or_pack_expr() { diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index ff9a5ee393..427b6c299d 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -66,6 +66,7 @@ std::ostream& ReturnPtrn::stream(Tab& tab, std::ostream& os) const { std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", dbg()); } std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } +std::ostream& ErrorExpr::stream(Tab&, std::ostream& os) const { return os << ""; } std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { os << value(); @@ -80,22 +81,22 @@ std::ostream& ExtremumExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { - if (!has_braces() && decls_.num_decls() == 0) { - if (expr()) return expr()->stream(tab, os); - return os << ""; + if (!has_braces()) { + if (decls_.num_decls() == 0) return expr()->stream(tab, os); + } else { + os << '{'; } - if (has_braces()) os << '{'; os << std::endl; ++tab; decls_.stream(tab, os); - if (expr()) tab.print(os, "{}", S(tab, expr())); - --tab; + (--tab).print(os, "{}", S(tab, expr())); if (has_braces()) tab.print(os << std::endl, "}}"); return os; } std::ostream& TypeExpr ::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } + std::ostream& ArrowExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{} -> {}", S(tab, dom()), S(tab, codom())); } @@ -113,8 +114,7 @@ std::ostream& LamExpr::Dom::stream(Tab& tab, std::ostream& os) const { return os; } std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { - os << tag() << ' '; - if (dbg()) os << dbg(); + print(os, "{} {}", tag(), dbg()); if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; print(os, "{}", R(tab, doms())); if (codom()) print(os, ": {}", S(tab, codom())); @@ -150,11 +150,6 @@ std::ostream& InsertExpr::stream(Tab& tab, std::ostream& os) const { return print(os, ".ins({}, {}, {})", S(tab, tuple()), S(tab, index()), S(tab, value())); } -std::ostream& ErrorExpr::stream(Tab& tab, std::ostream& os) const { - if (type()) return print(os, "", S(tab, type())); - return os << ""; -} - /* * Decl */ From ea0a1481eb6d2de246de17c77b4c641f0984531c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 02:38:23 +0200 Subject: [PATCH 17/95] wip: bind names --- include/thorin/ast/ast.h | 31 ++++++++++++++++++------------- src/thorin/ast/bind.cpp | 20 +++++++++++++------- src/thorin/ast/parser.cpp | 26 +++++++------------------- src/thorin/ast/stream.cpp | 3 ++- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 7578bca032..f2c81b5ef1 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -81,7 +81,6 @@ class Node : public fe::RuntimeCast { public: Loc loc() const { return loc_; } - virtual void bind(Scopes&) const = 0; virtual std::ostream& stream(Tab&, std::ostream&) const = 0; void dump() const; @@ -93,12 +92,18 @@ class Expr : public Node { protected: Expr(Loc loc) : Node(loc) {} + +public: + virtual void bind(Scopes&) const = 0; }; class Decl : public Node { protected: Decl(Loc loc) : Node(loc) {} + +public: + virtual void bind(Scopes&) const = 0; }; class RecDecl : public Decl { @@ -135,7 +140,6 @@ class Ptrn : public Decl { Ptrn(Loc loc) : Decl(loc) {} - // virtual const Def* type(World&, Def2Fields&) const = 0; [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); }; @@ -158,8 +162,6 @@ class IdPtrn : public Ptrn { return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } - // void bind(Scopes&, const Def*, bool rebind = false) const override {} - // const Def* type(World&, Def2Fields&) const override {} void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -187,8 +189,6 @@ class GroupPtrn : public Ptrn { return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } - // void bind(Scopes&, const Def*, bool rebind = false) const override {} - // const Def* type(World&, Def2Fields&) const override {} void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -218,8 +218,6 @@ class TuplePtrn : public Ptrn { const Ptrn* ptrn(size_t i) const { return ptrns_[i].get(); } size_t num_ptrns() const { return ptrns().size(); } - // void bind(Scopes&, const Def*, bool rebind = false) const override {} - // const Def* type(World&, Def2Fields&) const override {} void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -242,8 +240,6 @@ class ReturnPtrn : public Ptrn { Dbg dbg() const { return dbg_; } const Expr* type() const { return type_; } - // void bind(Scopes&, const Def*, bool rebind = false) const override {} - // const Def* type(World&, Def2Fields&) const override {} void bind(Scopes&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -406,7 +402,7 @@ class PiExpr : public Expr { bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } - void bind(Scopes&) const override; + void bind(Scopes&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -455,7 +451,7 @@ class LamExpr : public Expr { bool has_bang() const { return has_bang_; } const Expr* filter() const { return filter_.get(); } - void bind(Scopes&) const override; + void bind(Scopes&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -659,6 +655,15 @@ class ErrorExpr : public Expr { std::ostream& stream(Tab&, std::ostream&) const override; }; +class InferExpr : public Expr { +public: + InferExpr(Loc loc) + : Expr(loc) {} + + void bind(Scopes&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; +}; + /* * Further Decls */ @@ -789,7 +794,7 @@ class Module : public Node { void compile(AST&) const; void bind(AST&) const; - void bind(Scopes&) const override; + void bind(Scopes&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index c850c214bb..98af487dfc 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -80,6 +80,7 @@ void SigmaDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } void TypeExpr ::bind(Scopes& s) const { if (level()) level()->bind(s); } void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } void ErrorExpr ::bind(Scopes&) const {} +void InferExpr ::bind(Scopes&) const {} void PrimaryExpr ::bind(Scopes&) const {} void SigmaDecl ::bind_rec(Scopes& s) const { body()->bind(s); } void PiDecl ::bind_rec(Scopes& s) const { body()->bind(s); } @@ -103,9 +104,7 @@ void IdPtrn::bind(Scopes& s) const { void TuplePtrn::bind(Scopes& s) const { s.bind(dbg(), nullptr, rebind()); - s.push(); for (const auto& ptrn : ptrns()) ptrn->bind(s); - s.pop(); } void GroupPtrn::bind(Scopes& s) const { @@ -139,7 +138,7 @@ void PiExpr::Dom::bind(Scopes& s) const { ptrn()->bind(s); } void PiExpr::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); - if (codom()) codom()->bind(s); + codom()->bind(s); s.pop(); } @@ -148,7 +147,7 @@ void LamExpr::Dom::bind(Scopes& s) const { ptrn()->bind(s); } void LamExpr::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); - if (codom()) codom()->bind(s); + codom()->bind(s); if (tag() == Tok::Tag::K_fn) { ret_ = s.ast().ptr(s.ast(), codom()); ret_->bind(s); @@ -160,7 +159,7 @@ void LamExpr::bind(Scopes& s) const { void LamDecl::bind(Scopes& s) const { s.push(); for (const auto& dom : lam()->doms()) dom->bind(s); - if (auto codom = lam()->codom()) codom->bind(s); + lam()->codom()->bind(s); if (lam()->tag() == Tok::Tag::K_fun) { lam()->ret_ = s.ast().ptr(s.ast(), lam()->codom()); lam()->ret_->bind(s); @@ -188,7 +187,11 @@ void RetExpr::bind(Scopes& s) const { arg()->bind(s); } -void SigmaExpr::bind(Scopes& s) const { ptrn()->bind(s); } +void SigmaExpr::bind(Scopes& s) const { + s.push(); + ptrn()->bind(s); + s.pop(); +} void TupleExpr::bind(Scopes& s) const { for (const auto& elem : elems()) elem->bind(s); @@ -225,7 +228,10 @@ void LetDecl::bind(Scopes& s) const { ptrn()->bind(s); } -void AxiomDecl::bind(Scopes& s) const { type()->bind(s); } +void AxiomDecl::bind(Scopes& s) const { + type()->bind(s); + s.bind(dbg(), this); +} void DeclsBlock::bind(Scopes& s) const { for (size_t i = 0, e = num_decls(), r = 0; true; ++i) { diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 6a82be58c3..b0079c6cbe 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -211,6 +211,7 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::K_I16: case Tag::K_I32: case Tag::K_I64: + case Tag::M_char: case Tag::T_star: case Tag::T_box: { auto tok = lex(); @@ -219,8 +220,6 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::M_lit: return parse_lit_expr(); case Tag::T_bot: case Tag::T_top: return parse_extremum_expr(); - //case Tag::L_c: return world().lit_i8(lex().lit_c()); - //case Tag::L_i: return lex().lit_i(); case Tag::M_anx: case Tag::M_id: return ptr(lex().dbg()); //case Tag::M_str: return world().tuple(lex().sym())->set(prev_); @@ -360,19 +359,9 @@ Ptr Parser::parse_lam_expr() { doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); - auto codom = (tag != Tag::K_cn && tag != Tag::K_con) - ? (expect(Tag::T_colon, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) - : nullptr; - + auto codom + = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : ptr(prev_); auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : Ptr(); -#if 0 - if (!body) { - if (!is_decl) error(prev_, "body of a {}", entity); - if (auto [_, __, filter] = funs.back(); filter) error(prev_, "cannot specify filter of a {}", entity); - } -#endif - - // if (is_decl) expect(Tag::T_semicolon, "end of "s + entity); return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } @@ -572,7 +561,7 @@ Ptrs Parser::parse_decls() { Ptr Parser::parse_axiom_decl() { auto track = tracker(); eat(Tag::K_ax); - Dbg dbg, normalizer; + Dbg dbg, normalizer, curry, trip; if (auto name = expect(Tag::M_anx, "annex name of an axiom")) dbg = name.dbg(); else @@ -589,11 +578,10 @@ Ptr Parser::parse_axiom_decl() { auto type = parse_type_ascr("type ascription of an axiom"); - if (accept(Tag::T_comma)) { - if (auto tok = expect(Tag::M_id, "normalizer of an axiom")) normalizer = tok.dbg(); + if (ahead(0).isa(Tag::T_comma) && ahead(1).isa(Tag::M_id)) { + lex(); + normalizer = lex().dbg(); } - - Dbg curry, trip; if (accept(Tag::T_comma)) { if (auto c = expect(Tag::M_lit, "curry counter for axiom")) curry = c.dbg(); if (accept(Tag::T_comma)) { diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 427b6c299d..954faf33ba 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -67,6 +67,7 @@ std::ostream& ReturnPtrn::stream(Tab& tab, std::ostream& os) const { std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", dbg()); } std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } std::ostream& ErrorExpr::stream(Tab&, std::ostream& os) const { return os << ""; } +std::ostream& InferExpr::stream(Tab&, std::ostream& os) const { return os << ""; } std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { os << value(); @@ -117,7 +118,7 @@ std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { print(os, "{} {}", tag(), dbg()); if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; print(os, "{}", R(tab, doms())); - if (codom()) print(os, ": {}", S(tab, codom())); + if (!codom()->isa()) print(os, ": {}", S(tab, codom())); if (body()) print(os, " = {}", S(tab, body())); return os; } From 43294aa77a67c2d3f85414303e5b125693d977af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 04:08:00 +0200 Subject: [PATCH 18/95] most stuff parsing and binding again --- include/thorin/ast/ast.h | 43 +++++++++++++++++++++++++++- include/thorin/ast/parser.h | 8 +++--- include/thorin/util/pool.h | 2 +- src/thorin/ast/bind.cpp | 57 +++++++++++++++++++++++++++---------- src/thorin/ast/parser.cpp | 21 ++++++++------ 5 files changed, 101 insertions(+), 30 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index f2c81b5ef1..388e758e05 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -14,6 +14,7 @@ namespace thorin::ast { +class Module; class Scopes; template using Ptr = fe::Arena::Ptr; @@ -769,6 +770,7 @@ class SigmaDecl : public RecDecl { , type_(std::move(type)) , body_(std::move(body)) {} + Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } @@ -786,18 +788,57 @@ class SigmaDecl : public RecDecl { * Module */ +class Import { +public: + Import& operator=(const Import&) = delete; + Import(const Import&) = delete; + Import() noexcept = default; + + Import(Import&& other) + : Import() { + swap(*this, other); + } + Import(Dbg dbg, Tok::Tag tag, Ptr&& module) noexcept + : dbg_(dbg) + , tag_(tag) + , module_(std::move(module)) {} + + Dbg dbg() const { return dbg_; } + Tok::Tag tag() const { return tag_; } + const Module* module() const { return module_.get(); } + + void bind(Scopes&) const; + std::ostream& stream(Tab&, std::ostream&) const; + + friend void swap(Import& i1, Import& i2) noexcept { + using std::swap; + swap(i1.dbg_, i2.dbg_); + swap(i1.tag_, i2.tag_); + swap(i1.module_, i2.module_); + } + +private: + Dbg dbg_; + Tok::Tag tag_; + Ptr module_; +}; + class Module : public Node { public: - Module(Loc loc, Ptrs&& decls) + Module(Loc loc, std::deque&& imports, Ptrs&& decls) : Node(loc) + , imports_(std::move(imports)) , decls_(std::move(decls)) {} + const auto& imports() const { return imports_; } + void compile(AST&) const; void bind(AST&) const; void bind(Scopes&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: + std::deque imports_; DeclsBlock decls_; }; diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index ee776188c7..95abe56df0 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -37,8 +37,8 @@ class Parser : public fe::Parser { Ptr import(std::string_view sv) { return import(driver().sym(sv)); } Ptr import(Sym, std::ostream* md = nullptr); Ptr import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); - void plugin(Sym); - void plugin(const char* name) { return plugin(driver().sym(name)); } + Ptr plugin(Sym); + Ptr plugin(const char* name) { return plugin(driver().sym(name)); } private: template auto ptr(Args&&... args) { @@ -55,8 +55,8 @@ class Parser : public fe::Parser { Dbg parse_id(std::string_view ctxt = {}); std::pair parse_annex(std::string_view ctxt = {}); Dbg parse_name(std::string_view ctxt = {}); - void parse_import(); - void parse_plugin(); + Import parse_import(); + Import parse_plugin(); Ptr parse_type_ascr(std::string_view ctxt = {}); template void parse_list(std::string ctxt, Tok::Tag delim_l, F f, Tok::Tag sep = Tok::Tag::T_comma) { diff --git a/include/thorin/util/pool.h b/include/thorin/util/pool.h index 54cf5b373a..8f6fe94113 100644 --- a/include/thorin/util/pool.h +++ b/include/thorin/util/pool.h @@ -192,7 +192,7 @@ template class Pool { } ///@} - friend void swap(Pool& p1, Pool& p2) { + friend void swap(Pool& p1, Pool& p2) noexcept { using std::swap; swap(p1.arena_, p2.arena_); swap(p1.pool_, p2.pool_); diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 98af487dfc..5dc6359d14 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -2,6 +2,8 @@ #include "fe/assert.h" +using namespace std::string_literals; + namespace thorin::ast { using Tag = Tok::Tag; @@ -75,15 +77,11 @@ class Scopes { // clang-format off void ExtremumExpr::bind(Scopes& s) const { if ( type()) type()->bind(s); } void LitExpr ::bind(Scopes& s) const { if ( type()) type()->bind(s); } -void PiDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } -void SigmaDecl ::bind(Scopes& s) const { if ( type()) type()->bind(s); } void TypeExpr ::bind(Scopes& s) const { if (level()) level()->bind(s); } void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } void ErrorExpr ::bind(Scopes&) const {} void InferExpr ::bind(Scopes&) const {} void PrimaryExpr ::bind(Scopes&) const {} -void SigmaDecl ::bind_rec(Scopes& s) const { body()->bind(s); } -void PiDecl ::bind_rec(Scopes& s) const { body()->bind(s); } // clang-format on void Module::bind(AST& ast) const { @@ -91,7 +89,12 @@ void Module::bind(AST& ast) const { bind(scopes); } -void Module::bind(Scopes& s) const { decls_.bind(s); } +void Module::bind(Scopes& s) const { + for (const auto& import : imports()) import.bind(s); + decls_.bind(s); +} + +void Import::bind(Scopes& s) const { module()->bind(s); } /* * Ptrn @@ -223,16 +226,6 @@ void InsertExpr::bind(Scopes& s) const { * Decl */ -void LetDecl::bind(Scopes& s) const { - value()->bind(s); - ptrn()->bind(s); -} - -void AxiomDecl::bind(Scopes& s) const { - type()->bind(s); - s.bind(dbg(), this); -} - void DeclsBlock::bind(Scopes& s) const { for (size_t i = 0, e = num_decls(), r = 0; true; ++i) { if (i < e && decl(i)->isa()) { @@ -247,4 +240,38 @@ void DeclsBlock::bind(Scopes& s) const { } } +void LetDecl::bind(Scopes& s) const { + value()->bind(s); + ptrn()->bind(s); +} + +void AxiomDecl::bind(Scopes& s) const { + type()->bind(s); + + if (num_subs() == 0) { + s.bind(dbg(), this); + } else { + for (const auto& aliases : subs()) { + for (const auto& alias : aliases) { + auto sym = s.ast().sym(dbg().sym.str() + "."s + alias.sym.str()); + s.bind(Dbg(dbg().loc, sym), this); + } + } + } +} + +void PiDecl::bind(Scopes& s) const { + if (type()) type()->bind(s); + s.bind(dbg(), this); +} + +void PiDecl::bind_rec(Scopes& s) const { body()->bind(s); } + +void SigmaDecl::bind(Scopes& s) const { + if (type()) type()->bind(s); + s.bind(dbg(), this); +} + +void SigmaDecl::bind_rec(Scopes& s) const { body()->bind(s); } + } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index b0079c6cbe..03d416cc31 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -26,17 +26,18 @@ using Tag = Tok::Tag; Ptr Parser::parse_module() { auto track = tracker(); + std::deque imports; while (true) if (ahead().tag() == Tag::K_import) - parse_import(); + imports.emplace_back(parse_import()); else if (ahead().tag() == Tag::K_plugin) - parse_plugin(); + imports.emplace_back(parse_plugin()); else break; auto decls = parse_decls(); expect(Tag::EoF, "module"); - return ptr(track, std::move(decls)); + return ptr(track, std::move(imports), std::move(decls)); } Ptr Parser::import(Sym name, std::ostream* md) { @@ -74,27 +75,29 @@ Ptr Parser::import(std::istream& is, const fs::path* path, std::ostream* return mod; } -void Parser::plugin(Sym name) { +Ptr Parser::plugin(Sym name) { if (!driver().flags().bootstrap && !driver().is_loaded(name)) driver().load(name); - import(name); + return import(name); } /* * misc */ -void Parser::parse_import() { +Import Parser::parse_import() { eat(Tag::K_import); auto name = expect(Tag::M_id, "import name"); expect(Tag::T_semicolon, "end of import"); - import(name.sym()); + auto module = import(name.sym()); + return Import(name.dbg(), Tag::K_import, std::move(module)); } -void Parser::parse_plugin() { +Import Parser::parse_plugin() { eat(Tag::K_plugin); auto name = expect(Tag::M_id, "thorin/plugin name"); expect(Tag::T_semicolon, "end of import"); - plugin(name.sym()); + auto module = plugin(name.sym()); + return Import(name.dbg(), Tag::K_plugin, std::move(module)); } Dbg Parser::parse_id(std::string_view ctxt) { From 492ee66c00841b13129e270f8f7052340d5a13b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 20:06:23 +0200 Subject: [PATCH 19/95] stubs for emit --- include/thorin/ast/ast.h | 85 +++++++++++++++++++++++++++++++------ include/thorin/ast/parser.h | 6 +-- src/thorin/CMakeLists.txt | 1 + src/thorin/ast/ast.cpp | 5 ++- src/thorin/ast/bind.cpp | 11 +++-- src/thorin/ast/parser.cpp | 8 ++-- src/thorin/ast/stream.cpp | 2 +- src/thorin/cli/main.cpp | 2 +- 8 files changed, 91 insertions(+), 29 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 388e758e05..f20326d217 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -16,6 +16,7 @@ namespace thorin::ast { class Module; class Scopes; +class Emitter; template using Ptr = fe::Arena::Ptr; template using Ptrs = std::deque>; @@ -96,6 +97,7 @@ class Expr : public Node { public: virtual void bind(Scopes&) const = 0; + virtual Ref emit(Emitter&) const = 0; }; class Decl : public Node { @@ -103,33 +105,51 @@ class Decl : public Node { Decl(Loc loc) : Node(loc) {} +public: + Ref def() const { return def_; } + +protected: + mutable Ref def_ = nullptr; +}; + +class ValDecl : public Decl { +protected: + ValDecl(Loc loc) + : Decl(loc) {} + public: virtual void bind(Scopes&) const = 0; + Ref emit(Emitter& e) const { return def_ ? def_ : def_ = emit_(e); } + +private: + virtual Ref emit_(Emitter&) const = 0; }; -class RecDecl : public Decl { +class RecDecl : public ValDecl { protected: RecDecl(Loc loc) - : Decl(loc) {} + : ValDecl(loc) {} public: - virtual void bind_rec(Scopes&) const = 0; + virtual void bind_rec(Scopes&) const = 0; + virtual void emit_rec(Emitter&) const = 0; }; class DeclsBlock { public: - DeclsBlock(Ptrs&& decls) + DeclsBlock(Ptrs&& decls) : decls_(std::move(decls)) {} const auto& decls() const { return decls_; } - const Decl* decl(size_t i) const { return decls_[i].get(); } + const ValDecl* decl(size_t i) const { return decls_[i].get(); } size_t num_decls() const { return decls_.size(); } std::ostream& stream(Tab&, std::ostream&) const; void bind(Scopes&) const; + void emit(Emitter&) const; private: - Ptrs decls_; + Ptrs decls_; }; /* @@ -141,6 +161,10 @@ class Ptrn : public Decl { Ptrn(Loc loc) : Decl(loc) {} + virtual void bind(Scopes&) const = 0; + virtual Ref emit_(Emitter&, Ref) const = 0; + Ref emit(Emitter& e, Ref def) const { return def_ ? def_ : def_ = emit_(e, def); } + [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); }; @@ -164,6 +188,7 @@ class IdPtrn : public Ptrn { } void bind(Scopes&) const override; + Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -191,6 +216,7 @@ class GroupPtrn : public Ptrn { } void bind(Scopes&) const override; + Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -220,6 +246,7 @@ class TuplePtrn : public Ptrn { size_t num_ptrns() const { return ptrns().size(); } void bind(Scopes&) const override; + Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -242,6 +269,7 @@ class ReturnPtrn : public Ptrn { const Expr* type() const { return type_; } void bind(Scopes&) const override; + Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -264,6 +292,7 @@ class IdExpr : public Expr { const Decl* decl() const { return decl_; } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -284,6 +313,7 @@ class PrimaryExpr : public Expr { Tok::Tag tag() const { return tag_; } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -302,6 +332,7 @@ class LitExpr : public Expr { const Expr* type() const { return type_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -321,6 +352,7 @@ class ExtremumExpr : public Expr { const Expr* type() const { return type_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -331,7 +363,7 @@ class ExtremumExpr : public Expr { /// `{ decl_0 ... decl_n-1 e }` or `decl_0 ... decl_n-1` (used internaly) class BlockExpr : public Expr { public: - BlockExpr(Loc loc, bool has_braces, Ptrs&& decls, Ptr&& expr) + BlockExpr(Loc loc, bool has_braces, Ptrs&& decls, Ptr&& expr) : Expr(loc) , has_braces_(has_braces) , decls_(std::move(decls)) @@ -341,6 +373,7 @@ class BlockExpr : public Expr { const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -359,6 +392,7 @@ class TypeExpr : public Expr { const Expr* level() const { return level_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -380,6 +414,7 @@ class ArrowExpr : public Expr { const Expr* codom() const { return codom_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -404,6 +439,7 @@ class PiExpr : public Expr { const Ptrn* ptrn() const { return ptrn_.get(); } void bind(Scopes&) const; + Ref emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -425,6 +461,7 @@ class PiExpr : public Expr { const Expr* codom() const { return codom_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -453,6 +490,7 @@ class LamExpr : public Expr { const Expr* filter() const { return filter_.get(); } void bind(Scopes&) const; + Ref emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -480,6 +518,7 @@ class LamExpr : public Expr { const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -507,6 +546,7 @@ class AppExpr : public Expr { const Expr* arg() const { return arg_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -531,6 +571,7 @@ class RetExpr : public Expr { const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -551,6 +592,7 @@ class SigmaExpr : public Expr { const Ptrn* ptrn() const { return ptrn_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -571,6 +613,7 @@ class TupleExpr : public Expr { size_t num_elems() const { return elems().size(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -591,6 +634,7 @@ template class ArrOrPackExpr : public Expr { const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -618,6 +662,7 @@ class ExtractExpr : public Expr { const auto& index() const { return index_; } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -639,6 +684,7 @@ class InsertExpr : public Expr { const Expr* value() const { return value_.get(); } void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -653,6 +699,7 @@ class ErrorExpr : public Expr { : Expr(loc) {} void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; }; @@ -662,6 +709,7 @@ class InferExpr : public Expr { : Expr(loc) {} void bind(Scopes&) const override; + Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; }; @@ -670,10 +718,10 @@ class InferExpr : public Expr { */ /// `.let ptrn: type = value;` -class LetDecl : public Decl { +class LetDecl : public ValDecl { public: LetDecl(Loc loc, Ptr&& ptrn, Ptr&& value) - : Decl(loc) + : ValDecl(loc) , ptrn_(std::move(ptrn)) , value_(std::move(value)) {} @@ -681,6 +729,7 @@ class LetDecl : public Decl { const Expr* value() const { return value_.get(); } void bind(Scopes&) const override; + Ref emit_(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -689,10 +738,10 @@ class LetDecl : public Decl { }; /// `.ax ptrn: type = value;` -class AxiomDecl : public Decl { +class AxiomDecl : public ValDecl { public: AxiomDecl(Loc loc, Dbg dbg, std::deque&& subs, Ptr&& type, Dbg normalizer, Dbg curry, Dbg trip) - : Decl(loc) + : ValDecl(loc) , dbg_(dbg) , subs_(std::move(subs)) , type_(std::move(type)) @@ -710,6 +759,7 @@ class AxiomDecl : public Decl { Dbg trip() const { return trip_; } void bind(Scopes&) const override; + Ref emit_(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -735,6 +785,8 @@ class PiDecl : public RecDecl { void bind(Scopes&) const override; void bind_rec(Scopes&) const override; + Ref emit_(Emitter&) const override; + void emit_rec(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -755,6 +807,8 @@ class LamDecl : public RecDecl { void bind(Scopes&) const override; void bind_rec(Scopes&) const override; + Ref emit_(Emitter&) const override; + void emit_rec(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -776,6 +830,8 @@ class SigmaDecl : public RecDecl { void bind(Scopes&) const override; void bind_rec(Scopes&) const override; + Ref emit_(Emitter&) const override; + void emit_rec(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -808,6 +864,7 @@ class Import { const Module* module() const { return module_.get(); } void bind(Scopes&) const; + void emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const; friend void swap(Import& i1, Import& i2) noexcept { @@ -825,16 +882,18 @@ class Import { class Module : public Node { public: - Module(Loc loc, std::deque&& imports, Ptrs&& decls) + Module(Loc loc, std::deque&& imports, Ptrs&& decls) : Node(loc) , imports_(std::move(imports)) , decls_(std::move(decls)) {} const auto& imports() const { return imports_; } - void compile(AST&) const; + void compile(AST&, World&) const; void bind(AST&) const; void bind(Scopes&) const; + void emit(AST&, World&) const; + void emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 95abe56df0..7e53c0584e 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -106,9 +106,9 @@ class Parser : public fe::Parser { /// If @p ctxt ... /// * ... empty: **Only** decls are parsed. @returns `nullptr` /// * ... **non**-empty: Decls are parsed, then an expression. @returns expression. - Ptrs parse_decls(); - Ptr parse_axiom_decl(); - Ptr parse_let_decl(); + Ptrs parse_decls(); + Ptr parse_axiom_decl(); + Ptr parse_let_decl(); Ptr parse_pi_decl(); Ptr parse_lam_decl(); Ptr parse_sigma_decl(); diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index c3dff2087f..039c20647b 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(libthorin be/h/bootstrap.cpp ast/ast.cpp ast/bind.cpp + ast/emit.cpp ast/lexer.cpp ast/parser.cpp ast/stream.cpp diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 4f55fae6a0..ef2cebd7bc 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -28,7 +28,10 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { return {}; } -void Module::compile(AST& ast) const { bind(ast); } +void Module::compile(AST& ast, World& world) const { + bind(ast); + // emit(ast, world); +} #if 0 /* diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 5dc6359d14..83b9c9d245 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -14,7 +14,6 @@ class DummyDecl : public Decl { : Decl(Loc()) {} std::ostream& stream(Tab&, std::ostream& os) const override { return os << ""; } - void bind(Scopes&) const override { fe::unreachable(); } }; class Scopes { @@ -45,7 +44,7 @@ class Scopes { if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; ast().error(dbg.loc, "'{}' not found", dbg.sym); - bind(dbg, dummy_.get()); // put into scope to prevent further errors + bind(dbg, dummy()); // put into scope to prevent further errors return nullptr; } @@ -75,9 +74,9 @@ class Scopes { */ // clang-format off -void ExtremumExpr::bind(Scopes& s) const { if ( type()) type()->bind(s); } -void LitExpr ::bind(Scopes& s) const { if ( type()) type()->bind(s); } -void TypeExpr ::bind(Scopes& s) const { if (level()) level()->bind(s); } +void ExtremumExpr::bind(Scopes& s) const { if (type()) type()->bind(s); } +void LitExpr ::bind(Scopes& s) const { if (type()) type()->bind(s); } +void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } void ErrorExpr ::bind(Scopes&) const {} void InferExpr ::bind(Scopes&) const {} @@ -127,7 +126,7 @@ void ReturnPtrn::bind(Scopes& s) const { void BlockExpr::bind(Scopes& s) const { s.push(); decls_.bind(s); - if (expr()) expr()->bind(s); + expr()->bind(s); s.pop(); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 03d416cc31..08260e6bd6 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -542,8 +542,8 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { * decls */ -Ptrs Parser::parse_decls() { - Ptrs decls; +Ptrs Parser::parse_decls() { + Ptrs decls; while (true) { // clang-format off switch (ahead().tag()) { @@ -561,7 +561,7 @@ Ptrs Parser::parse_decls() { } } -Ptr Parser::parse_axiom_decl() { +Ptr Parser::parse_axiom_decl() { auto track = tracker(); eat(Tag::K_ax); Dbg dbg, normalizer, curry, trip; @@ -596,7 +596,7 @@ Ptr Parser::parse_axiom_decl() { return ptr(track, dbg, std::move(subs), std::move(type), normalizer, curry, trip); } -Ptr Parser::parse_let_decl() { +Ptr Parser::parse_let_decl() { auto track = tracker(); eat(Tag::K_let); auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration", Tok::Prec::Bot, true); diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 954faf33ba..278076cb42 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -96,7 +96,7 @@ std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { return os; } -std::ostream& TypeExpr ::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } +std::ostream& TypeExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } std::ostream& ArrowExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{} -> {}", S(tab, dom()), S(tab, codom())); diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 45ae222773..50d1704ea1 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -176,7 +176,7 @@ int main(int argc, char** argv) { if (os[AST]) { auto mod = parser.import(driver.sym(input), os[Md]); - mod->compile(ast); + mod->compile(ast, world); Tab tab; mod->stream(tab, *os[AST]); } From f411ef579cf77b472f336c0355edf517961e20d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 23:33:17 +0200 Subject: [PATCH 20/95] reorganize Ptrn/Decl --- external/fe | 2 +- include/thorin/ast/ast.h | 55 ++++++++++++++------------------------- src/thorin/ast/bind.cpp | 11 +++----- src/thorin/ast/parser.cpp | 7 ++++- src/thorin/ast/stream.cpp | 4 +-- 5 files changed, 32 insertions(+), 47 deletions(-) diff --git a/external/fe b/external/fe index 670700f342..44a856a8b5 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 670700f34244ba68805fe3dd72874a8ee6dfc60b +Subproject commit 44a856a8b5db4049e2760f9a9cbd0be281a3330f diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index f20326d217..3f3f6ce5cf 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -158,8 +158,13 @@ class DeclsBlock { class Ptrn : public Decl { public: - Ptrn(Loc loc) - : Decl(loc) {} + Ptrn(Loc loc, bool rebind, Dbg dbg) + : Decl(loc) + , dbg_(dbg) + , rebind_(rebind) {} + + bool rebind() const { return rebind_; } + Dbg dbg() const { return dbg_; } virtual void bind(Scopes&) const = 0; virtual Ref emit_(Emitter&, Ref) const = 0; @@ -167,19 +172,19 @@ class Ptrn : public Decl { [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); + +private: + Dbg dbg_; + bool rebind_; }; /// `dbg: type` class IdPtrn : public Ptrn { public: IdPtrn(Loc loc, bool rebind, Dbg dbg, Ptr&& type) - : Ptrn(loc) - , rebind_(rebind) - , dbg_(dbg) + : Ptrn(loc, rebind, dbg) , type_(std::move(type)) {} - bool rebind() const { return rebind_; } - Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } static Ptr mk_type(AST& ast, Ptr&& type) { @@ -193,49 +198,34 @@ class IdPtrn : public Ptrn { private: bool rebind_; - Dbg dbg_; Ptr type_; }; -/// `dbg_0 ... dbg_n-1: type` +/// `dbg_0 ... dbg_n-2 id` where `id` = `dbg_n-1: type` class GroupPtrn : public Ptrn { public: - GroupPtrn(Loc loc, Dbgs&& dbgs, Ptr&& type) - : Ptrn(loc) - , dbgs_(std::move(dbgs)) - , type_(std::move(type)) {} + GroupPtrn(Dbg dbg, const IdPtrn* id) + : Ptrn(dbg.loc, false, dbg) + , id_(id) {} - const auto& dbgs() const { return dbgs_; } - Dbg dbg(size_t i) const { return dbgs_[i]; } - size_t num_dbgs() const { return dbgs_.size(); } - const Expr* type() const { return type_.get(); } - - static Ptr mk_type(AST& ast, Ptr&& type) { - auto loc = type->loc(); - return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); - } + const IdPtrn* id() const { return id_; } void bind(Scopes&) const override; Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Dbgs dbgs_; - Ptr type_; + const IdPtrn* id_; }; /// `dbg::(ptrn_0, ..., ptrn_n-1)` or `dbg::[ptrn_0, ..., ptrn_n-1]` class TuplePtrn : public Ptrn { public: TuplePtrn(Loc loc, bool rebind, Dbg dbg, Tok::Tag delim_l, Ptrs&& ptrns) - : Ptrn(loc) - , rebind_(rebind) - , dbg_(dbg) + : Ptrn(loc, rebind, dbg) , delim_l_(delim_l) , ptrns_(std::move(ptrns)) {} - bool rebind() const { return rebind_; } - Dbg dbg() const { return dbg_; } Tok::Tag delim_l() const { return delim_l_; } Tok::Tag delim_r() const { return Tok::delim_l2r(delim_l()); } bool is_paren() const { return delim_l() == Tok::Tag::D_paren_l; } @@ -250,8 +240,6 @@ class TuplePtrn : public Ptrn { std::ostream& stream(Tab&, std::ostream&) const override; private: - bool rebind_; - Dbg dbg_; Tok::Tag delim_l_; Ptrs ptrns_; }; @@ -261,11 +249,9 @@ class TuplePtrn : public Ptrn { class ReturnPtrn : public Ptrn { public: ReturnPtrn(AST& ast, const Expr* type) - : Ptrn(type->loc()) - , dbg_(type->loc(), ast.sym_return()) + : Ptrn(type->loc(), false, {type->loc(), ast.sym_return()}) , type_(type) {} - Dbg dbg() const { return dbg_; } const Expr* type() const { return type_; } void bind(Scopes&) const override; @@ -273,7 +259,6 @@ class ReturnPtrn : public Ptrn { std::ostream& stream(Tab&, std::ostream&) const override; private: - Dbg dbg_; const Expr* type_; }; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 83b9c9d245..fe941287b1 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -101,21 +101,18 @@ void Import::bind(Scopes& s) const { module()->bind(s); } void IdPtrn::bind(Scopes& s) const { if (type()) type()->bind(s); - s.bind(dbg(), nullptr, rebind()); + s.bind(dbg(), this, rebind()); } void TuplePtrn::bind(Scopes& s) const { - s.bind(dbg(), nullptr, rebind()); + s.bind(dbg(), this, rebind()); for (const auto& ptrn : ptrns()) ptrn->bind(s); } -void GroupPtrn::bind(Scopes& s) const { - type()->bind(s); - for (auto dbg : dbgs()) s.bind(dbg, nullptr, false); -} +void GroupPtrn::bind(Scopes& s) const { s.bind(dbg(), this, rebind()); } void ReturnPtrn::bind(Scopes& s) const { - s.bind(dbg(), this); + s.bind(dbg(), this, rebind()); // No need to check this->type(); it's shared and has already been checked. } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 08260e6bd6..9fc4d9ce9f 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -498,8 +498,13 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { while (auto tok = accept(Tag::M_id)) dbgs.emplace_back(tok.dbg()); if (accept(Tag::T_colon)) { // identifier group: x y x: T + auto dbg = dbgs.back(); auto type = parse_expr("type of an identifier group within a tuple pattern"); - ptrns.emplace_back(ptr(track, std::move(dbgs), std::move(type))); + auto id = ptr(dbg.loc + type->loc().finis, false, dbg, std::move(type)); + + for (auto dbg : dbgs | std::views::take(dbgs.size() - 1)) + ptrns.emplace_back(ptr(dbg, id.get())); + ptrns.emplace_back(std::move(id)); return; } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 278076cb42..f57d6cb1aa 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -45,9 +45,7 @@ std::ostream& IdPtrn::stream(Tab& tab, std::ostream& os) const { return os << ""; } -std::ostream& GroupPtrn::stream(Tab& tab, std::ostream& os) const { - return print(os, "{ }: {}", dbgs(), S(tab, type())); -} +std::ostream& GroupPtrn::stream(Tab&, std::ostream& os) const { return os << dbg(); } std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { if (dbg()) print(os, "{}::", dbg()); From 3773dba117220f6461a97e992142b4e70ce83168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 2 Apr 2024 23:33:42 +0200 Subject: [PATCH 21/95] missing file --- src/thorin/ast/emit.cpp | 263 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 src/thorin/ast/emit.cpp diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp new file mode 100644 index 0000000000..2ecaf2db32 --- /dev/null +++ b/src/thorin/ast/emit.cpp @@ -0,0 +1,263 @@ +#include "thorin/ast/ast.h" + +#include "fe/assert.h" + +using namespace std::string_literals; + +namespace thorin::ast { + +using Tag = Tok::Tag; + +class Emitter { +public: + Emitter(AST& ast, World& world) + : ast_(ast) + , world_(world) {} + + AST& ast() const { return ast_; } + World& world() const { return world_; } + +private: + AST& ast_; + World& world_; + DefMap> fields_; +}; + +/* + * AST + */ + +Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } +Ref InferExpr::emit(Emitter&) const { fe::unreachable(); } + +Ref IdExpr::emit(Emitter&) const { return decl_->def(); } + +Ref ExtremumExpr::emit(Emitter& e) const { + auto t = type() ? type()->emit(e) : e.world().type<0>(); + return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t))->set(loc()); +} + +Ref LitExpr::emit(Emitter& /*e*/) const { + // auto t = type() ? type()->emit(e) : e.world().type<0>(); + // TODO + return {}; +} + +Ref TypeExpr::emit(Emitter& e) const { + auto l = level()->emit(e); + return e.world().type(l)->set(loc()); +} + +Ref PrimaryExpr ::emit(Emitter& e) const { + switch (tag()) { + // clang-format off + case Tag::K_Univ: return e.world().univ(); + case Tag::K_Nat: return e.world().type_nat(); + case Tag::K_Idx: return e.world().type_idx(); + case Tag::K_Bool: return e.world().type_bool(); + case Tag::K_ff: return e.world().lit_ff(); + case Tag::K_tt: return e.world().lit_tt(); + case Tag::K_i1: return e.world().lit_i1(); + case Tag::K_i8: return e.world().lit_i8(); + case Tag::K_i16: return e.world().lit_i16(); + case Tag::K_i32: return e.world().lit_i32(); + case Tag::K_i64: return e.world().lit_i64(); + case Tag::K_I1: return e.world().type_i1(); + case Tag::K_I8: return e.world().type_i8(); + case Tag::K_I16: return e.world().type_i16(); + case Tag::K_I32: return e.world().type_i32(); + case Tag::K_I64: return e.world().type_i64(); + case Tag::M_char: return nullptr; // TODO + case Tag::T_star: return e.world().type<0>(); + case Tag::T_box: return e.world().type<1>(); + default: fe::unreachable(); + // clang-format on + } +} + +void Module::emit(AST& ast, World& world) const { + auto emitter = Emitter(ast, world); + emit(emitter); +} + +void Module::emit(Emitter& e) const { + for (const auto& import : imports()) import.emit(e); + decls_.emit(e); +} + +void Import::emit(Emitter& e) const { module()->emit(e); } + +/* + * Ptrn + */ + +Ref IdPtrn::emit_(Emitter&, Ref def) const { return def; } + +Ref TuplePtrn::emit_(Emitter& e, Ref def) const { + for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_(e, def->proj(n, i)); + return {}; +} + +Ref GroupPtrn::emit_(Emitter&, Ref def) const { return def; } + +Ref ReturnPtrn::emit_(Emitter& e, Ref def) const { + type()->emit(e); + return def; +} + +/* + * Expr + */ + +Ref BlockExpr::emit(Emitter& e) const { + decls_.emit(e); + return expr()->emit(e); +} + +Ref ArrowExpr::emit(Emitter& e) const { + auto d = dom()->emit(e); + auto c = codom()->emit(e); + return e.world().pi(d, c)->set(loc()); +} + +Ref PiExpr::Dom::emit(Emitter&) const { + // ptrn()->emit(e); + return {}; +} + +Ref PiExpr::emit(Emitter& e) const { + for (const auto& dom : doms()) dom->emit(e); + codom()->emit(e); + return {}; +} + +Ref LamExpr::Dom::emit(Emitter&) const { + // ptrn()->emit(e); + return {}; +} + +Ref LamExpr::emit(Emitter& e) const { + for (const auto& dom : doms()) dom->emit(e); + codom()->emit(e); + body()->emit(e); + return {}; +} + +Ref LamDecl::emit_(Emitter& e) const { + for (const auto& dom : lam()->doms()) dom->emit(e); + lam()->codom()->emit(e); + return {}; +} + +void LamDecl::emit_rec(Emitter& e) const { + for (const auto& dom : lam()->doms()) dom->emit(e); + // if (auto ret = lam()->ret()) ret->emit(e); + body()->emit(e); +} + +Ref AppExpr::emit(Emitter& e) const { + auto c = callee()->emit(e); + auto a = arg()->emit(e); + return e.world().app(c, a)->set(loc()); +} + +Ref RetExpr::emit(Emitter& e) const { + // ptrn()->emit(e); + callee()->emit(e); + arg()->emit(e); + return {}; +} + +Ref SigmaExpr::emit(Emitter&) const { + // ptrn()->emit(e); + return {}; +} + +Ref TupleExpr::emit(Emitter& e) const { + DefVec elems(num_elems(), [&](size_t i) { return elem(i)->emit(e); }); + return e.world().tuple(elems)->set(loc()); +} + +template Ref ArrOrPackExpr::emit(Emitter& e) const { + /*auto s =*/shape()->emit(e); + if (dbg() && dbg().sym != '_') { + // auto mut = arr ? e.world().mut_arr( + body()->emit(e); + } + return {}; +} + +template Ref ArrOrPackExpr::emit(Emitter&) const; +template Ref ArrOrPackExpr::emit(Emitter&) const; + +Ref ExtractExpr::emit(Emitter& e) const { + auto t = tuple()->emit(e); + if (auto expr = std::get_if>(&index())) { + auto i = (*expr)->emit(e); + return e.world().extract(t, i)->set(loc()); + } + + // auto dbg = std::get(index()); + return {}; +} + +Ref InsertExpr::emit(Emitter& e) const { + auto t = tuple()->emit(e); + auto i = index()->emit(e); + auto v = value()->emit(e); + return e.world().insert(t, i, v)->set(loc()); +} + +/* + * Decl + */ + +void DeclsBlock::emit(Emitter& e) const { + for (size_t i = 0, n = num_decls(), r = 0; true; ++i) { + if (i < n && decl(i)->isa()) { + if (!decl(r)->isa()) r = i; + } else if (r < n && decl(r)->isa()) { + for (size_t j = r; j != i; ++j) decl(j)->as()->emit_rec(e); + r = i; + } + + if (i == n) break; + decl(i)->emit(e); + } +} + +Ref LetDecl::emit_(Emitter& e) const { + auto v = value()->emit(e); + ptrn()->emit(e, v); + return v; +} + +Ref AxiomDecl::emit_(Emitter& e) const { + type()->emit(e); + + if (num_subs() == 0) { + } else { + for (const auto& aliases : subs()) { + for (const auto& alias : aliases) { + // auto sym = s.ast().sym(dbg().sym.str() + "."s + alias.sym.str()); + } + } + } + return {}; +} + +Ref PiDecl::emit_(Emitter& e) const { + if (type()) type()->emit(e); + return {}; +} + +void PiDecl::emit_rec(Emitter& e) const { body()->emit(e); } + +Ref SigmaDecl::emit_(Emitter& e) const { + if (type()) type()->emit(e); + return {}; +} + +void SigmaDecl::emit_rec(Emitter& e) const { body()->emit(e); } + +} // namespace thorin::ast From 0c24f7bfeec285ba663a19ec6cfbc920ac44c1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 3 Apr 2024 00:14:38 +0200 Subject: [PATCH 22/95] silence double rebind --- external/fe | 2 +- include/thorin/ast/ast.h | 14 +++++++------- src/thorin/ast/bind.cpp | 42 ++++++++++++++++++++-------------------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/external/fe b/external/fe index 44a856a8b5..a937e008ee 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 44a856a8b5db4049e2760f9a9cbd0be281a3330f +Subproject commit a937e008eeebc09c2e0a28cd6174b950ec47ce9f diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 3f3f6ce5cf..b6c5f972a3 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -166,8 +166,8 @@ class Ptrn : public Decl { bool rebind() const { return rebind_; } Dbg dbg() const { return dbg_; } - virtual void bind(Scopes&) const = 0; - virtual Ref emit_(Emitter&, Ref) const = 0; + virtual void bind(Scopes&, bool quiet = false) const = 0; + virtual Ref emit_(Emitter&, Ref) const = 0; Ref emit(Emitter& e, Ref def) const { return def_ ? def_ : def_ = emit_(e, def); } [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); @@ -192,7 +192,7 @@ class IdPtrn : public Ptrn { return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } - void bind(Scopes&) const override; + void bind(Scopes&, bool quiet = false) const override; Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -210,7 +210,7 @@ class GroupPtrn : public Ptrn { const IdPtrn* id() const { return id_; } - void bind(Scopes&) const override; + void bind(Scopes&, bool quiet = false) const override; Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -235,7 +235,7 @@ class TuplePtrn : public Ptrn { const Ptrn* ptrn(size_t i) const { return ptrns_[i].get(); } size_t num_ptrns() const { return ptrns().size(); } - void bind(Scopes&) const override; + void bind(Scopes&, bool quiet = false) const override; Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -254,7 +254,7 @@ class ReturnPtrn : public Ptrn { const Expr* type() const { return type_; } - void bind(Scopes&) const override; + void bind(Scopes&, bool quiet = false) const override; Ref emit_(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -474,7 +474,7 @@ class LamExpr : public Expr { bool has_bang() const { return has_bang_; } const Expr* filter() const { return filter_.get(); } - void bind(Scopes&) const; + void bind(Scopes&, bool quiet = false) const; Ref emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index fe941287b1..3b9002a59b 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -48,7 +48,7 @@ class Scopes { return nullptr; } - void bind(Dbg dbg, const Decl* decl, bool rebind = false) { + void bind(Dbg dbg, const Decl* decl, bool rebind = false, bool quiet = false) { auto [loc, sym] = dbg; if (!sym || sym == '_') return; // don't do anything with '_' @@ -56,7 +56,7 @@ class Scopes { top()[sym] = std::pair(loc, decl); } else if (auto [i, ins] = top().emplace(sym, std::pair(loc, decl)); !ins) { auto [prev_loc, prev_decl] = i->second; - if (!prev_decl->isa()) { // if prev_decl stems from an error - don't complain + if (!quiet && !prev_decl->isa()) { // if prev_decl stems from an error - don't complain ast().error(loc, "redeclaration of '{}'", sym); ast().note(prev_loc, "previous declaration here"); } @@ -99,20 +99,20 @@ void Import::bind(Scopes& s) const { module()->bind(s); } * Ptrn */ -void IdPtrn::bind(Scopes& s) const { - if (type()) type()->bind(s); - s.bind(dbg(), this, rebind()); +void IdPtrn::bind(Scopes& s, bool quiet) const { + if (!quiet && type()) type()->bind(s); + s.bind(dbg(), this, rebind(), quiet); } -void TuplePtrn::bind(Scopes& s) const { - s.bind(dbg(), this, rebind()); - for (const auto& ptrn : ptrns()) ptrn->bind(s); +void TuplePtrn::bind(Scopes& s, bool quiet) const { + s.bind(dbg(), this, rebind(), quiet); + for (const auto& ptrn : ptrns()) ptrn->bind(s, quiet); } -void GroupPtrn::bind(Scopes& s) const { s.bind(dbg(), this, rebind()); } +void GroupPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } -void ReturnPtrn::bind(Scopes& s) const { - s.bind(dbg(), this, rebind()); +void ReturnPtrn::bind(Scopes& s, bool quiet) const { + s.bind(dbg(), this, rebind(), quiet); // No need to check this->type(); it's shared and has already been checked. } @@ -141,7 +141,14 @@ void PiExpr::bind(Scopes& s) const { s.pop(); } -void LamExpr::Dom::bind(Scopes& s) const { ptrn()->bind(s); } +void PiDecl::bind(Scopes& s) const { + if (type()) type()->bind(s); + s.bind(dbg(), this); +} + +void PiDecl::bind_rec(Scopes& s) const { body()->bind(s); } + +void LamExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } void LamExpr::bind(Scopes& s) const { s.push(); @@ -169,8 +176,8 @@ void LamDecl::bind(Scopes& s) const { void LamDecl::bind_rec(Scopes& s) const { s.push(); - for (const auto& dom : lam()->doms()) dom->bind(s); - if (auto ret = lam()->ret()) ret->bind(s); + for (const auto& dom : lam()->doms()) dom->bind(s, true); + if (auto ret = lam()->ret()) ret->bind(s, true); body()->bind(s); s.pop(); } @@ -256,13 +263,6 @@ void AxiomDecl::bind(Scopes& s) const { } } -void PiDecl::bind(Scopes& s) const { - if (type()) type()->bind(s); - s.bind(dbg(), this); -} - -void PiDecl::bind_rec(Scopes& s) const { body()->bind(s); } - void SigmaDecl::bind(Scopes& s) const { if (type()) type()->bind(s); s.bind(dbg(), this); From e5c7f289ecb0c3965accb3c940b617b097172aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 3 Apr 2024 01:32:30 +0200 Subject: [PATCH 23/95] wip: emit literals --- include/thorin/util/dbg.h | 15 ++++-- src/thorin/ast/ast.cpp | 2 +- src/thorin/ast/emit.cpp | 49 +++++++++++++++++-- src/thorin/cli/main.cpp | 100 +++++++++++++++++++------------------- 4 files changed, 109 insertions(+), 57 deletions(-) diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index fd65ecc997..4d9910fd2b 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -1,12 +1,12 @@ #pragma once #include +#include #include #include #include #include -#include #include "thorin/util/print.h" @@ -18,14 +18,21 @@ using fe::Loc; using fe::Pos; using fe::Sym; +struct Error : std::logic_error { + Error(Loc loc, const std::string& what) + : std::logic_error(what) + , loc(loc) {} + + Loc loc; +}; + /// @name Formatted Output ///@{ /// Prefixes error message with `: error: `. -template [[noreturn]] void error(Loc loc, const char* fmt, Args&&... args) { +template [[noreturn]] void error(Loc loc, const char* fmt, Args&&... args) { std::ostringstream o; - print(o, "{}{}: {}error: {}", rang::fg::yellow, loc, rang::fg::red, rang::fg::reset); print(o, fmt, std::forward(args)...); - throw T(o.str()); + throw Error(loc, o.str()); } ///@} diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index ef2cebd7bc..d3b550f928 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -30,7 +30,7 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { void Module::compile(AST& ast, World& world) const { bind(ast); - // emit(ast, world); + emit(ast, world); } #if 0 diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 2ecaf2db32..2daebefaec 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "thorin/ast/ast.h" #include "fe/assert.h" @@ -37,9 +40,49 @@ Ref ExtremumExpr::emit(Emitter& e) const { return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t))->set(loc()); } -Ref LitExpr::emit(Emitter& /*e*/) const { - // auto t = type() ? type()->emit(e) : e.world().type<0>(); - // TODO +Ref LitExpr::emit(Emitter& e) const { + int base = 10; + auto [loc, sym] = value(); + auto c_str = sym.c_str(); + size_t b = 0; + bool sign = false; + + if (sym[b] == '+') + ++b; + else if (sym[b] == '-') + ++b, sign = true; + + if (sym.size() == b) error(loc, "signed literal '{}' without value", value()); + + if (sym.size() >= b + 1) { + switch (sym[b + 1]) { + // clang-format off + case 'b': + case 'B': base = 2, b += 2; break; + case 'o': + case 'O': base = 8, b += 2; break; + case 'x': + case 'X': base = 16, b += 2; break; + default: break; + // clang-format on + } + } + + char* end; + auto val = std::strtoull(c_str + b, &end, base); + + if (*end == '\0') { + if (sign) error(loc, "negative .Nat literal '{}' not allowed", value()); + return e.world().lit_nat(val)->set(loc); + } + + if (*end == 'i' || *end == 'I') { + auto width = std::strtoull(end + 1, nullptr, base); + if (width != 64 && val >= Idx::bitwidth2size(width)) + error(loc, "value '{}' doesn't fit in given bit width '{}'", val, width); + return e.world().lit_int(width, val)->set(loc); + } + return {}; } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 50d1704ea1..7a46b9a770 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -1,11 +1,8 @@ #include #include -#include -#include -#include - #include +#include #include "thorin/config.h" #include "thorin/driver.h" @@ -136,58 +133,63 @@ int main(int argc, char** argv) { if (input[0] == '-' || input.substr(0, 2) == "--") throw std::invalid_argument("error: unknown option " + input); - auto path = fs::path(input); - world.set(path.filename().replace_extension().string()); - auto ast = ast::AST(driver); - auto parser = ast::Parser(ast); + try { + auto path = fs::path(input); + world.set(path.filename().replace_extension().string()); + auto ast = ast::AST(driver); + auto parser = ast::Parser(ast); #if 0 - parser.import(driver.sym(input), os[Md]); - - if (auto dep = os[D]) { - if (auto autogen_h = output[H]; !autogen_h.empty()) { - *dep << autogen_h << ": "; - assert(!driver.imports().empty()); - for (auto sep = ""; const auto& [path, _] : driver.imports() | std::views::drop(1)) { - *dep << sep << path; - sep = " \\\n "; + parser.import(driver.sym(input), os[Md]); + + if (auto dep = os[D]) { + if (auto autogen_h = output[H]; !autogen_h.empty()) { + *dep << autogen_h << ": "; + assert(!driver.imports().empty()); + for (auto sep = ""; const auto& [path, _] : driver.imports() | std::views::drop(1)) { + *dep << sep << path; + sep = " \\\n "; + } + } else { + throw std::invalid_argument("error: --output-d requires --output-h"); } - } else { - throw std::invalid_argument("error: --output-d requires --output-h"); + *dep << std::endl; } - *dep << std::endl; - } - if (flags.bootstrap) { - if (auto h = os[H]) - bootstrap(driver, world.sym(fs::path{path}.filename().replace_extension().string()), *h); - opt = std::min(opt, 1); - } + if (flags.bootstrap) { + if (auto h = os[H]) + bootstrap(driver, world.sym(fs::path{path}.filename().replace_extension().string()), *h); + opt = std::min(opt, 1); + } - switch (opt) { - case 0: break; - case 1: Phase::run(world); break; - case 2: - parser.import("opt"); - optimize(world); - break; - default: error("illegal optimization level '{}'", opt); - } + switch (opt) { + case 0: break; + case 1: Phase::run(world); break; + case 2: + parser.import("opt"); + optimize(world); + break; + default: error("illegal optimization level '{}'", opt); + } #endif - if (os[AST]) { - auto mod = parser.import(driver.sym(input), os[Md]); - mod->compile(ast, world); - Tab tab; - mod->stream(tab, *os[AST]); - } - if (os[Thorin]) world.dump(*os[Thorin]); - if (os[Dot]) world.dot(*os[Dot], dot_all_annexes, dot_follow_types); - - if (os[LL]) { - if (auto backend = driver.backend("ll")) - backend(world, *os[LL]); - else - error("'ll' emitter not loaded; try loading 'mem' plugin"); + if (os[AST]) { + auto mod = parser.import(driver.sym(input), os[Md]); + mod->compile(ast, world); + Tab tab; + mod->stream(tab, *os[AST]); + } + if (os[Thorin]) world.dump(*os[Thorin]); + if (os[Dot]) world.dot(*os[Dot], dot_all_annexes, dot_follow_types); + + if (os[LL]) { + if (auto backend = driver.backend("ll")) + backend(world, *os[LL]); + else + error("'ll' emitter not loaded; try loading 'mem' plugin"); + } + } catch (const Error& e) { // e.loc.path doesn't exist anymore in outer scope so catch Error here + errln("{}{}: {}error:{} {}", rang::fg::yellow, e.loc, rang::fg::red, rang::fg::reset, e.what()); + return EXIT_FAILURE; } } catch (const std::exception& e) { errln("{}", e.what()); From 782108476a04efefa99a6cb5717fead86e36536b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 3 Apr 2024 12:32:59 +0200 Subject: [PATCH 24/95] bug fix --- docs/Doxyfile.in | 2 +- external/fe | 2 +- src/thorin/ast/emit.cpp | 2 +- src/thorin/cli/main.cpp | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index dd42bcd201..1821a2db83 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -598,7 +598,7 @@ HIDE_UNDOC_CLASSES = NO # documentation. # The default value is: NO. -HIDE_FRIEND_COMPOUNDS = YES +HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these diff --git a/external/fe b/external/fe index a937e008ee..4c947056fb 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit a937e008eeebc09c2e0a28cd6174b950ec47ce9f +Subproject commit 4c947056fb2821325355a28ca74e61b731a98a89 diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 2daebefaec..e6b0557839 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -54,7 +54,7 @@ Ref LitExpr::emit(Emitter& e) const { if (sym.size() == b) error(loc, "signed literal '{}' without value", value()); - if (sym.size() >= b + 1) { + if (sym.size() > b + 1) { switch (sym[b + 1]) { // clang-format off case 'b': diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 7a46b9a770..b534ba66c9 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include #include From 399eb7e7f1bde129af5659f037f1b4881f1011ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 3 Apr 2024 19:01:53 +0200 Subject: [PATCH 25/95] wip: emit for Ptrns --- include/thorin/ast/ast.h | 43 ++++++++++++++---------- src/thorin/ast/ast.cpp | 64 ------------------------------------ src/thorin/ast/emit.cpp | 71 ++++++++++++++++++++++++++++++---------- 3 files changed, 80 insertions(+), 98 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index b6c5f972a3..800c6376d8 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -118,11 +118,8 @@ class ValDecl : public Decl { : Decl(loc) {} public: - virtual void bind(Scopes&) const = 0; - Ref emit(Emitter& e) const { return def_ ? def_ : def_ = emit_(e); } - -private: - virtual Ref emit_(Emitter&) const = 0; + virtual void bind(Scopes&) const = 0; + virtual void emit(Emitter&) const = 0; }; class RecDecl : public ValDecl { @@ -165,17 +162,21 @@ class Ptrn : public Decl { bool rebind() const { return rebind_; } Dbg dbg() const { return dbg_; } + bool is_anon() const { return !dbg().sym || dbg().sym == '_'; } virtual void bind(Scopes&, bool quiet = false) const = 0; - virtual Ref emit_(Emitter&, Ref) const = 0; - Ref emit(Emitter& e, Ref def) const { return def_ ? def_ : def_ = emit_(e, def); } + virtual Ref emit_value(Emitter&, Ref) const = 0; + Ref emit_type(Emitter& e) const { return thorin_type_ ? thorin_type_ : thorin_type_ = emit_type_(e); } [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); private: + virtual Ref emit_type_(Emitter&) const = 0; + Dbg dbg_; bool rebind_; + mutable Ref thorin_type_ = nullptr; }; /// `dbg: type` @@ -193,10 +194,12 @@ class IdPtrn : public Ptrn { } void bind(Scopes&, bool quiet = false) const override; - Ref emit_(Emitter&, Ref) const override; + Ref emit_value(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_type_(Emitter&) const override; + bool rebind_; Ptr type_; }; @@ -211,10 +214,12 @@ class GroupPtrn : public Ptrn { const IdPtrn* id() const { return id_; } void bind(Scopes&, bool quiet = false) const override; - Ref emit_(Emitter&, Ref) const override; + Ref emit_value(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_type_(Emitter&) const override; + const IdPtrn* id_; }; @@ -236,10 +241,12 @@ class TuplePtrn : public Ptrn { size_t num_ptrns() const { return ptrns().size(); } void bind(Scopes&, bool quiet = false) const override; - Ref emit_(Emitter&, Ref) const override; + Ref emit_value(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_type_(Emitter&) const override; + Tok::Tag delim_l_; Ptrs ptrns_; }; @@ -255,10 +262,12 @@ class ReturnPtrn : public Ptrn { const Expr* type() const { return type_; } void bind(Scopes&, bool quiet = false) const override; - Ref emit_(Emitter&, Ref) const override; + Ref emit_value(Emitter&, Ref) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_type_(Emitter&) const override; + const Expr* type_; }; @@ -699,7 +708,7 @@ class InferExpr : public Expr { }; /* - * Further Decls + * Decls */ /// `.let ptrn: type = value;` @@ -714,7 +723,7 @@ class LetDecl : public ValDecl { const Expr* value() const { return value_.get(); } void bind(Scopes&) const override; - Ref emit_(Emitter&) const override; + void emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -744,7 +753,7 @@ class AxiomDecl : public ValDecl { Dbg trip() const { return trip_; } void bind(Scopes&) const override; - Ref emit_(Emitter&) const override; + void emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -770,7 +779,7 @@ class PiDecl : public RecDecl { void bind(Scopes&) const override; void bind_rec(Scopes&) const override; - Ref emit_(Emitter&) const override; + void emit(Emitter&) const override; void emit_rec(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -792,7 +801,7 @@ class LamDecl : public RecDecl { void bind(Scopes&) const override; void bind_rec(Scopes&) const override; - Ref emit_(Emitter&) const override; + void emit(Emitter&) const override; void emit_rec(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -815,7 +824,7 @@ class SigmaDecl : public RecDecl { void bind(Scopes&) const override; void bind_rec(Scopes&) const override; - Ref emit_(Emitter&) const override; + void emit(Emitter&) const override; void emit_rec(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index d3b550f928..a2a75f18c5 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -33,68 +33,4 @@ void Module::compile(AST& ast, World& world) const { emit(ast, world); } -#if 0 -/* - * type - */ - -const Def* IdPtrn::type(World& world, Def2Fields&) const { - if (type_) return type_; - return type_ = world.mut_infer_type()->set(loc()); -} - -const Def* TuplePtrn::type(World& world, Def2Fields& def2fields) const { - if (type_) return type_; - - auto n = num_ptrns(); - auto ops = DefVec(n, [&](size_t i) { return ptrn(i)->type(world, def2fields); }); - - if (std::ranges::all_of(ptrns_, [](auto&& b) { return b->is_anonymous(); })) { - if (decl_) return type_ = decl_->set(ops); - return type_ = world.sigma(ops)->set(loc()); - } - - assert(n > 0); - auto type = world.umax(ops); - - Sigma* sigma; - if (decl_) { - if (auto s = decl_->isa_mut()) - sigma = s; - else { - sigma = world.mut_sigma(type, n)->set(loc(), sym()); - if (auto infer = decl_->isa()) { - if (infer->is_set()) { - if (infer->op() != sigma) - error(infer->loc(), "inferred different sigma '{}' for '{}'", infer->op(), sigma); - } else { - infer->set(sigma); - } - } - } - } else { - sigma = world.mut_sigma(type, n)->set(loc(), sym()); - } - - assert_emplace(def2fields, sigma, Vector(n, [this](size_t i) { return ptrn(i)->sym(); })); - - sigma->set(0, ops[0]); - for (size_t i = 1; i != n; ++i) { - if (auto infer = infers_[i - 1]) infer->set(sigma->var(n, i - 1)->set(ptrn(i - 1)->sym())); - sigma->set(i, ops[i]); - } - - auto var = sigma->var()->as(); - VarRewriter rw(var, var); - sigma->reset(0, ops[0]); - for (size_t i = 1; i != n; ++i) sigma->reset(i, rw.rewrite(ops[i])); - - if (!decl_) { - if (auto imm = sigma->immutabilize()) return type_ = imm; - } - - return type_ = sigma; -} -#endif - } // namespace thorin::ast diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index e6b0557839..cd1386b618 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -1,6 +1,8 @@ #include #include +#include "thorin/rewrite.h" + #include "thorin/ast/ast.h" #include "fe/assert.h" @@ -131,23 +133,63 @@ void Module::emit(Emitter& e) const { void Import::emit(Emitter& e) const { module()->emit(e); } /* - * Ptrn + * Ptrn::emit_value */ -Ref IdPtrn::emit_(Emitter&, Ref def) const { return def; } +Ref IdPtrn::emit_value(Emitter&, Ref def) const { return def; } -Ref TuplePtrn::emit_(Emitter& e, Ref def) const { - for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_(e, def->proj(n, i)); +Ref TuplePtrn::emit_value(Emitter& e, Ref def) const { + for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_value(e, def->proj(n, i)); return {}; } -Ref GroupPtrn::emit_(Emitter&, Ref def) const { return def; } +Ref GroupPtrn::emit_value(Emitter&, Ref def) const { return def; } -Ref ReturnPtrn::emit_(Emitter& e, Ref def) const { +Ref ReturnPtrn::emit_value(Emitter& e, Ref def) const { type()->emit(e); return def; } +/* + * Ptrn::emit_Type + */ + +Ref IdPtrn::emit_type_(Emitter& e) const { + if (type()) return type()->emit(e); + return e.world().mut_infer_type()->set(loc()); +} + +Ref GroupPtrn::emit_type_(Emitter& e) const { return id()->emit_type(e); } + +Ref TuplePtrn::emit_type_(Emitter& e) const { + auto n = num_ptrns(); + auto ops = DefVec(n, [&](size_t i) { return ptrn(i)->emit_type(e); }); + + if (std::ranges::all_of(ptrns_, [](auto&& b) { return b->is_anon(); })) return e.world().sigma(ops)->set(loc()); + + assert(n > 0); + auto type = e.world().umax(ops); + auto sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); + + // assert_emplace(def2fields, sigma, Vector(n, [this](size_t i) { return ptrn(i)->sym(); })); + + sigma->set(0, ops[0]); + for (size_t i = 1; i != n; ++i) { + // if (auto infer = infers_[i - 1]) infer->set(sigma->var(n, i - 1)->set(ptrn(i - 1)->sym())); + sigma->set(i, ops[i]); + } + + auto var = sigma->var()->as(); + VarRewriter rw(var, var); + sigma->reset(0, ops[0]); + for (size_t i = 1; i != n; ++i) sigma->reset(i, rw.rewrite(ops[i])); + + if (auto imm = sigma->immutabilize()) return imm; + return sigma; +} + +Ref ReturnPtrn::emit_type_(Emitter&) const { fe::unreachable(); } + /* * Expr */ @@ -186,10 +228,9 @@ Ref LamExpr::emit(Emitter& e) const { return {}; } -Ref LamDecl::emit_(Emitter& e) const { +void LamDecl::emit(Emitter& e) const { for (const auto& dom : lam()->doms()) dom->emit(e); lam()->codom()->emit(e); - return {}; } void LamDecl::emit_rec(Emitter& e) const { @@ -269,13 +310,12 @@ void DeclsBlock::emit(Emitter& e) const { } } -Ref LetDecl::emit_(Emitter& e) const { +void LetDecl::emit(Emitter& e) const { auto v = value()->emit(e); - ptrn()->emit(e, v); - return v; + def_ = ptrn()->emit_value(e, v); } -Ref AxiomDecl::emit_(Emitter& e) const { +void AxiomDecl::emit(Emitter& e) const { type()->emit(e); if (num_subs() == 0) { @@ -286,19 +326,16 @@ Ref AxiomDecl::emit_(Emitter& e) const { } } } - return {}; } -Ref PiDecl::emit_(Emitter& e) const { +void PiDecl::emit(Emitter& e) const { if (type()) type()->emit(e); - return {}; } void PiDecl::emit_rec(Emitter& e) const { body()->emit(e); } -Ref SigmaDecl::emit_(Emitter& e) const { +void SigmaDecl::emit(Emitter& e) const { if (type()) type()->emit(e); - return {}; } void SigmaDecl::emit_rec(Emitter& e) const { body()->emit(e); } From 0df9a6f1b0d081104a61bac37c5cae595af56277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 5 Apr 2024 03:56:20 +0200 Subject: [PATCH 26/95] .rec decl for recursive Sigma/Pi Also: switched role of LamDecl/LamExpr --- include/thorin/ast/ast.h | 148 +++++++++---------------- include/thorin/ast/parser.h | 7 +- include/thorin/ast/tok.h | 6 +- include/thorin/def.h | 1 - src/thorin/ast/ast.cpp | 12 +- src/thorin/ast/bind.cpp | 76 ++++++------- src/thorin/ast/emit.cpp | 43 +++---- src/thorin/ast/parser.cpp | 125 +++++++++------------ src/thorin/ast/stream.cpp | 47 ++++---- src/thorin/def.cpp | 3 - src/thorin/plug/compile/compile.thorin | 24 ++-- 11 files changed, 199 insertions(+), 293 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 800c6376d8..06f2c50ef3 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -14,6 +14,7 @@ namespace thorin::ast { +class LamDecl; class Module; class Scopes; class Emitter; @@ -72,8 +73,6 @@ class AST { Sym sym_return_; }; -class Scopes; - class Node : public fe::RuntimeCast { protected: Node(Loc loc) @@ -122,16 +121,6 @@ class ValDecl : public Decl { virtual void emit(Emitter&) const = 0; }; -class RecDecl : public ValDecl { -protected: - RecDecl(Loc loc) - : ValDecl(loc) {} - -public: - virtual void bind_rec(Scopes&) const = 0; - virtual void emit_rec(Emitter&) const = 0; -}; - class DeclsBlock { public: DeclsBlock(Ptrs&& decls) @@ -464,66 +453,19 @@ class PiExpr : public Expr { Ptr codom_; }; -/// One of: -/// * `λ dom_0 ... dom_n-1 -> codom` -/// * `.cn dom_0 ... dom_n-1` -/// * `.fn dom_0 ... dom_n-1 -> codom` -/// * `.lam dbg dom_0 ... dom_n-1 -> codom` -/// * `.con dbg dom_0 ... dom_n-1` -/// * `.fun dbg dom_0 ... dom_n-1 -> codom` +/// Wraps a LamDecl as Expr. class LamExpr : public Expr { public: - class Dom : public PiExpr::Dom { - public: - Dom(Loc loc, bool has_bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) - : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) - , has_bang_(has_bang) - , filter_(std::move(filter)) {} - - bool has_bang() const { return has_bang_; } - const Expr* filter() const { return filter_.get(); } - - void bind(Scopes&, bool quiet = false) const; - Ref emit(Emitter&) const; - std::ostream& stream(Tab&, std::ostream&) const override; - - private: - bool has_bang_; - Ptr filter_; - }; + LamExpr(Ptr&& lam); - LamExpr(Loc loc, Tok::Tag tag, bool is_external, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) - : Expr(loc) - , tag_(tag) - , is_external_(is_external) - , dbg_(dbg) - , doms_(std::move(doms)) - , codom_(std::move(codom)) - , body_(std::move(body)) {} - - Tok::Tag tag() const { return tag_; } - bool is_external() const { return is_external_; } - Dbg dbg() const { return dbg_; } - const auto& doms() const { return doms_; } - const Dom* dom(size_t i) const { return doms_[i].get(); } - size_t num_doms() const { return doms_.size(); } - const Expr* codom() const { return codom_.get(); } - const ReturnPtrn* ret() const { return ret_.get(); } - const Expr* body() const { return body_.get(); } + const LamDecl* lam() const { return lam_.get(); } void bind(Scopes&) const override; Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Tok::Tag tag_; - bool is_external_; - Dbg dbg_; - Ptrs doms_; - Ptr codom_; - Ptr body_; - mutable Ptr ret_; - friend class LamDecl; + Ptr lam_; }; /// `callee arg` @@ -764,11 +706,11 @@ class AxiomDecl : public ValDecl { Dbg curry_, trip_; }; -/// `.Pi dbg: type = body´ -class PiDecl : public RecDecl { +/// `.rec dbg: type = body` +class RecDecl : public ValDecl { public: - PiDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) - : RecDecl(loc) + RecDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) + : ValDecl(loc) , dbg_(dbg) , type_(std::move(type)) , body_(std::move(body)) {} @@ -778,9 +720,9 @@ class PiDecl : public RecDecl { const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; - void bind_rec(Scopes&) const override; void emit(Emitter&) const override; - void emit_rec(Emitter&) const override; + virtual void bind_rec(Scopes&) const; + virtual void emit_rec(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -789,38 +731,48 @@ class PiDecl : public RecDecl { Ptr body_; }; -/// Just wraps a LamDecl as Expr. +/// One of: +/// * `λ dom_0 ... dom_n-1 -> codom` +/// * `.cn dom_0 ... dom_n-1` +/// * `.fn dom_0 ... dom_n-1 -> codom` +/// * `.lam dbg dom_0 ... dom_n-1 -> codom` +/// * `.con dbg dom_0 ... dom_n-1` +/// * `.fun dbg dom_0 ... dom_n-1 -> codom` class LamDecl : public RecDecl { public: - LamDecl(Ptr&& lam) - : RecDecl(lam->loc()) - , lam_(std::move(lam)) {} + class Dom : public PiExpr::Dom { + public: + Dom(Loc loc, bool has_bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) + : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) + , has_bang_(has_bang) + , filter_(std::move(filter)) {} - const LamExpr* lam() const { return lam_.get(); } - const Expr* body() const { return lam()->body(); } + bool has_bang() const { return has_bang_; } + const Expr* filter() const { return filter_.get(); } - void bind(Scopes&) const override; - void bind_rec(Scopes&) const override; - void emit(Emitter&) const override; - void emit_rec(Emitter&) const override; - std::ostream& stream(Tab&, std::ostream&) const override; + void bind(Scopes&, bool quiet = false) const; + Ref emit(Emitter&) const; + std::ostream& stream(Tab&, std::ostream&) const override; -private: - Ptr lam_; -}; + private: + bool has_bang_; + Ptr filter_; + }; -/// `.Sigma dbg: type = body` -class SigmaDecl : public RecDecl { -public: - SigmaDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) - : RecDecl(loc) - , dbg_(dbg) - , type_(std::move(type)) - , body_(std::move(body)) {} + LamDecl(Loc loc, Tok::Tag tag, bool is_external, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) + : RecDecl(loc, dbg, nullptr, std::move(body)) + , tag_(tag) + , is_external_(is_external) + , doms_(std::move(doms)) + , codom_(std::move(codom)) {} - Dbg dbg() const { return dbg_; } - const Expr* type() const { return type_.get(); } - const Expr* body() const { return body_.get(); } + Tok::Tag tag() const { return tag_; } + bool is_external() const { return is_external_; } + const auto& doms() const { return doms_; } + const Dom* dom(size_t i) const { return doms_[i].get(); } + size_t num_doms() const { return doms_.size(); } + const Expr* codom() const { return codom_.get(); } + const ReturnPtrn* ret() const { return ret_.get(); } void bind(Scopes&) const override; void bind_rec(Scopes&) const override; @@ -829,9 +781,11 @@ class SigmaDecl : public RecDecl { std::ostream& stream(Tab&, std::ostream&) const override; private: - Dbg dbg_; - Ptr type_; - Ptr body_; + Tok::Tag tag_; + bool is_external_; + Ptrs doms_; + Ptr codom_; + mutable Ptr ret_; }; /* diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 7e53c0584e..6d6c03eacd 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -85,8 +85,8 @@ class Parser : public fe::Parser { Ptr parse_extremum_expr(); Ptr parse_type_expr(); Ptr parse_ret_expr(); - Ptr parse_pi_expr(); - Ptr parse_lam_expr(); + Ptr parse_pi_expr(); + Ptr parse_lam_expr(); Ptr parse_sigma_expr(); Ptr parse_tuple_expr(); Ptr parse_insert_expr(); @@ -109,9 +109,8 @@ class Parser : public fe::Parser { Ptrs parse_decls(); Ptr parse_axiom_decl(); Ptr parse_let_decl(); - Ptr parse_pi_decl(); Ptr parse_lam_decl(); - Ptr parse_sigma_decl(); + Ptr parse_rec_decl(); ///@} /// @name error messages diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 9a87b2553d..f44b81cb53 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -1,9 +1,6 @@ #pragma once -#include - #include "thorin/util/dbg.h" -#include "thorin/util/types.h" namespace thorin { @@ -20,16 +17,15 @@ namespace ast { m(K_ax, ".ax" ) \ m(K_def, ".def" ) \ m(K_let, ".let" ) \ + m(K_rec, ".rec" ) \ m(K_ret, ".ret" ) \ m(K_Nat, ".Nat" ) \ m(K_Idx, ".Idx" ) \ m(K_extern, ".extern") \ - m(K_Sigma, ".Sigma" ) \ m(K_Type, ".Type" ) \ m(K_Univ, ".Univ" ) \ m(K_Cn, ".Cn" ) \ m(K_Fn, ".Fn" ) \ - m(K_Pi, ".Pi" ) \ m(K_con, ".con" ) \ m(K_fun, ".fun" ) \ m(K_lam, ".lam" ) \ diff --git a/include/thorin/def.h b/include/thorin/def.h index fee3560711..02c850c9cf 100644 --- a/include/thorin/def.h +++ b/include/thorin/def.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index a2a75f18c5..73ca7312b8 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -1,13 +1,11 @@ #include "thorin/ast/ast.h" -#include "thorin/check.h" -#include "thorin/def.h" -#include "thorin/driver.h" -#include "thorin/rewrite.h" -#include "thorin/world.h" - namespace thorin::ast { +LamExpr::LamExpr(Ptr&& lam) + : Expr(lam->loc()) + , lam_(std::move(lam)) {} + /* * Ptrn::to_expr/to_ptrn */ @@ -30,7 +28,7 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { void Module::compile(AST& ast, World& world) const { bind(ast); - emit(ast, world); + // emit(ast, world); } } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 3b9002a59b..6b88930326 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -141,45 +141,9 @@ void PiExpr::bind(Scopes& s) const { s.pop(); } -void PiDecl::bind(Scopes& s) const { - if (type()) type()->bind(s); - s.bind(dbg(), this); -} - -void PiDecl::bind_rec(Scopes& s) const { body()->bind(s); } - -void LamExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } - void LamExpr::bind(Scopes& s) const { - s.push(); - for (const auto& dom : doms()) dom->bind(s); - codom()->bind(s); - if (tag() == Tok::Tag::K_fn) { - ret_ = s.ast().ptr(s.ast(), codom()); - ret_->bind(s); - } - body()->bind(s); - s.pop(); -} - -void LamDecl::bind(Scopes& s) const { - s.push(); - for (const auto& dom : lam()->doms()) dom->bind(s); - lam()->codom()->bind(s); - if (lam()->tag() == Tok::Tag::K_fun) { - lam()->ret_ = s.ast().ptr(s.ast(), lam()->codom()); - lam()->ret_->bind(s); - } - s.pop(); - s.bind(lam()->dbg(), this); -} - -void LamDecl::bind_rec(Scopes& s) const { - s.push(); - for (const auto& dom : lam()->doms()) dom->bind(s, true); - if (auto ret = lam()->ret()) ret->bind(s, true); - body()->bind(s); - s.pop(); + lam()->bind(s); + lam()->bind_rec(s); } void AppExpr::bind(Scopes& s) const { @@ -243,11 +207,6 @@ void DeclsBlock::bind(Scopes& s) const { } } -void LetDecl::bind(Scopes& s) const { - value()->bind(s); - ptrn()->bind(s); -} - void AxiomDecl::bind(Scopes& s) const { type()->bind(s); @@ -263,11 +222,38 @@ void AxiomDecl::bind(Scopes& s) const { } } -void SigmaDecl::bind(Scopes& s) const { +void LetDecl::bind(Scopes& s) const { + value()->bind(s); + ptrn()->bind(s); +} + +void RecDecl::bind(Scopes& s) const { if (type()) type()->bind(s); s.bind(dbg(), this); } -void SigmaDecl::bind_rec(Scopes& s) const { body()->bind(s); } +void RecDecl::bind_rec(Scopes& s) const { body()->bind(s); } + +void LamDecl::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } + +void LamDecl::bind(Scopes& s) const { + s.push(); + for (const auto& dom : doms()) dom->bind(s); + codom()->bind(s); + if (tag() == Tok::Tag::K_fun) { + ret_ = s.ast().ptr(s.ast(), codom()); + ret_->bind(s); + } + s.pop(); + s.bind(dbg(), this); +} + +void LamDecl::bind_rec(Scopes& s) const { + s.push(); + for (const auto& dom : doms()) dom->bind(s, true); + if (ret()) ret()->bind(s, true); + body()->bind(s); + s.pop(); +} } // namespace thorin::ast diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index cd1386b618..321a31953e 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -216,27 +216,10 @@ Ref PiExpr::emit(Emitter& e) const { return {}; } -Ref LamExpr::Dom::emit(Emitter&) const { - // ptrn()->emit(e); - return {}; -} - Ref LamExpr::emit(Emitter& e) const { - for (const auto& dom : doms()) dom->emit(e); - codom()->emit(e); - body()->emit(e); - return {}; -} - -void LamDecl::emit(Emitter& e) const { - for (const auto& dom : lam()->doms()) dom->emit(e); - lam()->codom()->emit(e); -} - -void LamDecl::emit_rec(Emitter& e) const { - for (const auto& dom : lam()->doms()) dom->emit(e); - // if (auto ret = lam()->ret()) ret->emit(e); - body()->emit(e); + lam()->emit(e); + lam()->emit_rec(e); + return lam()->def(); } Ref AppExpr::emit(Emitter& e) const { @@ -328,16 +311,26 @@ void AxiomDecl::emit(Emitter& e) const { } } -void PiDecl::emit(Emitter& e) const { +void RecDecl::emit(Emitter& e) const { if (type()) type()->emit(e); } -void PiDecl::emit_rec(Emitter& e) const { body()->emit(e); } +void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } -void SigmaDecl::emit(Emitter& e) const { - if (type()) type()->emit(e); +Ref LamDecl::Dom::emit(Emitter&) const { + // ptrn()->emit(e); + return {}; +} + +void LamDecl::emit(Emitter& e) const { + for (const auto& dom : doms()) dom->emit(e); + codom()->emit(e); } -void SigmaDecl::emit_rec(Emitter& e) const { body()->emit(e); } +void LamDecl::emit_rec(Emitter& e) const { + for (const auto& dom : doms()) dom->emit(e); + // if (auto ret = lam()->ret()) ret->emit(e); + body()->emit(e); +} } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 9fc4d9ce9f..ecd2f9e050 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -2,17 +2,8 @@ #include #include -#include -#include -#include -#include -#include "thorin/check.h" -#include "thorin/def.h" #include "thorin/driver.h" -#include "thorin/rewrite.h" - -#include "thorin/util/sys.h" using namespace std::string_literals; @@ -295,7 +286,7 @@ Ptr Parser::parse_type_expr() { return ptr(track, std::move(level)); } -Ptr Parser::parse_pi_expr() { +Ptr Parser::parse_pi_expr() { auto track = tracker(); auto tag = lex().tag(); @@ -324,50 +315,7 @@ Ptr Parser::parse_pi_expr() { return ptr(track.loc(), tag, std::move(doms), std::move(codom)); } -Ptr Parser::parse_lam_expr() { - auto track = tracker(); - auto tag = lex().tag(); - auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Tok::Prec::Bot : Tok::Prec::Pi; - bool external = (bool)accept(Tag::K_extern); - - bool decl; - std::string entity; - // clang-format off - switch (tag) { - case Tag::T_lm: decl = false; entity = "function expression"; break; - case Tag::K_cn: decl = false; entity = "continuation expression"; break; - case Tag::K_fn: decl = false; entity = "returning continuation expression"; break; - case Tag::K_lam: decl = true ; entity = "function declaration"; break; - case Tag::K_con: decl = true ; entity = "continuation declaration"; break; - case Tag::K_fun: decl = true ; entity = "returning continuation declaration"; break; - default: fe::unreachable(); - } - // clang-format on - - auto dbg = decl ? parse_name(entity) : Dbg(); - Ptrs doms; - do { - auto track = tracker(); - bool bang = (bool)accept(Tag::T_bang); - bool implicit = (bool)accept(Tag::T_dot); - auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); - - Ptr filter; - if (auto tok = accept(Tag::T_at)) { - expect(Tag::D_paren_l, "opening parenthesis of a filter"); - filter = parse_expr("filter"); - expect(Tag::D_paren_r, "closing parenthesis of a filter"); - } - - doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); - } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); - - auto codom - = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : ptr(prev_); - auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : Ptr(); - - return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); -} +Ptr Parser::parse_lam_expr() { return ptr(parse_lam_decl()); } Ptr Parser::parse_ret_expr() { auto track = tracker(); @@ -555,8 +503,7 @@ Ptrs Parser::parse_decls() { case Tag::T_semicolon: lex(); break; // eat up stray semicolons case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break; case Tag::K_let: decls.emplace_back(parse_let_decl()); break; - case Tag::K_Sigma: decls.emplace_back(parse_sigma_decl()); break; - case Tag::K_Pi: decls.emplace_back(parse_pi_decl()); break; + case Tag::K_rec: decls.emplace_back(parse_rec_decl()); break; case Tag::K_con: case Tag::K_fun: case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break; @@ -612,28 +559,60 @@ Ptr Parser::parse_let_decl() { return ptr(track, std::move(ptrn), std::move(value)); } -Ptr Parser::parse_pi_decl() { +Ptr Parser::parse_rec_decl() { auto track = tracker(); - eat(Tag::K_Pi); - auto dbg = parse_name("pi declaration"); - auto type = accept(Tag::T_colon) ? parse_expr("type of a pi declaration") : Ptr(); - auto body = accept(Tag::T_assign) ? parse_expr("body of a pi declaration") : Ptr(); - expect(Tag::T_semicolon, "end of a pi declaration"); - - return ptr(track, dbg, std::move(type), std::move(body)); + eat(Tag::K_rec); + auto dbg = parse_name("recursive declaration"); + auto type = accept(Tag::T_colon) ? parse_expr("type of a recursive declaration") : ptr(prev_); + expect(Tag::T_assign, "recursive declaration"); + auto body = parse_expr("body of a recursive declaration"); + expect(Tag::T_semicolon, "end of a recursive declaration"); + return ptr(track, dbg, std::move(type), std::move(body)); } -Ptr Parser::parse_lam_decl() { return ptr(parse_lam_expr()); } +Ptr Parser::parse_lam_decl() { + auto track = tracker(); + auto tag = lex().tag(); + auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Tok::Prec::Bot : Tok::Prec::Pi; + bool external = (bool)accept(Tag::K_extern); -Ptr Parser::parse_sigma_decl() { - auto track = tracker(); - eat(Tag::K_Sigma); - auto dbg = parse_name("sigma declaration"); - auto type = accept(Tag::T_colon) ? parse_expr("type of a sigma declaration") : Ptr(); - auto body = accept(Tag::T_assign) ? parse_expr("body of a sigma declaration") : Ptr(); - expect(Tag::T_semicolon, "end of a sigma declaration"); + bool decl; + std::string entity; + // clang-format off + switch (tag) { + case Tag::T_lm: decl = false; entity = "function expression"; break; + case Tag::K_cn: decl = false; entity = "continuation expression"; break; + case Tag::K_fn: decl = false; entity = "returning continuation expression"; break; + case Tag::K_lam: decl = true ; entity = "function declaration"; break; + case Tag::K_con: decl = true ; entity = "continuation declaration"; break; + case Tag::K_fun: decl = true ; entity = "returning continuation declaration"; break; + default: fe::unreachable(); + } + // clang-format on + + auto dbg = decl ? parse_name(entity) : Dbg(); + Ptrs doms; + do { + auto track = tracker(); + bool bang = (bool)accept(Tag::T_bang); + bool implicit = (bool)accept(Tag::T_dot); + auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); + + Ptr filter; + if (auto tok = accept(Tag::T_at)) { + expect(Tag::D_paren_l, "opening parenthesis of a filter"); + filter = parse_expr("filter"); + expect(Tag::D_paren_r, "closing parenthesis of a filter"); + } + + doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); + } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); + + auto codom + = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : ptr(prev_); + auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : Ptr(); - return ptr(track, dbg, std::move(type), std::move(body)); + return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } } // namespace thorin::ast diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index f57d6cb1aa..e8bf51431b 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -106,20 +106,7 @@ std::ostream& PiExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{} -> {}", tag(), R(tab, doms()), S(tab, codom())); } -std::ostream& LamExpr::Dom::stream(Tab& tab, std::ostream& os) const { - if (has_bang()) os << '!'; - PiExpr::Dom::stream(tab, os); - if (filter()) print(os, "@({})", filter()); - return os; -} -std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { - print(os, "{} {}", tag(), dbg()); - if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; - print(os, "{}", R(tab, doms())); - if (!codom()->isa()) print(os, ": {}", S(tab, codom())); - if (body()) print(os, " = {}", S(tab, body())); - return os; -} +std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{};", S(tab, lam())); } std::ostream& AppExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{} {}", S(tab, callee()), S(tab, arg())); @@ -158,10 +145,6 @@ std::ostream& DeclsBlock::stream(Tab& tab, std::ostream& os) const { return os; } -std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { - return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); -} - std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { print(os, ".ax {}", dbg()); if (num_subs() != 0) { @@ -179,9 +162,31 @@ std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { return os << ";"; } -std::ostream& PiDecl::stream(Tab& /*tab*/, std::ostream& os) const { return print(os, ".Pi"); } -std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return print(os, "{};", S(tab, lam())); } -std::ostream& SigmaDecl::stream(Tab& /*tab*/, std::ostream& os) const { return print(os, ".Sigma"); } +std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { + return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); +} + +std::ostream& RecDecl::stream(Tab& tab, std::ostream& os) const { + print(os, ".rec {}", dbg()); + if (!type()->isa()) print(os, ": {}", S(tab, type())); + return print(os, " = {};", S(tab, body())); +} + +std::ostream& LamDecl::Dom::stream(Tab& tab, std::ostream& os) const { + if (has_bang()) os << '!'; + PiExpr::Dom::stream(tab, os); + if (filter()) print(os, "@({})", filter()); + return os; +} + +std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { + print(os, "{} {}", tag(), dbg()); + if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; + print(os, "{}", R(tab, doms())); + if (!codom()->isa()) print(os, ": {}", S(tab, codom())); + if (body()) print(os, " = {}", S(tab, body())); + return os; +} /* * Module diff --git a/src/thorin/def.cpp b/src/thorin/def.cpp index 8fd0231541..0068c6c9ce 100644 --- a/src/thorin/def.cpp +++ b/src/thorin/def.cpp @@ -1,9 +1,6 @@ #include "thorin/def.h" #include -#include -#include -#include #include "thorin/rewrite.h" #include "thorin/world.h" diff --git a/src/thorin/plug/compile/compile.thorin b/src/thorin/plug/compile/compile.thorin index d585b0ad92..08a99749af 100644 --- a/src/thorin/plug/compile/compile.thorin +++ b/src/thorin/plug/compile/compile.thorin @@ -23,9 +23,9 @@ /// /// Types for functions that accept an arbitrary number of phases and passes respectively. /// -.Pi %compile.Pipeline: □ = Π %compile.Phase -> %compile.Pipeline; -.Pi %compile.PassList: □ = Π %compile.Pass -> %compile.PassList; -.Pi %compile.CombinedPhase: □ = Π %compile.Phase -> %compile.CombinedPhase; +.rec %compile.Pipeline: □ = Π %compile.Phase -> %compile.Pipeline; +.rec %compile.PassList: □ = Π %compile.Pass -> %compile.PassList; +.rec %compile.CombinedPhase: □ = Π %compile.Phase -> %compile.CombinedPhase; /// /// (This is a forward declaration for opt.thorin.) /// @@ -38,16 +38,16 @@ /// We expect the name in the tag before the `_` to be the name of the plugin (as given in `Plugin.plugin_name`). /// (This is a forward declaration for opt.thorin.) /// -.ax %compile.core_plugin : %compile.Plugin; -.ax %compile.mem_plugin : %compile.Plugin; -.ax %compile.demo_plugin : %compile.Plugin; -.ax %compile.affine_plugin : %compile.Plugin; +.ax %compile.core_plugin: %compile.Plugin; +.ax %compile.mem_plugin: %compile.Plugin; +.ax %compile.demo_plugin: %compile.Plugin; +.ax %compile.affine_plugin: %compile.Plugin; .ax %compile.autodiff_plugin: %compile.Plugin; -.ax %compile.clos_plugin : %compile.Plugin; -.ax %compile.direct_plugin : %compile.Plugin; -.ax %compile.refly_plugin : %compile.Plugin; -.ax %compile.regex_plugin : %compile.Plugin; -.ax %compile.matrix_plugin : %compile.Plugin; +.ax %compile.clos_plugin: %compile.Plugin; +.ax %compile.direct_plugin: %compile.Plugin; +.ax %compile.refly_plugin: %compile.Plugin; +.ax %compile.regex_plugin: %compile.Plugin; +.ax %compile.matrix_plugin: %compile.Plugin; /// /// ### %opt.is_loaded /// From 403f642e7cb719677fadfdd3ecddd698727b4cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 9 Apr 2024 14:42:09 +0200 Subject: [PATCH 27/95] wip: emit --- include/thorin/ast/ast.h | 93 ++++++++++++++++++++++++++------------- include/thorin/world.h | 2 - src/thorin/ast/bind.cpp | 38 +++++++++++++++- src/thorin/ast/emit.cpp | 33 +++++++------- src/thorin/ast/parser.cpp | 8 ++-- src/thorin/ast/stream.cpp | 8 ++-- src/thorin/cli/main.cpp | 2 - src/thorin/def.cpp | 5 +-- src/thorin/dot.cpp | 1 - src/thorin/lattice.cpp | 3 -- src/thorin/world.cpp | 1 - 11 files changed, 124 insertions(+), 70 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 06f2c50ef3..a8245fe695 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -152,20 +152,21 @@ class Ptrn : public Decl { bool rebind() const { return rebind_; } Dbg dbg() const { return dbg_; } bool is_anon() const { return !dbg().sym || dbg().sym == '_'; } + Ref thorin_type() const { return thorin_type_; } virtual void bind(Scopes&, bool quiet = false) const = 0; virtual Ref emit_value(Emitter&, Ref) const = 0; - Ref emit_type(Emitter& e) const { return thorin_type_ ? thorin_type_ : thorin_type_ = emit_type_(e); } + virtual Ref emit_type(Emitter&) const = 0; [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); -private: - virtual Ref emit_type_(Emitter&) const = 0; +protected: + mutable Ref thorin_type_ = nullptr; +private: Dbg dbg_; bool rebind_; - mutable Ref thorin_type_ = nullptr; }; /// `dbg: type` @@ -184,11 +185,10 @@ class IdPtrn : public Ptrn { void bind(Scopes&, bool quiet = false) const override; Ref emit_value(Emitter&, Ref) const override; + Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Ref emit_type_(Emitter&) const override; - bool rebind_; Ptr type_; }; @@ -204,11 +204,10 @@ class GroupPtrn : public Ptrn { void bind(Scopes&, bool quiet = false) const override; Ref emit_value(Emitter&, Ref) const override; + Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Ref emit_type_(Emitter&) const override; - const IdPtrn* id_; }; @@ -231,11 +230,10 @@ class TuplePtrn : public Ptrn { void bind(Scopes&, bool quiet = false) const override; Ref emit_value(Emitter&, Ref) const override; + Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Ref emit_type_(Emitter&) const override; - Tok::Tag delim_l_; Ptrs ptrns_; }; @@ -252,11 +250,10 @@ class ReturnPtrn : public Ptrn { void bind(Scopes&, bool quiet = false) const override; Ref emit_value(Emitter&, Ref) const override; + Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Ref emit_type_(Emitter&) const override; - const Expr* type_; }; @@ -413,32 +410,42 @@ class PiExpr : public Expr { public: class Dom : public Node { public: - Dom(Loc loc, bool is_implicit, Ptr&& ptrn) + Dom(Loc loc, bool is_implicit, Ptr&& ptrn, size_t index) : Node(loc) , is_implicit_(is_implicit) - , ptrn_(std::move(ptrn)) {} + , ptrn_(std::move(ptrn)) + , index_(index) {} bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } - - void bind(Scopes&) const; - Ref emit(Emitter&) const; + const PiExpr* pi() const { return pi_; } + size_t index() const { return index_; } + bool is_first() const { return index_ == 0; } + bool is_last() const { return pi()->doms().size() == index() + 1; } + void link(const PiExpr* pi) const { pi_ = pi; } + + virtual void bind(Scopes& scopes, bool quiet = false) const; + virtual Ref emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: bool is_implicit_; Ptr ptrn_; + size_t index_; + mutable const PiExpr* pi_ = nullptr; }; PiExpr(Loc loc, Tok::Tag tag, Ptrs&& doms, Ptr&& codom) : Expr(loc) , tag_(tag) , doms_(std::move(doms)) - , codom_(std::move(codom)) {} + , codom_(std::move(codom)) { + for (const auto& dom : this->doms()) dom->link(this); + } private: Tok::Tag tag() const { return tag_; } - const auto& doms() const { return doms_; } + const Ptrs& doms() const { return doms_; } const Dom* dom(size_t i) const { return doms_[i].get(); } size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } @@ -740,23 +747,45 @@ class RecDecl : public ValDecl { /// * `.fun dbg dom_0 ... dom_n-1 -> codom` class LamDecl : public RecDecl { public: - class Dom : public PiExpr::Dom { + class Dom : public Node { public: - Dom(Loc loc, bool has_bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) - : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) - , has_bang_(has_bang) - , filter_(std::move(filter)) {} + struct Thorin { + Lam* lam; + Ref filter; + }; - bool has_bang() const { return has_bang_; } - const Expr* filter() const { return filter_.get(); } + Dom(Loc loc, Tok bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter, size_t index) + : Node(loc) + , bang_(bang) + , is_implicit_(is_implicit) + , ptrn_(std::move(ptrn)) + , filter_(std::move(filter)) + , index_(index) {} - void bind(Scopes&, bool quiet = false) const; - Ref emit(Emitter&) const; + bool is_implicit() const { return is_implicit_; } + Tok bang() const { return bang_; } + bool has_bang() const { return (bool)bang(); } + const Ptrn* ptrn() const { return ptrn_.get(); } + const Expr* filter() const { return filter_.get(); } + const LamDecl* lam() const { return lam_; } + size_t index() const { return index_; } + bool is_first() const { return index_ == 0; } + bool is_last() const { return lam()->doms().size() == index() + 1; } + void link(const LamDecl* lam) const { lam_ = lam; } + const Thorin& thorin() const { return thorin_; } + + void bind(Scopes& scopes, bool quiet = false) const; + void emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: - bool has_bang_; + Tok bang_; + bool is_implicit_; + Ptr ptrn_; Ptr filter_; + size_t index_; + mutable const LamDecl* lam_; + mutable Thorin thorin_; }; LamDecl(Loc loc, Tok::Tag tag, bool is_external, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) @@ -764,11 +793,13 @@ class LamDecl : public RecDecl { , tag_(tag) , is_external_(is_external) , doms_(std::move(doms)) - , codom_(std::move(codom)) {} + , codom_(std::move(codom)) { + for (const auto& dom : this->doms()) dom->link(this); + } Tok::Tag tag() const { return tag_; } bool is_external() const { return is_external_; } - const auto& doms() const { return doms_; } + const Ptrs& doms() const { return doms_; } const Dom* dom(size_t i) const { return doms_[i].get(); } size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } diff --git a/include/thorin/world.h b/include/thorin/world.h index cdfba01bff..54b0fe1ecf 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -17,7 +16,6 @@ #include "thorin/tuple.h" #include "thorin/util/dbg.h" -#include "thorin/util/hash.h" #include "thorin/util/log.h" namespace thorin { diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 6b88930326..903588faf3 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -132,7 +132,7 @@ void ArrowExpr::bind(Scopes& s) const { codom()->bind(s); } -void PiExpr::Dom::bind(Scopes& s) const { ptrn()->bind(s); } +void PiExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } void PiExpr::bind(Scopes& s) const { s.push(); @@ -234,11 +234,45 @@ void RecDecl::bind(Scopes& s) const { void RecDecl::bind_rec(Scopes& s) const { body()->bind(s); } -void LamDecl::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } +void LamDecl::Dom::bind(Scopes& s, bool quiet) const { + if (!quiet && has_bang() && filter()) { + s.ast().error(filter()->loc(), "explicit filter specified on top of '!' annotation"); + s.ast().note(bang().loc(), "'!' here"); + } + + ptrn()->bind(s, quiet); +} void LamDecl::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); + + if (num_doms() != 0) { + if (auto bang = doms().back()->bang()) { + if (tag() == Tag::K_lam || tag() == Tag::T_lm) + s.ast().warn( + bang.loc(), + "'!' superfluous as the last curried function group of a '{}' receives a '.tt'-filter by default", + tag()); + if (auto filter = doms().back()->filter()) { + if (auto pe = filter->isa()) { + if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm)) + s.ast().warn(filter->loc(), + "'.tt'-filter superfluous as the last curried function group of a '{}' receives a " + "'.tt' filter by default", + tag()); + if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm)) + s.ast().warn(filter->loc(), + "'.ff'-filter superfluous as the last curried function group of a '{}' receives a " + "'.ff' filter by default", + tag()); + } + } + } + } + + if (!codom()->isa() && (tag() == Tag::K_con || tag() == Tag::K_cn)) + s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); codom()->bind(s); if (tag() == Tok::Tag::K_fun) { ret_ = s.ast().ptr(s.ast(), codom()); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 321a31953e..4effb8f997 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -1,14 +1,7 @@ -#include -#include - #include "thorin/rewrite.h" #include "thorin/ast/ast.h" -#include "fe/assert.h" - -using namespace std::string_literals; - namespace thorin::ast { using Tag = Tok::Tag; @@ -154,14 +147,13 @@ Ref ReturnPtrn::emit_value(Emitter& e, Ref def) const { * Ptrn::emit_Type */ -Ref IdPtrn::emit_type_(Emitter& e) const { - if (type()) return type()->emit(e); - return e.world().mut_infer_type()->set(loc()); +Ref IdPtrn::emit_type(Emitter& e) const { + return thorin_type_ = type() ? type()->emit(e) : e.world().mut_infer_type()->set(loc()); } -Ref GroupPtrn::emit_type_(Emitter& e) const { return id()->emit_type(e); } +Ref GroupPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } -Ref TuplePtrn::emit_type_(Emitter& e) const { +Ref TuplePtrn::emit_type(Emitter& e) const { auto n = num_ptrns(); auto ops = DefVec(n, [&](size_t i) { return ptrn(i)->emit_type(e); }); @@ -185,10 +177,10 @@ Ref TuplePtrn::emit_type_(Emitter& e) const { for (size_t i = 1; i != n; ++i) sigma->reset(i, rw.rewrite(ops[i])); if (auto imm = sigma->immutabilize()) return imm; - return sigma; + return thorin_type_ = sigma; } -Ref ReturnPtrn::emit_type_(Emitter&) const { fe::unreachable(); } +Ref ReturnPtrn::emit_type(Emitter&) const { fe::unreachable(); } /* * Expr @@ -305,6 +297,7 @@ void AxiomDecl::emit(Emitter& e) const { } else { for (const auto& aliases : subs()) { for (const auto& alias : aliases) { + outln("{}", alias); // auto sym = s.ast().sym(dbg().sym.str() + "."s + alias.sym.str()); } } @@ -317,18 +310,22 @@ void RecDecl::emit(Emitter& e) const { void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } -Ref LamDecl::Dom::emit(Emitter&) const { - // ptrn()->emit(e); - return {}; +void LamDecl::Dom::emit(Emitter& e) const { + auto dom_t = ptrn()->emit_type(e); + auto pi = e.world().mut_pi(e.world().type_infer_univ(), is_implicit())->set_dom(dom_t); + thorin_.filter = has_bang() ? e.world().lit_tt() : filter()->emit(e); + thorin_.lam = e.world().mut_lam(pi); } void LamDecl::emit(Emitter& e) const { for (const auto& dom : doms()) dom->emit(e); codom()->emit(e); + + if (is_external()) doms().front()->thorin().lam->make_external(); } void LamDecl::emit_rec(Emitter& e) const { - for (const auto& dom : doms()) dom->emit(e); + for (const auto& dom : doms()) dom->ptrn()->emit_value(e, dom->thorin().lam->var()); // if (auto ret = lam()->ret()) ret->emit(e); body()->emit(e); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index ecd2f9e050..a024b7b4f2 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -299,12 +299,13 @@ Ptr Parser::parse_pi_expr() { } Ptrs doms; + size_t i = 0; do { auto track = tracker(); auto implicit = (bool)accept(Tag::T_dot); auto prec = tag == Tag::K_Cn ? Tok::Prec::Bot : Tok::Prec::App; auto ptrn = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec); - doms.emplace_back(ptr(track, implicit, std::move(ptrn))); + doms.emplace_back(ptr(track, implicit, std::move(ptrn), i++)); } while (ahead().isa(Tag::T_dot) || ahead().isa(Tag::D_brckt_l) || ahead().isa(Tag::T_backtick) || (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon_colon))); @@ -592,9 +593,10 @@ Ptr Parser::parse_lam_decl() { auto dbg = decl ? parse_name(entity) : Dbg(); Ptrs doms; + size_t i = 0; do { auto track = tracker(); - bool bang = (bool)accept(Tag::T_bang); + auto bang = accept(Tag::T_bang); bool implicit = (bool)accept(Tag::T_dot); auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); @@ -605,7 +607,7 @@ Ptr Parser::parse_lam_decl() { expect(Tag::D_paren_r, "closing parenthesis of a filter"); } - doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); + doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter), i++)); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); auto codom diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index e8bf51431b..07f3a01871 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -99,9 +99,11 @@ std::ostream& TypeExpr::stream(Tab& tab, std::ostream& os) const { return print( std::ostream& ArrowExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{} -> {}", S(tab, dom()), S(tab, codom())); } -std::ostream& PiExpr::Dom ::stream(Tab& tab, std::ostream& os) const { + +std::ostream& PiExpr::Dom::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); } + std::ostream& PiExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{} -> {}", tag(), R(tab, doms()), S(tab, codom())); } @@ -174,8 +176,8 @@ std::ostream& RecDecl::stream(Tab& tab, std::ostream& os) const { std::ostream& LamDecl::Dom::stream(Tab& tab, std::ostream& os) const { if (has_bang()) os << '!'; - PiExpr::Dom::stream(tab, os); - if (filter()) print(os, "@({})", filter()); + print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); + if (filter()) print(os, "@({})", S(tab, filter())); return os; } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index b534ba66c9..b46db41ba0 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -12,8 +12,6 @@ #include "thorin/ast/parser.h" #include "thorin/be/h/bootstrap.h" #include "thorin/pass/optimize.h" -#include "thorin/pass/pass.h" -#include "thorin/pass/pipelinebuilder.h" #include "thorin/phase/phase.h" #include "thorin/util/sys.h" diff --git a/src/thorin/def.cpp b/src/thorin/def.cpp index 0068c6c9ce..4c63475992 100644 --- a/src/thorin/def.cpp +++ b/src/thorin/def.cpp @@ -5,10 +5,6 @@ #include "thorin/rewrite.h" #include "thorin/world.h" -#include "thorin/analyses/scope.h" - -#include "fe/assert.h" - using namespace std::literals; namespace thorin { @@ -40,6 +36,7 @@ Def::Def(World* w, node_t node, const Def* type, Defs ops, flags_t flags) } else { vars_.local = Vars(); muts_.local = Muts(); + for (auto op : extended_ops()) { vars_.local = world().merge(vars_.local, op->local_vars()); muts_.local = world().merge(muts_.local, op->local_muts()); diff --git a/src/thorin/dot.cpp b/src/thorin/dot.cpp index 5843e72be0..c5ca032339 100644 --- a/src/thorin/dot.cpp +++ b/src/thorin/dot.cpp @@ -5,7 +5,6 @@ #include "thorin/def.h" #include "thorin/world.h" -#include "thorin/analyses/scope.h" #include "thorin/util/print.h" namespace thorin { diff --git a/src/thorin/lattice.cpp b/src/thorin/lattice.cpp index ba73dfa95e..70cdaf1fd3 100644 --- a/src/thorin/lattice.cpp +++ b/src/thorin/lattice.cpp @@ -1,8 +1,5 @@ #include "thorin/lattice.h" -#include "thorin/lam.h" -#include "thorin/world.h" - #include "thorin/util/util.h" namespace thorin { diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index adf8f08a7d..f9658a811e 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -6,7 +6,6 @@ #include "thorin/rewrite.h" #include "thorin/tuple.h" -#include "thorin/analyses/scope.h" #include "thorin/util/util.h" namespace thorin { From a5be85e5360da975379bd49f669424e03a91d517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 10 Apr 2024 23:43:24 +0200 Subject: [PATCH 28/95] wip: emit lams --- include/thorin/ast/ast.h | 41 ++++------- include/thorin/world.h | 18 ++--- src/thorin/ast/ast.cpp | 2 +- src/thorin/ast/bind.cpp | 49 ++++++++------ src/thorin/ast/emit.cpp | 138 ++++++++++++++++++++++++-------------- src/thorin/ast/parser.cpp | 8 +-- src/thorin/ast/stream.cpp | 4 +- src/thorin/cli/main.cpp | 17 ++--- src/thorin/world.cpp | 6 +- 9 files changed, 157 insertions(+), 126 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index a8245fe695..f8d2d23ce2 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -152,7 +152,6 @@ class Ptrn : public Decl { bool rebind() const { return rebind_; } Dbg dbg() const { return dbg_; } bool is_anon() const { return !dbg().sym || dbg().sym == '_'; } - Ref thorin_type() const { return thorin_type_; } virtual void bind(Scopes&, bool quiet = false) const = 0; virtual Ref emit_value(Emitter&, Ref) const = 0; @@ -161,9 +160,6 @@ class Ptrn : public Decl { [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); -protected: - mutable Ref thorin_type_ = nullptr; - private: Dbg dbg_; bool rebind_; @@ -249,8 +245,8 @@ class ReturnPtrn : public Ptrn { const Expr* type() const { return type_; } void bind(Scopes&, bool quiet = false) const override; - Ref emit_value(Emitter&, Ref) const override; - Ref emit_type(Emitter&) const override; + Ref emit_value(Emitter&, Ref) const override { fe::unreachable(); } + Ref emit_type(Emitter&) const override { fe::unreachable(); } std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -418,30 +414,25 @@ class PiExpr : public Expr { bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } - const PiExpr* pi() const { return pi_; } - size_t index() const { return index_; } - bool is_first() const { return index_ == 0; } - bool is_last() const { return pi()->doms().size() == index() + 1; } - void link(const PiExpr* pi) const { pi_ = pi; } virtual void bind(Scopes& scopes, bool quiet = false) const; - virtual Ref emit(Emitter&) const; + virtual void emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: bool is_implicit_; Ptr ptrn_; size_t index_; - mutable const PiExpr* pi_ = nullptr; + mutable Pi* pi_ = nullptr; + + friend class PiExpr; }; PiExpr(Loc loc, Tok::Tag tag, Ptrs&& doms, Ptr&& codom) : Expr(loc) , tag_(tag) , doms_(std::move(doms)) - , codom_(std::move(codom)) { - for (const auto& dom : this->doms()) dom->link(this); - } + , codom_(std::move(codom)) {} private: Tok::Tag tag() const { return tag_; } @@ -456,7 +447,7 @@ class PiExpr : public Expr { private: Tok::Tag tag_; - Ptrs doms_; + mutable Ptrs doms_; Ptr codom_; }; @@ -750,6 +741,7 @@ class LamDecl : public RecDecl { class Dom : public Node { public: struct Thorin { + const Pi* pi; Lam* lam; Ref filter; }; @@ -767,15 +759,11 @@ class LamDecl : public RecDecl { bool has_bang() const { return (bool)bang(); } const Ptrn* ptrn() const { return ptrn_.get(); } const Expr* filter() const { return filter_.get(); } - const LamDecl* lam() const { return lam_; } - size_t index() const { return index_; } - bool is_first() const { return index_ == 0; } - bool is_last() const { return lam()->doms().size() == index() + 1; } - void link(const LamDecl* lam) const { lam_ = lam; } const Thorin& thorin() const { return thorin_; } void bind(Scopes& scopes, bool quiet = false) const; - void emit(Emitter&) const; + void emit_type(Emitter&) const; + void emit_value(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -784,8 +772,9 @@ class LamDecl : public RecDecl { Ptr ptrn_; Ptr filter_; size_t index_; - mutable const LamDecl* lam_; mutable Thorin thorin_; + + friend class LamDecl; }; LamDecl(Loc loc, Tok::Tag tag, bool is_external, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) @@ -793,9 +782,7 @@ class LamDecl : public RecDecl { , tag_(tag) , is_external_(is_external) , doms_(std::move(doms)) - , codom_(std::move(codom)) { - for (const auto& dom : this->doms()) dom->link(this); - } + , codom_(std::move(codom)) {} Tok::Tag tag() const { return tag_; } bool is_external() const { return is_external_; } diff --git a/include/thorin/world.h b/include/thorin/world.h index 54b0fe1ecf..785f3be9e3 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -241,13 +241,13 @@ class World { /// Pi with codom thorin::Bot%tom ///@{ // clang-format off - const Pi* cn() { return cn(sigma()); } - const Pi* cn(Ref dom ) { return pi( dom , Bot()); } - const Pi* cn(Defs dom ) { return cn(sigma(dom) ); } - const Pi* fn(Ref dom, Ref codom) { return cn({ dom , cn(codom)}); } - const Pi* fn(Defs dom, Ref codom) { return fn(sigma(dom), codom ); } - const Pi* fn(Ref dom, Defs codom) { return fn( dom , sigma(codom)); } - const Pi* fn(Defs dom, Defs codom) { return fn(sigma(dom ), sigma(codom)); } + const Pi* cn( bool implicit = false) { return cn(sigma( ), implicit); } + const Pi* cn(Ref dom, bool implicit = false) { return pi( dom , type_bot(), implicit); } + const Pi* cn(Defs dom, bool implicit = false) { return cn(sigma(dom), implicit); } + const Pi* fn(Ref dom, Ref codom, bool implicit = false) { return cn({ dom , cn(codom)}, implicit); } + const Pi* fn(Defs dom, Ref codom, bool implicit = false) { return fn(sigma(dom), codom, implicit); } + const Pi* fn(Ref dom, Defs codom, bool implicit = false) { return fn( dom , sigma(codom), implicit); } + const Pi* fn(Defs dom, Defs codom, bool implicit = false) { return fn(sigma(dom), sigma(codom), implicit); } // clang-format on ///@} @@ -411,7 +411,7 @@ class World { Ref ext(Ref type); Ref bot(Ref type) { return ext(type); } Ref top(Ref type) { return ext(type); } - Ref Bot() { return data_.Bot; } + Ref type_bot() { return data_.type_bot; } Ref top_nat() { return data_.top_nat; } template TBound* mut_bound(Ref type, size_t size) { return insert>(size, type, size); } /// A *mut*able Bound of Type @p l%evel. @@ -636,7 +636,7 @@ class World { const Univ* univ; const Type* type_0; const Type* type_1; - const thorin::Bot* Bot; + const Bot* type_bot; const Def* type_bool; const Top* top_nat; const Sigma* sigma; diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 73ca7312b8..6c5dcc3864 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -28,7 +28,7 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { void Module::compile(AST& ast, World& world) const { bind(ast); - // emit(ast, world); + emit(ast, world); } } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 903588faf3..67694065e2 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -105,8 +105,8 @@ void IdPtrn::bind(Scopes& s, bool quiet) const { } void TuplePtrn::bind(Scopes& s, bool quiet) const { - s.bind(dbg(), this, rebind(), quiet); for (const auto& ptrn : ptrns()) ptrn->bind(s, quiet); + s.bind(dbg(), this, rebind(), quiet); } void GroupPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } @@ -136,7 +136,12 @@ void PiExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } void PiExpr::bind(Scopes& s) const { s.push(); + for (const auto& dom : doms()) dom->bind(s); + + if (!codom()->isa() && tag() == Tag::K_Cn) + s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); + codom()->bind(s); s.pop(); } @@ -247,37 +252,37 @@ void LamDecl::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); - if (num_doms() != 0) { - if (auto bang = doms().back()->bang()) { - if (tag() == Tag::K_lam || tag() == Tag::T_lm) - s.ast().warn( - bang.loc(), - "'!' superfluous as the last curried function group of a '{}' receives a '.tt'-filter by default", - tag()); - if (auto filter = doms().back()->filter()) { - if (auto pe = filter->isa()) { - if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm)) - s.ast().warn(filter->loc(), - "'.tt'-filter superfluous as the last curried function group of a '{}' receives a " - "'.tt' filter by default", - tag()); - if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm)) - s.ast().warn(filter->loc(), - "'.ff'-filter superfluous as the last curried function group of a '{}' receives a " - "'.ff' filter by default", - tag()); - } - } + if (auto bang = doms().back()->bang()) { + if (tag() == Tag::K_lam || tag() == Tag::T_lm) + s.ast().warn( + bang.loc(), + "'!' superfluous as the last curried function group of a '{}' receives a '.tt'-filter by default", + tag()); + } + if (auto filter = doms().back()->filter()) { + if (auto pe = filter->isa()) { + if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm)) + s.ast().warn(filter->loc(), + "'.tt'-filter superfluous as the last curried function group of a '{}' receives a " + "'.tt' filter by default", + tag()); + if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm)) + s.ast().warn(filter->loc(), + "'.ff'-filter superfluous as the last curried function group of a '{}' receives a " + "'.ff' filter by default", + tag()); } } if (!codom()->isa() && (tag() == Tag::K_con || tag() == Tag::K_cn)) s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); codom()->bind(s); + if (tag() == Tok::Tag::K_fun) { ret_ = s.ast().ptr(s.ast(), codom()); ret_->bind(s); } + s.pop(); s.bind(dbg(), this); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 4effb8f997..de9bf9451d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -28,7 +28,7 @@ class Emitter { Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } Ref InferExpr::emit(Emitter&) const { fe::unreachable(); } -Ref IdExpr::emit(Emitter&) const { return decl_->def(); } +Ref IdExpr::emit(Emitter&) const { return decl_->def()->set(dbg()); } Ref ExtremumExpr::emit(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type<0>(); @@ -129,59 +129,38 @@ void Import::emit(Emitter& e) const { module()->emit(e); } * Ptrn::emit_value */ -Ref IdPtrn::emit_value(Emitter&, Ref def) const { return def; } +Ref IdPtrn::emit_value(Emitter&, Ref def) const { return def_ = def->set(dbg()); } Ref TuplePtrn::emit_value(Emitter& e, Ref def) const { for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_value(e, def->proj(n, i)); - return {}; + return def_ = def->set(dbg()); } -Ref GroupPtrn::emit_value(Emitter&, Ref def) const { return def; } - -Ref ReturnPtrn::emit_value(Emitter& e, Ref def) const { - type()->emit(e); - return def; -} +Ref GroupPtrn::emit_value(Emitter&, Ref def) const { return def_ = def; } /* * Ptrn::emit_Type */ -Ref IdPtrn::emit_type(Emitter& e) const { - return thorin_type_ = type() ? type()->emit(e) : e.world().mut_infer_type()->set(loc()); -} +Ref IdPtrn::emit_type(Emitter& e) const { return type() ? type()->emit(e) : e.world().mut_infer_type()->set(loc()); } Ref GroupPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } Ref TuplePtrn::emit_type(Emitter& e) const { - auto n = num_ptrns(); - auto ops = DefVec(n, [&](size_t i) { return ptrn(i)->emit_type(e); }); - - if (std::ranges::all_of(ptrns_, [](auto&& b) { return b->is_anon(); })) return e.world().sigma(ops)->set(loc()); - - assert(n > 0); - auto type = e.world().umax(ops); + auto n = num_ptrns(); + auto type = e.world().type_infer_univ(); auto sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); + auto var = sigma->var()->set(dbg()); - // assert_emplace(def2fields, sigma, Vector(n, [this](size_t i) { return ptrn(i)->sym(); })); - - sigma->set(0, ops[0]); - for (size_t i = 1; i != n; ++i) { - // if (auto infer = infers_[i - 1]) infer->set(sigma->var(n, i - 1)->set(ptrn(i - 1)->sym())); - sigma->set(i, ops[i]); + for (size_t i = 0; i != n; ++i) { + sigma->set(i, ptrn(i)->emit_type(e)); + ptrn(i)->emit_value(e, var->proj(n, i)); } - auto var = sigma->var()->as(); - VarRewriter rw(var, var); - sigma->reset(0, ops[0]); - for (size_t i = 1; i != n; ++i) sigma->reset(i, rw.rewrite(ops[i])); - if (auto imm = sigma->immutabilize()) return imm; - return thorin_type_ = sigma; + return sigma; } -Ref ReturnPtrn::emit_type(Emitter&) const { fe::unreachable(); } - /* * Expr */ @@ -197,15 +176,39 @@ Ref ArrowExpr::emit(Emitter& e) const { return e.world().pi(d, c)->set(loc()); } -Ref PiExpr::Dom::emit(Emitter&) const { - // ptrn()->emit(e); - return {}; +void PiExpr::Dom::emit(Emitter& e) const { + pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); + pi_->set_dom(ptrn()->emit_type(e)); + ptrn()->emit_value(e, pi_->var()); } Ref PiExpr::emit(Emitter& e) const { - for (const auto& dom : doms()) dom->emit(e); - codom()->emit(e); - return {}; + for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1)) dom->emit(e); + const auto& last_d = doms_.back(); + Ref cod; + + if (tag() == Tag::K_Fn) { + auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); + auto var = sigma->var()->set(last_d->loc().anew_begin()); + sigma->set(0, last_d->ptrn()->emit_type(e)); + last_d->ptrn()->emit_value(e, var->proj(2, 0)); + sigma->set(1, codom()->emit(e)); + + Ref dom_t = sigma; + if (auto imm = sigma->immutabilize()) return dom_t = imm; + + cod = e.world().cn(dom_t, last_d->is_implicit()); + } else { + cod = tag() == Tag::T_Pi ? codom()->emit(e) : e.world().type_bot(); + last_d->emit(e); + last_d->pi_->set_codom(cod); + } + + for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1) | std::ranges::views::reverse) { + dom->pi_->set_codom(cod); + cod = dom->pi_; + } + return doms().front()->pi_; } Ref LamExpr::emit(Emitter& e) const { @@ -291,9 +294,13 @@ void LetDecl::emit(Emitter& e) const { } void AxiomDecl::emit(Emitter& e) const { - type()->emit(e); + auto [plugin, tag, sub] = Annex::split(e.world(), dbg().sym); + auto p = Annex::mangle(plugin); + auto t = Annex::mangle(tag); + auto ty = type()->emit(e); if (num_subs() == 0) { + def_ = e.world().axiom(nullptr, 0, 0, ty, *p, *t, 0); } else { for (const auto& aliases : subs()) { for (const auto& alias : aliases) { @@ -310,24 +317,53 @@ void RecDecl::emit(Emitter& e) const { void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } -void LamDecl::Dom::emit(Emitter& e) const { - auto dom_t = ptrn()->emit_type(e); - auto pi = e.world().mut_pi(e.world().type_infer_univ(), is_implicit())->set_dom(dom_t); - thorin_.filter = has_bang() ? e.world().lit_tt() : filter()->emit(e); - thorin_.lam = e.world().mut_lam(pi); +void LamDecl::Dom::emit_type(Emitter& e) const { + thorin_.pi = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); + thorin_.pi->set_dom(ptrn()->emit_type(e)); + ptrn()->emit_value(e, thorin_.pi->var()); +} + +void LamDecl::Dom::emit_value(Emitter& e) const { + thorin_.lam = e.world().mut_lam(thorin_.pi); + thorin_.filter = (has_bang() || !filter()) ? e.world().lit_tt() : filter()->emit(e); // TODO ff for con/cn + ptrn()->emit_value(e, thorin_.lam->var()); } void LamDecl::emit(Emitter& e) const { - for (const auto& dom : doms()) dom->emit(e); - codom()->emit(e); + for (size_t il = 0, n = num_doms() - 1; il != n; ++il) { + for (size_t ip = il; ip != n; ++ip) dom(ip)->emit_type(e); + auto cod = codom()->emit(e); - if (is_external()) doms().front()->thorin().lam->make_external(); + for (size_t ip = n; ip-- != il;) { + dom(ip)->thorin_.pi->set_codom(cod); + cod = dom(ip)->thorin_.pi; + } + + dom(il)->emit_value(e); + auto& thorin = dom(il)->thorin_; + if (il != 0) dom(il - 1)->thorin_.lam->set(dom(il - 1)->thorin_.filter, thorin.lam); + } + + if (tag() == Tag::K_fn || tag() == Tag::K_fun) { + const auto& last_d = doms_.back(); + + auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); + auto var = sigma->var()->set(last_d->loc().anew_begin()); + sigma->set(0, last_d->ptrn()->emit_type(e)); + last_d->ptrn()->emit_value(e, var->proj(2, 0)); + sigma->set(1, codom()->emit(e)); + + last_d->thorin_.pi = e.world().cn(sigma, last_d->is_implicit()); + last_d->thorin_.pi->set_dom(last_d->ptrn()->emit_type(e)); + ptrn()->emit_value(e, thorin_.pi->var()); + } } void LamDecl::emit_rec(Emitter& e) const { - for (const auto& dom : doms()) dom->ptrn()->emit_value(e, dom->thorin().lam->var()); - // if (auto ret = lam()->ret()) ret->emit(e); - body()->emit(e); + const auto fst = doms().front().get(); + const auto lst = doms().back().get(); + lst->thorin_.lam->set(lst->thorin_.filter, body()->emit(e)); + if (is_external()) fst->thorin().lam->make_external(); } } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index a024b7b4f2..0126ed6769 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -257,7 +257,7 @@ Ptr Parser::parse_extremum_expr() { auto track = tracker(); auto tag = lex().tag(); auto [_, r] = Tok::prec(Tok::Prec::Lit); - auto type = accept(Tag::T_colon) ? parse_expr("type of "s + Tok::tag2str(tag), r) : Ptr(); + auto type = accept(Tag::T_colon) ? parse_expr("type of "s + Tok::tag2str(tag), r) : nullptr; return ptr(track, tag, std::move(type)); } @@ -265,7 +265,7 @@ Ptr Parser::parse_lit_expr() { auto track = tracker(); auto value = lex(); auto [_, r] = Tok::prec(Tok::Prec::Lit); - auto type = accept(Tag::T_colon) ? parse_expr("literal", r) : Ptr(); + auto type = accept(Tag::T_colon) ? parse_expr("literal", r) : nullptr; return ptr(track, value.dbg(), std::move(type)); } @@ -311,7 +311,7 @@ Ptr Parser::parse_pi_expr() { auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) - : nullptr; + : ptr(prev_); return ptr(track.loc(), tag, std::move(doms), std::move(codom)); } @@ -612,7 +612,7 @@ Ptr Parser::parse_lam_decl() { auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : ptr(prev_); - auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : Ptr(); + auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : nullptr; return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 07f3a01871..92d680477f 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -105,7 +105,9 @@ std::ostream& PiExpr::Dom::stream(Tab& tab, std::ostream& os) const { } std::ostream& PiExpr::stream(Tab& tab, std::ostream& os) const { - return print(os, "{}{} -> {}", tag(), R(tab, doms()), S(tab, codom())); + print(os, "{} {}", tag(), R(tab, doms())); + if (!codom()->isa()) print(os, " -> {}", S(tab, codom())); + return os; } std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{};", S(tab, lam())); } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index b46db41ba0..3d2b496735 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -172,18 +172,19 @@ int main(int argc, char** argv) { } #endif - if (os[AST]) { - auto mod = parser.import(driver.sym(input), os[Md]); - mod->compile(ast, world); + auto mod = parser.import(driver.sym(input), os[Md]); + if (auto s = os[AST]) { Tab tab; - mod->stream(tab, *os[AST]); + mod->stream(tab, *s); } - if (os[Thorin]) world.dump(*os[Thorin]); - if (os[Dot]) world.dot(*os[Dot], dot_all_annexes, dot_follow_types); + mod->compile(ast, world); - if (os[LL]) { + if (auto s = os[Thorin]) world.dump(*s); + if (auto s = os[Dot]) world.dot(*s, dot_all_annexes, dot_follow_types); + + if (auto s = os[LL]) { if (auto backend = driver.backend("ll")) - backend(world, *os[LL]); + backend(world, *s); else error("'ll' emitter not loaded; try loading 'mem' plugin"); } diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index f9658a811e..b49e08ede6 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -42,7 +42,7 @@ World::World(Driver* driver, const State& state) data_.lit_univ_1 = lit_univ(1); data_.type_0 = type(lit_univ_0()); data_.type_1 = type(lit_univ_1()); - data_.Bot = insert(0, type()); + data_.type_bot = insert(0, type()); data_.sigma = insert(0, type(), Defs{})->as(); data_.tuple = insert(0, sigma(), Defs{})->as(); data_.type_nat = insert(0, *this); @@ -55,7 +55,7 @@ World::World(Driver* driver, const State& state) data_.lit_bool[0] = lit_idx(2, 0_u64); data_.lit_bool[1] = lit_idx(2, 1_u64); data_.lit_nat_max = lit_nat(nat_t(-1)); - data_.exit = mut_lam(cn(Bot()))->set(sym("exit")); + data_.exit = mut_lam(cn(type_bot()))->set(sym("exit")); } World::World(Driver* driver) @@ -458,7 +458,7 @@ template Ref World::bound(Defs ops) { auto kind = umax(ops); // has ext value? - if (std::ranges::any_of(ops, [&](Ref op) { return Up ? bool(op->isa()) : bool(op->isa()); })) + if (std::ranges::any_of(ops, [&](Ref op) { return Up ? bool(op->isa()) : bool(op->isa()); })) return ext(kind); // ignore: ext From 6d2e230e9027d8a9cf5a73d96917f93e2f5aac08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 00:01:29 +0200 Subject: [PATCH 29/95] LamDecl::Dom inherits from PiExpr::Dom --- include/thorin/ast/ast.h | 32 +++++++++----------------- src/thorin/ast/emit.cpp | 48 ++++++++++++++++++--------------------- src/thorin/ast/parser.cpp | 6 ++--- 3 files changed, 35 insertions(+), 51 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index f8d2d23ce2..ed3b1bf36b 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -406,24 +406,24 @@ class PiExpr : public Expr { public: class Dom : public Node { public: - Dom(Loc loc, bool is_implicit, Ptr&& ptrn, size_t index) + Dom(Loc loc, bool is_implicit, Ptr&& ptrn) : Node(loc) , is_implicit_(is_implicit) - , ptrn_(std::move(ptrn)) - , index_(index) {} + , ptrn_(std::move(ptrn)) {} bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } virtual void bind(Scopes& scopes, bool quiet = false) const; - virtual void emit(Emitter&) const; + void emit_type(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; + protected: + mutable Pi* pi_ = nullptr; + private: bool is_implicit_; Ptr ptrn_; - size_t index_; - mutable Pi* pi_ = nullptr; friend class PiExpr; }; @@ -738,40 +738,30 @@ class RecDecl : public ValDecl { /// * `.fun dbg dom_0 ... dom_n-1 -> codom` class LamDecl : public RecDecl { public: - class Dom : public Node { + class Dom : public PiExpr::Dom { public: struct Thorin { - const Pi* pi; Lam* lam; Ref filter; }; - Dom(Loc loc, Tok bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter, size_t index) - : Node(loc) + Dom(Loc loc, Tok bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) + : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) , bang_(bang) - , is_implicit_(is_implicit) - , ptrn_(std::move(ptrn)) - , filter_(std::move(filter)) - , index_(index) {} + , filter_(std::move(filter)) {} - bool is_implicit() const { return is_implicit_; } Tok bang() const { return bang_; } bool has_bang() const { return (bool)bang(); } - const Ptrn* ptrn() const { return ptrn_.get(); } const Expr* filter() const { return filter_.get(); } const Thorin& thorin() const { return thorin_; } - void bind(Scopes& scopes, bool quiet = false) const; - void emit_type(Emitter&) const; + void bind(Scopes& scopes, bool quiet = false) const override; void emit_value(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: Tok bang_; - bool is_implicit_; - Ptr ptrn_; Ptr filter_; - size_t index_; mutable Thorin thorin_; friend class LamDecl; diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index de9bf9451d..a50443e287 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -176,17 +176,18 @@ Ref ArrowExpr::emit(Emitter& e) const { return e.world().pi(d, c)->set(loc()); } -void PiExpr::Dom::emit(Emitter& e) const { +void PiExpr::Dom::emit_type(Emitter& e) const { pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); pi_->set_dom(ptrn()->emit_type(e)); ptrn()->emit_value(e, pi_->var()); } Ref PiExpr::emit(Emitter& e) const { - for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1)) dom->emit(e); - const auto& last_d = doms_.back(); + for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1)) dom->emit_type(e); + // const auto& last_d = doms_.back(); Ref cod; +#if 0 if (tag() == Tag::K_Fn) { auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); auto var = sigma->var()->set(last_d->loc().anew_begin()); @@ -203,6 +204,7 @@ Ref PiExpr::emit(Emitter& e) const { last_d->emit(e); last_d->pi_->set_codom(cod); } +#endif for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1) | std::ranges::views::reverse) { dom->pi_->set_codom(cod); @@ -317,26 +319,20 @@ void RecDecl::emit(Emitter& e) const { void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } -void LamDecl::Dom::emit_type(Emitter& e) const { - thorin_.pi = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); - thorin_.pi->set_dom(ptrn()->emit_type(e)); - ptrn()->emit_value(e, thorin_.pi->var()); -} - void LamDecl::Dom::emit_value(Emitter& e) const { - thorin_.lam = e.world().mut_lam(thorin_.pi); + thorin_.lam = e.world().mut_lam(pi_); thorin_.filter = (has_bang() || !filter()) ? e.world().lit_tt() : filter()->emit(e); // TODO ff for con/cn ptrn()->emit_value(e, thorin_.lam->var()); } void LamDecl::emit(Emitter& e) const { - for (size_t il = 0, n = num_doms() - 1; il != n; ++il) { + for (size_t il = 0, n = num_doms(); il != n; ++il) { for (size_t ip = il; ip != n; ++ip) dom(ip)->emit_type(e); auto cod = codom()->emit(e); for (size_t ip = n; ip-- != il;) { - dom(ip)->thorin_.pi->set_codom(cod); - cod = dom(ip)->thorin_.pi; + dom(ip)->pi_->set_codom(cod); + cod = dom(ip)->pi_; } dom(il)->emit_value(e); @@ -344,19 +340,19 @@ void LamDecl::emit(Emitter& e) const { if (il != 0) dom(il - 1)->thorin_.lam->set(dom(il - 1)->thorin_.filter, thorin.lam); } - if (tag() == Tag::K_fn || tag() == Tag::K_fun) { - const auto& last_d = doms_.back(); - - auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); - auto var = sigma->var()->set(last_d->loc().anew_begin()); - sigma->set(0, last_d->ptrn()->emit_type(e)); - last_d->ptrn()->emit_value(e, var->proj(2, 0)); - sigma->set(1, codom()->emit(e)); - - last_d->thorin_.pi = e.world().cn(sigma, last_d->is_implicit()); - last_d->thorin_.pi->set_dom(last_d->ptrn()->emit_type(e)); - ptrn()->emit_value(e, thorin_.pi->var()); - } + // if (tag() == Tag::K_fn || tag() == Tag::K_fun) { + // const auto& last_d = doms_.back(); + // + // auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); + // auto var = sigma->var()->set(last_d->loc().anew_begin()); + // sigma->set(0, last_d->ptrn()->emit_type(e)); + // last_d->ptrn()->emit_value(e, var->proj(2, 0)); + // sigma->set(1, codom()->emit(e)); + // + // last_d->thorin_.pi = e.world().cn(sigma, last_d->is_implicit()); + // last_d->thorin_.pi->set_dom(last_d->ptrn()->emit_type(e)); + // ptrn()->emit_value(e, thorin_.pi->var()); + // } } void LamDecl::emit_rec(Emitter& e) const { diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 0126ed6769..c344267041 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -299,13 +299,12 @@ Ptr Parser::parse_pi_expr() { } Ptrs doms; - size_t i = 0; do { auto track = tracker(); auto implicit = (bool)accept(Tag::T_dot); auto prec = tag == Tag::K_Cn ? Tok::Prec::Bot : Tok::Prec::App; auto ptrn = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec); - doms.emplace_back(ptr(track, implicit, std::move(ptrn), i++)); + doms.emplace_back(ptr(track, implicit, std::move(ptrn))); } while (ahead().isa(Tag::T_dot) || ahead().isa(Tag::D_brckt_l) || ahead().isa(Tag::T_backtick) || (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon_colon))); @@ -593,7 +592,6 @@ Ptr Parser::parse_lam_decl() { auto dbg = decl ? parse_name(entity) : Dbg(); Ptrs doms; - size_t i = 0; do { auto track = tracker(); auto bang = accept(Tag::T_bang); @@ -607,7 +605,7 @@ Ptr Parser::parse_lam_decl() { expect(Tag::D_paren_r, "closing parenthesis of a filter"); } - doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter), i++)); + doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); auto codom From 16f94e577bcc83a1e5bdae35b68eea8482d49c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 01:15:20 +0200 Subject: [PATCH 30/95] wip: emit Pis & Lams --- include/thorin/ast/ast.h | 18 +++++---- src/thorin/ast/bind.cpp | 36 ++++++++--------- src/thorin/ast/emit.cpp | 85 +++++++++++++++++---------------------- src/thorin/ast/parser.cpp | 10 +++-- src/thorin/ast/stream.cpp | 9 +++-- 5 files changed, 79 insertions(+), 79 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index ed3b1bf36b..4c780b2dd3 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -413,9 +413,15 @@ class PiExpr : public Expr { bool is_implicit() const { return is_implicit_; } const Ptrn* ptrn() const { return ptrn_.get(); } + const IdPtrn* ret() const { return ret_.get(); } + + void add_ret(AST& ast, Ptr&& type) const { + auto loc = type->loc(); + ret_ = ast.ptr(loc, false, Dbg(loc, ast.sym_return()), std::move(type)); + } virtual void bind(Scopes& scopes, bool quiet = false) const; - void emit_type(Emitter&) const; + virtual void emit_type(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; protected: @@ -424,6 +430,7 @@ class PiExpr : public Expr { private: bool is_implicit_; Ptr ptrn_; + mutable Ptr ret_; friend class PiExpr; }; @@ -740,11 +747,6 @@ class LamDecl : public RecDecl { public: class Dom : public PiExpr::Dom { public: - struct Thorin { - Lam* lam; - Ref filter; - }; - Dom(Loc loc, Tok bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) , bang_(bang) @@ -753,7 +755,6 @@ class LamDecl : public RecDecl { Tok bang() const { return bang_; } bool has_bang() const { return (bool)bang(); } const Expr* filter() const { return filter_.get(); } - const Thorin& thorin() const { return thorin_; } void bind(Scopes& scopes, bool quiet = false) const override; void emit_value(Emitter&) const; @@ -762,7 +763,8 @@ class LamDecl : public RecDecl { private: Tok bang_; Ptr filter_; - mutable Thorin thorin_; + mutable Lam* lam_; + mutable Ref thorin_filter_; friend class LamDecl; }; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 67694065e2..104deed674 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -136,13 +136,11 @@ void PiExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } void PiExpr::bind(Scopes& s) const { s.push(); - for (const auto& dom : doms()) dom->bind(s); - - if (!codom()->isa() && tag() == Tag::K_Cn) - s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); - - codom()->bind(s); + if (codom()) { + if (tag() == Tag::K_Cn) s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); + codom()->bind(s); + } s.pop(); } @@ -240,12 +238,17 @@ void RecDecl::bind(Scopes& s) const { void RecDecl::bind_rec(Scopes& s) const { body()->bind(s); } void LamDecl::Dom::bind(Scopes& s, bool quiet) const { - if (!quiet && has_bang() && filter()) { - s.ast().error(filter()->loc(), "explicit filter specified on top of '!' annotation"); - s.ast().note(bang().loc(), "'!' here"); - } - ptrn()->bind(s, quiet); + if (ret()) ret()->bind(s); + + if (filter() && !quiet) { + if (has_bang()) { + s.ast().error(filter()->loc(), "explicit filter specified on top of '!' annotation"); + s.ast().note(bang().loc(), "'!' here"); + } + + filter()->bind(s); + } } void LamDecl::bind(Scopes& s) const { @@ -274,13 +277,10 @@ void LamDecl::bind(Scopes& s) const { } } - if (!codom()->isa() && (tag() == Tag::K_con || tag() == Tag::K_cn)) - s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); - codom()->bind(s); - - if (tag() == Tok::Tag::K_fun) { - ret_ = s.ast().ptr(s.ast(), codom()); - ret_->bind(s); + if (codom()) { + if (tag() == Tag::K_con || tag() == Tag::K_cn) + s.ast().error(codom()->loc(), "a continuation shall not have a codomain"); + codom()->bind(s); } s.pop(); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index a50443e287..41d6429d2b 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -177,39 +177,35 @@ Ref ArrowExpr::emit(Emitter& e) const { } void PiExpr::Dom::emit_type(Emitter& e) const { - pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); - pi_->set_dom(ptrn()->emit_type(e)); + pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); + auto type = ptrn()->emit_type(e); + + if (ret()) { + auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(ret()->loc()); + auto var = sigma->var()->set(ret()->loc().anew_begin()); + sigma->set(0, type); + ptrn()->emit_value(e, var->proj(2, 0)); + sigma->set(1, e.world().cn(ret()->emit_type(e))); + + if (auto imm = sigma->immutabilize()) + type = imm; + else + type = sigma; + } + + pi_->set_dom(type); ptrn()->emit_value(e, pi_->var()); } Ref PiExpr::emit(Emitter& e) const { - for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1)) dom->emit_type(e); - // const auto& last_d = doms_.back(); - Ref cod; - -#if 0 - if (tag() == Tag::K_Fn) { - auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); - auto var = sigma->var()->set(last_d->loc().anew_begin()); - sigma->set(0, last_d->ptrn()->emit_type(e)); - last_d->ptrn()->emit_value(e, var->proj(2, 0)); - sigma->set(1, codom()->emit(e)); - - Ref dom_t = sigma; - if (auto imm = sigma->immutabilize()) return dom_t = imm; - - cod = e.world().cn(dom_t, last_d->is_implicit()); - } else { - cod = tag() == Tag::T_Pi ? codom()->emit(e) : e.world().type_bot(); - last_d->emit(e); - last_d->pi_->set_codom(cod); - } -#endif + for (const auto& dom : doms()) dom->emit_type(e); - for (const auto& dom : doms() | std::ranges::views::take(num_doms() - 1) | std::ranges::views::reverse) { + auto cod = codom() ? codom()->emit(e) : e.world().type_bot(); + for (const auto& dom : doms() | std::ranges::views::reverse) { dom->pi_->set_codom(cod); cod = dom->pi_; } + return doms().front()->pi_; } @@ -320,15 +316,22 @@ void RecDecl::emit(Emitter& e) const { void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } void LamDecl::Dom::emit_value(Emitter& e) const { - thorin_.lam = e.world().mut_lam(pi_); - thorin_.filter = (has_bang() || !filter()) ? e.world().lit_tt() : filter()->emit(e); // TODO ff for con/cn - ptrn()->emit_value(e, thorin_.lam->var()); + lam_ = e.world().mut_lam(pi_); + thorin_filter_ = (has_bang() || !filter()) ? e.world().lit_tt() : filter()->emit(e); // TODO ff for con/cn + auto var = lam_->var(); + + if (ret()) { + ptrn()->emit_value(e, var->proj(2, 0)); + ret()->emit_value(e, var->proj(2, 1)); + } else { + ptrn()->emit_value(e, var); + } } void LamDecl::emit(Emitter& e) const { for (size_t il = 0, n = num_doms(); il != n; ++il) { for (size_t ip = il; ip != n; ++ip) dom(ip)->emit_type(e); - auto cod = codom()->emit(e); + auto cod = codom() ? codom()->emit(e) : e.world().type_bot(); for (size_t ip = n; ip-- != il;) { dom(ip)->pi_->set_codom(cod); @@ -336,30 +339,18 @@ void LamDecl::emit(Emitter& e) const { } dom(il)->emit_value(e); - auto& thorin = dom(il)->thorin_; - if (il != 0) dom(il - 1)->thorin_.lam->set(dom(il - 1)->thorin_.filter, thorin.lam); + if (il != 0) + dom(il - 1)->lam_->set(dom(il - 1)->thorin_filter_, dom(il)->lam_); + else + dom(il)->lam_->set(dbg().sym)->set(dbg().loc); } - - // if (tag() == Tag::K_fn || tag() == Tag::K_fun) { - // const auto& last_d = doms_.back(); - // - // auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(last_d->loc() + codom()->loc().finis); - // auto var = sigma->var()->set(last_d->loc().anew_begin()); - // sigma->set(0, last_d->ptrn()->emit_type(e)); - // last_d->ptrn()->emit_value(e, var->proj(2, 0)); - // sigma->set(1, codom()->emit(e)); - // - // last_d->thorin_.pi = e.world().cn(sigma, last_d->is_implicit()); - // last_d->thorin_.pi->set_dom(last_d->ptrn()->emit_type(e)); - // ptrn()->emit_value(e, thorin_.pi->var()); - // } } void LamDecl::emit_rec(Emitter& e) const { const auto fst = doms().front().get(); const auto lst = doms().back().get(); - lst->thorin_.lam->set(lst->thorin_.filter, body()->emit(e)); - if (is_external()) fst->thorin().lam->make_external(); + lst->lam_->set(lst->thorin_filter_, body()->emit(e)); + if (is_external()) fst->lam_->make_external(); } } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index c344267041..60b652b9a5 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -310,7 +310,9 @@ Ptr Parser::parse_pi_expr() { auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) - : ptr(prev_); + : nullptr; + + if (tag == Tag::K_Fn) doms.back()->add_ret(ast(), std::move(codom)); return ptr(track.loc(), tag, std::move(doms), std::move(codom)); } @@ -608,8 +610,10 @@ Ptr Parser::parse_lam_decl() { doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); - auto codom - = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : ptr(prev_); + auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : nullptr; + + if (tag == Tag::K_fn || tag == Tag::K_fun) doms.back()->add_ret(ast(), std::move(codom)); + auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : nullptr; return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 92d680477f..d2a2087291 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -101,12 +101,14 @@ std::ostream& ArrowExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& PiExpr::Dom::stream(Tab& tab, std::ostream& os) const { - return print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); + print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); + if (ret()) print(os, " -> {}", S(tab, ret()->type())); + return os; } std::ostream& PiExpr::stream(Tab& tab, std::ostream& os) const { print(os, "{} {}", tag(), R(tab, doms())); - if (!codom()->isa()) print(os, " -> {}", S(tab, codom())); + if (codom()) print(os, " -> {}", S(tab, codom())); return os; } @@ -180,6 +182,7 @@ std::ostream& LamDecl::Dom::stream(Tab& tab, std::ostream& os) const { if (has_bang()) os << '!'; print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); if (filter()) print(os, "@({})", S(tab, filter())); + if (ret()) print(os, ": {}", S(tab, ret()->type())); return os; } @@ -187,7 +190,7 @@ std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { print(os, "{} {}", tag(), dbg()); if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; print(os, "{}", R(tab, doms())); - if (!codom()->isa()) print(os, ": {}", S(tab, codom())); + if (codom()) print(os, ": {}", S(tab, codom())); if (body()) print(os, " = {}", S(tab, body())); return os; } From 004b277aaa11a21323131af40571405752ccc92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 02:18:57 +0200 Subject: [PATCH 31/95] emit: cleanup + RetExpr --- docs/coding.md | 2 +- docs/langref.md | 32 +++++++++--------- include/thorin/ast/ast.h | 3 +- src/thorin/ast/bind.cpp | 3 +- src/thorin/ast/emit.cpp | 70 ++++++++++++++++++++++++---------------- 5 files changed, 62 insertions(+), 48 deletions(-) diff --git a/docs/coding.md b/docs/coding.md index 7b45fb8ddb..315cec4f42 100644 --- a/docs/coding.md +++ b/docs/coding.md @@ -231,7 +231,7 @@ to configure the project. ### add_thorin_plugin Registers a new Thorin plugin. -``` +```cmake add_thorin_plugin( [SOURCES ...] [PRIVATE ...] diff --git a/docs/langref.md b/docs/langref.md index 16d25081ea..45e2f1de44 100644 --- a/docs/langref.md +++ b/docs/langref.md @@ -219,7 +219,7 @@ Tuple patterns allow for *groups*: * `[a b c: .Nat, d e: .Bool]` means `[a: .Nat, b: .Nat, c: .Nat, d: .Bool, e: .Bool]`. You can introduce an optional name for the whole tuple pattern: -``` +```rust .let abc::(a, b, c) = (1, 2, 3); ``` This will bind @@ -229,7 +229,7 @@ This will bind * `abc` to `(1, 2, 3)`. Here is another example: -``` +```rust Π.Tas::[T: *, as: .Nat][%mem.M, %mem.Ptr Tas] → [%mem.M, T] ``` @@ -237,7 +237,7 @@ Here is another example: Finally, you can put a \` in front of an identifier of a `()`-style pattern to (potentially) rebind a name to a different value. This is particularly useful, when dealing with memory: -``` +```rust .let (`mem, ptr) = %mem.alloc (I32, 0) mem; .let `mem = %mem.store (mem, ptr, 23:I32); .let (`mem, val) = %mem.load (mem, ptr); @@ -255,7 +255,7 @@ This is particularly useful, when dealing with memory: | e | `□` | alias for `.Type (1:.Univ)` | [Type](@ref thorin::Type) | | e | `.Nat` | natural number | [Nat](@ref thorin::Nat) | | e | `.Idx` | builtin of type `.Nat → *` | [Idx](@ref thorin::Idx) | -| e | `.Bool` | alias for `.Bool` | [Idx](@ref thorin::Idx) | +| e | `.Bool` | alias for `.Bool` | [Idx](@ref thorin::Idx) | #### Literals & Co. @@ -319,15 +319,15 @@ Expressions nesting is disambiguated according to the following precedence table @note The domain of a dependent function type binds slightly stronger than `→`. This has the effect that -``` +```rust Π T: * → T → T ``` has the expected binding like this: -``` +```rust (Π T: *) → (T → T) ``` Otherwise, `→` would be consumed by the domain: -``` +```rust Π T: (* → (T → T)) ↯ ``` @@ -344,7 +344,7 @@ The following table summarizes the different tokens used for functions declarati ### Declarations The following function *declarations* are all equivalent: -``` +```rust .lam f(T: *)((x y: T), return: T → ⊥)@(.ff): ⊥ = return x; .con f(T: *)((x y: T), return: .Cn T) = return x; .fun f(T: *) (x y: T): T = return x; @@ -355,7 +355,7 @@ Note that all partial evaluation filters default to `.tt` except for `.con`/`.cn The following function *expressions* are all equivalent. What is more, since they are bound by a *let declaration*, they have the exact same effect as the function *declarations* above: -``` +```rust .let f = λ (T: *)((x y: T), return: T → ⊥)@(.ff): ⊥ = return x; .let f = .lm (T: *)((x y: T), return: T → ⊥) : ⊥ = return x; .let f = .cn (T: *)((x y: T), return: .Cn T) = return x; @@ -365,7 +365,7 @@ What is more, since they are bound by a *let declaration*, they have the exact s ### Applications The following expressions for applying `f` are also equivalent: -``` +```rust f .Nat ((23, 42), .cn res: .Nat = use(res)) .ret res = f .Nat $ (23, 42); use(res) ``` @@ -373,7 +373,7 @@ f .Nat ((23, 42), .cn res: .Nat = use(res)) ### Function Types Finally, the following function types are all equivalent and denote the type of `f` above. -``` +```rust Π [T:*][[T, T], T → ⊥] → ⊥ .Cn [T:*][[T, T], .Cn T] .Fn [T:*] [T, T] → T @@ -393,16 +393,16 @@ Hence, using the symbol `_` will always result in a scoping error. ### Pis @note **Only** -``` +```rust Π x: e → e ``` introduces a new scope whereas -``` +```rust x: e → e ``` is a syntax error. If the variable name of a Pi's domain is elided and the domain is a sigma, its elements will be imported into the Pi's scope to make these elements available in the Pi's codomain: -``` +```rust Π [T: *, U: *] → [T, U] ``` @@ -417,12 +417,12 @@ Named elements of mutable sigmas are available for extracts/inserts. @note These names take precedence over the usual scope. In the following example, `i` refers to the first element `i` of `X` and **not** to the `i` introduced via `.let`: -``` +```rust .let i = 1_2; Π X: [i: .Nat, j: .Nat] → f X#i; ``` Use parentheses to refer to the `.let`-bounded `i`: -``` +```rust .let i = 1_2; Π X: [i: .Nat, j: .Nat] → f X#(i); ``` diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 4c780b2dd3..a777872b6d 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -757,14 +757,13 @@ class LamDecl : public RecDecl { const Expr* filter() const { return filter_.get(); } void bind(Scopes& scopes, bool quiet = false) const override; - void emit_value(Emitter&) const; + Lam* emit_value(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: Tok bang_; Ptr filter_; mutable Lam* lam_; - mutable Ref thorin_filter_; friend class LamDecl; }; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 104deed674..48a59a70ac 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -155,9 +155,10 @@ void AppExpr::bind(Scopes& s) const { } void RetExpr::bind(Scopes& s) const { - ptrn()->bind(s); callee()->bind(s); arg()->bind(s); + ptrn()->bind(s); + body()->bind(s); } void SigmaExpr::bind(Scopes& s) const { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 41d6429d2b..fc4f0dac5f 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -181,11 +181,13 @@ void PiExpr::Dom::emit_type(Emitter& e) const { auto type = ptrn()->emit_type(e); if (ret()) { - auto sigma = e.world().mut_sigma(e.world().type_infer_univ(), 2)->set(ret()->loc()); - auto var = sigma->var()->set(ret()->loc().anew_begin()); + auto ret_t = e.world().cn(ret()->emit_type(e)); + auto sigma_t = e.world().umax({type, ret_t}); + auto sigma = e.world().mut_sigma(sigma_t, 2)->set(ret()->loc()); + auto var = sigma->var()->set(ret()->loc().anew_begin()); sigma->set(0, type); ptrn()->emit_value(e, var->proj(2, 0)); - sigma->set(1, e.world().cn(ret()->emit_type(e))); + sigma->set(1, ret_t); if (auto imm = sigma->immutabilize()) type = imm; @@ -222,17 +224,22 @@ Ref AppExpr::emit(Emitter& e) const { } Ref RetExpr::emit(Emitter& e) const { - // ptrn()->emit(e); - callee()->emit(e); - arg()->emit(e); - return {}; -} + auto c = callee()->emit(e); + if (auto cn = Pi::ret_pi(c->type())) { + auto con = e.world().mut_lam(cn); + auto pair = e.world().tuple({arg()->emit(e), con}); + auto app = e.world().app(c, pair)->set(c->loc() + arg()->loc()); + ptrn()->emit_value(e, con->var()); + con->set(false, body()->emit(e)); + return app; + } -Ref SigmaExpr::emit(Emitter&) const { - // ptrn()->emit(e); - return {}; + error(c->loc(), "callee of a .ret expression must type as a returning continuation but got '{}' of type '{}'", c, + c->type()); } +Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } + Ref TupleExpr::emit(Emitter& e) const { DefVec elems(num_elems(), [&](size_t i) { return elem(i)->emit(e); }); return e.world().tuple(elems)->set(loc()); @@ -315,10 +322,9 @@ void RecDecl::emit(Emitter& e) const { void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } -void LamDecl::Dom::emit_value(Emitter& e) const { - lam_ = e.world().mut_lam(pi_); - thorin_filter_ = (has_bang() || !filter()) ? e.world().lit_tt() : filter()->emit(e); // TODO ff for con/cn - auto var = lam_->var(); +Lam* LamDecl::Dom::emit_value(Emitter& e) const { + lam_ = e.world().mut_lam(pi_); + auto var = lam_->var(); if (ret()) { ptrn()->emit_value(e, var->proj(2, 0)); @@ -326,31 +332,39 @@ void LamDecl::Dom::emit_value(Emitter& e) const { } else { ptrn()->emit_value(e, var); } + + return lam_; } void LamDecl::emit(Emitter& e) const { - for (size_t il = 0, n = num_doms(); il != n; ++il) { - for (size_t ip = il; ip != n; ++ip) dom(ip)->emit_type(e); + // Iterate over all doms: Build a Lam for cur dom, by furst building a curried Pi for the remaining doms. + for (size_t i = 0, n = num_doms(); i != n; ++i) { + for (const auto& dom : doms() | std::ranges::views::drop(i)) dom->emit_type(e); auto cod = codom() ? codom()->emit(e) : e.world().type_bot(); - for (size_t ip = n; ip-- != il;) { - dom(ip)->pi_->set_codom(cod); - cod = dom(ip)->pi_; + for (const auto& dom : doms() | std::ranges::views::drop(i) | std::ranges::views::reverse) { + dom->pi_->set_codom(cod); + cod = dom->pi_; } - dom(il)->emit_value(e); - if (il != 0) - dom(il - 1)->lam_->set(dom(il - 1)->thorin_filter_, dom(il)->lam_); + auto cur = dom(i); + auto lam = cur->emit_value(e); + auto f = cur->has_bang() ? e.world().lit_tt() + : cur->filter() ? cur->filter()->emit(e) + : (tag() == Tag::T_lm || tag() == Tag::K_lam) ? e.world().lit_tt() + : e.world().lit_ff(); + lam->set_filter(f); + + if (i == 0) + def_ = lam->set(dbg()); else - dom(il)->lam_->set(dbg().sym)->set(dbg().loc); + dom(i - 1)->lam_->set_body(lam); } } void LamDecl::emit_rec(Emitter& e) const { - const auto fst = doms().front().get(); - const auto lst = doms().back().get(); - lst->lam_->set(lst->thorin_filter_, body()->emit(e)); - if (is_external()) fst->lam_->make_external(); + doms().back()->lam_->set_body(body()->emit(e)); + if (is_external()) doms().front()->lam_->make_external(); } } // namespace thorin::ast From fd3b933465dd1d7382f46a257f97b88fa4591497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 02:33:32 +0200 Subject: [PATCH 32/95] emit: char --- include/thorin/ast/ast.h | 13 +++++++------ src/thorin/ast/emit.cpp | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index a777872b6d..04d45a9885 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -279,21 +279,22 @@ class IdExpr : public Expr { /// `tag` class PrimaryExpr : public Expr { public: - PrimaryExpr(Loc loc, Tok::Tag tag) - : Expr(loc) - , tag_(tag) {} PrimaryExpr(Tok tok) : Expr(tok.loc()) - , tag_(tok.tag()) {} + , tok_(tok) {} + PrimaryExpr(Loc loc, Tok::Tag tag) + : Expr(loc) + , tok_(loc, tag) {} - Tok::Tag tag() const { return tag_; } + Tok tok() const { return tok_; } + Tok::Tag tag() const { return tok_.tag(); } void bind(Scopes&) const override; Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Tok::Tag tag_; + Tok tok_; }; /// `tag:type` diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index fc4f0dac5f..70f43e0672 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -26,7 +26,7 @@ class Emitter { */ Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } -Ref InferExpr::emit(Emitter&) const { fe::unreachable(); } +Ref InferExpr::emit(Emitter& e) const { return e.world().type_infer_univ(); } Ref IdExpr::emit(Emitter&) const { return decl_->def()->set(dbg()); } @@ -105,7 +105,7 @@ Ref PrimaryExpr ::emit(Emitter& e) const { case Tag::K_I16: return e.world().type_i16(); case Tag::K_I32: return e.world().type_i32(); case Tag::K_I64: return e.world().type_i64(); - case Tag::M_char: return nullptr; // TODO + case Tag::M_char: return e.world().lit_i8(tok().chr()); case Tag::T_star: return e.world().type<0>(); case Tag::T_box: return e.world().type<1>(); default: fe::unreachable(); From 5bba5044aab7315a6ea4051e5cdabcf874b2de9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 04:24:07 +0200 Subject: [PATCH 33/95] improve error handling --- include/thorin/ast/ast.h | 24 +++++---------- include/thorin/def.h | 9 ------ include/thorin/util/dbg.h | 65 +++++++++++++++++++++++++++++++++------ src/thorin/ast/ast.cpp | 1 + src/thorin/check.cpp | 19 +++++++----- src/thorin/cli/main.cpp | 2 +- src/thorin/world.cpp | 39 +++++++++++++---------- 7 files changed, 100 insertions(+), 59 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 04d45a9885..f97e8ac3c3 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -31,6 +31,7 @@ class AST { , sym_return_(sym("return")) {} Driver& driver() { return driver_; } + const Error& error() { return err_; } /// @name Sym ///@{ @@ -47,30 +48,19 @@ class AST { /// @name Formatted Output ///@{ - /// Prefixes error message with `: error: `. - template void error(Loc loc, const char* fmt, Args&&... args) const { - ++num_errors_; - print(std::cerr, "{}{}: {}error: {}", rang::fg::yellow, loc, rang::fg::red, rang::fg::reset); - println(std::cerr, fmt, std::forward(args)...); - } - template void warn(Loc loc, const char* fmt, Args&&... args) const { - ++num_warnings_; - print(std::cerr, "{}{}: {}warning: {}", rang::fg::yellow, loc, rang::fg::magenta, rang::fg::reset); - println(std::cerr, fmt, std::forward(args)...); - } - template void note(Loc loc, const char* fmt, Args&&... args) const { - print(std::cerr, "{}{}: {}note: {}", rang::fg::yellow, loc, rang::fg::green, rang::fg::reset); - println(std::cerr, fmt, std::forward(args)...); - } + // clang-format off + template Error& error(Loc loc, const char* fmt, Args&&... args) const { return err_.error(loc, fmt, std::forward(args)...); } + template Error& warn (Loc loc, const char* fmt, Args&&... args) const { return err_.warn (loc, fmt, std::forward(args)...); } + template Error& note (Loc loc, const char* fmt, Args&&... args) const { return err_.note (loc, fmt, std::forward(args)...); } + // clang-format on ///@} private: - mutable int num_errors_ = 0; - mutable int num_warnings_ = 0; Driver& driver_; fe::Arena arena_; Sym sym_anon_; Sym sym_return_; + mutable Error err_; }; class Node : public fe::RuntimeCast { diff --git a/include/thorin/def.h b/include/thorin/def.h index 02c850c9cf..befaf615e6 100644 --- a/include/thorin/def.h +++ b/include/thorin/def.h @@ -614,15 +614,6 @@ std::ostream& operator<<(std::ostream&, const Def*); std::ostream& operator<<(std::ostream&, Ref); ///@} -/// @name Formatted Output -///@{ -/// Uses @p def->loc() as Loc%ation. -template -[[noreturn]] void error(const Def* def, const char* fmt, Args&&... args) { - error(def->loc(), fmt, std::forward(args)...); -} -///@} - /// @name DefDef ///@{ using DefDef = std::tuple; diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 4d9910fd2b..28147df029 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "thorin/util/print.h" @@ -18,21 +19,67 @@ using fe::Loc; using fe::Pos; using fe::Sym; -struct Error : std::logic_error { - Error(Loc loc, const std::string& what) - : std::logic_error(what) - , loc(loc) {} +struct Error : std::exception { + enum class Tag { + Error, + Warn, + Note, + }; - Loc loc; + struct Msg { + Loc loc; + Tag tag; + std::string str; + + friend std::ostream& operator<<(std::ostream& os, const Msg& msg) { + return print(os, "{}{}: {}: {}{}", rang::fg::yellow, msg.loc, msg.tag, rang::fg::reset, msg.str); + } + }; + + Error() = default; + Error(Loc loc, const std::string& str) + : msgs{ + {loc, Tag::Error, str} + } {} + + template Error& msg(Loc loc, Tag tag, const char* f, Args&&... args) { + msgs.emplace_back(loc, tag, fmt(f, std::forward(args)...)); + return *this; + } + + // clang-format off + template Error& error(Loc loc, const char* f, Args&&... args) { ++num_errors; return msg(loc, Tag::Error, f, std::forward(args)...); } + template Error& warn (Loc loc, const char* f, Args&&... args) { ++num_warnings; return msg(loc, Tag::Warn, f, std::forward(args)...); } + template Error& note (Loc loc, const char* f, Args&&... args) { ++num_notes; return msg(loc, Tag::Note, f, std::forward(args)...); } + // clang-format on + + friend std::ostream& operator<<(std::ostream& o, Tag tag) { + // clang-format off + switch (tag) { + case Tag::Error: return o << rang::fg::red << "error"; + case Tag::Warn: return o << rang::fg::magenta << "warning"; + case Tag::Note: return o << rang::fg::green << "note"; + default: fe::unreachable(); + } + // clang-format on + } + + friend std::ostream& operator<<(std::ostream& os, const Error& e) { + for (const auto& msg : e.msgs) os << msg << std::endl; + return os; + } + + std::vector msgs; + int num_errors = 0; + int num_warnings = 0; + int num_notes = 0; }; /// @name Formatted Output ///@{ /// Prefixes error message with `: error: `. -template [[noreturn]] void error(Loc loc, const char* fmt, Args&&... args) { - std::ostringstream o; - print(o, fmt, std::forward(args)...); - throw Error(loc, o.str()); +template [[noreturn]] void error(Loc loc, const char* f, Args&&... args) { + throw Error(loc, fmt(f, std::forward(args)...)); } ///@} diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 6c5dcc3864..10c45355af 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -28,6 +28,7 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { void Module::compile(AST& ast, World& world) const { bind(ast); + if (ast.error().num_errors) throw ast.error(); emit(ast, world); } diff --git a/src/thorin/check.cpp b/src/thorin/check.cpp index 883fddfe66..4979a84705 100644 --- a/src/thorin/check.cpp +++ b/src/thorin/check.cpp @@ -225,7 +225,7 @@ Ref Check::is_uniform(Defs defs) { void Arr::check() { auto t = body()->unfold_type(); if (!Check::alpha(t, type())) - error(type(), "declared sort '{}' of array does not match inferred one '{}'", type(), t); + error(type()->loc(), "declared sort '{}' of array does not match inferred one '{}'", type(), t); } void Sigma::check() { @@ -233,12 +233,17 @@ void Sigma::check() { } void Lam::check() { - if (!Check::alpha(filter()->type(), world().type_bool())) - error(filter(), "filter '{}' of lambda is of type '{}' but must be of type '.Bool'", filter(), + if (!Check::alpha(filter()->type(), world().type_bool())) { + error(filter()->loc(), "filter '{}' of lambda is of type '{}' but must be of type '.Bool'", filter(), filter()->type()); - if (!Check::assignable(codom(), body())) - error(body(), "body '{}' of lambda is of type \n'{}' but its codomain is of type \n'{}'", body(), - body()->type(), codom()); + } + if (!Check::assignable(codom(), body())) { + throw Error() + .error(body()->loc(), "body of function is not assignable to declared codomain") + .note(body()->loc(), "body: '{}'", body()) + .note(body()->loc(), "type: '{}'", body()->type()) + .note(codom()->loc(), "codomain: '{}'", codom()); + } } Ref Pi::infer(Ref dom, Ref codom) { @@ -249,7 +254,7 @@ Ref Pi::infer(Ref dom, Ref codom) { void Pi::check() { auto t = infer(dom(), codom()); if (!Check::alpha(t, type())) - error(type(), "declared sort '{}' of function type does not match inferred one '{}'", type(), t); + error(type()->loc(), "declared sort '{}' of function type does not match inferred one '{}'", type(), t); } #ifndef DOXYGEN diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 3d2b496735..2ec1d23395 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -189,7 +189,7 @@ int main(int argc, char** argv) { error("'ll' emitter not loaded; try loading 'mem' plugin"); } } catch (const Error& e) { // e.loc.path doesn't exist anymore in outer scope so catch Error here - errln("{}{}: {}error:{} {}", rang::fg::yellow, e.loc, rang::fg::red, rang::fg::reset, e.what()); + std::cerr << e; return EXIT_FAILURE; } } catch (const std::exception& e) { diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index b49e08ede6..e5ed8066dd 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -90,14 +90,16 @@ const Def* World::register_annex(flags_t f, const Def* def) { const Type* World::type(Ref level) { if (!level->type()->isa()) - error(level, "argument `{}` to `.Type` must be of type `.Univ` but is of type `{}`", level, level->type()); + error(level->loc(), "argument `{}` to `.Type` must be of type `.Univ` but is of type `{}`", level, + level->type()); return unify(1, level)->as(); } Ref World::uinc(Ref op, level_t offset) { if (!op->type()->isa()) - error(op, "operand '{}' of a universe increment must be of type `.Univ` but is of type `{}`", op, op->type()); + error(op->loc(), "operand '{}' of a universe increment must be of type `.Univ` but is of type `{}`", op, + op->type()); if (auto l = Lit::isa(op)) return lit_univ(*l + 1); return unify(1, op, offset); @@ -121,11 +123,11 @@ template Ref World::umax(Defs ops_) { if (auto type = r->isa()) r = type->level(); else - error(r, "operand '{}' must be a .Type of some level", r); + error(r->loc(), "operand '{}' must be a .Type of some level", r); } if (!r->type()->isa()) - error(r, "operand '{}' of a universe max must be of type '.Univ' but is of type '{}'", r, r->type()); + error(r->loc(), "operand '{}' of a universe max must be of type '.Univ' but is of type '{}'", r, r->type()); op = r; @@ -183,10 +185,15 @@ Ref World::app(Ref callee, Ref arg) { Infer::eliminate(Vector{&callee, &arg}); auto pi = callee->type()->isa(); - if (!pi) error(callee, "called expression '{}' : '{}' is not of function type", callee, callee->type()); - if (!Check::assignable(pi->dom(), arg)) - error(arg, "cannot pass argument \n'{}' of type \n'{}' to \n'{}' of domain \n'{}'", arg, arg->type(), callee, - pi->dom()); + if (!pi) error(callee->loc(), "called expression '{}' : '{}' is not of function type", callee, callee->type()); + if (!Check::assignable(pi->dom(), arg)) { + throw Error() + .error(arg->loc(), "cannot apply argument to callee") + .note(arg->loc(), "argument: '{}'", arg) + .note(arg->loc(), "type: '{}'", arg->type()) + .note(arg->loc(), "callee: '{}'", callee) + .note(arg->loc(), "type: '{}'", pi); + } if (auto imm = callee->isa_imm()) return imm->body(); if (auto lam = callee->isa_mut(); lam && lam->is_set() && lam->filter() != lit_ff()) { @@ -228,7 +235,7 @@ Ref World::tuple(Defs ops) { auto sigma = infer_sigma(*this, ops); auto t = tuple(sigma, ops); if (!Check::assignable(sigma, t)) - error(t, "cannot assign tuple '{}' of type '{}' to incompatible tuple type '{}'", t, t->type(), sigma); + error(t->loc(), "cannot assign tuple '{}' of type '{}' to incompatible tuple type '{}'", t, t->type(), sigma); return t; } @@ -301,7 +308,7 @@ Ref World::extract(Ref d, Ref index) { if (auto pack = d->isa_imm()) return pack->body(); if (!Check::alpha(type->arity(), size)) - error(index, "index '{}' does not fit within arity '{}'", index, type->arity()); + error(index->loc(), "index '{}' does not fit within arity '{}'", index, type->arity()); // extract(insert(x, index, val), index) -> val if (auto insert = d->isa()) { @@ -342,12 +349,12 @@ Ref World::insert(Ref d, Ref index, Ref val) { auto lidx = Lit::isa(index); if (!Check::alpha(type->arity(), size)) - error(index, "index '{}' does not fit within arity '{}'", index, type->arity()); + error(index->loc(), "index '{}' does not fit within arity '{}'", index, type->arity()); if (lidx) { auto target_type = type->proj(*lidx); if (!Check::assignable(target_type, val)) - error(val, "value of type {} is not assignable to type {}", val->type(), target_type); + error(val->loc(), "value of type {} is not assignable to type {}", val->type(), target_type); } if (auto l = Lit::isa(size); l && *l == 1) @@ -375,7 +382,7 @@ Ref World::insert(Ref d, Ref index, Ref val) { // TODO merge this code with pack Ref World::arr(Ref shape, Ref body) { - if (!is_shape(shape->type())) error(shape, "expected shape but got '{}' of type '{}'", shape, shape->type()); + if (!is_shape(shape->type())) error(shape->loc(), "expected shape but got '{}' of type '{}'", shape, shape->type()); if (auto a = Lit::isa(shape)) { if (*a == 0) return sigma(); @@ -402,7 +409,7 @@ Ref World::arr(Ref shape, Ref body) { } Ref World::pack(Ref shape, Ref body) { - if (!is_shape(shape->type())) error(shape, "expected shape but got '{}' of type '{}'", shape, shape->type()); + if (!is_shape(shape->type())) error(shape->loc(), "expected shape but got '{}' of type '{}'", shape, shape->type()); if (auto a = Lit::isa(shape)) { if (*a == 0) return tuple(); @@ -434,9 +441,9 @@ Ref World::pack(Defs shape, Ref body) { const Lit* World::lit(Ref type, u64 val) { if (auto size = Idx::size(type)) { if (auto s = Lit::isa(size)) { - if (*s != 0 && val >= *s) error(type, "index '{}' does not fit within arity '{}'", size, val); + if (*s != 0 && val >= *s) error(type->loc(), "index '{}' does not fit within arity '{}'", size, val); } else if (val != 0) { // 0 of any size is allowed - error(type, "cannot create literal '{}' of '.Idx {}' as size is unknown", val, size); + error(type->loc(), "cannot create literal '{}' of '.Idx {}' as size is unknown", val, size); } } From 37b52b07ec2bc70885ce9392a02e5eaec1f17eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 16:58:33 +0200 Subject: [PATCH 34/95] polish --- external/fe | 2 +- include/thorin/ast/lexer.h | 2 ++ include/thorin/util/dbg.h | 49 +++++++++++++++++++++++++------------- include/thorin/util/log.h | 3 +++ src/thorin/ast/ast.cpp | 2 +- src/thorin/ast/stream.cpp | 8 ++++++- 6 files changed, 46 insertions(+), 20 deletions(-) diff --git a/external/fe b/external/fe index 4c947056fb..bb688e460a 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit 4c947056fb2821325355a28ca74e61b731a98a89 +Subproject commit bb688e460af322bd89341471ac100515fee5fea4 diff --git a/include/thorin/ast/lexer.h b/include/thorin/ast/lexer.h index 1b8f34cc8b..8c1c2a1faf 100644 --- a/include/thorin/ast/lexer.h +++ b/include/thorin/ast/lexer.h @@ -9,6 +9,8 @@ namespace thorin::ast { +namespace fs = std::filesystem; + class AST; class Lexer : public fe::Lexer<3, Lexer> { diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 28147df029..956f1a94a4 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -13,13 +13,12 @@ namespace thorin { -namespace fs = std::filesystem; - using fe::Loc; using fe::Pos; using fe::Sym; -struct Error : std::exception { +class Error : std::exception { +public: enum class Tag { Error, Warn, @@ -33,25 +32,40 @@ struct Error : std::exception { friend std::ostream& operator<<(std::ostream& os, const Msg& msg) { return print(os, "{}{}: {}: {}{}", rang::fg::yellow, msg.loc, msg.tag, rang::fg::reset, msg.str); + return print(os, "{}{}: {}: {}{}", rang::fg::yellow, msg.loc, msg.tag, rang::fg::reset, msg.str); } }; + /// @name Constructors + ///@{ Error() = default; - Error(Loc loc, const std::string& str) - : msgs{ + Error(Loc loc, const std::string& str) ///< Creates a single Tag::Error message. + : msgs_{ {loc, Tag::Error, str} } {} - - template Error& msg(Loc loc, Tag tag, const char* f, Args&&... args) { - msgs.emplace_back(loc, tag, fmt(f, std::forward(args)...)); + ///@} + + /// @name Getters + ///@{ + const auto& msgs() const { return msgs_; } + int num_errors() const { return num_errors_; } + int num_warnings() const { return num_warnings_; } + int num_notes() const { return num_notes_; } + ///@} + + /// @name Add formatted message + ///@{ + template Error& msg(Loc loc, Tag tag, const char* s, Args&&... args) { + msgs_.emplace_back(loc, tag, fmt(s, std::forward(args)...)); return *this; } // clang-format off - template Error& error(Loc loc, const char* f, Args&&... args) { ++num_errors; return msg(loc, Tag::Error, f, std::forward(args)...); } - template Error& warn (Loc loc, const char* f, Args&&... args) { ++num_warnings; return msg(loc, Tag::Warn, f, std::forward(args)...); } - template Error& note (Loc loc, const char* f, Args&&... args) { ++num_notes; return msg(loc, Tag::Note, f, std::forward(args)...); } + template Error& error(Loc loc, const char* s, Args&&... args) { ++num_errors_; return msg(loc, Tag::Error, s, std::forward(args)...); } + template Error& warn (Loc loc, const char* s, Args&&... args) { ++num_warnings_; return msg(loc, Tag::Warn, s, std::forward(args)...); } + template Error& note (Loc loc, const char* s, Args&&... args) { ++num_notes_; return msg(loc, Tag::Note, s, std::forward(args)...); } // clang-format on + //@} friend std::ostream& operator<<(std::ostream& o, Tag tag) { // clang-format off @@ -65,19 +79,20 @@ struct Error : std::exception { } friend std::ostream& operator<<(std::ostream& os, const Error& e) { - for (const auto& msg : e.msgs) os << msg << std::endl; + for (const auto& msg : e.msgs()) os << msg << std::endl; return os; } - std::vector msgs; - int num_errors = 0; - int num_warnings = 0; - int num_notes = 0; +private: + std::vector msgs_; + int num_errors_ = 0; + int num_warnings_ = 0; + int num_notes_ = 0; }; /// @name Formatted Output ///@{ -/// Prefixes error message with `: error: `. +/// Single Error that `throw`s immediately. template [[noreturn]] void error(Loc loc, const char* f, Args&&... args) { throw Error(loc, fmt(f, std::forward(args)...)); } diff --git a/include/thorin/util/log.h b/include/thorin/util/log.h index e9e51f6971..4addc5674f 100644 --- a/include/thorin/util/log.h +++ b/include/thorin/util/log.h @@ -1,6 +1,7 @@ #pragma once #include + #include #include "thorin/flags.h" @@ -9,6 +10,8 @@ namespace thorin { +namespace fs = std::filesystem; + /// Facility to log what you are doing. /// @see @ref fmt "Formatted Output", @ref log "Logging Macros" class Log { diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 10c45355af..33eee70fe8 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -28,7 +28,7 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { void Module::compile(AST& ast, World& world) const { bind(ast); - if (ast.error().num_errors) throw ast.error(); + if (ast.error().num_errors() != 0) throw ast.error(); emit(ast, world); } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index d2a2087291..851150f360 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -5,6 +5,8 @@ namespace thorin::ast { +using Tag = Tok::Tag; + struct S { S(Tab& tab, const Node* node) : tab(tab) @@ -63,10 +65,14 @@ std::ostream& ReturnPtrn::stream(Tab& tab, std::ostream& os) const { */ std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", dbg()); } -std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } std::ostream& ErrorExpr::stream(Tab&, std::ostream& os) const { return os << ""; } std::ostream& InferExpr::stream(Tab&, std::ostream& os) const { return os << ""; } +std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { + if (tag() == Tag::M_char) return print(os, "'{}'", (char)tok().chr()); // TODO escape etc + return print(os, "{}", tag()); +} + std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { os << value(); if (type()) print(os, ": {}", S(tab, type())); From 642075bd2a6f6bede290fccef87a634e0c3571d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 17:06:45 +0200 Subject: [PATCH 35/95] removed ReturnPtrn: not needed anymore --- include/thorin/ast/ast.h | 21 --------------------- src/thorin/ast/bind.cpp | 6 ------ src/thorin/ast/stream.cpp | 6 ------ 3 files changed, 33 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index f97e8ac3c3..20695a835a 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -224,25 +224,6 @@ class TuplePtrn : public Ptrn { Ptrs ptrns_; }; -/// Dummy Ptrn to introduce `return: type`. -/// @note ReturnPtrn::type is **not** owned. -class ReturnPtrn : public Ptrn { -public: - ReturnPtrn(AST& ast, const Expr* type) - : Ptrn(type->loc(), false, {type->loc(), ast.sym_return()}) - , type_(type) {} - - const Expr* type() const { return type_; } - - void bind(Scopes&, bool quiet = false) const override; - Ref emit_value(Emitter&, Ref) const override { fe::unreachable(); } - Ref emit_type(Emitter&) const override { fe::unreachable(); } - std::ostream& stream(Tab&, std::ostream&) const override; - -private: - const Expr* type_; -}; - /* * Expr */ @@ -772,7 +753,6 @@ class LamDecl : public RecDecl { const Dom* dom(size_t i) const { return doms_[i].get(); } size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } - const ReturnPtrn* ret() const { return ret_.get(); } void bind(Scopes&) const override; void bind_rec(Scopes&) const override; @@ -785,7 +765,6 @@ class LamDecl : public RecDecl { bool is_external_; Ptrs doms_; Ptr codom_; - mutable Ptr ret_; }; /* diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 48a59a70ac..a7d30f18e4 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -111,11 +111,6 @@ void TuplePtrn::bind(Scopes& s, bool quiet) const { void GroupPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } -void ReturnPtrn::bind(Scopes& s, bool quiet) const { - s.bind(dbg(), this, rebind(), quiet); - // No need to check this->type(); it's shared and has already been checked. -} - /* * Expr */ @@ -291,7 +286,6 @@ void LamDecl::bind(Scopes& s) const { void LamDecl::bind_rec(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s, true); - if (ret()) ret()->bind(s, true); body()->bind(s); s.pop(); } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 851150f360..f621c7a22a 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -54,12 +54,6 @@ std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { return print(os, "{}{, }{}", delim_l(), R(tab, ptrns()), delim_r()); } -std::ostream& ReturnPtrn::stream(Tab& tab, std::ostream& os) const { - os << dbg(); - if (type()) print(os, ": {}", S(tab, type())); - return os; -} - /* * Expr */ From 9e8db1febe3083f074f14d877be8c72e8035b4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 11 Apr 2024 20:40:45 +0200 Subject: [PATCH 36/95] Annex: only use Driver instead of whole World --- include/thorin/ast/ast.h | 3 +-- include/thorin/plugin.h | 5 +++-- include/thorin/world.h | 2 +- src/thorin/ast/emit.cpp | 26 +++++++++++++++++++++++--- src/thorin/plugin.cpp | 18 +++++++++--------- src/thorin/world.cpp | 2 +- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 20695a835a..49a4cd6918 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -679,8 +679,7 @@ class AxiomDecl : public ValDecl { Dbg dbg_; std::deque subs_; Ptr type_; - Dbg normalizer_; - Dbg curry_, trip_; + Dbg normalizer_, curry_, trip_; }; /// `.rec dbg: type = body` diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index 677e40c337..7ce6ce5279 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -12,6 +12,7 @@ namespace thorin { +class Driver; class PipelineBuilder; /// @name Plugin Interface @@ -90,9 +91,9 @@ struct Annex { /// Reverts an Axiom::mangle%d string to a Sym. /// Ignores lower 16-bit of @p u. - static Sym demangle(World&, plugin_t u); + static Sym demangle(Driver&, plugin_t u); - static std::array split(World&, Sym); + static std::array split(Driver&, Sym); ///@} /// @name Annex Name diff --git a/include/thorin/world.h b/include/thorin/world.h index 785f3be9e3..70fe206325 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -165,7 +165,7 @@ class World { template const Def* annex(Id id) { auto flags = static_cast(id); if (auto i = move_.annexes.find(flags); i != move_.annexes.end()) return i->second; - error("Axiom with ID '{}' not found; demangled plugin name is '{}'", flags, Annex::demangle(*this, flags)); + error("Axiom with ID '{}' not found; demangled plugin name is '{}'", flags, Annex::demangle(driver(), flags)); } /// Get Axiom from a plugin. diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 70f43e0672..962087e09d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -13,7 +13,8 @@ class Emitter { , world_(world) {} AST& ast() const { return ast_; } - World& world() const { return world_; } + World& world() { return world_; } + Driver& driver() { return world().driver(); } private: AST& ast_; @@ -298,14 +299,33 @@ void LetDecl::emit(Emitter& e) const { def_ = ptrn()->emit_value(e, v); } +static u8 parse_u8(u8 u, Dbg dbg, std::string_view ctxt) { + if (dbg) { + auto sym = dbg.sym; + char* end; + u = std::strtoull(sym.c_str(), &end, 10); + if (sym.c_str() + sym.size() != end) error(dbg.loc, "{} count '{}' is not a number", ctxt, dbg); + } + return u; +} + void AxiomDecl::emit(Emitter& e) const { - auto [plugin, tag, sub] = Annex::split(e.world(), dbg().sym); + auto [plugin, tag, sub] = Annex::split(e.driver(), dbg().sym); + auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin, tag, dbg().loc); auto p = Annex::mangle(plugin); auto t = Annex::mangle(tag); auto ty = type()->emit(e); + auto [cu, tr] = Axiom::infer_curry_and_trip(ty); + + if (!plugin) error(dbg().loc, "invalid axiom name '{}'", dbg().sym); + if (sub) error(dbg().loc, "axiom '{}' must not have a subtag", dbg().sym); + + cu = parse_u8(cu, curry(), "curry"); + tr = parse_u8(tr, trip(), "trip"); if (num_subs() == 0) { - def_ = e.world().axiom(nullptr, 0, 0, ty, *p, *t, 0); + auto norm = e.driver().normalizer(*p, *t, 0); + def_ = e.world().axiom(norm, cu, tr, ty, *p, *t, 0); } else { for (const auto& aliases : subs()) { for (const auto& alias : aliases) { diff --git a/src/thorin/plugin.cpp b/src/thorin/plugin.cpp index 152719284f..01fe06486f 100644 --- a/src/thorin/plugin.cpp +++ b/src/thorin/plugin.cpp @@ -1,6 +1,6 @@ #include "thorin/plugin.h" -#include "thorin/world.h" +#include "thorin/driver.h" using namespace std::literals; @@ -34,12 +34,12 @@ std::optional Annex::mangle(Sym s) { return result << 16_u64; } -Sym Annex::demangle(World& world, plugin_t u) { +Sym Annex::demangle(Driver& driver, plugin_t u) { std::string result; for (size_t i = 0; i != Max_Plugin_Size; ++i) { u64 c = (u & 0xfc00000000000000_u64) >> 58_u64; if (c == 0) - return world.sym(result); + return driver.sym(result); else if (c == 1) result += '_'; else if (2 <= c && c < 28) @@ -52,10 +52,10 @@ Sym Annex::demangle(World& world, plugin_t u) { u <<= 6_u64; } - return world.sym(result); + return driver.sym(result); } -std::array Annex::split(World& world, Sym s) { +std::array Annex::split(Driver& driver, Sym s) { if (!s) return {}; if (s[0] != '%') return {}; auto sv = subview(s, 1); @@ -63,17 +63,17 @@ std::array Annex::split(World& world, Sym s) { auto dot = sv.find('.'); if (dot == std::string_view::npos) return {}; - auto plugin = world.sym(subview(sv, 0, dot)); + auto plugin = driver.sym(subview(sv, 0, dot)); if (!mangle(plugin)) return {}; auto tag = subview(sv, dot + 1); if (auto dot = tag.find('.'); dot != std::string_view::npos) { - auto sub = world.sym(subview(tag, dot + 1)); + auto sub = driver.sym(subview(tag, dot + 1)); tag = subview(tag, 0, dot); - return {plugin, world.sym(tag), sub}; + return {plugin, driver.sym(tag), sub}; } - return {plugin, world.sym(tag), {}}; + return {plugin, driver.sym(tag), {}}; } } // namespace thorin diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index e5ed8066dd..86b293da72 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -77,7 +77,7 @@ Sym World::sym(std::string_view s) { return driver().sym(s); } Sym World::sym(const std::string& s) { return driver().sym(s); } const Def* World::register_annex(flags_t f, const Def* def) { - auto plugin = Annex::demangle(*this, f); + auto plugin = Annex::demangle(driver(), f); if (driver().is_loaded(plugin)) { assert_emplace(move_.annexes, f, def); return def; From c01dd4b2f04f1e60e939560b8e9e10c947751740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 12 Apr 2024 00:47:21 +0200 Subject: [PATCH 37/95] introduce AxiomDecl::Alias --- include/thorin/ast/ast.h | 35 +++++++++++++++++++++--- include/thorin/plugin.h | 2 +- src/thorin/ast/bind.cpp | 48 ++++++++++++++++++++++++++++----- src/thorin/ast/emit.cpp | 56 ++++++++++++++++++++++----------------- src/thorin/ast/parser.cpp | 7 ++--- src/thorin/ast/stream.cpp | 4 ++- src/thorin/plugin.cpp | 2 +- 7 files changed, 113 insertions(+), 41 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 49a4cd6918..9b940fc4f8 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -502,7 +502,7 @@ class SigmaExpr : public Expr { : Expr(ptrn->loc()) , ptrn_(std::move(ptrn)) {} - const Ptrn* ptrn() const { return ptrn_.get(); } + const TuplePtrn* ptrn() const { return ptrn_.get(); } void bind(Scopes&) const override; Ref emit(Emitter&) const override; @@ -653,7 +653,27 @@ class LetDecl : public ValDecl { /// `.ax ptrn: type = value;` class AxiomDecl : public ValDecl { public: - AxiomDecl(Loc loc, Dbg dbg, std::deque&& subs, Ptr&& type, Dbg normalizer, Dbg curry, Dbg trip) + class Alias : public Decl { + public: + Alias(Dbg dbg) + : Decl(dbg.loc) + , dbg_(dbg) {} + + Dbg dbg() const { return dbg_; } + + void bind(Scopes&, const AxiomDecl*) const; + void emit(Emitter&) const; + std::ostream& stream(Tab&, std::ostream&) const override; + + private: + Dbg dbg_; + mutable Dbg full_; + mutable const AxiomDecl* axiom_ = nullptr; + + friend class AxiomDecl; + }; + + AxiomDecl(Loc loc, Dbg dbg, std::deque>&& subs, Ptr&& type, Dbg normalizer, Dbg curry, Dbg trip) : ValDecl(loc) , dbg_(dbg) , subs_(std::move(subs)) @@ -677,9 +697,18 @@ class AxiomDecl : public ValDecl { private: Dbg dbg_; - std::deque subs_; + std::deque> subs_; Ptr type_; Dbg normalizer_, curry_, trip_; + mutable struct { + Sym plugin, tag, sub; + } sym_; + mutable struct { + plugin_t plugin = 0; + tag_t tag = 0; + std::optional curry, trip; + } id_; + mutable Ref thorin_type_; }; /// `.rec dbg: type = body` diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index 7ce6ce5279..0d35832bcf 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -93,7 +93,7 @@ struct Annex { /// Ignores lower 16-bit of @p u. static Sym demangle(Driver&, plugin_t u); - static std::array split(Driver&, Sym); + static std::tuple split(Driver&, Sym); ///@} /// @name Annex Name diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index a7d30f18e4..aac2b6ead2 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -2,7 +2,7 @@ #include "fe/assert.h" -using namespace std::string_literals; +using namespace std::literals; namespace thorin::ast { @@ -27,6 +27,7 @@ class Scopes { } AST& ast() const { return ast_; } + Driver& driver() const { return ast().driver(); } Scope& top() { return scopes_.back(); } const Decl* dummy() const { return dummy_.get(); } @@ -63,10 +64,13 @@ class Scopes { } } + tag_t next_tag(plugin_t p) { return plugin2tag_.emplace(p, 0).first->second; } + private: AST& ast_; Ptr dummy_; std::deque scopes_; + absl::flat_hash_map plugin2tag_; }; /* @@ -206,18 +210,48 @@ void DeclsBlock::bind(Scopes& s) const { } } +static std::optional parse_u8(AST& ast, Dbg dbg, std::string_view ctxt) { + if (dbg) { + auto sym = dbg.sym; + char* end; + auto res = std::strtoull(sym.c_str(), &end, 10); + if (sym.c_str() + sym.size() != end) + ast.error(dbg.loc, "{} count '{}' is not a number", ctxt, dbg); + else + return res; + } + return {}; +} + +void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { + axiom_ = axiom; + auto sym = s.ast().sym(axiom->dbg().sym.str() + "."s + dbg().sym.str()); + full_ = Dbg(dbg().loc, sym); + s.bind(full_, this); +} + void AxiomDecl::bind(Scopes& s) const { type()->bind(s); + std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym); + + if (auto p = Annex::mangle(sym_.plugin)) { + id_.plugin = *p; + id_.tag = s.next_tag(*p); + } else { + s.ast().error(dbg().loc, "invalid axiom name '{}'", dbg()); + } + + if (sym_.sub) error(dbg().loc, "axiom '{}' must not have a subtag", dbg().sym); + + id_.curry = parse_u8(s.ast(), curry_, "curry"sv); + id_.trip = parse_u8(s.ast(), trip_, "trip"sv); + if (num_subs() == 0) { s.bind(dbg(), this); } else { - for (const auto& aliases : subs()) { - for (const auto& alias : aliases) { - auto sym = s.ast().sym(dbg().sym.str() + "."s + alias.sym.str()); - s.bind(Dbg(dbg().loc, sym), this); - } - } + for (const auto& aliases : subs()) + for (const auto& alias : aliases) alias->bind(s, this); } } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 962087e09d..281e8374c6 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -299,45 +299,51 @@ void LetDecl::emit(Emitter& e) const { def_ = ptrn()->emit_value(e, v); } -static u8 parse_u8(u8 u, Dbg dbg, std::string_view ctxt) { - if (dbg) { - auto sym = dbg.sym; - char* end; - u = std::strtoull(sym.c_str(), &end, 10); - if (sym.c_str() + sym.size() != end) error(dbg.loc, "{} count '{}' is not a number", ctxt, dbg); - } - return u; +void AxiomDecl::Alias::emit(Emitter& e) const { + auto norm = e.driver().normalizer(axiom_->id_.plugin, axiom_->id_.tag, 0); + const auto& id = axiom_->id_; + def_ = e.world().axiom(norm, *id.curry, *id.trip, axiom_->thorin_type_, id.plugin, id.tag, 0); } void AxiomDecl::emit(Emitter& e) const { auto [plugin, tag, sub] = Annex::split(e.driver(), dbg().sym); auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin, tag, dbg().loc); - auto p = Annex::mangle(plugin); - auto t = Annex::mangle(tag); - auto ty = type()->emit(e); - auto [cu, tr] = Axiom::infer_curry_and_trip(ty); + thorin_type_ = type()->emit(e); + auto [curry, trip] = Axiom::infer_curry_and_trip(thorin_type_); - if (!plugin) error(dbg().loc, "invalid axiom name '{}'", dbg().sym); - if (sub) error(dbg().loc, "axiom '{}' must not have a subtag", dbg().sym); + if (id_.curry) { + if (*id_.curry > curry) error(curry_.loc, "curry counter cannot be greater than {}", curry); + } else { + id_.curry = curry; + } - cu = parse_u8(cu, curry(), "curry"); - tr = parse_u8(tr, trip(), "trip"); + if (!id_.trip) id_.trip = trip; if (num_subs() == 0) { - auto norm = e.driver().normalizer(*p, *t, 0); - def_ = e.world().axiom(norm, cu, tr, ty, *p, *t, 0); + auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); + def_ = e.world().axiom(norm, curry, trip, type()->emit(e), id_.plugin, id_.tag, 0); } else { - for (const auto& aliases : subs()) { - for (const auto& alias : aliases) { - outln("{}", alias); - // auto sym = s.ast().sym(dbg().sym.str() + "."s + alias.sym.str()); - } - } + for (const auto& aliases : subs()) + for (const auto& alias : aliases) alias->emit(e); } } void RecDecl::emit(Emitter& e) const { - if (type()) type()->emit(e); + auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); + + if (auto sigma = body()->isa()) { + def_ = e.world().mut_sigma(t, sigma->ptrn()->num_ptrns()); + } else if (auto pi = body()->isa()) { + def_ = e.world().mut_pi(t); + } else if (auto lam = body()->isa()) { + if (auto infer = t->isa()) t = e.world().mut_pi(t, e.world().type_infer_univ()); + if (auto pi = t->isa()) + def_ = e.world().mut_lam(pi); + else + error(type()->loc(), "type of a function must be a function type"); + } else { + error(body()->loc(), "unsupported expression for a recursive declaration"); + } } void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 60b652b9a5..117e552dfa 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -524,12 +524,13 @@ Ptr Parser::parse_axiom_decl() { else dbg = Dbg(prev_, ast().sym("")); - std::deque subs; + std::deque> subs; if (ahead().isa(Tag::D_paren_l)) { parse_list("tag list of an axiom", Tag::D_paren_l, [&]() { auto& aliases = subs.emplace_back(); - aliases.emplace_back(parse_id("tag of an axiom")); - while (accept(Tag::T_assign)) aliases.emplace_back(parse_id("alias of an axiom tag")); + aliases.emplace_back(ptr(parse_id("tag of an axiom"))); + while (accept(Tag::T_assign)) + aliases.emplace_back(ptr(parse_id("alias of an axiom tag"))); }); } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index f621c7a22a..1edad08213 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -151,12 +151,14 @@ std::ostream& DeclsBlock::stream(Tab& tab, std::ostream& os) const { return os; } +std::ostream& AxiomDecl::Alias::stream(Tab&, std::ostream& os) const { return os << dbg(); } + std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { print(os, ".ax {}", dbg()); if (num_subs() != 0) { os << '('; for (auto sep = ""; const auto& aliases : subs()) { - print(os, "{}{ = }", sep, aliases); + print(os, "{}{ = }", sep, R(tab, aliases)); sep = ", "; } os << ')'; diff --git a/src/thorin/plugin.cpp b/src/thorin/plugin.cpp index 01fe06486f..7861ec09c7 100644 --- a/src/thorin/plugin.cpp +++ b/src/thorin/plugin.cpp @@ -55,7 +55,7 @@ Sym Annex::demangle(Driver& driver, plugin_t u) { return driver.sym(result); } -std::array Annex::split(Driver& driver, Sym s) { +std::tuple Annex::split(Driver& driver, Sym s) { if (!s) return {}; if (s[0] != '%') return {}; auto sv = subview(s, 1); From 18e227ed0810218daad2e08950d004ffb652199c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 12 Apr 2024 17:04:59 +0200 Subject: [PATCH 38/95] RecDecl now works for LamExpr --- include/thorin/ast/ast.h | 42 ++++++++++++++++++++++++++------------- src/thorin/ast/bind.cpp | 35 ++++++++++++++++++++++---------- src/thorin/ast/emit.cpp | 43 ++++++++++++++++++++++++++-------------- 3 files changed, 80 insertions(+), 40 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 9b940fc4f8..2911fc59a8 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -86,7 +86,11 @@ class Expr : public Node { public: virtual void bind(Scopes&) const = 0; + virtual void bind_decl(Scopes&) const { fe::unreachable(); } + virtual void bind_body(Scopes&) const { fe::unreachable(); } virtual Ref emit(Emitter&) const = 0; + virtual Ref emit_decl(Emitter&) const { fe::unreachable(); } + virtual void emit_body(Emitter&) const { fe::unreachable(); } }; class Decl : public Node { @@ -107,8 +111,8 @@ class ValDecl : public Decl { : Decl(loc) {} public: - virtual void bind(Scopes&) const = 0; - virtual void emit(Emitter&) const = 0; + virtual void bind_decl(Scopes&) const = 0; + virtual void emit_decl(Emitter&) const = 0; }; class DeclsBlock { @@ -215,6 +219,8 @@ class TuplePtrn : public Ptrn { size_t num_ptrns() const { return ptrns().size(); } void bind(Scopes&, bool quiet = false) const override; + void bind_decl(Scopes&) const; + void bind_body(Scopes&) const; Ref emit_value(Emitter&, Ref) const override; Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -438,7 +444,11 @@ class LamExpr : public Expr { const LamDecl* lam() const { return lam_.get(); } void bind(Scopes&) const override; + void bind_decl(Scopes&) const override; + void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; + Ref emit_decl(Emitter&) const override; + void emit_body(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -505,7 +515,11 @@ class SigmaExpr : public Expr { const TuplePtrn* ptrn() const { return ptrn_.get(); } void bind(Scopes&) const override; + void bind_decl(Scopes&) const override; + void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; + Ref emit_decl(Emitter&) const override; + void emit_body(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -641,8 +655,8 @@ class LetDecl : public ValDecl { const Ptrn* ptrn() const { return ptrn_.get(); } const Expr* value() const { return value_.get(); } - void bind(Scopes&) const override; - void emit(Emitter&) const override; + void bind_decl(Scopes&) const override; + void emit_decl(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -691,8 +705,8 @@ class AxiomDecl : public ValDecl { Dbg curry() const { return curry_; } Dbg trip() const { return trip_; } - void bind(Scopes&) const override; - void emit(Emitter&) const override; + void bind_decl(Scopes&) const override; + void emit_decl(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -724,10 +738,10 @@ class RecDecl : public ValDecl { const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } - void bind(Scopes&) const override; - void emit(Emitter&) const override; - virtual void bind_rec(Scopes&) const; - virtual void emit_rec(Emitter&) const; + void bind_decl(Scopes&) const override; + void emit_decl(Emitter&) const override; + virtual void bind_body(Scopes&) const; + virtual void emit_body(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -782,10 +796,10 @@ class LamDecl : public RecDecl { size_t num_doms() const { return doms_.size(); } const Expr* codom() const { return codom_.get(); } - void bind(Scopes&) const override; - void bind_rec(Scopes&) const override; - void emit(Emitter&) const override; - void emit_rec(Emitter&) const override; + void bind_decl(Scopes&) const override; + void bind_body(Scopes&) const override; + void emit_decl(Emitter&) const override; + void emit_body(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index aac2b6ead2..a019ee1328 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -108,6 +108,9 @@ void IdPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } +void TuplePtrn::bind_decl(Scopes& s) const {} +void TuplePtrn::bind_body(Scopes& s) const {} + void TuplePtrn::bind(Scopes& s, bool quiet) const { for (const auto& ptrn : ptrns()) ptrn->bind(s, quiet); s.bind(dbg(), this, rebind(), quiet); @@ -143,9 +146,12 @@ void PiExpr::bind(Scopes& s) const { s.pop(); } +void LamExpr::bind_decl(Scopes& s) const { lam()->bind_decl(s); } +void LamExpr::bind_body(Scopes& s) const { lam()->bind_body(s); } + void LamExpr::bind(Scopes& s) const { - lam()->bind(s); - lam()->bind_rec(s); + bind_decl(s); + bind_body(s); } void AppExpr::bind(Scopes& s) const { @@ -160,9 +166,13 @@ void RetExpr::bind(Scopes& s) const { body()->bind(s); } +void SigmaExpr::bind_decl(Scopes& s) const { ptrn()->bind_decl(s); } +void SigmaExpr::bind_body(Scopes& s) const { ptrn()->bind_body(s); } + void SigmaExpr::bind(Scopes& s) const { s.push(); - ptrn()->bind(s); + bind_decl(s); + bind_body(s); s.pop(); } @@ -201,12 +211,12 @@ void DeclsBlock::bind(Scopes& s) const { if (i < e && decl(i)->isa()) { if (!decl(r)->isa()) r = i; } else if (r < e && decl(r)->isa()) { - for (size_t j = r; j != i; ++j) decl(j)->as()->bind_rec(s); + for (size_t j = r; j != i; ++j) decl(j)->as()->bind_body(s); r = i; } if (i == e) break; - decl(i)->bind(s); + decl(i)->bind_decl(s); } } @@ -230,7 +240,7 @@ void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { s.bind(full_, this); } -void AxiomDecl::bind(Scopes& s) const { +void AxiomDecl::bind_decl(Scopes& s) const { type()->bind(s); std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym); @@ -255,17 +265,20 @@ void AxiomDecl::bind(Scopes& s) const { } } -void LetDecl::bind(Scopes& s) const { +void LetDecl::bind_decl(Scopes& s) const { value()->bind(s); ptrn()->bind(s); } -void RecDecl::bind(Scopes& s) const { +void RecDecl::bind_decl(Scopes& s) const { if (type()) type()->bind(s); s.bind(dbg(), this); + + if (!body()->isa() && !body()->isa() && !body()->isa()) + s.ast().error(body()->loc(), "unsupported expression for a recursive declaration"); } -void RecDecl::bind_rec(Scopes& s) const { body()->bind(s); } +void RecDecl::bind_body(Scopes& s) const { body()->bind(s); } void LamDecl::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); @@ -281,7 +294,7 @@ void LamDecl::Dom::bind(Scopes& s, bool quiet) const { } } -void LamDecl::bind(Scopes& s) const { +void LamDecl::bind_decl(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); @@ -317,7 +330,7 @@ void LamDecl::bind(Scopes& s) const { s.bind(dbg(), this); } -void LamDecl::bind_rec(Scopes& s) const { +void LamDecl::bind_body(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s, true); body()->bind(s); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 281e8374c6..8ff57e2aa4 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -29,7 +29,7 @@ class Emitter { Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } Ref InferExpr::emit(Emitter& e) const { return e.world().type_infer_univ(); } -Ref IdExpr::emit(Emitter&) const { return decl_->def()->set(dbg()); } +Ref IdExpr::emit(Emitter&) const { return decl_->def(); } Ref ExtremumExpr::emit(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type<0>(); @@ -212,10 +212,13 @@ Ref PiExpr::emit(Emitter& e) const { return doms().front()->pi_; } +Ref LamExpr::emit_decl(Emitter& e) const { return lam()->emit_decl(e), lam()->def(); } +void LamExpr::emit_body(Emitter& e) const { lam()->emit_body(e); } + Ref LamExpr::emit(Emitter& e) const { - lam()->emit(e); - lam()->emit_rec(e); - return lam()->def(); + auto res = emit_decl(e); + emit_body(e); + return res; } Ref AppExpr::emit(Emitter& e) const { @@ -239,6 +242,9 @@ Ref RetExpr::emit(Emitter& e) const { c->type()); } +Ref SigmaExpr::emit_decl(Emitter& e) const { return {}; } +void SigmaExpr::emit_body(Emitter& e) const {} + Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } Ref TupleExpr::emit(Emitter& e) const { @@ -285,16 +291,16 @@ void DeclsBlock::emit(Emitter& e) const { if (i < n && decl(i)->isa()) { if (!decl(r)->isa()) r = i; } else if (r < n && decl(r)->isa()) { - for (size_t j = r; j != i; ++j) decl(j)->as()->emit_rec(e); + for (size_t j = r; j != i; ++j) decl(j)->as()->emit_body(e); r = i; } if (i == n) break; - decl(i)->emit(e); + decl(i)->emit_decl(e); } } -void LetDecl::emit(Emitter& e) const { +void LetDecl::emit_decl(Emitter& e) const { auto v = value()->emit(e); def_ = ptrn()->emit_value(e, v); } @@ -305,7 +311,7 @@ void AxiomDecl::Alias::emit(Emitter& e) const { def_ = e.world().axiom(norm, *id.curry, *id.trip, axiom_->thorin_type_, id.plugin, id.tag, 0); } -void AxiomDecl::emit(Emitter& e) const { +void AxiomDecl::emit_decl(Emitter& e) const { auto [plugin, tag, sub] = Annex::split(e.driver(), dbg().sym); auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin, tag, dbg().loc); thorin_type_ = type()->emit(e); @@ -328,25 +334,32 @@ void AxiomDecl::emit(Emitter& e) const { } } -void RecDecl::emit(Emitter& e) const { +void RecDecl::emit_decl(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); + def_ = body()->emit_decl(e); +#if 0 if (auto sigma = body()->isa()) { def_ = e.world().mut_sigma(t, sigma->ptrn()->num_ptrns()); } else if (auto pi = body()->isa()) { def_ = e.world().mut_pi(t); } else if (auto lam = body()->isa()) { +# if 0 if (auto infer = t->isa()) t = e.world().mut_pi(t, e.world().type_infer_univ()); if (auto pi = t->isa()) def_ = e.world().mut_lam(pi); else error(type()->loc(), "type of a function must be a function type"); - } else { - error(body()->loc(), "unsupported expression for a recursive declaration"); +# endif + def_ = body()->emit_decl(e); } +#endif } -void RecDecl::emit_rec(Emitter& e) const { body()->emit(e); } +void RecDecl::emit_body(Emitter& e) const { + body()->emit_body(e); + def_->as_mut()->make_external(); +} Lam* LamDecl::Dom::emit_value(Emitter& e) const { lam_ = e.world().mut_lam(pi_); @@ -362,7 +375,7 @@ Lam* LamDecl::Dom::emit_value(Emitter& e) const { return lam_; } -void LamDecl::emit(Emitter& e) const { +void LamDecl::emit_decl(Emitter& e) const { // Iterate over all doms: Build a Lam for cur dom, by furst building a curried Pi for the remaining doms. for (size_t i = 0, n = num_doms(); i != n; ++i) { for (const auto& dom : doms() | std::ranges::views::drop(i)) dom->emit_type(e); @@ -382,13 +395,13 @@ void LamDecl::emit(Emitter& e) const { lam->set_filter(f); if (i == 0) - def_ = lam->set(dbg()); + def_ = lam->set(loc(), dbg().sym); else dom(i - 1)->lam_->set_body(lam); } } -void LamDecl::emit_rec(Emitter& e) const { +void LamDecl::emit_body(Emitter& e) const { doms().back()->lam_->set_body(body()->emit(e)); if (is_external()) doms().front()->lam_->make_external(); } From 546ae2306fea991d9cb23736fe11605e4693b4f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 12 Apr 2024 21:23:24 +0200 Subject: [PATCH 39/95] wip: emit rec decls --- include/thorin/ast/ast.h | 23 ++++++++++++------ include/thorin/util/dbg.h | 16 +++++++----- src/thorin/ast/ast.cpp | 2 ++ src/thorin/ast/bind.cpp | 6 +++++ src/thorin/ast/emit.cpp | 51 +++++++++++++++++++++++++-------------- src/thorin/cli/main.cpp | 2 +- 6 files changed, 67 insertions(+), 33 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 2911fc59a8..0b3e99d5c9 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -30,8 +30,11 @@ class AST { , sym_anon_(sym("_")) , sym_return_(sym("return")) {} + /// @name Getters + ///@{ Driver& driver() { return driver_; } const Error& error() { return err_; } + ///@} /// @name Sym ///@{ @@ -89,8 +92,8 @@ class Expr : public Node { virtual void bind_decl(Scopes&) const { fe::unreachable(); } virtual void bind_body(Scopes&) const { fe::unreachable(); } virtual Ref emit(Emitter&) const = 0; - virtual Ref emit_decl(Emitter&) const { fe::unreachable(); } - virtual void emit_body(Emitter&) const { fe::unreachable(); } + virtual Ref emit_decl(Emitter&, Ref /*type*/) const { fe::unreachable(); } + virtual void emit_body(Emitter&, Ref /*decl*/) const { fe::unreachable(); } }; class Decl : public Node { @@ -427,7 +430,11 @@ class PiExpr : public Expr { const Expr* codom() const { return codom_.get(); } void bind(Scopes&) const override; + void bind_decl(Scopes&) const override; + void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; + Ref emit_decl(Emitter&, Ref type) const override; + void emit_body(Emitter&, Ref decl) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -447,8 +454,8 @@ class LamExpr : public Expr { void bind_decl(Scopes&) const override; void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; - Ref emit_decl(Emitter&) const override; - void emit_body(Emitter&) const override; + Ref emit_decl(Emitter&, Ref type) const override; + void emit_body(Emitter&, Ref decl) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -518,8 +525,8 @@ class SigmaExpr : public Expr { void bind_decl(Scopes&) const override; void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; - Ref emit_decl(Emitter&) const override; - void emit_body(Emitter&) const override; + Ref emit_decl(Emitter&, Ref type) const override; + void emit_body(Emitter&, Ref decl) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -798,8 +805,8 @@ class LamDecl : public RecDecl { void bind_decl(Scopes&) const override; void bind_body(Scopes&) const override; - void emit_decl(Emitter&) const override; - void emit_body(Emitter&) const override; + void emit_decl(Emitter& e) const override; + void emit_body(Emitter& e) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 956f1a94a4..7ac5c5fee1 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -48,9 +48,13 @@ class Error : std::exception { /// @name Getters ///@{ const auto& msgs() const { return msgs_; } - int num_errors() const { return num_errors_; } - int num_warnings() const { return num_warnings_; } - int num_notes() const { return num_notes_; } + size_t num_msgs() const { + assert(num_errors() + num_warnings() + num_notes() == msgs_.size()); + return msgs_.size(); + } + size_t num_errors() const { return num_errors_; } + size_t num_warnings() const { return num_warnings_; } + size_t num_notes() const { return num_notes_; } ///@} /// @name Add formatted message @@ -85,9 +89,9 @@ class Error : std::exception { private: std::vector msgs_; - int num_errors_ = 0; - int num_warnings_ = 0; - int num_notes_ = 0; + size_t num_errors_ = 0; + size_t num_warnings_ = 0; + size_t num_notes_ = 0; }; /// @name Formatted Output diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 33eee70fe8..c16f4221f7 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -30,6 +30,8 @@ void Module::compile(AST& ast, World& world) const { bind(ast); if (ast.error().num_errors() != 0) throw ast.error(); emit(ast, world); + // HACK + if (ast.error().num_errors() == 0 && ast.error().num_msgs() != 0) std::cerr << ast.error(); } } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index a019ee1328..7cfb985c9d 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -136,6 +136,9 @@ void ArrowExpr::bind(Scopes& s) const { void PiExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } +void PiExpr::bind_decl(Scopes&) const {} +void PiExpr::bind_body(Scopes&) const {} + void PiExpr::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); @@ -272,6 +275,9 @@ void LetDecl::bind_decl(Scopes& s) const { void RecDecl::bind_decl(Scopes& s) const { if (type()) type()->bind(s); + if (!type()->isa() && body()->isa()) + s.ast().warn(type()->loc(), "type of recursive declaration ignored for function expression"); + s.bind(dbg(), this); if (!body()->isa() && !body()->isa() && !body()->isa()) diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 8ff57e2aa4..cc0dbbe751 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -178,7 +178,7 @@ Ref ArrowExpr::emit(Emitter& e) const { } void PiExpr::Dom::emit_type(Emitter& e) const { - pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); + if (!pi_) pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); auto type = ptrn()->emit_type(e); if (ret()) { @@ -200,6 +200,13 @@ void PiExpr::Dom::emit_type(Emitter& e) const { ptrn()->emit_value(e, pi_->var()); } +Ref PiExpr::emit_decl(Emitter& e, Ref type) const { + const auto& first = doms().front(); + return first->pi_ = e.world().mut_pi(type, first->is_implicit()); +} + +void PiExpr::emit_body(Emitter& e, Ref) const { emit(e); } + Ref PiExpr::emit(Emitter& e) const { for (const auto& dom : doms()) dom->emit_type(e); @@ -212,12 +219,12 @@ Ref PiExpr::emit(Emitter& e) const { return doms().front()->pi_; } -Ref LamExpr::emit_decl(Emitter& e) const { return lam()->emit_decl(e), lam()->def(); } -void LamExpr::emit_body(Emitter& e) const { lam()->emit_body(e); } +Ref LamExpr::emit_decl(Emitter& e, Ref) const { return lam()->emit_decl(e), lam()->def(); } +void LamExpr::emit_body(Emitter& e, Ref) const { lam()->emit_body(e); } Ref LamExpr::emit(Emitter& e) const { - auto res = emit_decl(e); - emit_body(e); + auto res = emit_decl(e, {}); + emit_body(e, {}); return res; } @@ -242,8 +249,8 @@ Ref RetExpr::emit(Emitter& e) const { c->type()); } -Ref SigmaExpr::emit_decl(Emitter& e) const { return {}; } -void SigmaExpr::emit_body(Emitter& e) const {} +Ref SigmaExpr::emit_decl(Emitter& e, Ref type) const { return {}; } +void SigmaExpr::emit_body(Emitter&, Ref decl) const {} Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } @@ -253,11 +260,21 @@ Ref TupleExpr::emit(Emitter& e) const { } template Ref ArrOrPackExpr::emit(Emitter& e) const { - /*auto s =*/shape()->emit(e); - if (dbg() && dbg().sym != '_') { - // auto mut = arr ? e.world().mut_arr( - body()->emit(e); + auto s = shape()->emit(e); + if (!dbg() && dbg().sym != '_') { + auto b = body()->emit(e); + return arr ? e.world().arr(s, b) : e.world().pack(s, b); + } else { +#if 0 + auto t = e.world().type_infer_univ(); + auto a = e.world().mut_arr(t); //TODO packs + a->set_shape(s); + shape() + + if (arr) +#endif } + return {}; } @@ -308,7 +325,7 @@ void LetDecl::emit_decl(Emitter& e) const { void AxiomDecl::Alias::emit(Emitter& e) const { auto norm = e.driver().normalizer(axiom_->id_.plugin, axiom_->id_.tag, 0); const auto& id = axiom_->id_; - def_ = e.world().axiom(norm, *id.curry, *id.trip, axiom_->thorin_type_, id.plugin, id.tag, 0); + def_ = e.world().axiom(norm, *id.curry, *id.trip, axiom_->thorin_type_, id.plugin, id.tag, 0)->set(dbg()); } void AxiomDecl::emit_decl(Emitter& e) const { @@ -327,7 +344,8 @@ void AxiomDecl::emit_decl(Emitter& e) const { if (num_subs() == 0) { auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); - def_ = e.world().axiom(norm, curry, trip, type()->emit(e), id_.plugin, id_.tag, 0); + def_ = e.world().axiom(norm, curry, trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); + def_->dump(); } else { for (const auto& aliases : subs()) for (const auto& alias : aliases) alias->emit(e); @@ -336,7 +354,7 @@ void AxiomDecl::emit_decl(Emitter& e) const { void RecDecl::emit_decl(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); - def_ = body()->emit_decl(e); + def_ = body()->emit_decl(e, t); #if 0 if (auto sigma = body()->isa()) { @@ -356,10 +374,7 @@ void RecDecl::emit_decl(Emitter& e) const { #endif } -void RecDecl::emit_body(Emitter& e) const { - body()->emit_body(e); - def_->as_mut()->make_external(); -} +void RecDecl::emit_body(Emitter& e) const { body()->emit_body(e, def_); } Lam* LamDecl::Dom::emit_value(Emitter& e) const { lam_ = e.world().mut_lam(pi_); diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 2ec1d23395..4f230e6851 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -179,8 +179,8 @@ int main(int argc, char** argv) { } mod->compile(ast, world); - if (auto s = os[Thorin]) world.dump(*s); if (auto s = os[Dot]) world.dot(*s, dot_all_annexes, dot_follow_types); + if (auto s = os[Thorin]) world.dump(*s); if (auto s = os[LL]) { if (auto backend = driver.backend("ll")) From 72715b09092bce7e253a5311dccdff16e42abe52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 12 Apr 2024 22:05:09 +0200 Subject: [PATCH 40/95] wip: getting more emits to work --- src/thorin/ast/bind.cpp | 9 ++++++--- src/thorin/ast/emit.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 7cfb985c9d..a278cd788d 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -81,12 +81,16 @@ class Scopes { void ExtremumExpr::bind(Scopes& s) const { if (type()) type()->bind(s); } void LitExpr ::bind(Scopes& s) const { if (type()) type()->bind(s); } void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } -void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } void ErrorExpr ::bind(Scopes&) const {} void InferExpr ::bind(Scopes&) const {} void PrimaryExpr ::bind(Scopes&) const {} // clang-format on +void IdExpr ::bind(Scopes& s) const { + decl_ = s.find(dbg()); + assert(decl_); +} + void Module::bind(AST& ast) const { auto scopes = Scopes(ast); bind(scopes); @@ -174,8 +178,7 @@ void SigmaExpr::bind_body(Scopes& s) const { ptrn()->bind_body(s); } void SigmaExpr::bind(Scopes& s) const { s.push(); - bind_decl(s); - bind_body(s); + ptrn()->bind(s); s.pop(); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index cc0dbbe751..3bbcc37fe8 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -29,7 +29,10 @@ class Emitter { Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } Ref InferExpr::emit(Emitter& e) const { return e.world().type_infer_univ(); } -Ref IdExpr::emit(Emitter&) const { return decl_->def(); } +Ref IdExpr::emit(Emitter&) const { + assert(decl()); + return decl()->def(); +} Ref ExtremumExpr::emit(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type<0>(); @@ -345,7 +348,6 @@ void AxiomDecl::emit_decl(Emitter& e) const { if (num_subs() == 0) { auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); def_ = e.world().axiom(norm, curry, trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); - def_->dump(); } else { for (const auto& aliases : subs()) for (const auto& alias : aliases) alias->emit(e); From b36b35a2f795782e55a2458b4387561886254250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 01:43:43 +0200 Subject: [PATCH 41/95] wip: emit --- include/thorin/ast/ast.h | 18 ++++++---- src/thorin/ast/bind.cpp | 16 ++++++--- src/thorin/ast/emit.cpp | 69 ++++++++++++++++++++++----------------- src/thorin/ast/parser.cpp | 5 +-- src/thorin/world.cpp | 4 +-- 5 files changed, 66 insertions(+), 46 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 0b3e99d5c9..a0a4a1c254 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -175,6 +175,10 @@ class IdPtrn : public Ptrn { auto loc = type->loc(); return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } + static Ptr mk_id(AST& ast, Dbg dbg, Ptr&& type) { + auto loc = (type && dbg) ? dbg.loc + type->loc() : type ? type->loc() : dbg.loc; + return ast.ptr(loc, false, dbg, std::move(type)); + } void bind(Scopes&, bool quiet = false) const override; Ref emit_value(Emitter&, Ref) const override; @@ -406,7 +410,8 @@ class PiExpr : public Expr { std::ostream& stream(Tab&, std::ostream&) const override; protected: - mutable Pi* pi_ = nullptr; + mutable Pi* pi_ = nullptr; + mutable Pi* decl_ = nullptr; private: bool is_implicit_; @@ -557,14 +562,12 @@ class TupleExpr : public Expr { /// `«dbg: shape; body»` or `‹dbg: shape; body›` template class ArrOrPackExpr : public Expr { public: - ArrOrPackExpr(Loc loc, Dbg dbg, Ptr&& shape, Ptr&& body) + ArrOrPackExpr(Loc loc, Ptr&& shape, Ptr&& body) : Expr(loc) - , dbg_(dbg) , shape_(std::move(shape)) , body_(std::move(body)) {} - Dbg dbg() const { return dbg_; } - const Expr* shape() const { return shape_.get(); } + const IdPtrn* shape() const { return shape_.get(); } const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; @@ -572,8 +575,7 @@ template class ArrOrPackExpr : public Expr { std::ostream& stream(Tab&, std::ostream&) const override; private: - Dbg dbg_; - Ptr shape_; + Ptr shape_; Ptr body_; }; @@ -594,6 +596,7 @@ class ExtractExpr : public Expr { const Expr* tuple() const { return tuple_.get(); } const auto& index() const { return index_; } + const Decl* decl() const { return decl_; } void bind(Scopes&) const override; Ref emit(Emitter&) const override; @@ -602,6 +605,7 @@ class ExtractExpr : public Expr { private: Ptr tuple_; std::variant, Dbg> index_; + mutable const Decl* decl_ = nullptr; }; /// `.ins(tuple, index, value)` diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index a278cd788d..195db72e3c 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -38,14 +38,16 @@ class Scopes { scopes_.pop_back(); } - const Decl* find(Dbg dbg) { + const Decl* find(Dbg dbg, bool quiet = false) { if (!dbg || dbg.sym == '_') return nullptr; for (auto& scope : scopes_ | std::ranges::views::reverse) if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; - ast().error(dbg.loc, "'{}' not found", dbg.sym); - bind(dbg, dummy()); // put into scope to prevent further errors + if (!quiet) { + ast().error(dbg.loc, "'{}' not found", dbg.sym); + bind(dbg, dummy()); // put into scope to prevent further errors + } return nullptr; } @@ -198,8 +200,12 @@ template void ArrOrPackExpr::bind(Scopes&) const; void ExtractExpr::bind(Scopes& s) const { tuple()->bind(s); - if (auto expr = std::get_if>(&index())) (*expr)->bind(s); - // We check for Dbg case during "emit" as we need full type info. + if (auto expr = std::get_if>(&index())) + (*expr)->bind(s); + else { + auto dbg = std::get(index()); + decl_ = s.find(dbg, true); + } } void InsertExpr::bind(Scopes& s) const { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 3bbcc37fe8..444eb60f85 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -16,10 +16,11 @@ class Emitter { World& world() { return world_; } Driver& driver() { return world().driver(); } + absl::node_hash_map, GIDHash, GIDEq> sigma2sym2idx; + private: AST& ast_; World& world_; - DefMap> fields_; }; /* @@ -72,6 +73,7 @@ Ref LitExpr::emit(Emitter& e) const { if (*end == '\0') { if (sign) error(loc, "negative .Nat literal '{}' not allowed", value()); + if (type()) return e.world().lit(type()->emit(e), val); return e.world().lit_nat(val)->set(loc); } @@ -151,14 +153,16 @@ Ref IdPtrn::emit_type(Emitter& e) const { return type() ? type()->emit(e) : e.wo Ref GroupPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } Ref TuplePtrn::emit_type(Emitter& e) const { - auto n = num_ptrns(); - auto type = e.world().type_infer_univ(); - auto sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); - auto var = sigma->var()->set(dbg()); + auto n = num_ptrns(); + auto type = e.world().type_infer_univ(); + auto sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); + auto var = sigma->var()->set(dbg()); + auto& sym2idx = e.sigma2sym2idx[sigma]; for (size_t i = 0; i != n; ++i) { sigma->set(i, ptrn(i)->emit_type(e)); ptrn(i)->emit_value(e, var->proj(n, i)); + sym2idx[ptrn(i)->dbg().sym] = i; } if (auto imm = sigma->immutabilize()) return imm; @@ -181,7 +185,7 @@ Ref ArrowExpr::emit(Emitter& e) const { } void PiExpr::Dom::emit_type(Emitter& e) const { - if (!pi_) pi_ = e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); + pi_ = decl_ ? decl_ : e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); auto type = ptrn()->emit_type(e); if (ret()) { @@ -204,8 +208,8 @@ void PiExpr::Dom::emit_type(Emitter& e) const { } Ref PiExpr::emit_decl(Emitter& e, Ref type) const { - const auto& first = doms().front(); - return first->pi_ = e.world().mut_pi(type, first->is_implicit()); + const auto& first = doms().front(); + return first->decl_ = e.world().mut_pi(type, first->is_implicit()); } void PiExpr::emit_body(Emitter& e, Ref) const { emit(e); } @@ -234,7 +238,7 @@ Ref LamExpr::emit(Emitter& e) const { Ref AppExpr::emit(Emitter& e) const { auto c = callee()->emit(e); auto a = arg()->emit(e); - return e.world().app(c, a)->set(loc()); + return e.world().iapp(c, a)->set(loc()); } Ref RetExpr::emit(Emitter& e) const { @@ -252,8 +256,8 @@ Ref RetExpr::emit(Emitter& e) const { c->type()); } -Ref SigmaExpr::emit_decl(Emitter& e, Ref type) const { return {}; } -void SigmaExpr::emit_body(Emitter&, Ref decl) const {} +Ref SigmaExpr::emit_decl(Emitter&, Ref) const { return {}; } +void SigmaExpr::emit_body(Emitter&, Ref) const {} Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } @@ -263,36 +267,41 @@ Ref TupleExpr::emit(Emitter& e) const { } template Ref ArrOrPackExpr::emit(Emitter& e) const { - auto s = shape()->emit(e); - if (!dbg() && dbg().sym != '_') { + auto s = shape()->emit_type(e); + if (shape()->is_anon()) { auto b = body()->emit(e); return arr ? e.world().arr(s, b) : e.world().pack(s, b); - } else { -#if 0 - auto t = e.world().type_infer_univ(); - auto a = e.world().mut_arr(t); //TODO packs - a->set_shape(s); - shape() - - if (arr) -#endif } - - return {}; + auto t = e.world().type_infer_univ(); + auto a = e.world().mut_arr(t); // TODO packs + a->set_shape(s); + auto var = a->var(); + shape()->emit_value(e, var); + return a->set_body(body()->emit(e)); } template Ref ArrOrPackExpr::emit(Emitter&) const; template Ref ArrOrPackExpr::emit(Emitter&) const; Ref ExtractExpr::emit(Emitter& e) const { - auto t = tuple()->emit(e); - if (auto expr = std::get_if>(&index())) { - auto i = (*expr)->emit(e); - return e.world().extract(t, i)->set(loc()); + auto tup = tuple()->emit(e); + if (auto dbg = std::get_if(&index())) { + if (auto sigma = tup->type()->isa_mut()) { + if (auto i = e.sigma2sym2idx.find(sigma); i != e.sigma2sym2idx.end()) { + auto sigma = i->first->as_mut(); + const auto& sym2idx = i->second; + if (auto i = sym2idx.find(dbg->sym); i != sym2idx.end()) + return e.world().extract(tup, sigma->num_ops(), i->second)->set(loc()); + } + } + + if (decl()) return e.world().extract(tup, decl()->def())->set(loc()); + error(dbg->loc, "cannot resolve index '{}' for extraction", dbg); } - // auto dbg = std::get(index()); - return {}; + auto expr = std::get>(index()).get(); + auto i = expr->emit(e); + return e.world().extract(tup, i)->set(loc()); } Ref InsertExpr::emit(Emitter& e) const { diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 117e552dfa..7461381c23 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -215,7 +215,7 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::T_bot: case Tag::T_top: return parse_extremum_expr(); case Tag::M_anx: - case Tag::M_id: return ptr(lex().dbg()); + case Tag::M_id: return ptr(lex().dbg()); //case Tag::M_str: return world().tuple(lex().sym())->set(prev_); default: if (ctxt.empty()) return nullptr; @@ -236,12 +236,13 @@ template Ptr Parser::parse_arr_or_pack_expr() { } auto shape = parse_expr(arr ? "shape of an array" : "shape of a pack"); + auto ptrn = IdPtrn::mk_id(ast(), dbg, std::move(shape)); expect(Tag::T_semicolon, arr ? "array" : "pack"); auto body = parse_expr(arr ? "body of an array" : "body of a pack"); expect(arr ? Tag::D_quote_r : Tag::D_angle_r, arr ? "closing delimiter of an array" : "closing delimiter of a pack"); - return ptr>(track, dbg, std::move(shape), std::move(body)); + return ptr>(track, std::move(ptrn), std::move(body)); } Ptr Parser::parse_block_expr(std::string_view ctxt) { diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 86b293da72..1f65fe47bc 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -191,8 +191,8 @@ Ref World::app(Ref callee, Ref arg) { .error(arg->loc(), "cannot apply argument to callee") .note(arg->loc(), "argument: '{}'", arg) .note(arg->loc(), "type: '{}'", arg->type()) - .note(arg->loc(), "callee: '{}'", callee) - .note(arg->loc(), "type: '{}'", pi); + .note(callee->loc(), "callee: '{}'", callee) + .note(callee->loc(), "type: '{}'", pi); } if (auto imm = callee->isa_imm()) return imm->body(); From 682f17fde04a4582f732d6dd2d59e75e4a6c845f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 01:48:16 +0200 Subject: [PATCH 42/95] bug fix --- src/thorin/ast/emit.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 444eb60f85..94ba7e9fa9 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -201,10 +201,11 @@ void PiExpr::Dom::emit_type(Emitter& e) const { type = imm; else type = sigma; + pi_->set_dom(type); + } else { + pi_->set_dom(type); + ptrn()->emit_value(e, pi_->var()); } - - pi_->set_dom(type); - ptrn()->emit_value(e, pi_->var()); } Ref PiExpr::emit_decl(Emitter& e, Ref type) const { From 9ea0001bfe79b6968ca89ec8daa7dae2609eb08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 02:40:16 +0200 Subject: [PATCH 43/95] wip: emit --- include/thorin/ast/ast.h | 19 ++++++------------- include/thorin/ast/parser.h | 15 ++++++++++++--- src/thorin/ast/bind.cpp | 2 +- src/thorin/ast/emit.cpp | 6 ++++-- src/thorin/ast/parser.cpp | 36 ++++++++++++++---------------------- src/thorin/ast/stream.cpp | 7 ++++++- 6 files changed, 43 insertions(+), 42 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index a0a4a1c254..144d8cc37d 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -824,18 +824,11 @@ class LamDecl : public RecDecl { * Module */ -class Import { +class Import : public Node { public: - Import& operator=(const Import&) = delete; - Import(const Import&) = delete; - Import() noexcept = default; - - Import(Import&& other) - : Import() { - swap(*this, other); - } - Import(Dbg dbg, Tok::Tag tag, Ptr&& module) noexcept - : dbg_(dbg) + Import(Loc loc, Dbg dbg, Tok::Tag tag, Ptr&& module) + : Node(loc) + , dbg_(dbg) , tag_(tag) , module_(std::move(module)) {} @@ -862,7 +855,7 @@ class Import { class Module : public Node { public: - Module(Loc loc, std::deque&& imports, Ptrs&& decls) + Module(Loc loc, Ptrs&& imports, Ptrs&& decls) : Node(loc) , imports_(std::move(imports)) , decls_(std::move(decls)) {} @@ -877,7 +870,7 @@ class Module : public Node { std::ostream& stream(Tab&, std::ostream&) const override; private: - std::deque imports_; + Ptrs imports_; DeclsBlock decls_; }; diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 6d6c03eacd..1d224ebc05 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -28,6 +28,8 @@ constexpr size_t Look_Ahead = 2; /// * If default argument is **elided** we have the same behavior as in 1. /// * If default argument is **provided** we have the same behavior as in 2. class Parser : public fe::Parser { + using Super = fe::Parser; + public: Parser(AST& ast) : ast_(ast) {} @@ -55,8 +57,8 @@ class Parser : public fe::Parser { Dbg parse_id(std::string_view ctxt = {}); std::pair parse_annex(std::string_view ctxt = {}); Dbg parse_name(std::string_view ctxt = {}); - Import parse_import(); - Import parse_plugin(); + Ptr parse_import_or_plugin(); + Ptr parse_plugin(); Ptr parse_type_ascr(std::string_view ctxt = {}); template void parse_list(std::string ctxt, Tok::Tag delim_l, F f, Tok::Tag sep = Tok::Tag::T_comma) { @@ -129,12 +131,19 @@ class Parser : public fe::Parser { msg.append(Tok::tag2str(tag)).append("'"); syntax_err(msg, ctxt); } + + using Super::expect; + template Tok expect(Tok::Tag tag, const char* f, Args&&... args) { + std::ostringstream oss; + print(oss, f, std::forward(args)...); + return Super::expect(tag, oss.str()); + } ///@} AST& ast_; Lexer* lexer_ = nullptr; - friend class fe::Parser; + friend Super; }; } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 195db72e3c..a3cc63516c 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -99,7 +99,7 @@ void Module::bind(AST& ast) const { } void Module::bind(Scopes& s) const { - for (const auto& import : imports()) import.bind(s); + for (const auto& import : imports()) import->bind(s); decls_.bind(s); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 94ba7e9fa9..6688b27e6c 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -125,7 +125,7 @@ void Module::emit(AST& ast, World& world) const { } void Module::emit(Emitter& e) const { - for (const auto& import : imports()) import.emit(e); + for (const auto& import : imports()) import->emit(e); decls_.emit(e); } @@ -406,7 +406,9 @@ void LamDecl::emit_decl(Emitter& e) const { // Iterate over all doms: Build a Lam for cur dom, by furst building a curried Pi for the remaining doms. for (size_t i = 0, n = num_doms(); i != n; ++i) { for (const auto& dom : doms() | std::ranges::views::drop(i)) dom->emit_type(e); - auto cod = codom() ? codom()->emit(e) : e.world().type_bot(); + auto cod = codom() ? codom()->emit(e) + : (tag() == Tag::T_lm || tag() == Tag::K_lam) ? e.world().mut_infer_type() + : e.world().type_bot(); for (const auto& dom : doms() | std::ranges::views::drop(i) | std::ranges::views::reverse) { dom->pi_->set_codom(cod); diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 7461381c23..1fe25f2ce9 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -17,15 +17,14 @@ using Tag = Tok::Tag; Ptr Parser::parse_module() { auto track = tracker(); - std::deque imports; - while (true) - if (ahead().tag() == Tag::K_import) - imports.emplace_back(parse_import()); - else if (ahead().tag() == Tag::K_plugin) - imports.emplace_back(parse_plugin()); - else + Ptrs imports; + while (true) { + if (ahead().isa(Tag::K_import) || ahead().isa(Tag::K_plugin)) { + if (auto import = parse_import_or_plugin()) imports.emplace_back(std::move(import)); + } else { break; - + } + } auto decls = parse_decls(); expect(Tag::EoF, "module"); return ptr(track, std::move(imports), std::move(decls)); @@ -75,20 +74,13 @@ Ptr Parser::plugin(Sym name) { * misc */ -Import Parser::parse_import() { - eat(Tag::K_import); - auto name = expect(Tag::M_id, "import name"); - expect(Tag::T_semicolon, "end of import"); - auto module = import(name.sym()); - return Import(name.dbg(), Tag::K_import, std::move(module)); -} - -Import Parser::parse_plugin() { - eat(Tag::K_plugin); - auto name = expect(Tag::M_id, "thorin/plugin name"); - expect(Tag::T_semicolon, "end of import"); - auto module = plugin(name.sym()); - return Import(name.dbg(), Tag::K_plugin, std::move(module)); +Ptr Parser::parse_import_or_plugin() { + auto track = tracker(); + auto tag = lex().tag(); + auto name = expect(Tag::M_id, "{} name", tag == Tag::K_import ? "import" : "plugin"); + expect(Tag::T_semicolon, "end of {}", tag == Tag::K_import ? "import" : "plugin"); + if (auto module = import(name.sym())) return ptr(track, name.dbg(), tag, std::move(module)); + return {}; } Dbg Parser::parse_id(std::string_view ctxt) { diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 1edad08213..43eb95950e 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -201,6 +201,11 @@ std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { * Module */ -std::ostream& Module::stream(Tab& tab, std::ostream& os) const { return decls_.stream(tab, os); } +std::ostream& Import::stream(Tab&, std::ostream& os) const { return println(os, "{} '{}';", tag(), "TODO"); } + +std::ostream& Module::stream(Tab& tab, std::ostream& os) const { + for (const auto& import : imports()) import->stream(tab, os); + return decls_.stream(tab, os); +} } // namespace thorin::ast From dd77870ce194bff7c619510a727df321f8b3002b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 18:11:48 +0200 Subject: [PATCH 44/95] emit: make lits work again --- include/thorin/ast/ast.h | 65 ++++++++--------------- include/thorin/ast/tok.h | 47 +++++++++++----- include/thorin/world.h | 2 + src/thorin/ast/bind.cpp | 36 ++++++------- src/thorin/ast/emit.cpp | 109 ++++++++++++++------------------------ src/thorin/ast/lexer.cpp | 54 ++++++++++++------- src/thorin/ast/parser.cpp | 36 +++++-------- src/thorin/ast/stream.cpp | 14 ++--- src/thorin/ast/tok.cpp | 2 +- src/thorin/cli/main.cpp | 2 +- src/thorin/world.cpp | 1 + 11 files changed, 170 insertions(+), 198 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 144d8cc37d..13a09617ed 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -25,14 +25,15 @@ template using Ptrs = std::deque>; class AST { public: - AST(Driver& driver) - : driver_(driver) + AST(World& world) + : world_(world) , sym_anon_(sym("_")) , sym_return_(sym("return")) {} /// @name Getters ///@{ - Driver& driver() { return driver_; } + World& world() { return world_; } + Driver& driver() { return world().driver(); } const Error& error() { return err_; } ///@} @@ -59,7 +60,7 @@ class AST { ///@} private: - Driver& driver_; + World& world_; fe::Arena arena_; Sym sym_anon_; Sym sym_return_; @@ -263,53 +264,32 @@ class IdExpr : public Expr { /// `tag` class PrimaryExpr : public Expr { public: - PrimaryExpr(Tok tok) - : Expr(tok.loc()) - , tok_(tok) {} PrimaryExpr(Loc loc, Tok::Tag tag) : Expr(loc) - , tok_(loc, tag) {} + , tag_(tag) {} + PrimaryExpr(Tok tok) + : PrimaryExpr(tok.loc(), tok.tag()) {} - Tok tok() const { return tok_; } - Tok::Tag tag() const { return tok_.tag(); } + Tok::Tag tag() const { return tag_; } void bind(Scopes&) const override; Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: - Tok tok_; + Tok::Tag tag_; }; -/// `tag:type` +/// `tok:type` class LitExpr : public Expr { public: - LitExpr(Loc loc, Dbg value, Ptr&& type) + LitExpr(Loc loc, Tok tok, Ptr&& type) : Expr(loc) - , value_(value) + , tok_(tok) , type_(std::move(type)) {} - Dbg value() const { return value_; } - const Expr* type() const { return type_.get(); } - - void bind(Scopes&) const override; - Ref emit(Emitter&) const override; - std::ostream& stream(Tab&, std::ostream&) const override; - -private: - Dbg value_; - Ptr type_; -}; - -/// `tag:type` -class ExtremumExpr : public Expr { -public: - ExtremumExpr(Loc loc, Tok::Tag tag, Ptr&& type) - : Expr(loc) - , tag_(tag) - , type_(std::move(type)) {} - - Tok::Tag tag() const { return tag_; } + Tok tok() const { return tok_; } + Tok::Tag tag() const { return tok_.tag(); } const Expr* type() const { return type_.get(); } void bind(Scopes&) const override; @@ -317,7 +297,7 @@ class ExtremumExpr : public Expr { std::ostream& stream(Tab&, std::ostream&) const override; private: - Tok::Tag tag_; + Tok tok_; Ptr type_; }; @@ -687,7 +667,7 @@ class AxiomDecl : public ValDecl { Dbg dbg() const { return dbg_; } void bind(Scopes&, const AxiomDecl*) const; - void emit(Emitter&) const; + void emit(Emitter&, sub_t) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -698,7 +678,7 @@ class AxiomDecl : public ValDecl { friend class AxiomDecl; }; - AxiomDecl(Loc loc, Dbg dbg, std::deque>&& subs, Ptr&& type, Dbg normalizer, Dbg curry, Dbg trip) + AxiomDecl(Loc loc, Dbg dbg, std::deque>&& subs, Ptr&& type, Dbg normalizer, Tok curry, Tok trip) : ValDecl(loc) , dbg_(dbg) , subs_(std::move(subs)) @@ -713,8 +693,8 @@ class AxiomDecl : public ValDecl { const auto& sub(size_t i) const { return subs_[i]; } const Expr* type() const { return type_.get(); } Dbg normalizer() const { return normalizer_; } - Dbg curry() const { return curry_; } - Dbg trip() const { return trip_; } + Tok curry() const { return curry_; } + Tok trip() const { return trip_; } void bind_decl(Scopes&) const override; void emit_decl(Emitter&) const override; @@ -724,14 +704,15 @@ class AxiomDecl : public ValDecl { Dbg dbg_; std::deque> subs_; Ptr type_; - Dbg normalizer_, curry_, trip_; + Dbg normalizer_; + Tok curry_, trip_; mutable struct { Sym plugin, tag, sub; } sym_; mutable struct { plugin_t plugin = 0; tag_t tag = 0; - std::optional curry, trip; + uint8_t curry, trip; } id_; mutable Ref thorin_type_; }; diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index f44b81cb53..17de21c5fb 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -53,12 +53,15 @@ constexpr auto Num_Keys = size_t(0) THORIN_KEY(CODE); #define THORIN_TOK(m) \ m(EoF, "" ) \ /* literals */ \ + m(L_s, "") \ + m(L_u, "" ) \ + m(L_i, "" ) \ + m(L_f, "") \ + m(L_c, "" ) \ + m(L_str, "" ) \ /* misc */ \ m(M_id, "" ) \ m(M_anx, "" ) \ - m(M_str, "" ) \ - m(M_lit, "" ) \ - m(M_char, "") \ /* delimiters */ \ m(D_angle_l, "‹") \ m(D_angle_r, "›") \ @@ -150,26 +153,42 @@ class Tok { , tag_(tag) {} Tok(Loc loc, char8_t c) : loc_(loc) - , tag_(Tag::M_char) + , tag_(Tag::L_c) , c_(c) {} + Tok(Loc loc, uint64_t u) + : loc_(loc) + , tag_(Tag::L_u) + , u_(u) {} + Tok(Loc loc, int64_t s) + : loc_(loc) + , tag_(Tag::L_s) + , u_(std::bit_cast(s)) {} + Tok(Loc loc, double d) + : loc_(loc) + , tag_(Tag::L_f) + , u_(std::bit_cast(d)) {} + Tok(Loc loc, const Lit* i) + : loc_(loc) + , tag_(Tag::L_i) + , i_(i) {} Tok(Loc loc, Tag tag, Sym sym) : loc_(loc) , tag_(tag) - , sym_(sym) {} + , sym_(sym) { + assert(tag == Tag::M_id || tag == Tag::M_anx || tag == Tag::L_str); + } bool isa(Tag tag) const { return tag == tag_; } Tag tag() const { return tag_; } Dbg dbg() const { return {loc(), sym()}; } Loc loc() const { return loc_; } explicit operator bool() const { return tag_ != Tag::Nil; } - char8_t chr() const { - assert(isa(Tag::M_char)); - return c_; - } - Sym sym() const { - assert(isa(Tag::M_anx) || isa(Tag::M_id) || isa(Tag::M_str) || isa(Tag::M_lit)); - return sym_; - } + // clang-format off + const Lit* lit_i() const { assert(isa(Tag::L_i)); return i_; } + char8_t lit_c() const { assert(isa(Tag::L_c)); return c_; } + uint64_t lit_u() const { assert(isa(Tag::L_u ) || isa(Tag::L_s ) || isa(Tag::L_f )); return u_; } + Sym sym() const { assert(isa(Tag::M_anx) || isa(Tag::M_id) || isa(Tag::L_str)); return sym_; } + // clang-format on std::string str() const; friend std::ostream& operator<<(std::ostream&, Tok); @@ -180,7 +199,9 @@ class Tok { Tag tag_ = Tag::Nil; union { Sym sym_; + uint64_t u_; char8_t c_; + const Lit* i_; }; }; diff --git a/include/thorin/world.h b/include/thorin/world.h index 70fe206325..10373452f0 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -412,6 +412,7 @@ class World { Ref bot(Ref type) { return ext(type); } Ref top(Ref type) { return ext(type); } Ref type_bot() { return data_.type_bot; } + Ref type_top() { return data_.type_top; } Ref top_nat() { return data_.top_nat; } template TBound* mut_bound(Ref type, size_t size) { return insert>(size, type, size); } /// A *mut*able Bound of Type @p l%evel. @@ -637,6 +638,7 @@ class World { const Type* type_0; const Type* type_1; const Bot* type_bot; + const Top* type_top; const Def* type_bool; const Top* top_nat; const Sigma* sigma; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index a3cc63516c..498f580e71 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -80,8 +80,6 @@ class Scopes { */ // clang-format off -void ExtremumExpr::bind(Scopes& s) const { if (type()) type()->bind(s); } -void LitExpr ::bind(Scopes& s) const { if (type()) type()->bind(s); } void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } void ErrorExpr ::bind(Scopes&) const {} void InferExpr ::bind(Scopes&) const {} @@ -93,6 +91,16 @@ void IdExpr ::bind(Scopes& s) const { assert(decl_); } +void LitExpr::bind(Scopes& s) const { + if (type()) { + type()->bind(s); + if (tag() == Tag::L_str || tag() == Tag::L_c || tag() == Tag::L_i) + s.ast().error(type()->loc(), "a {} shall not have a type annotation", tag()); + } else { + if (tag() == Tag::L_f) s.ast().error(loc(), "type annotation mandatory for floating point literal"); + } +} + void Module::bind(AST& ast) const { auto scopes = Scopes(ast); bind(scopes); @@ -140,7 +148,10 @@ void ArrowExpr::bind(Scopes& s) const { codom()->bind(s); } -void PiExpr::Dom::bind(Scopes& s, bool quiet) const { ptrn()->bind(s, quiet); } +void PiExpr::Dom::bind(Scopes& s, bool quiet) const { + ptrn()->bind(s, quiet); + if (ret()) ret()->bind(s, quiet); +} void PiExpr::bind_decl(Scopes&) const {} void PiExpr::bind_body(Scopes&) const {} @@ -232,19 +243,6 @@ void DeclsBlock::bind(Scopes& s) const { } } -static std::optional parse_u8(AST& ast, Dbg dbg, std::string_view ctxt) { - if (dbg) { - auto sym = dbg.sym; - char* end; - auto res = std::strtoull(sym.c_str(), &end, 10); - if (sym.c_str() + sym.size() != end) - ast.error(dbg.loc, "{} count '{}' is not a number", ctxt, dbg); - else - return res; - } - return {}; -} - void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { axiom_ = axiom; auto sym = s.ast().sym(axiom->dbg().sym.str() + "."s + dbg().sym.str()); @@ -266,9 +264,6 @@ void AxiomDecl::bind_decl(Scopes& s) const { if (sym_.sub) error(dbg().loc, "axiom '{}' must not have a subtag", dbg().sym); - id_.curry = parse_u8(s.ast(), curry_, "curry"sv); - id_.trip = parse_u8(s.ast(), trip_, "trip"sv); - if (num_subs() == 0) { s.bind(dbg(), this); } else { @@ -296,8 +291,7 @@ void RecDecl::bind_decl(Scopes& s) const { void RecDecl::bind_body(Scopes& s) const { body()->bind(s); } void LamDecl::Dom::bind(Scopes& s, bool quiet) const { - ptrn()->bind(s, quiet); - if (ret()) ret()->bind(s); + PiExpr::Dom::bind(s, quiet); if (filter() && !quiet) { if (has_bang()) { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 6688b27e6c..6780c8487f 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -35,58 +35,6 @@ Ref IdExpr::emit(Emitter&) const { return decl()->def(); } -Ref ExtremumExpr::emit(Emitter& e) const { - auto t = type() ? type()->emit(e) : e.world().type<0>(); - return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t))->set(loc()); -} - -Ref LitExpr::emit(Emitter& e) const { - int base = 10; - auto [loc, sym] = value(); - auto c_str = sym.c_str(); - size_t b = 0; - bool sign = false; - - if (sym[b] == '+') - ++b; - else if (sym[b] == '-') - ++b, sign = true; - - if (sym.size() == b) error(loc, "signed literal '{}' without value", value()); - - if (sym.size() > b + 1) { - switch (sym[b + 1]) { - // clang-format off - case 'b': - case 'B': base = 2, b += 2; break; - case 'o': - case 'O': base = 8, b += 2; break; - case 'x': - case 'X': base = 16, b += 2; break; - default: break; - // clang-format on - } - } - - char* end; - auto val = std::strtoull(c_str + b, &end, base); - - if (*end == '\0') { - if (sign) error(loc, "negative .Nat literal '{}' not allowed", value()); - if (type()) return e.world().lit(type()->emit(e), val); - return e.world().lit_nat(val)->set(loc); - } - - if (*end == 'i' || *end == 'I') { - auto width = std::strtoull(end + 1, nullptr, base); - if (width != 64 && val >= Idx::bitwidth2size(width)) - error(loc, "value '{}' doesn't fit in given bit width '{}'", val, width); - return e.world().lit_int(width, val)->set(loc); - } - - return {}; -} - Ref TypeExpr::emit(Emitter& e) const { auto l = level()->emit(e); return e.world().type(l)->set(loc()); @@ -111,7 +59,6 @@ Ref PrimaryExpr ::emit(Emitter& e) const { case Tag::K_I16: return e.world().type_i16(); case Tag::K_I32: return e.world().type_i32(); case Tag::K_I64: return e.world().type_i64(); - case Tag::M_char: return e.world().lit_i8(tok().chr()); case Tag::T_star: return e.world().type<0>(); case Tag::T_box: return e.world().type<1>(); default: fe::unreachable(); @@ -119,6 +66,25 @@ Ref PrimaryExpr ::emit(Emitter& e) const { } } +Ref LitExpr::emit(Emitter& e) const { + // auto t = type() ? type()->emit(e) : e.world().type<0>(); + // return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t))->set(loc()); + auto t = type() ? type()->emit(e) : nullptr; + // clang-format off + switch (tag()){ + case Tag::L_f: + case Tag::L_s: + case Tag::L_u: return (t ? e.world().lit(t, tok().lit_u()) : e.world().lit_nat(tok().lit_u()))->set(loc()); + case Tag::L_i: return tok().lit_i(); + case Tag::L_c: return e.world().lit_i8(tok().lit_c()); + case Tag::L_str: return e.world().tuple(tok().sym())->set(loc()); + case Tag::T_bot: return t ? e.world().bot(t)->set(loc()) : *e.world().type_bot(); + case Tag::T_top: return t ? e.world().top(t)->set(loc()) : *e.world().type_top(); + default: fe::unreachable(); + } + // clang-format on +} + void Module::emit(AST& ast, World& world) const { auto emitter = Emitter(ast, world); emit(emitter); @@ -335,32 +301,39 @@ void LetDecl::emit_decl(Emitter& e) const { def_ = ptrn()->emit_value(e, v); } -void AxiomDecl::Alias::emit(Emitter& e) const { - auto norm = e.driver().normalizer(axiom_->id_.plugin, axiom_->id_.tag, 0); +void AxiomDecl::Alias::emit(Emitter& e, sub_t sub) const { + auto norm = e.driver().normalizer(axiom_->id_.plugin, axiom_->id_.tag, 0); // TODO only one normalizer const auto& id = axiom_->id_; - def_ = e.world().axiom(norm, *id.curry, *id.trip, axiom_->thorin_type_, id.plugin, id.tag, 0)->set(dbg()); + def_ = e.world().axiom(norm, id.curry, id.trip, axiom_->thorin_type_, id.plugin, id.tag, sub)->set(dbg()); } void AxiomDecl::emit_decl(Emitter& e) const { - auto [plugin, tag, sub] = Annex::split(e.driver(), dbg().sym); - auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin, tag, dbg().loc); - thorin_type_ = type()->emit(e); - auto [curry, trip] = Axiom::infer_curry_and_trip(thorin_type_); - - if (id_.curry) { - if (*id_.curry > curry) error(curry_.loc, "curry counter cannot be greater than {}", curry); + auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym); + auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin_s, tag_s, dbg().loc); + thorin_type_ = type()->emit(e); + auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); + + if (curry_) { + id_.curry = curry_.lit_u(); + if (id_.curry > i_curry) error(curry_.loc(), "curry counter cannot be greater than {}", i_curry); } else { - id_.curry = curry; + id_.curry = i_curry; } - if (!id_.trip) id_.trip = trip; + if (trip_) { + id_.trip = trip_.lit_u(); + if (id_.trip > id_.curry) + error(curry_.loc(), "trip counter '{}' cannot be greater than curry counter '{}'", id_.trip, id_.curry); + } else { + id_.trip = i_trip; + } if (num_subs() == 0) { auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); - def_ = e.world().axiom(norm, curry, trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); + def_ = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); } else { - for (const auto& aliases : subs()) - for (const auto& alias : aliases) alias->emit(e); + for (sub_t i = 0, n = num_subs(); i != n; ++i) + for (const auto& alias : sub(i)) alias->emit(e, i); } } diff --git a/src/thorin/ast/lexer.cpp b/src/thorin/ast/lexer.cpp index 4e389aeb80..a351ab40dd 100644 --- a/src/thorin/ast/lexer.cpp +++ b/src/thorin/ast/lexer.cpp @@ -117,7 +117,7 @@ Tok Lexer::lex() { if (accept(utf8::isdigit)) { parse_digits(); parse_exp(); - return {loc_, Tag::M_str, sym()}; + return {loc_, f64(std::strtod(str_.c_str(), nullptr))}; } return tok(Tag::T_dot); @@ -133,7 +133,7 @@ Tok Lexer::lex() { if (accept('\"')) { while (lex_char() != '"') {} str_.pop_back(); // remove final '"' - return {loc_, Tag::M_str, sym()}; + return {loc_, Tag::L_str, sym()}; } if (lex_id()) { @@ -196,41 +196,52 @@ std::optional Lexer::parse_lit() { int base = 10; std::optional sign; - if (accept('+')) { + if (accept('+')) { sign = false; - } else if (accept('-')) { + } else if (accept('-')) { if (accept('>')) return tok(Tag::T_arrow); sign = true; } // prefix starting with '0' - if (accept('0')) { - if (accept('b')) base = 2; - else if (accept('B')) base = 2; - else if (accept('o')) base = 8; - else if (accept('O')) base = 8; - else if (accept('x')) base = 16; - else if (accept('X')) base = 16; + if (accept('0')) { + if (accept('b')) base = 2; + else if (accept('B')) base = 2; + else if (accept('o')) base = 8; + else if (accept('O')) base = 8; + else if (accept('x')) base = 16; + else if (accept('X')) base = 16; } parse_digits(base); if (accept(utf8::any('i', 'I'))) { + if (sign) str_.insert(0, "-"sv); + auto val = std::strtoull(str_.c_str(), nullptr, base); + str_.clear(); parse_digits(); - return Tok{loc_, Tag::M_lit, sym()}; + auto width = std::strtoull(str_.c_str(), nullptr, 10); + return Tok{loc_, ast().world().lit_int(width, val)}; } if (!sign && base == 10) { if (utf8::isrange(ahead(), U'₀', U'₉')) { - while (accept(utf8::isrange(U'₀', U'₉'))) {} - return Tok{loc_, Tag::M_lit, sym()}; - } else if (accept('_')) { + auto i = std::strtoull(str_.c_str(), nullptr, 10); + std::string mod; + while (utf8::isrange(ahead(), U'₀', U'₉')) mod += next() - U'₀' + '0'; + auto m = std::strtoull(mod.c_str(), nullptr, 10); + return Tok{loc_, ast().world().lit_idx_mod(m, i)}; + } else if (accept('_')) { + auto i = std::strtoull(str_.c_str(), nullptr, 10); + str_.clear(); if (accept(utf8::isdigit)) { - parse_digits(); - return Tok{loc_, Tag::M_lit, sym()}; + parse_digits(10); + auto m = std::strtoull(str_.c_str(), nullptr, 10); + return Tok{loc_, ast().world().lit_idx_mod(m, i)}; } else { ast().error(loc_, "stray underscore in .Idx literal; size is missing"); - return {}; + auto i = std::strtoull(str_.c_str(), nullptr, 10); + return Tok{loc_, u64(i)}; } } } @@ -253,7 +264,12 @@ std::optional Lexer::parse_lit() { return {}; } - return Tok{loc_, Tag::M_lit, sym()}; + if (is_float && base == 16) str_.insert(0, "0x"sv); + if (sign && *sign) str_.insert(0, "-"sv); + + if (is_float) return Tok{loc_, f64(std::strtod (str_.c_str(), nullptr ))}; + if (sign) return Tok{loc_, u64(std::strtoll (str_.c_str(), nullptr, base))}; + else return Tok{loc_, u64(std::strtoull(str_.c_str(), nullptr, base))}; } void Lexer::parse_digits(int base /*= 10*/) { diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 1fe25f2ce9..b214abb55f 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -196,19 +196,18 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::K_I8: case Tag::K_I16: case Tag::K_I32: - case Tag::K_I64: - case Tag::M_char: case Tag::T_star: - case Tag::T_box: { - auto tok = lex(); - return ptr(tok); - } - case Tag::M_lit: return parse_lit_expr(); + case Tag::T_box: return ptr(lex()); + case Tag::T_bot: - case Tag::T_top: return parse_extremum_expr(); + case Tag::T_top: + case Tag::L_str: + case Tag::L_c: + case Tag::L_s: + case Tag::L_u: + case Tag::L_f: return parse_lit_expr(); case Tag::M_anx: case Tag::M_id: return ptr(lex().dbg()); - //case Tag::M_str: return world().tuple(lex().sym())->set(prev_); default: if (ctxt.empty()) return nullptr; syntax_err("primary expression", ctxt); @@ -246,20 +245,12 @@ Ptr Parser::parse_block_expr(std::string_view ctxt) { return ptr(track, /*has_braces*/ ctxt.empty(), std::move(decls), std::move(expr)); } -Ptr Parser::parse_extremum_expr() { - auto track = tracker(); - auto tag = lex().tag(); - auto [_, r] = Tok::prec(Tok::Prec::Lit); - auto type = accept(Tag::T_colon) ? parse_expr("type of "s + Tok::tag2str(tag), r) : nullptr; - return ptr(track, tag, std::move(type)); -} - Ptr Parser::parse_lit_expr() { auto track = tracker(); - auto value = lex(); + auto tok = lex(); auto [_, r] = Tok::prec(Tok::Prec::Lit); auto type = accept(Tag::T_colon) ? parse_expr("literal", r) : nullptr; - return ptr(track, value.dbg(), std::move(type)); + return ptr(track, tok, std::move(type)); } Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, Dbg(ahead().loc(), Sym()))); } @@ -511,7 +502,8 @@ Ptrs Parser::parse_decls() { Ptr Parser::parse_axiom_decl() { auto track = tracker(); eat(Tag::K_ax); - Dbg dbg, normalizer, curry, trip; + Dbg dbg, normalizer; + Tok curry, trip; if (auto name = expect(Tag::M_anx, "annex name of an axiom")) dbg = name.dbg(); else @@ -534,9 +526,9 @@ Ptr Parser::parse_axiom_decl() { normalizer = lex().dbg(); } if (accept(Tag::T_comma)) { - if (auto c = expect(Tag::M_lit, "curry counter for axiom")) curry = c.dbg(); + if (auto c = expect(Tag::L_u, "curry counter for axiom")) curry = c; if (accept(Tag::T_comma)) { - if (auto t = expect(Tag::M_lit, "trip count for axiom")) trip = t.dbg(); + if (auto t = expect(Tag::L_u, "trip count for axiom")) trip = t; } } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 43eb95950e..d1e6249eaf 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -61,19 +61,11 @@ std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { std::ostream& IdExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", dbg()); } std::ostream& ErrorExpr::stream(Tab&, std::ostream& os) const { return os << ""; } std::ostream& InferExpr::stream(Tab&, std::ostream& os) const { return os << ""; } - -std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { - if (tag() == Tag::M_char) return print(os, "'{}'", (char)tok().chr()); // TODO escape etc - return print(os, "{}", tag()); -} +std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(os, "{}", tag()); } std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { - os << value(); - if (type()) print(os, ": {}", S(tab, type())); - return os; -} - -std::ostream& ExtremumExpr::stream(Tab& tab, std::ostream& os) const { + // if (tag() == Tag::L_c) return print(os, "'{}'", (char)tok().lit_c()); // TODO escape etc + // os << value(); os << tag(); if (type()) print(os, ": {}", S(tab, type())); return os; diff --git a/src/thorin/ast/tok.cpp b/src/thorin/ast/tok.cpp index 83abf09c83..3324f98f4c 100644 --- a/src/thorin/ast/tok.cpp +++ b/src/thorin/ast/tok.cpp @@ -28,7 +28,7 @@ std::string Tok::str() const { /// @name std::ostream operator ///@{ std::ostream& operator<<(std::ostream& os, Tok tok) { - if (tok.isa(Tok::Tag::M_anx) || tok.isa(Tok::Tag::M_id) || tok.isa(Tok::Tag::M_str)) return os << tok.sym(); + if (tok.isa(Tok::Tag::M_anx) || tok.isa(Tok::Tag::M_id) || tok.isa(Tok::Tag::L_str)) return os << tok.sym(); return os << Tok::tag2str(tok.tag()); } ///@} diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 4f230e6851..c82abd9fe2 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -136,7 +136,7 @@ int main(int argc, char** argv) { try { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); - auto ast = ast::AST(driver); + auto ast = ast::AST(world); auto parser = ast::Parser(ast); #if 0 parser.import(driver.sym(input), os[Md]); diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 1f65fe47bc..e67f54f2c3 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -43,6 +43,7 @@ World::World(Driver* driver, const State& state) data_.type_0 = type(lit_univ_0()); data_.type_1 = type(lit_univ_1()); data_.type_bot = insert(0, type()); + data_.type_top = insert(0, type()); data_.sigma = insert(0, type(), Defs{})->as(); data_.tuple = insert(0, sigma(), Defs{})->as(); data_.type_nat = insert(0, *this); From 6d8b822fef0cf233341e5bb8dbb09546bd5e25f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 20:23:53 +0200 Subject: [PATCH 45/95] emit packs --- src/thorin/ast/emit.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 6780c8487f..0a424a9d15 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -235,16 +235,28 @@ Ref TupleExpr::emit(Emitter& e) const { template Ref ArrOrPackExpr::emit(Emitter& e) const { auto s = shape()->emit_type(e); - if (shape()->is_anon()) { + if (shape()->is_anon()) { // immutable auto b = body()->emit(e); return arr ? e.world().arr(s, b) : e.world().pack(s, b); } + auto t = e.world().type_infer_univ(); - auto a = e.world().mut_arr(t); // TODO packs + auto a = e.world().mut_arr(t); a->set_shape(s); - auto var = a->var(); - shape()->emit_value(e, var); - return a->set_body(body()->emit(e)); + + if (arr) { + auto var = a->var(); + shape()->emit_value(e, var); + return a->set_body(body()->emit(e)); + } else { + auto p = e.world().mut_pack(a); + auto var = p->var(); + shape()->emit_value(e, var); + auto b = body()->emit(e); + a->set_body(b->type()); + p->set(b); + return p; + } } template Ref ArrOrPackExpr::emit(Emitter&) const; From f95c41dfa8b7dc5896e2bc9e94ea9efb9a42e6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 20:27:53 +0200 Subject: [PATCH 46/95] emit: immutabilize arr/pack if possible --- src/thorin/ast/emit.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 0a424a9d15..a9ecaeb34d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -247,7 +247,9 @@ template Ref ArrOrPackExpr::emit(Emitter& e) const { if (arr) { auto var = a->var(); shape()->emit_value(e, var); - return a->set_body(body()->emit(e)); + a->set_body(body()->emit(e)); + if (auto imm = a->immutabilize()) return imm; + return a; } else { auto p = e.world().mut_pack(a); auto var = p->var(); @@ -255,6 +257,7 @@ template Ref ArrOrPackExpr::emit(Emitter& e) const { auto b = body()->emit(e); a->set_body(b->type()); p->set(b); + if (auto imm = p->immutabilize()) return imm; return p; } } From 1356939e2a1ce8655e460066e1e24281f436267e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 22:11:35 +0200 Subject: [PATCH 47/95] introduce DeclExpr --- external/fe | 2 +- include/thorin/ast/ast.h | 24 +++++++++++++++++++----- include/thorin/ast/parser.h | 3 ++- src/thorin/ast/bind.cpp | 6 +++++- src/thorin/ast/emit.cpp | 29 +++++++---------------------- src/thorin/ast/parser.cpp | 33 ++++++++++++++++++++++++--------- src/thorin/ast/stream.cpp | 11 ++++------- 7 files changed, 62 insertions(+), 46 deletions(-) diff --git a/external/fe b/external/fe index bb688e460a..abd1c5a65e 160000 --- a/external/fe +++ b/external/fe @@ -1 +1 @@ -Subproject commit bb688e460af322bd89341471ac100515fee5fea4 +Subproject commit abd1c5a65ed50396aed748832f6054f3fde30ff2 diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 13a09617ed..98bb6cf3d5 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -301,16 +301,31 @@ class LitExpr : public Expr { Ptr type_; }; -/// `{ decl_0 ... decl_n-1 e }` or `decl_0 ... decl_n-1` (used internaly) +/// `{ e }` +/// @deprecated will be removed; use `( e )` instead. class BlockExpr : public Expr { public: - BlockExpr(Loc loc, bool has_braces, Ptrs&& decls, Ptr&& expr) + BlockExpr(Loc loc, Ptr&& expr) + : Expr(loc) + , expr_(std::move(expr)) {} + + const Expr* expr() const { return expr_.get(); } + + void bind(Scopes&) const override; + Ref emit(Emitter&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Ptr expr_; +}; + +class DeclExpr : public Expr { +public: + DeclExpr(Loc loc, Ptrs&& decls, Ptr&& expr) : Expr(loc) - , has_braces_(has_braces) , decls_(std::move(decls)) , expr_(std::move(expr)) {} - bool has_braces() const { return has_braces_; } const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; @@ -318,7 +333,6 @@ class BlockExpr : public Expr { std::ostream& stream(Tab&, std::ostream&) const override; private: - bool has_braces_; DeclsBlock decls_; Ptr expr_; }; diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 1d224ebc05..e88e5e2d45 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -82,7 +82,8 @@ class Parser : public fe::Parser { /// @name parse primary exprs ///@{ template Ptr parse_arr_or_pack_expr(); - Ptr parse_block_expr(std::string_view ctxt); ///< Empty @p ctxt means an explicit BlockExpr `{ d* e }`. + Ptr parse_block_expr(); + Ptr parse_decl_expr(); Ptr parse_lit_expr(); Ptr parse_extremum_expr(); Ptr parse_type_expr(); diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 498f580e71..679caeac02 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -136,9 +136,13 @@ void GroupPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind() * Expr */ +void DeclExpr::bind(Scopes& s) const { + decls_.bind(s); + expr()->bind(s); +} + void BlockExpr::bind(Scopes& s) const { s.push(); - decls_.bind(s); expr()->bind(s); s.pop(); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index a9ecaeb34d..39675a6af7 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -139,11 +139,13 @@ Ref TuplePtrn::emit_type(Emitter& e) const { * Expr */ -Ref BlockExpr::emit(Emitter& e) const { +Ref DeclExpr::emit(Emitter& e) const { decls_.emit(e); return expr()->emit(e); } +Ref BlockExpr::emit(Emitter& e) const { return expr()->emit(e); } + Ref ArrowExpr::emit(Emitter& e) const { auto d = dom()->emit(e); auto c = codom()->emit(e); @@ -323,10 +325,10 @@ void AxiomDecl::Alias::emit(Emitter& e, sub_t sub) const { } void AxiomDecl::emit_decl(Emitter& e) const { - auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym); - auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin_s, tag_s, dbg().loc); - thorin_type_ = type()->emit(e); - auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); + // auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym); + // auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin_s, tag_s, dbg().loc); + thorin_type_ = type()->emit(e); + auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); if (curry_) { id_.curry = curry_.lit_u(); @@ -355,23 +357,6 @@ void AxiomDecl::emit_decl(Emitter& e) const { void RecDecl::emit_decl(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); def_ = body()->emit_decl(e, t); - -#if 0 - if (auto sigma = body()->isa()) { - def_ = e.world().mut_sigma(t, sigma->ptrn()->num_ptrns()); - } else if (auto pi = body()->isa()) { - def_ = e.world().mut_pi(t); - } else if (auto lam = body()->isa()) { -# if 0 - if (auto infer = t->isa()) t = e.world().mut_pi(t, e.world().type_infer_univ()); - if (auto pi = t->isa()) - def_ = e.world().mut_lam(pi); - else - error(type()->loc(), "type of a function must be a function type"); -# endif - def_ = body()->emit_decl(e); - } -#endif } void RecDecl::emit_body(Emitter& e) const { body()->emit_body(e, def_); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index b214abb55f..04605604c6 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -169,16 +169,25 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::K_Cn: case Tag::K_Fn: case Tag::T_Pi: return parse_pi_expr(); + case Tag::K_cn: case Tag::K_fn: case Tag::T_lm: return parse_lam_expr(); + + case Tag::K_ax: + case Tag::K_let: + case Tag::K_rec: + case Tag::K_con: + case Tag::K_fun: + case Tag::K_lam: return parse_decl_expr(); + case Tag::K_ins: return parse_insert_expr(); case Tag::K_ret: return parse_ret_expr(); case Tag::D_quote_l: return parse_arr_or_pack_expr(); case Tag::D_angle_l: return parse_arr_or_pack_expr(); case Tag::D_brckt_l: return parse_sigma_expr(); case Tag::D_paren_l: return parse_tuple_expr(); - case Tag::D_brace_l: return parse_block_expr({}); + case Tag::D_brace_l: return parse_block_expr(); case Tag::K_Type: return parse_type_expr(); case Tag::K_Univ: @@ -236,13 +245,19 @@ template Ptr Parser::parse_arr_or_pack_expr() { return ptr>(track, std::move(ptrn), std::move(body)); } -Ptr Parser::parse_block_expr(std::string_view ctxt) { +Ptr Parser::parse_block_expr() { + auto track = tracker(); + eat(Tag::D_brace_l); + auto expr = parse_expr("final expression in a block expressoin"); + expect(Tag::D_brace_r, "block expression"); + return ptr(track, std::move(expr)); +} + +Ptr Parser::parse_decl_expr() { auto track = tracker(); - if (ctxt.empty()) eat(Tag::D_brace_l); auto decls = parse_decls(); - auto expr = parse_expr("final expression in a "s + (ctxt.empty() ? "block expressoin"s : std::string(ctxt))); - if (ctxt.empty()) expect(Tag::D_brace_r, "block expression"); - return ptr(track, /*has_braces*/ ctxt.empty(), std::move(decls), std::move(expr)); + auto expr = parse_expr("final expression of a delcaration expression"); + return ptr(track, std::move(decls), std::move(expr)); } Ptr Parser::parse_lit_expr() { @@ -312,8 +327,8 @@ Ptr Parser::parse_ret_expr() { expect(Tag::T_dollar, "separator of a ret expression"); auto arg = parse_expr("argument of ret expression"); expect(Tag::T_semicolon, "let expression"); - auto decls = parse_block_expr("body of a ret expression"); - return ptr(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(decls)); + auto body = parse_expr("body of a ret expression"); + return ptr(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(body)); } /* @@ -600,7 +615,7 @@ Ptr Parser::parse_lam_decl() { if (tag == Tag::K_fn || tag == Tag::K_fun) doms.back()->add_ret(ast(), std::move(codom)); - auto body = accept(Tag::T_assign) ? parse_block_expr("body of a "s + entity) : nullptr; + auto body = accept(Tag::T_assign) ? parse_expr("body of a "s + entity) : nullptr; return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index d1e6249eaf..30a3c769f4 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -71,21 +71,18 @@ std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { return os; } -std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { - if (!has_braces()) { - if (decls_.num_decls() == 0) return expr()->stream(tab, os); - } else { - os << '{'; - } +std::ostream& DeclExpr::stream(Tab& tab, std::ostream& os) const { + if (decls_.num_decls() == 0) return expr()->stream(tab, os); os << std::endl; ++tab; decls_.stream(tab, os); (--tab).print(os, "{}", S(tab, expr())); - if (has_braces()) tab.print(os << std::endl, "}}"); return os; } +std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{{ {} }}", S(tab, expr())); } + std::ostream& TypeExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "(.Type {})", S(tab, level())); } std::ostream& ArrowExpr::stream(Tab& tab, std::ostream& os) const { From 68d300c1f2e2c440cfb17b3c17bb71d496c80827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 13 Apr 2024 22:51:08 +0200 Subject: [PATCH 48/95] introduced "where" expression --- include/thorin/ast/ast.h | 8 ++++++-- include/thorin/ast/tok.h | 2 ++ src/thorin/ast/parser.cpp | 24 +++++++++++++++--------- src/thorin/ast/stream.cpp | 31 +++++++++++++++++++++---------- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 98bb6cf3d5..93bc2b39c8 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -319,13 +319,16 @@ class BlockExpr : public Expr { Ptr expr_; }; +/// `decls e` or `e .where decls` if @p where is `true`. class DeclExpr : public Expr { public: - DeclExpr(Loc loc, Ptrs&& decls, Ptr&& expr) + DeclExpr(Loc loc, Ptrs&& decls, Ptr&& expr, bool where) : Expr(loc) , decls_(std::move(decls)) - , expr_(std::move(expr)) {} + , expr_(std::move(expr)) + , where_(where) {} + bool where() const { return where_; } const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; @@ -335,6 +338,7 @@ class DeclExpr : public Expr { private: DeclsBlock decls_; Ptr expr_; + bool where_; }; /// `.Type level` diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 17de21c5fb..0125d165ab 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -19,6 +19,7 @@ namespace ast { m(K_let, ".let" ) \ m(K_rec, ".rec" ) \ m(K_ret, ".ret" ) \ + m(K_where, ".where" ) \ m(K_Nat, ".Nat" ) \ m(K_Idx, ".Idx" ) \ m(K_extern, ".extern") \ @@ -103,6 +104,7 @@ constexpr auto Num_Keys = size_t(0) THORIN_KEY(CODE); /* left prec, right */ \ m(Nil, Bot, Nil ) \ m(Nil, Nil, Nil ) \ + m(Nil, Where, Where ) \ m(Lam, Arrow, Arrow ) \ m(Nil, Lam, Pi ) \ m(Nil, Pi, App ) \ diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 04605604c6..b461ac6857 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -107,29 +107,35 @@ Ptr Parser::parse_type_ascr(std::string_view ctxt) { * exprs */ -Ptr Parser::parse_expr(std::string_view ctxt, Tok::Prec p) { +Ptr Parser::parse_expr(std::string_view ctxt, Tok::Prec curr_prec) { auto track = tracker(); auto lhs = parse_primary_expr(ctxt); - return parse_infix_expr(track, std::move(lhs), p); + return parse_infix_expr(track, std::move(lhs), curr_prec); } -Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec p) { +Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec curr_prec) { while (true) { // If operator in ahead has less left precedence: reduce (break). if (ahead().isa(Tag::T_extract)) { - if (auto extract = parse_extract_expr(track, std::move(lhs), p)) + if (auto extract = parse_extract_expr(track, std::move(lhs), curr_prec)) lhs = std::move(extract); else break; } else if (ahead().isa(Tag::T_arrow)) { auto [l, r] = Tok::prec(Tok::Prec::Arrow); - if (l < p) break; + if (l < curr_prec) break; lex(); auto rhs = parse_expr("right-hand side of an function type", r); lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); + } else if (ahead().isa(Tag::K_where)) { + auto [l, r] = Tok::prec(Tok::Prec::Where); + if (l < curr_prec) break; + lex(); + auto decls = parse_decls(); + lhs = ptr(track, std::move(decls), std::move(lhs), true); } else { auto [l, r] = Tok::prec(Tok::Prec::App); - if (l < p) break; + if (l < curr_prec) break; bool is_explicit = (bool)accept(Tag::T_at); if (auto rhs = parse_expr({}, r)) // if we can parse an expression, it's an App lhs = ptr(track.loc(), is_explicit, std::move(lhs), std::move(rhs)); @@ -141,9 +147,9 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec p) return lhs; } -Ptr Parser::parse_extract_expr(Tracker track, Ptr&& lhs, Tok::Prec p) { +Ptr Parser::parse_extract_expr(Tracker track, Ptr&& lhs, Tok::Prec curr_prec) { auto [l, r] = Tok::prec(Tok::Prec::Extract); - if (l < p) return nullptr; + if (l < curr_prec) return nullptr; lex(); if (auto tok = accept(Tag::M_id)) return ptr(track.loc(), std::move(lhs), tok.dbg()); auto rhs = parse_expr("right-hand side of an extract", r); @@ -257,7 +263,7 @@ Ptr Parser::parse_decl_expr() { auto track = tracker(); auto decls = parse_decls(); auto expr = parse_expr("final expression of a delcaration expression"); - return ptr(track, std::move(decls), std::move(expr)); + return ptr(track, std::move(decls), std::move(expr), false); } Ptr Parser::parse_lit_expr() { diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 30a3c769f4..7927aa0cbf 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -64,21 +64,32 @@ std::ostream& InferExpr::stream(Tab&, std::ostream& os) const { return os << "stream(os, 0); + case Tag::L_f: return os << std::bit_cast(tok().lit_u()); + case Tag::L_s: + case Tag::L_u: + os << tok().lit_u(); + if (type()) print(os, ": {}", S(tab, type())); + break; + default: os << "TODO"; + } return os; } std::ostream& DeclExpr::stream(Tab& tab, std::ostream& os) const { if (decls_.num_decls() == 0) return expr()->stream(tab, os); - os << std::endl; - ++tab; - decls_.stream(tab, os); - (--tab).print(os, "{}", S(tab, expr())); - return os; + if (where()) { + println(os, "{} .where", S(tab, expr())); + ++tab; + return decls_.stream(tab, os); + } else { + os << std::endl; + ++tab; + decls_.stream(tab, os); + return (--tab).print(os, "{}", S(tab, expr())); + } } std::ostream& BlockExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{{ {} }}", S(tab, expr())); } @@ -183,7 +194,7 @@ std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { print(os, "{}", R(tab, doms())); if (codom()) print(os, ": {}", S(tab, codom())); if (body()) print(os, " = {}", S(tab, body())); - return os; + return os << ';'; } /* From 79feb0f24ccc29a82a87cd48bb796579968dacb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 14 Apr 2024 00:06:19 +0200 Subject: [PATCH 49/95] wip: reconnect to the rest again --- include/thorin/ast/ast.h | 8 ++++++-- src/thorin/ast/parser.cpp | 3 ++- src/thorin/ast/stream.cpp | 29 ++++++++++++++++++----------- src/thorin/cli/main.cpp | 17 +++++++---------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 93bc2b39c8..08a82cf21e 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -423,7 +423,9 @@ class PiExpr : public Expr { : Expr(loc) , tag_(tag) , doms_(std::move(doms)) - , codom_(std::move(codom)) {} + , codom_(std::move(codom)) { + assert(num_doms() != 0); + } private: Tok::Tag tag() const { return tag_; } @@ -797,7 +799,9 @@ class LamDecl : public RecDecl { , tag_(tag) , is_external_(is_external) , doms_(std::move(doms)) - , codom_(std::move(codom)) {} + , codom_(std::move(codom)) { + assert(num_doms() != 0); + } Tok::Tag tag() const { return tag_; } bool is_external() const { return is_external_; } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index b461ac6857..6a6d7d42f8 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -220,7 +220,8 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::L_c: case Tag::L_s: case Tag::L_u: - case Tag::L_f: return parse_lit_expr(); + case Tag::L_f: + case Tag::L_i: return parse_lit_expr(); case Tag::M_anx: case Tag::M_id: return ptr(lex().dbg()); default: diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 7927aa0cbf..0110fe8864 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -65,7 +65,7 @@ std::ostream& PrimaryExpr::stream(Tab&, std::ostream& os) const { return print(o std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { switch (tag()) { - case Tag::L_i: return tok().lit_i()->stream(os, 0); + case Tag::L_i: return print(os, "{}", tok().lit_i()); case Tag::L_f: return os << std::bit_cast(tok().lit_u()); case Tag::L_s: case Tag::L_u: @@ -78,17 +78,16 @@ std::ostream& LitExpr::stream(Tab& tab, std::ostream& os) const { } std::ostream& DeclExpr::stream(Tab& tab, std::ostream& os) const { - if (decls_.num_decls() == 0) return expr()->stream(tab, os); - if (where()) { - println(os, "{} .where", S(tab, expr())); + tab.println(os, "{} .where", S(tab, expr())); ++tab; - return decls_.stream(tab, os); + decls_.stream(tab, os); + --tab; + return os; } else { - os << std::endl; - ++tab; + for (const auto& decl : decls_.decls()) tab.println(os, "{}", S(tab, decl.get())); decls_.stream(tab, os); - return (--tab).print(os, "{}", S(tab, expr())); + return print(os, "{}", S(tab, expr())); } } @@ -190,10 +189,18 @@ std::ostream& LamDecl::Dom::stream(Tab& tab, std::ostream& os) const { std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { print(os, "{} {}", tag(), dbg()); - if (num_doms() > 0 && !doms().front()->ptrn()->isa()) os << ' '; + if (!doms().front()->ptrn()->isa()) os << ' '; print(os, "{}", R(tab, doms())); if (codom()) print(os, ": {}", S(tab, codom())); - if (body()) print(os, " = {}", S(tab, body())); + if (body()) { + if (body()->isa()) { + os << " =" << std::endl; + (++tab).print(os, "{}", S(tab, body())); + --tab; + } else { + print(os, " = {}", S(tab, body())); + } + } return os << ';'; } @@ -201,7 +208,7 @@ std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { * Module */ -std::ostream& Import::stream(Tab&, std::ostream& os) const { return println(os, "{} '{}';", tag(), "TODO"); } +std::ostream& Import::stream(Tab& tab, std::ostream& os) const { return tab.println(os, "{} '{}';", tag(), "TODO"); } std::ostream& Module::stream(Tab& tab, std::ostream& os) const { for (const auto& import : imports()) import->stream(tab, os); diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index c82abd9fe2..240daa6c1f 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -138,8 +138,13 @@ int main(int argc, char** argv) { world.set(path.filename().replace_extension().string()); auto ast = ast::AST(world); auto parser = ast::Parser(ast); -#if 0 - parser.import(driver.sym(input), os[Md]); + auto mod = parser.import(driver.sym(input), os[Md]); + mod->compile(ast, world); + + if (auto s = os[AST]) { + Tab tab; + mod->stream(tab, *s); + } if (auto dep = os[D]) { if (auto autogen_h = output[H]; !autogen_h.empty()) { @@ -170,14 +175,6 @@ int main(int argc, char** argv) { break; default: error("illegal optimization level '{}'", opt); } -#endif - - auto mod = parser.import(driver.sym(input), os[Md]); - if (auto s = os[AST]) { - Tab tab; - mod->stream(tab, *s); - } - mod->compile(ast, world); if (auto s = os[Dot]) world.dot(*s, dot_all_annexes, dot_follow_types); if (auto s = os[Thorin]) world.dump(*s); From e692e20417289b0ac8242047ba483705d579dcef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 14 Apr 2024 01:09:40 +0200 Subject: [PATCH 50/95] allow redecl of axiom with subs --- include/thorin/ast/ast.h | 3 ++- src/thorin/ast/bind.cpp | 8 ++++++++ src/thorin/ast/emit.cpp | 28 +++++++++++++++++----------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 08a82cf21e..14f09c411f 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -687,13 +687,14 @@ class AxiomDecl : public ValDecl { Dbg dbg() const { return dbg_; } void bind(Scopes&, const AxiomDecl*) const; - void emit(Emitter&, sub_t) const; + void emit(Emitter&, sub_t, NormalizeFn) const; std::ostream& stream(Tab&, std::ostream&) const override; private: Dbg dbg_; mutable Dbg full_; mutable const AxiomDecl* axiom_ = nullptr; + mutable sub_t sub_ = 0; friend class AxiomDecl; }; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 679caeac02..27a374706a 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -271,6 +271,14 @@ void AxiomDecl::bind_decl(Scopes& s) const { if (num_subs() == 0) { s.bind(dbg(), this); } else { + if (auto old = s.find(dbg(), true)) { + if (auto old_ax = old->isa()) { + if (old_ax->num_subs() == 0) { + s.ast().error(dbg().loc, "redeclared sub-less axiom '{}' with subs", dbg()); + s.ast().note(old_ax->dbg().loc, "previous location here"); + } + } + } for (const auto& aliases : subs()) for (const auto& alias : aliases) alias->bind(s, this); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 39675a6af7..c84662d743 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -318,21 +318,21 @@ void LetDecl::emit_decl(Emitter& e) const { def_ = ptrn()->emit_value(e, v); } -void AxiomDecl::Alias::emit(Emitter& e, sub_t sub) const { - auto norm = e.driver().normalizer(axiom_->id_.plugin, axiom_->id_.tag, 0); // TODO only one normalizer +void AxiomDecl::Alias::emit(Emitter& e, sub_t sub, NormalizeFn norm) const { const auto& id = axiom_->id_; - def_ = e.world().axiom(norm, id.curry, id.trip, axiom_->thorin_type_, id.plugin, id.tag, sub)->set(dbg()); + outln("{}: {} - {} - {}", dbg(), id.plugin, (int)id.tag, (int)sub_); + def_ = e.world().axiom(norm, id.curry, id.trip, axiom_->thorin_type_, id.plugin, id.tag, sub)->set(dbg()); } void AxiomDecl::emit_decl(Emitter& e) const { - // auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym); - // auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin_s, tag_s, dbg().loc); - thorin_type_ = type()->emit(e); - auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); + auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym); + auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin_s, tag_s, dbg().loc); + thorin_type_ = type()->emit(e); + auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); if (curry_) { id_.curry = curry_.lit_u(); - if (id_.curry > i_curry) error(curry_.loc(), "curry counter cannot be greater than {}", i_curry); + if (id_.curry > i_curry) error(curry_.loc(), "curry counter cannot be greater than {}", (int)i_curry); } else { id_.curry = i_curry; } @@ -340,7 +340,8 @@ void AxiomDecl::emit_decl(Emitter& e) const { if (trip_) { id_.trip = trip_.lit_u(); if (id_.trip > id_.curry) - error(curry_.loc(), "trip counter '{}' cannot be greater than curry counter '{}'", id_.trip, id_.curry); + error(curry_.loc(), "trip counter '{}' cannot be greater than curry counter '{}'", (int)id_.trip, + (int)id_.curry); } else { id_.trip = i_trip; } @@ -349,8 +350,13 @@ void AxiomDecl::emit_decl(Emitter& e) const { auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); def_ = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); } else { - for (sub_t i = 0, n = num_subs(); i != n; ++i) - for (const auto& alias : sub(i)) alias->emit(e, i); + for (sub_t i = 0, n = num_subs(); i != n; ++i) { + auto norm = e.driver().normalizer(id_.plugin, id_.tag, i); + for (const auto& alias : sub(i)) { + alias->sub_ = i; + alias->emit(e, i, norm); + } + } } } From 4c99dd230a6477d94d2d01c3c99a549462e108b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 15 Apr 2024 12:37:51 +0200 Subject: [PATCH 51/95] semicolon is now optional at the end of .let/.ax/.rec --- src/thorin/ast/parser.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 6a6d7d42f8..29c32204e1 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -554,7 +554,6 @@ Ptr Parser::parse_axiom_decl() { } } - expect(Tag::T_semicolon, "end of an axiom"); return ptr(track, dbg, std::move(subs), std::move(type), normalizer, curry, trip); } @@ -565,7 +564,6 @@ Ptr Parser::parse_let_decl() { expect(Tag::T_assign, "let"); auto type = parse_type_ascr(); auto value = parse_expr("value of a let declaration"); - expect(Tag::T_semicolon, "let declaration"); return ptr(track, std::move(ptrn), std::move(value)); } @@ -576,7 +574,6 @@ Ptr Parser::parse_rec_decl() { auto type = accept(Tag::T_colon) ? parse_expr("type of a recursive declaration") : ptr(prev_); expect(Tag::T_assign, "recursive declaration"); auto body = parse_expr("body of a recursive declaration"); - expect(Tag::T_semicolon, "end of a recursive declaration"); return ptr(track, dbg, std::move(type), std::move(body)); } From c61298f41c15340c5eafea95cb9f3dfeb968c2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 16 Apr 2024 03:13:11 +0200 Subject: [PATCH 52/95] first tests are working again --- examples/hello.cpp | 5 ++-- gtest/automaton.cpp | 15 ++++++---- gtest/lexer.cpp | 52 +++++++++++++++++++++++----------- gtest/restricted_dep_types.cpp | 8 +++--- gtest/test.cpp | 46 ++++++++++++++---------------- include/thorin/ast/ast.h | 4 +-- include/thorin/plugin.h | 1 - include/thorin/util/dbg.h | 10 ++++++- include/thorin/util/print.h | 12 ++++++++ src/thorin/ast/emit.cpp | 41 ++++++++++++++++++++++++--- src/thorin/ast/lexer.cpp | 2 +- src/thorin/plug/opt/opt.cpp | 2 +- 12 files changed, 136 insertions(+), 62 deletions(-) diff --git a/examples/hello.cpp b/examples/hello.cpp index 5daea14a1d..e9206efab3 100644 --- a/examples/hello.cpp +++ b/examples/hello.cpp @@ -14,10 +14,11 @@ using namespace thorin::plug; int main(int, char**) { try { Driver driver; - auto& w = driver.world(); + auto& w = driver.world(); + auto ast = ast::AST(w); driver.log().set(&std::cerr).set(Log::Level::Debug); - auto parser = ast::Parser(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "core"}) parser.plugin(plugin); // .Cn [%mem.M, I32, %mem.Ptr (I32, 0) .Cn [%mem.M, I32]] diff --git a/gtest/automaton.cpp b/gtest/automaton.cpp index 1fb11ad545..2aeb04eaf8 100644 --- a/gtest/automaton.cpp +++ b/gtest/automaton.cpp @@ -156,7 +156,8 @@ TEST(Automaton, NFAAorBplusA) { TEST(Automaton, Regex2NFA) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); auto pattern = w.call( @@ -169,7 +170,8 @@ TEST(Automaton, Regex2NFA) { TEST(Automaton, Regex2NFAAorBplusA) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); auto pattern = w.call( @@ -188,7 +190,8 @@ TEST(Automaton, Regex2NFAAorBplusA) { TEST(Automaton, Regex2NFA1or5or9) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); // %regex.disj 2 (%regex.disj 2 (%regex.range ‹2; 49I8›, %regex.range ‹2; 53I8›), %regex.range ‹2; @@ -208,7 +211,8 @@ TEST(Automaton, Regex2NFA1or5or9) { TEST(Automaton, Regex2NFANot1or5or9) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); // %regex.not_ (%regex.disj 2 (%regex.disj 2 (%regex.range ‹2; 49I8›, %regex.range ‹2; 53I8›), @@ -229,7 +233,8 @@ TEST(Automaton, Regex2NFANot1or5or9) { TEST(Automaton, Regex2NFANotwds) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); // %regex.not_ (%regex.conj 3 (%regex.cls.w, %regex.cls.d, %regex.cls.s)) diff --git a/gtest/lexer.cpp b/gtest/lexer.cpp index 8d1c7ec91a..8408b0e69b 100644 --- a/gtest/lexer.cpp +++ b/gtest/lexer.cpp @@ -5,6 +5,7 @@ #include +#include #include using namespace std::literals; @@ -13,8 +14,10 @@ using namespace thorin::ast; TEST(Lexer, Toks) { Driver driver; - std::istringstream is("{ } ( ) [ ] ‹ › « » : , . .lam .Pi λ Π 23₀₁₂₃₄₅₆₇₈₉"); - Lexer lexer(driver.world(), is); + auto& w = driver.world(); + auto ast = AST(w); + std::istringstream is("{ } ( ) [ ] ‹ › « » : , . .lam λ Π 23₀₁₂₃₄₅₆₇₈₉"); + Lexer lexer(ast, is); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::D_brace_l)); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::D_brace_r)); @@ -30,7 +33,6 @@ TEST(Lexer, Toks) { EXPECT_TRUE(lexer.lex().isa(Tok::Tag::T_comma)); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::T_dot)); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::K_lam)); - EXPECT_TRUE(lexer.lex().isa(Tok::Tag::K_Pi)); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::T_lm)); EXPECT_TRUE(lexer.lex().isa(Tok::Tag::T_Pi)); auto tok = lexer.lex(); @@ -41,30 +43,45 @@ TEST(Lexer, Toks) { TEST(Lexer, Errors) { Driver driver; + auto& w = driver.world(); + auto ast = ast::AST(w); std::istringstream is1("asdf \xc0\xc0"); - Lexer l1(driver.world(), is1); + Lexer l1(ast, is1); l1.lex(); - EXPECT_ANY_THROW(l1.lex()); + l1.lex(); + EXPECT_GE(ast.error().num_errors(), 1); + EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("invalid UTF-8")); + ast.error().clear(); std::istringstream is2("foo \xaa"); - Lexer l2(driver.world(), is2); + Lexer l2(ast, is2); l2.lex(); - EXPECT_ANY_THROW(l2.lex()); + l2.lex(); + EXPECT_GE(ast.error().num_errors(), 1); + EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("invalid UTF-8")); + ast.error().clear(); std::istringstream is3("+"); - Lexer l3(driver.world(), is3); - EXPECT_ANY_THROW(l3.lex()); + Lexer l3(ast, is3); + l3.lex(); + EXPECT_GE(ast.error().num_errors(), 1); + EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("stray")); + ast.error().clear(); std::istringstream is4("-"); - Lexer l4(driver.world(), is4); - EXPECT_ANY_THROW(l4.lex()); + Lexer l4(ast, is4); + l4.lex(); + EXPECT_GE(ast.error().num_errors(), 1); + EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("stray")); } TEST(Lexer, Eof) { Driver driver; + auto& w = driver.world(); + auto ast = AST(w); std::istringstream is(""); - Lexer lexer(driver.world(), is); + Lexer lexer(ast, is); for (int i = 0; i < 10; i++) EXPECT_TRUE(lexer.lex().isa(Tok::Tag::EoF)); } @@ -72,10 +89,11 @@ class Real : public testing::TestWithParam {}; TEST_P(Real, sign) { Driver driver; - World& w = driver.world(); + auto& w = driver.world(); + auto ast = AST(w); // clang-format off - auto check = [&w](std::string s, f64 r) { + auto check = [&ast](std::string s, f64 r) { const auto sign = GetParam(); switch (sign) { case 0: break; @@ -85,7 +103,7 @@ TEST_P(Real, sign) { } std::istringstream is(s); - Lexer lexer(w, is); + Lexer lexer(ast, is); auto tag = lexer.lex(); EXPECT_TRUE(tag.isa(Tok::Tag::L_f)); @@ -104,11 +122,11 @@ TEST_P(Real, sign) { // clang-format on std::istringstream is1("0x2.34"); - Lexer l1(w, is1); + Lexer l1(ast, is1); EXPECT_ANY_THROW(l1.lex()); std::istringstream is2("2.34e"); - Lexer l2(w, is2); + Lexer l2(ast, is2); EXPECT_ANY_THROW(l2.lex()); } diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index 853adb673c..13401b878f 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include @@ -28,7 +26,8 @@ TEST(RestrictedDependentTypes, join_singleton) { auto test_on_world = [](auto test) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math"}) parser.plugin(plugin); auto i32_t = w.type_i32(); @@ -219,7 +218,8 @@ TEST(RestrictedDependentTypes, join_singleton) { TEST(RestrictedDependentTypes, ll) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); for (auto plugin : {"compile", "mem", "core", "math"}) parser.plugin(plugin); auto mem_t = w.annex(); diff --git a/gtest/test.cpp b/gtest/test.cpp index ae1657bafb..9919d0c894 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -1,7 +1,5 @@ #include -#include -#include #include #include @@ -19,7 +17,8 @@ using namespace thorin::plug; TEST(Zip, fold) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); std::istringstream iss(".plugin core;" ".let _32 = .i32;" @@ -29,12 +28,12 @@ TEST(Zip, fold) { ".let c = ((6:I32, 8:I32, 10:I32), (12:I32, 14:I32, 16:I32));" ".let r = %core.zip (2, (2, 3)) (2, (I32, I32), 1, I32, %core.wrap.add 0) (a, b);"); parser.import(iss); - auto c = parser.scopes().find({Loc(), driver.sym("c")}); - auto r = parser.scopes().find({Loc(), driver.sym("r")}); + // auto c = parser.scopes().find({Loc(), driver.sym("c")}); + // auto r = parser.scopes().find({Loc(), driver.sym("r")}); - EXPECT_TRUE(r->is_term()); - EXPECT_TRUE(!r->type()->is_term()); - EXPECT_EQ(c, r); + // EXPECT_TRUE(r->is_term()); + // EXPECT_TRUE(!r->type()->is_term()); + // EXPECT_EQ(c, r); } TEST(World, simplify_one_tuple) { @@ -63,33 +62,32 @@ TEST(World, dependent_extract) { } TEST(Annex, mangle) { - Driver driver; - World& w = driver.world(); + Driver d; - EXPECT_EQ(Annex::demangle(w, *Annex::mangle(w.sym("test"))), w.sym("test")); - EXPECT_EQ(Annex::demangle(w, *Annex::mangle(w.sym("azAZ09_"))), w.sym("azAZ09_")); - EXPECT_EQ(Annex::demangle(w, *Annex::mangle(w.sym("01234567"))), w.sym("01234567")); - EXPECT_FALSE(Annex::mangle(w.sym("012345678"))); - EXPECT_FALSE(Annex::mangle(w.sym("!"))); + EXPECT_EQ(Annex::demangle(d, *Annex::mangle(d.sym("test"))), d.sym("test")); + EXPECT_EQ(Annex::demangle(d, *Annex::mangle(d.sym("azAZ09_"))), d.sym("azAZ09_")); + EXPECT_EQ(Annex::demangle(d, *Annex::mangle(d.sym("01234567"))), d.sym("01234567")); + EXPECT_FALSE(Annex::mangle(d.sym("012345678"))); + EXPECT_FALSE(Annex::mangle(d.sym("!"))); // Check whether lower 16 bits are properly ignored - EXPECT_EQ(Annex::demangle(w, *Annex::mangle(w.sym("test")) | 0xFF_u64), w.sym("test")); - EXPECT_EQ(Annex::demangle(w, *Annex::mangle(w.sym("01234567")) | 0xFF_u64), w.sym("01234567")); + EXPECT_EQ(Annex::demangle(d, *Annex::mangle(d.sym("test")) | 0xFF_u64), d.sym("test")); + EXPECT_EQ(Annex::demangle(d, *Annex::mangle(d.sym("01234567")) | 0xFF_u64), d.sym("01234567")); } TEST(Annex, split) { - Driver driver; - World& w = driver.world(); + Driver d; - auto [plugin, group, tag] = Annex::split(w, w.sym("%foo.bar.baz")); - EXPECT_EQ(plugin, w.sym("foo")); - EXPECT_EQ(group, w.sym("bar")); - EXPECT_EQ(tag, w.sym("baz")); + auto [plugin, group, tag] = Annex::split(d, d.sym("%foo.bar.baz")); + EXPECT_EQ(plugin, d.sym("foo")); + EXPECT_EQ(group, d.sym("bar")); + EXPECT_EQ(tag, d.sym("baz")); } TEST(trait, idx) { Driver driver; World& w = driver.world(); - auto parser = ast::Parser(w); + auto ast = ast::AST(w); + auto parser = ast::Parser(ast); parser.plugin("core"); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'00FF_n))), 1); diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 14f09c411f..f0e397e750 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -34,7 +33,8 @@ class AST { ///@{ World& world() { return world_; } Driver& driver() { return world().driver(); } - const Error& error() { return err_; } + Error& error() { return err_; } + const Error& error() const { return err_; } ///@} /// @name Sym diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index 0d35832bcf..c74daeb040 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 7ac5c5fee1..92831a2201 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -39,7 +39,8 @@ class Error : std::exception { /// @name Constructors ///@{ Error() = default; - Error(Loc loc, const std::string& str) ///< Creates a single Tag::Error message. + /// Creates a single Tag::Error message. + Error(Loc loc, const std::string& str) : msgs_{ {loc, Tag::Error, str} } {} @@ -57,6 +58,13 @@ class Error : std::exception { size_t num_notes() const { return num_notes_; } ///@} + void clear() { + num_errors_ = 0; + num_warnings_ = 0; + num_notes_ = 0; + msgs_.clear(); + } + /// @name Add formatted message ///@{ template Error& msg(Loc loc, Tag tag, const char* s, Args&&... args) { diff --git a/include/thorin/util/print.h b/include/thorin/util/print.h index 9fcbd481b3..de29225899 100644 --- a/include/thorin/util/print.h +++ b/include/thorin/util/print.h @@ -108,7 +108,19 @@ template std::ostream& print(std::ostream& os, const cha } else if constexpr (std::is_invocable_v) { std::invoke(t, os); } else if constexpr (detail::Printable) { + auto flags = std::ios_base::fmtflags(os.flags()); + + if (spec == "b") + assert(false && "TODO"); + else if (spec == "o") + os << std::oct; + else if (spec == "d") + os << std::dec; + else if (spec == "x") + os << std::hex; + os << t; + os.flags(flags); } else if constexpr (detail::Elemable) { detail::range(os, t.range, t.f, spec.c_str()); } else if constexpr (std::ranges::range) { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index c84662d743..c738467c0d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -2,6 +2,8 @@ #include "thorin/ast/ast.h" +using namespace std::literals; + namespace thorin::ast { using Tag = Tok::Tag; @@ -18,6 +20,24 @@ class Emitter { absl::node_hash_map, GIDHash, GIDEq> sigma2sym2idx; + void register_if_annex(Dbg dbg, Ref def) { + if (dbg && dbg.sym.front() == '%') { + auto [plugin, tag, sub] = Annex::split(driver(), dbg.sym); + auto name = world().sym("%"s + plugin.str() + "."s + tag.str()); + auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc); + plugin_t p = *Annex::mangle(plugin); + tag_t t = annex.tag_id; + sub_t s = annex.subs.size(); + + if (sub) { + auto& aliases = annex.subs.emplace_back(); + aliases.emplace_back(sub); + } + + world().register_annex(p | (t << 8) | s, def); + } + } + private: AST& ast_; World& world_; @@ -316,12 +336,13 @@ void DeclsBlock::emit(Emitter& e) const { void LetDecl::emit_decl(Emitter& e) const { auto v = value()->emit(e); def_ = ptrn()->emit_value(e, v); + + if (auto id = ptrn()->isa()) e.register_if_annex(id->dbg(), def_); } void AxiomDecl::Alias::emit(Emitter& e, sub_t sub, NormalizeFn norm) const { const auto& id = axiom_->id_; - outln("{}: {} - {} - {}", dbg(), id.plugin, (int)id.tag, (int)sub_); - def_ = e.world().axiom(norm, id.curry, id.trip, axiom_->thorin_type_, id.plugin, id.tag, sub)->set(dbg()); + def_ = e.world().axiom(norm, id.curry, id.trip, axiom_->thorin_type_, id.plugin, id.tag, sub)->set(dbg()); } void AxiomDecl::emit_decl(Emitter& e) const { @@ -346,15 +367,22 @@ void AxiomDecl::emit_decl(Emitter& e) const { id_.trip = i_trip; } + if (!is_new && annex.pi != (thorin_type_->isa() != nullptr)) + error(dbg().loc, "all declarations of annex '{}' have to be function types if any is", dbg().sym); + annex.pi = thorin_type_->isa() != nullptr; + annex.normalizer = normalizer().sym; + if (num_subs() == 0) { auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); def_ = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); } else { for (sub_t i = 0, n = num_subs(); i != n; ++i) { - auto norm = e.driver().normalizer(id_.plugin, id_.tag, i); + auto norm = e.driver().normalizer(id_.plugin, id_.tag, i); + auto& aliases = annex.subs.emplace_back(std::deque()); for (const auto& alias : sub(i)) { alias->sub_ = i; alias->emit(e, i, norm); + aliases.emplace_back(alias->dbg().sym); } } } @@ -365,7 +393,11 @@ void RecDecl::emit_decl(Emitter& e) const { def_ = body()->emit_decl(e, t); } -void RecDecl::emit_body(Emitter& e) const { body()->emit_body(e, def_); } +void RecDecl::emit_body(Emitter& e) const { + body()->emit_body(e, def_); + // TODO immutabilize? + e.register_if_annex(dbg(), def_); +} Lam* LamDecl::Dom::emit_value(Emitter& e) const { lam_ = e.world().mut_lam(pi_); @@ -412,6 +444,7 @@ void LamDecl::emit_decl(Emitter& e) const { void LamDecl::emit_body(Emitter& e) const { doms().back()->lam_->set_body(body()->emit(e)); if (is_external()) doms().front()->lam_->make_external(); + e.register_if_annex(dbg(), def_); } } // namespace thorin::ast diff --git a/src/thorin/ast/lexer.cpp b/src/thorin/ast/lexer.cpp index a351ab40dd..2d7c59da2b 100644 --- a/src/thorin/ast/lexer.cpp +++ b/src/thorin/ast/lexer.cpp @@ -166,7 +166,7 @@ Tok Lexer::lex() { continue; } - ast().error({loc_.path, peek_}, "invalid input char '{}'", utf8::Char32(ahead())); + ast().error({loc_.path, peek_}, "invalid input char '{x}'", (uint32_t)utf8::Char32(ahead()).c); next(); } } diff --git a/src/thorin/plug/opt/opt.cpp b/src/thorin/plug/opt/opt.cpp index 859832cb16..f95e449380 100644 --- a/src/thorin/plug/opt/opt.cpp +++ b/src/thorin/plug/opt/opt.cpp @@ -23,7 +23,7 @@ extern "C" THORIN_EXPORT Plugin thorin_get_plugin() { auto then_phase = args[2]; auto else_phase = args[3]; auto name = plugin_axiom->sym(); // name has the form %opt.tag - auto [_, tag, __] = Annex::split(world, name); // where tag = [plugin]_plugin + auto [_, tag, __] = Annex::split(driver, name); // where tag = [plugin]_plugin auto plugin = tag.view().substr(0, tag.view().find('_')); // we want to extract the plugin bool is_loaded = driver.is_loaded(driver.sym(plugin)); From 5d964ec4c92880d90a90349cba67191b7ea1342b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 16 Apr 2024 17:12:57 +0200 Subject: [PATCH 53/95] bug fixes when registerring annexes --- gtest/helpers.cpp | 4 ++-- gtest/helpers.h | 7 ++----- gtest/test.cpp | 12 ++++++------ include/thorin/ast/ast.h | 9 ++++++--- include/thorin/util/dbg.h | 3 --- include/thorin/world.h | 2 +- src/thorin/ast/ast.cpp | 13 +++++++++++-- src/thorin/ast/bind.cpp | 10 ++-------- src/thorin/ast/emit.cpp | 36 +++++++++++++++++++++--------------- src/thorin/cli/main.cpp | 2 +- src/thorin/dot.cpp | 5 +---- src/thorin/dump.cpp | 1 + src/thorin/world.cpp | 1 + 13 files changed, 55 insertions(+), 50 deletions(-) diff --git a/gtest/helpers.cpp b/gtest/helpers.cpp index bd13ac559d..8642515893 100644 --- a/gtest/helpers.cpp +++ b/gtest/helpers.cpp @@ -1,7 +1,7 @@ -#include "helpers.h" - #include +#include + namespace thorin::gtest { std::string test_name() { diff --git a/gtest/helpers.h b/gtest/helpers.h index ce4fc4a722..c0ee99782c 100644 --- a/gtest/helpers.h +++ b/gtest/helpers.h @@ -1,12 +1,9 @@ -#ifndef THORIN_GTEST_HELPERS_H -#define THORIN_GTEST_HELPERS_H +#pragma once -#include +#include namespace thorin::gtest { std::string test_name(); } - -#endif diff --git a/gtest/test.cpp b/gtest/test.cpp index 9919d0c894..ec6118e6fb 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -9,8 +11,6 @@ #include -#include "helpers.h" - using namespace thorin; using namespace thorin::plug; @@ -85,10 +85,10 @@ TEST(Annex, split) { TEST(trait, idx) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - parser.plugin("core"); + World& w = driver.world(); + w.log().set(Log::Level::Debug); + w.log().set(&std::cout); + ast::load_plugin(w, "core"); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'00FF_n))), 1); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'0100_n))), 1); diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index f0e397e750..692c3cc4ea 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -687,7 +687,7 @@ class AxiomDecl : public ValDecl { Dbg dbg() const { return dbg_; } void bind(Scopes&, const AxiomDecl*) const; - void emit(Emitter&, sub_t, NormalizeFn) const; + void emit(Emitter&, const Axiom*) const; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -866,10 +866,10 @@ class Module : public Node { const auto& imports() const { return imports_; } - void compile(AST&, World&) const; + void compile(AST&) const; void bind(AST&) const; void bind(Scopes&) const; - void emit(AST&, World&) const; + void emit(AST&) const; void emit(Emitter&) const; std::ostream& stream(Tab&, std::ostream&) const override; @@ -878,4 +878,7 @@ class Module : public Node { DeclsBlock decls_; }; +void load_plugin(World&, Sym); +inline void load_plugin(World& w, std::string_view sv) { return load_plugin(w, w.sym(sv)); } + } // namespace thorin::ast diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 92831a2201..ff70a2c2a0 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - #include #include #include diff --git a/include/thorin/world.h b/include/thorin/world.h index 10373452f0..20c2af1a9b 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -165,7 +165,7 @@ class World { template const Def* annex(Id id) { auto flags = static_cast(id); if (auto i = move_.annexes.find(flags); i != move_.annexes.end()) return i->second; - error("Axiom with ID '{}' not found; demangled plugin name is '{}'", flags, Annex::demangle(driver(), flags)); + error("Axiom with ID '{x}' not found; demangled plugin name is '{}'", flags, Annex::demangle(driver(), flags)); } /// Get Axiom from a plugin. diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index c16f4221f7..25251b0133 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -1,5 +1,7 @@ #include "thorin/ast/ast.h" +#include "thorin/ast/parser.h" + namespace thorin::ast { LamExpr::LamExpr(Ptr&& lam) @@ -26,12 +28,19 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { return {}; } -void Module::compile(AST& ast, World& world) const { +void Module::compile(AST& ast) const { bind(ast); if (ast.error().num_errors() != 0) throw ast.error(); - emit(ast, world); + emit(ast); // HACK if (ast.error().num_errors() == 0 && ast.error().num_msgs() != 0) std::cerr << ast.error(); } +void load_plugin(World& world, Sym plugin) { + auto ast = AST(world); + auto parser = Parser(ast); + auto mod = parser.plugin(plugin); + mod->compile(ast); +} + } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 27a374706a..85a9eca5bf 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -1,7 +1,5 @@ #include "thorin/ast/ast.h" -#include "fe/assert.h" - using namespace std::literals; namespace thorin::ast { @@ -66,8 +64,6 @@ class Scopes { } } - tag_t next_tag(plugin_t p) { return plugin2tag_.emplace(p, 0).first->second; } - private: AST& ast_; Ptr dummy_; @@ -259,12 +255,10 @@ void AxiomDecl::bind_decl(Scopes& s) const { std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym); - if (auto p = Annex::mangle(sym_.plugin)) { + if (auto p = Annex::mangle(sym_.plugin)) id_.plugin = *p; - id_.tag = s.next_tag(*p); - } else { + else s.ast().error(dbg().loc, "invalid axiom name '{}'", dbg()); - } if (sym_.sub) error(dbg().loc, "axiom '{}' must not have a subtag", dbg().sym); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index c738467c0d..4d75ddcb47 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -10,12 +10,11 @@ using Tag = Tok::Tag; class Emitter { public: - Emitter(AST& ast, World& world) - : ast_(ast) - , world_(world) {} + Emitter(AST& ast) + : ast_(ast) {} AST& ast() const { return ast_; } - World& world() { return world_; } + World& world() { return ast().world(); } Driver& driver() { return world().driver(); } absl::node_hash_map, GIDHash, GIDEq> sigma2sym2idx; @@ -40,7 +39,6 @@ class Emitter { private: AST& ast_; - World& world_; }; /* @@ -105,8 +103,8 @@ Ref LitExpr::emit(Emitter& e) const { // clang-format on } -void Module::emit(AST& ast, World& world) const { - auto emitter = Emitter(ast, world); +void Module::emit(AST& ast) const { + auto emitter = Emitter(ast); emit(emitter); } @@ -340,9 +338,9 @@ void LetDecl::emit_decl(Emitter& e) const { if (auto id = ptrn()->isa()) e.register_if_annex(id->dbg(), def_); } -void AxiomDecl::Alias::emit(Emitter& e, sub_t sub, NormalizeFn norm) const { +void AxiomDecl::Alias::emit(Emitter& e, const Axiom* axiom) const { const auto& id = axiom_->id_; - def_ = e.world().axiom(norm, id.curry, id.trip, axiom_->thorin_type_, id.plugin, id.tag, sub)->set(dbg()); + def_ = axiom; } void AxiomDecl::emit_decl(Emitter& e) const { @@ -369,19 +367,27 @@ void AxiomDecl::emit_decl(Emitter& e) const { if (!is_new && annex.pi != (thorin_type_->isa() != nullptr)) error(dbg().loc, "all declarations of annex '{}' have to be function types if any is", dbg().sym); + + id_.tag = annex.tag_id; annex.pi = thorin_type_->isa() != nullptr; annex.normalizer = normalizer().sym; if (num_subs() == 0) { - auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); - def_ = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); + auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); + auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); + def_ = axiom; + e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64), axiom); } else { + sub_t offset = annex.subs.size(); for (sub_t i = 0, n = num_subs(); i != n; ++i) { - auto norm = e.driver().normalizer(id_.plugin, id_.tag, i); + sub_t s = i + offset; + auto norm = e.driver().normalizer(id_.plugin, id_.tag, s); auto& aliases = annex.subs.emplace_back(std::deque()); - for (const auto& alias : sub(i)) { - alias->sub_ = i; - alias->emit(e, i, norm); + auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, s)->set(dbg()); + e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64) | flags_t(s), axiom); + for (const auto& alias : sub(s)) { + alias->sub_ = s; + alias->emit(e, axiom); aliases.emplace_back(alias->dbg().sym); } } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 240daa6c1f..7854bb8292 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -139,7 +139,7 @@ int main(int argc, char** argv) { auto ast = ast::AST(world); auto parser = ast::Parser(ast); auto mod = parser.import(driver.sym(input), os[Md]); - mod->compile(ast, world); + mod->compile(ast); if (auto s = os[AST]) { Tab tab; diff --git a/src/thorin/dot.cpp b/src/thorin/dot.cpp index c5ca032339..168b3334b6 100644 --- a/src/thorin/dot.cpp +++ b/src/thorin/dot.cpp @@ -92,16 +92,13 @@ class Dot { static constexpr auto NL = " "; auto loc = escape(def->loc()); auto type = escape(def->type()); - std::ostringstream oss; - oss << "0x" << std::hex << def->flags(); - auto flags = oss.str(); escape(loc); print(os_, "tooltip=\""); print(os_, "expr: {}{}", def, NL); print(os_, "type: {}{}", type, NL); print(os_, "name: {}{}", def->sym(), NL); print(os_, "gid: {}{}", def->gid(), NL); - print(os_, "flags: {}{}", flags, NL); + print(os_, "flags: 0x{x}{}", def->flags(), NL); print(os_, "free_vars: {{{, }}}{}", def->free_vars(), NL); print(os_, "local_vars: {{{, }}}{}", def->local_vars(), NL); print(os_, "local_muts: {{{, }}}{}", def->local_muts(), NL); diff --git a/src/thorin/dump.cpp b/src/thorin/dump.cpp index 3b649bd3e9..7fd1c8a352 100644 --- a/src/thorin/dump.cpp +++ b/src/thorin/dump.cpp @@ -180,6 +180,7 @@ std::ostream& operator<<(std::ostream& os, Inline u) { } else if (auto var = u->isa()) { return print(os, "{}", var->unique_name()); } else if (auto pi = u->isa()) { + return os << "TODO"; if (Pi::isa_cn(pi)) return print(os, ".Cn {}", pi->dom()); if (auto mut = pi->isa_mut(); mut && mut->var()) return print(os, "Π {}: {} {} {}", mut->var(), pi->dom(), arw, pi->codom()); diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index e67f54f2c3..793e2479de 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -78,6 +78,7 @@ Sym World::sym(std::string_view s) { return driver().sym(s); } Sym World::sym(const std::string& s) { return driver().sym(s); } const Def* World::register_annex(flags_t f, const Def* def) { + DLOG("register: 0x{f} -> {}", f, def); auto plugin = Annex::demangle(driver(), f); if (driver().is_loaded(plugin)) { assert_emplace(move_.annexes, f, def); From fe235a030c90274eefc3bba4a14521a0bb2260e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 17 Apr 2024 15:03:13 +0200 Subject: [PATCH 54/95] bug fixes --- gtest/lexer.cpp | 17 +++++++++++------ gtest/restricted_dep_types.cpp | 7 +++---- gtest/test.cpp | 9 +++------ include/thorin/ast/ast.h | 6 +++++- include/thorin/util/dbg.h | 4 +++- src/thorin/ast/ast.cpp | 30 ++++++++++++++++++++++-------- src/thorin/ast/bind.cpp | 14 +++++--------- src/thorin/ast/emit.cpp | 2 +- 8 files changed, 53 insertions(+), 36 deletions(-) diff --git a/gtest/lexer.cpp b/gtest/lexer.cpp index 8408b0e69b..e5cf3ab0d9 100644 --- a/gtest/lexer.cpp +++ b/gtest/lexer.cpp @@ -50,7 +50,7 @@ TEST(Lexer, Errors) { l1.lex(); l1.lex(); EXPECT_GE(ast.error().num_errors(), 1); - EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("invalid UTF-8")); + EXPECT_TRUE(ast.error().msgs().front().str.starts_with("invalid UTF-8")); ast.error().clear(); std::istringstream is2("foo \xaa"); @@ -58,21 +58,21 @@ TEST(Lexer, Errors) { l2.lex(); l2.lex(); EXPECT_GE(ast.error().num_errors(), 1); - EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("invalid UTF-8")); + EXPECT_TRUE(ast.error().msgs().front().str.starts_with("invalid UTF-8")); ast.error().clear(); std::istringstream is3("+"); Lexer l3(ast, is3); l3.lex(); EXPECT_GE(ast.error().num_errors(), 1); - EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("stray")); + EXPECT_TRUE(ast.error().msgs().front().str.starts_with("stray")); ast.error().clear(); std::istringstream is4("-"); Lexer l4(ast, is4); l4.lex(); EXPECT_GE(ast.error().num_errors(), 1); - EXPECT_TRUE(ast.error().msgs()[0].str.starts_with("stray")); + EXPECT_TRUE(ast.error().msgs().front().str.starts_with("stray")); } TEST(Lexer, Eof) { @@ -123,11 +123,16 @@ TEST_P(Real, sign) { std::istringstream is1("0x2.34"); Lexer l1(ast, is1); - EXPECT_ANY_THROW(l1.lex()); + l1.lex(); + EXPECT_EQ(ast.error().num_errors(), 1); + EXPECT_TRUE(ast.error().msgs().front().str == "hexadecimal floating constants require an exponent"sv); + ast.error().clear(); std::istringstream is2("2.34e"); Lexer l2(ast, is2); - EXPECT_ANY_THROW(l2.lex()); + l2.lex(); + EXPECT_EQ(ast.error().num_errors(), 1); + EXPECT_TRUE(ast.error().msgs().front().str == "exponent has no digits"); } INSTANTIATE_TEST_SUITE_P(Lexer, Real, testing::Range(0, 3)); diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index 13401b878f..552f50c419 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -17,6 +17,7 @@ #include #include +using namespace std::literals; using namespace thorin; using namespace thorin::plug; @@ -25,10 +26,8 @@ using namespace thorin::plug; TEST(RestrictedDependentTypes, join_singleton) { auto test_on_world = [](auto test) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math"}) parser.plugin(plugin); + World& w = driver.world(); + ast::load_plugin(w, {"compile"sv, "mem"sv, "core"sv, "math"sv}); auto i32_t = w.type_i32(); auto i64_t = w.type_i64(); diff --git a/gtest/test.cpp b/gtest/test.cpp index ec6118e6fb..e4b18cacd9 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -86,8 +86,6 @@ TEST(Annex, split) { TEST(trait, idx) { Driver driver; World& w = driver.world(); - w.log().set(Log::Level::Debug); - w.log().set(&std::cout); ast::load_plugin(w, "core"); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'00FF_n))), 1); @@ -275,11 +273,10 @@ TEST(FV, free_vars) { auto Nat = w.type_nat(); auto lx = w.mut_lam(Nat, {Nat, Nat}); auto ly = w.mut_lam(Nat, {Nat, Nat}); - auto x = lx->var()->set("x"); - auto y = ly->var()->set("y"); + auto x = lx->var()->set("x")->as(); + auto y = ly->var()->set("y")->as(); lx->set(false, w.tuple({x, y})); - auto fvs = lx->free_vars(); - outln("{, }", fvs); + EXPECT_EQ(lx->free_vars(), w.vars(y)); } TEST(ADT, Span) { diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 692c3cc4ea..83ce3994b9 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -878,7 +878,11 @@ class Module : public Node { DeclsBlock decls_; }; -void load_plugin(World&, Sym); +void load_plugin(World&, View); +inline void load_plugin(World& w, View svs) { + return load_plugin(w, Vector(svs.size(), [&](size_t i) { return w.sym(svs[i]); })); +} +inline void load_plugin(World& w, Sym sym) { return load_plugin(w, View({sym})); } inline void load_plugin(World& w, std::string_view sv) { return load_plugin(w, w.sym(sv)); } } // namespace thorin::ast diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index ff70a2c2a0..4ec8a9eeb9 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -72,7 +72,9 @@ class Error : std::exception { // clang-format off template Error& error(Loc loc, const char* s, Args&&... args) { ++num_errors_; return msg(loc, Tag::Error, s, std::forward(args)...); } template Error& warn (Loc loc, const char* s, Args&&... args) { ++num_warnings_; return msg(loc, Tag::Warn, s, std::forward(args)...); } - template Error& note (Loc loc, const char* s, Args&&... args) { ++num_notes_; return msg(loc, Tag::Note, s, std::forward(args)...); } + template Error& note (Loc loc, const char* s, Args&&... args) { + assert(num_errors() > 0 || num_warnings() > 0); /* */ ++num_notes_; return msg(loc, Tag::Note, s, std::forward(args)...); + } // clang-format on //@} diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 25251b0133..3791c65e1a 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -29,18 +29,32 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { } void Module::compile(AST& ast) const { + const auto& err = ast.error(); bind(ast); - if (ast.error().num_errors() != 0) throw ast.error(); + if (err.num_errors() != 0) throw err; emit(ast); - // HACK - if (ast.error().num_errors() == 0 && ast.error().num_msgs() != 0) std::cerr << ast.error(); + + assert(err.num_errors() == 0 && "If an error occurs during emit, an exception should have been thrown"); + if (err.num_warnings() != 0) + ast.driver().WLOG("{} warning(s) encountered while compiling module\n{}", err.num_warnings(), err); } -void load_plugin(World& world, Sym plugin) { - auto ast = AST(world); - auto parser = Parser(ast); - auto mod = parser.plugin(plugin); - mod->compile(ast); +void load_plugin(World& world, View plugins) { + assert(!plugins.empty() && "must load at least one plugin"); + + auto ast = AST(world); + auto parser = Parser(ast); + auto imports = Ptrs(); + for (auto plugin : plugins) { + auto mod = parser.plugin(plugin); + imports.emplace_back(ast.ptr(mod->loc(), Dbg(Loc(), plugin), Tok::Tag::K_plugin, std::move(mod))); + } + auto mod = ast.ptr(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs()); + try { + mod->compile(ast); + } catch (const Error& err) { + world.ELOG("{} error(s) encountered while compiling plugins: '{, }'\n{}", err.num_errors(), plugins, err); + } } } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 85a9eca5bf..2198a65e78 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -76,17 +76,13 @@ class Scopes { */ // clang-format off -void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } -void ErrorExpr ::bind(Scopes&) const {} -void InferExpr ::bind(Scopes&) const {} -void PrimaryExpr ::bind(Scopes&) const {} +void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } +void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } +void ErrorExpr ::bind(Scopes&) const {} +void InferExpr ::bind(Scopes&) const {} +void PrimaryExpr::bind(Scopes&) const {} // clang-format on -void IdExpr ::bind(Scopes& s) const { - decl_ = s.find(dbg()); - assert(decl_); -} - void LitExpr::bind(Scopes& s) const { if (type()) { type()->bind(s); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 4d75ddcb47..ea3c6b575a 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -385,7 +385,7 @@ void AxiomDecl::emit_decl(Emitter& e) const { auto& aliases = annex.subs.emplace_back(std::deque()); auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, s)->set(dbg()); e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64) | flags_t(s), axiom); - for (const auto& alias : sub(s)) { + for (const auto& alias : sub(i)) { alias->sub_ = s; alias->emit(e, axiom); aliases.emplace_back(alias->dbg().sym); From a6ff9cb276a979003022540fb67bd14764f4b268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 19 Apr 2024 02:08:25 +0200 Subject: [PATCH 55/95] wip: bug fixing ... --- gtest/lexer.cpp | 2 ++ gtest/restricted_dep_types.cpp | 2 +- gtest/test.cpp | 2 +- include/thorin/ast/ast.h | 61 ++++++++++++++++++++++++++-------- include/thorin/ast/parser.h | 1 + include/thorin/ast/tok.h | 1 + include/thorin/tuple.h | 1 + include/thorin/util/dbg.h | 26 ++++++++++++++- lit/pow_pe.thorin | 2 ++ lit/ptrn.thorin | 2 ++ lit/rec.thorin | 2 -- lit/rec_pi.thorin | 5 ++- lit/str.thorin | 4 +-- src/thorin/ast/ast.cpp | 40 ++++++++++++---------- src/thorin/ast/bind.cpp | 8 +++++ src/thorin/ast/emit.cpp | 8 ++++- src/thorin/ast/parser.cpp | 11 ++++++ src/thorin/ast/stream.cpp | 5 ++- src/thorin/check.cpp | 12 ++++++- src/thorin/cli/main.cpp | 8 ++--- src/thorin/def.cpp | 6 ++-- src/thorin/world.cpp | 2 +- 22 files changed, 159 insertions(+), 52 deletions(-) diff --git a/gtest/lexer.cpp b/gtest/lexer.cpp index e5cf3ab0d9..f1a2378e82 100644 --- a/gtest/lexer.cpp +++ b/gtest/lexer.cpp @@ -73,6 +73,7 @@ TEST(Lexer, Errors) { l4.lex(); EXPECT_GE(ast.error().num_errors(), 1); EXPECT_TRUE(ast.error().msgs().front().str.starts_with("stray")); + ast.error().clear(); } TEST(Lexer, Eof) { @@ -133,6 +134,7 @@ TEST_P(Real, sign) { l2.lex(); EXPECT_EQ(ast.error().num_errors(), 1); EXPECT_TRUE(ast.error().msgs().front().str == "exponent has no digits"); + ast.error().clear(); } INSTANTIATE_TEST_SUITE_P(Lexer, Real, testing::Range(0, 3)); diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index 552f50c419..df58281d4b 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -27,7 +27,7 @@ TEST(RestrictedDependentTypes, join_singleton) { auto test_on_world = [](auto test) { Driver driver; World& w = driver.world(); - ast::load_plugin(w, {"compile"sv, "mem"sv, "core"sv, "math"sv}); + ast::load_plugins(w, {"compile"s, "mem"s, "core"s, "math"s}); auto i32_t = w.type_i32(); auto i64_t = w.type_i64(); diff --git a/gtest/test.cpp b/gtest/test.cpp index e4b18cacd9..8622541d30 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -86,7 +86,7 @@ TEST(Annex, split) { TEST(trait, idx) { Driver driver; World& w = driver.world(); - ast::load_plugin(w, "core"); + ast::load_plugins(w, "core"); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'00FF_n))), 1); EXPECT_EQ(Lit::as(op(core::trait::size, w.type_idx(0x0000'0000'0000'0100_n))), 1); diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 83ce3994b9..484dd7d44c 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -24,14 +24,18 @@ template using Ptrs = std::deque>; class AST { public: + AST() = default; AST(World& world) - : world_(world) - , sym_anon_(sym("_")) - , sym_return_(sym("return")) {} + : world_(&world) {} + AST(AST&& other) + : AST() { + swap(*this, other); + } + ~AST(); /// @name Getters ///@{ - World& world() { return world_; } + World& world() { return *world_; } Driver& driver() { return world().driver(); } Error& error() { return err_; } const Error& error() const { return err_; } @@ -42,8 +46,8 @@ class AST { Sym sym(const char* s) { return driver().sym(s); } Sym sym(std::string_view s) { return driver().sym(s); } Sym sym(const std::string& s) { return driver().sym(s); } - Sym sym_anon() const { return sym_anon_; } ///< `"_"`. - Sym sym_return() const { return sym_return_; } ///< `"return"`. + Sym sym_anon() { return sym("_"); } ///< `"_"`. + Sym sym_return() { return sym("return"); } ///< `"return"`. ///@} template auto ptr(Args&&... args) { @@ -59,11 +63,18 @@ class AST { // clang-format on ///@} + friend void swap(AST& a1, AST& a2) noexcept { + using std::swap; + // clang-format off + swap(a1.world_, a2.world_); + swap(a1.arena_, a2.arena_); + swap(a1.err_, a2.err_); + // clang-format on + } + private: - World& world_; + World* world_ = nullptr; fe::Arena arena_; - Sym sym_anon_; - Sym sym_return_; mutable Error err_; }; @@ -824,6 +835,28 @@ class LamDecl : public RecDecl { Ptr codom_; }; +/// `.cfun dbg dom -> codom` +class CFun : public ValDecl { +public: + CFun(Loc loc, Dbg dbg, Ptr&& dom, Ptr&& codom) + : ValDecl(loc) + , dbg_(dbg) + , dom_(std::move(dom)) + , codom_(std::move(codom)) {} + + Dbg dbg() const { return dbg_; } + const Ptrn* dom() const { return dom_.get(); } + const Expr* codom() const { return codom_.get(); } + + void bind_decl(Scopes&) const override; + void emit_decl(Emitter&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Dbg dbg_; + Ptr dom_; + Ptr codom_; +}; /* * Module */ @@ -878,11 +911,11 @@ class Module : public Node { DeclsBlock decls_; }; -void load_plugin(World&, View); -inline void load_plugin(World& w, View svs) { - return load_plugin(w, Vector(svs.size(), [&](size_t i) { return w.sym(svs[i]); })); +AST load_plugins(World&, View); +inline AST load_plugins(World& w, View plugins) { + return load_plugins(w, Vector(plugins.size(), [&](size_t i) { return w.sym(plugins[i]); })); } -inline void load_plugin(World& w, Sym sym) { return load_plugin(w, View({sym})); } -inline void load_plugin(World& w, std::string_view sv) { return load_plugin(w, w.sym(sv)); } +inline AST load_plugins(World& w, Sym sym) { return load_plugins(w, View({sym})); } +inline AST load_plugins(World& w, const std::string& plugin) { return load_plugins(w, w.sym(plugin)); } } // namespace thorin::ast diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index e88e5e2d45..aa0913c3f2 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -112,6 +112,7 @@ class Parser : public fe::Parser { Ptrs parse_decls(); Ptr parse_axiom_decl(); Ptr parse_let_decl(); + Ptr parse_cfun_decl(); Ptr parse_lam_decl(); Ptr parse_rec_decl(); ///@} diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 0125d165ab..175a7c0ec7 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -30,6 +30,7 @@ namespace ast { m(K_con, ".con" ) \ m(K_fun, ".fun" ) \ m(K_lam, ".lam" ) \ + m(K_cfun, ".cfun" ) \ m(K_cn, ".cn" ) \ m(K_fn, ".fn" ) \ m(K_ff, ".ff" ) \ diff --git a/include/thorin/tuple.h b/include/thorin/tuple.h index c72d28a911..4e18fb3683 100644 --- a/include/thorin/tuple.h +++ b/include/thorin/tuple.h @@ -29,6 +29,7 @@ class Sigma : public Def { /// @name Type Checking ///@{ void check() override; + static Ref infer(World&, Defs); ///@} THORIN_DEF_MIXIN(Sigma) diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 4ec8a9eeb9..464322bde7 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -35,7 +35,12 @@ class Error : std::exception { /// @name Constructors ///@{ - Error() = default; + Error() = default; + Error(const Error&) = default; + Error(Error&& other) + : Error() { + swap(*this, other); + } /// Creates a single Tag::Error message. Error(Loc loc, const std::string& str) : msgs_{ @@ -62,6 +67,14 @@ class Error : std::exception { msgs_.clear(); } + /// If errors occured, claim them and throw. + void ack() { + if (num_errors() != 0) { + auto errors = std::move(*this); + throw errors; + } + } + /// @name Add formatted message ///@{ template Error& msg(Loc loc, Tag tag, const char* s, Args&&... args) { @@ -94,6 +107,17 @@ class Error : std::exception { return os; } + friend void swap(Error& e1, Error& e2) noexcept { + using std::swap; + ; + // clang-format off + swap(e1.msgs_, e2.msgs_); + swap(e1.num_errors_, e2.num_errors_); + swap(e1.num_warnings_, e2.num_warnings_); + swap(e1.num_notes_, e2.num_notes_); + // clang-format on + } + private: std::vector msgs_; size_t num_errors_ = 0; diff --git a/lit/pow_pe.thorin b/lit/pow_pe.thorin index 4f7bea55fa..e114ad03e3 100644 --- a/lit/pow_pe.thorin +++ b/lit/pow_pe.thorin @@ -4,5 +4,7 @@ .lam pow(a b: .Nat)@(%core.pe.known b): .Nat = (%core.nat.mul (a, pow(a, %core.nat.sub (b, 1))), 1)#(%core.ncmp.e (b, 0)); +.let _ = 23; // HACK + .lam f(n: .Nat, x: <<%core.nat.mul (n, %core.nat.mul (n, n)); .Nat>>): [] = (); .lam g(m: .Nat, y: <>): [] = f (m, y); diff --git a/lit/ptrn.thorin b/lit/ptrn.thorin index 20184e123f..d14e6e61b5 100644 --- a/lit/ptrn.thorin +++ b/lit/ptrn.thorin @@ -4,4 +4,6 @@ .lam PtrN(n: .Nat, T: *): * = (PtrN (%core.nat.sub (n, 1), %mem.Ptr0 T), T)#(%core.ncmp.e (n, 0)); +.let _ = 23; // HACK + .fun .extern foo(mem: %mem.M, p: PtrN (4, .I32)): [%mem.M, PtrN (3, .I32)] = return (%mem.load (mem, p)); diff --git a/lit/rec.thorin b/lit/rec.thorin index 69001a2573..5fee6a85f8 100644 --- a/lit/rec.thorin +++ b/lit/rec.thorin @@ -1,8 +1,6 @@ // RUN: %thorin %s --output-ll %t.ll -o - | FileCheck %s .plugin core; -.lam is_even[.Nat]: .Bool; -.lam is_odd [.Nat]: .Bool; .lam is_even(i: .Nat): .Bool = (is_odd (%core.nat.sub (i, 1)), .tt)#(%core.ncmp.e (i, 0)); .lam is_odd (i: .Nat): .Bool = (is_even(%core.nat.sub (i, 1)), .ff)#(%core.ncmp.e (i, 0)); diff --git a/lit/rec_pi.thorin b/lit/rec_pi.thorin index 4b56a93b60..f013443799 100644 --- a/lit/rec_pi.thorin +++ b/lit/rec_pi.thorin @@ -6,12 +6,11 @@ .ax %phase.phase2: [] -> %phase.Phase; .ax %phase.phase3: [.Nat, .Bool] -> %phase.Phase; -.Pi PiPeline: * = |~| %phase.Phase -> PiPeline; // got the pun? XD -// anyway, we probably want to have a nicer way to specify recursive function types ... +.rec PiPeline: * = |~| %phase.Phase -> PiPeline; // got the pun? XD .ax %phase.pipe: PiPeline; -.let pipeline = %phase.pipe +.let pipeline = %phase.pipe (%phase.phase1 .tt) (%phase.phase2 ()) (%phase.phase3 (23, .tt)); diff --git a/lit/str.thorin b/lit/str.thorin index f43d368077..9487f89381 100644 --- a/lit/str.thorin +++ b/lit/str.thorin @@ -4,8 +4,8 @@ // RUN: %t | FileCheck %s .plugin core; -.fun println_char[%mem.M, .I8]: %mem.M; -.fun print_str[%mem.M, %mem.Ptr0 «⊤:.Nat; .I8»]: %mem.M; +.cfun println_char[%mem.M, .I8]: %mem.M; +.cfun print_str[%mem.M, %mem.Ptr0 «⊤:.Nat; .I8»]: %mem.M; .fun .extern main(mem: %mem.M, argc: .I32, argv: %mem.Ptr0 (%mem.Ptr0 .I8)): [%mem.M, .I32] = .let (`mem, p1) = %mem.slot («15; .I8», 0) (mem, 0); diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 3791c65e1a..81561f6d42 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -4,6 +4,12 @@ namespace thorin::ast { +AST::~AST() { + assert(error().num_errors() == 0 && "please encounter any errors before destroying this class"); + if (error().num_warnings() != 0) + driver().WLOG("{} warning(s) encountered while compiling module\n{}", error().num_warnings(), error()); +} + LamExpr::LamExpr(Ptr&& lam) : Expr(lam->loc()) , lam_(std::move(lam)) {} @@ -29,32 +35,32 @@ Ptr Ptrn::to_ptrn(Ptr&& expr) { } void Module::compile(AST& ast) const { - const auto& err = ast.error(); bind(ast); - if (err.num_errors() != 0) throw err; + ast.error().ack(); emit(ast); - - assert(err.num_errors() == 0 && "If an error occurs during emit, an exception should have been thrown"); - if (err.num_warnings() != 0) - ast.driver().WLOG("{} warning(s) encountered while compiling module\n{}", err.num_warnings(), err); } -void load_plugin(World& world, View plugins) { - assert(!plugins.empty() && "must load at least one plugin"); +AST load_plugins(World& world, View plugins) { + auto tag = Tok::Tag::K_import; + if (!world.driver().flags().bootstrap) { + for (auto plugin : plugins) world.driver().load(plugin); + tag = Tok::Tag::K_plugin; + } auto ast = AST(world); auto parser = Parser(ast); auto imports = Ptrs(); - for (auto plugin : plugins) { - auto mod = parser.plugin(plugin); - imports.emplace_back(ast.ptr(mod->loc(), Dbg(Loc(), plugin), Tok::Tag::K_plugin, std::move(mod))); - } - auto mod = ast.ptr(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs()); - try { - mod->compile(ast); - } catch (const Error& err) { - world.ELOG("{} error(s) encountered while compiling plugins: '{, }'\n{}", err.num_errors(), plugins, err); + + for (auto plugin : plugins) + if (auto mod = parser.import(plugin)) + imports.emplace_back(ast.ptr(mod->loc(), Dbg(Loc(), plugin), tag, std::move(mod))); + + if (!plugins.empty()) { + auto mod = ast.ptr(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs()); + // TODO return mod } + + return ast; } } // namespace thorin::ast diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 2198a65e78..12d0eb39f0 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -348,4 +348,12 @@ void LamDecl::bind_body(Scopes& s) const { s.pop(); } +void CFun::bind_decl(Scopes& s) const { + s.push(); + dom()->bind(s); + s.pop(); + codom()->bind(s); // we don't allow dependency here on dom + s.bind(dbg(), this); +} + } // namespace thorin::ast diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index ea3c6b575a..b6976389bf 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -225,7 +225,7 @@ Ref LamExpr::emit(Emitter& e) const { Ref AppExpr::emit(Emitter& e) const { auto c = callee()->emit(e); auto a = arg()->emit(e); - return e.world().iapp(c, a)->set(loc()); + return (is_explicit() ? e.world().app(c, a) : e.world().iapp(c, a))->set(loc()); } Ref RetExpr::emit(Emitter& e) const { @@ -453,4 +453,10 @@ void LamDecl::emit_body(Emitter& e) const { e.register_if_annex(dbg(), def_); } +void CFun::emit_decl(Emitter& e) const { + auto dom_t = dom()->emit_type(e); + auto ret_t = codom()->emit(e); + def_ = e.world().mut_fun(dom_t, ret_t)->set(dbg()); +} + } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 29c32204e1..ca58f623f7 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -510,6 +510,7 @@ Ptrs Parser::parse_decls() { switch (ahead().tag()) { case Tag::T_semicolon: lex(); break; // eat up stray semicolons case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break; + case Tag::K_cfun: decls.emplace_back(parse_cfun_decl()); break; case Tag::K_let: decls.emplace_back(parse_let_decl()); break; case Tag::K_rec: decls.emplace_back(parse_rec_decl()); break; case Tag::K_con: @@ -624,4 +625,14 @@ Ptr Parser::parse_lam_decl() { return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } +Ptr Parser::parse_cfun_decl() { + auto track = tracker(); + eat(Tag::K_cfun); + auto id = expect(Tag::M_id, "C function declaration"); + auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Tok::Prec::App); + expect(Tag::T_colon, "codomain of a C function"); + auto codom = parse_expr("codomain of a C function"); + return ptr(track, id.dbg(), std::move(dom), std::move(codom)); +} + } // namespace thorin::ast diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 0110fe8864..32a19e9c2c 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -114,7 +114,7 @@ std::ostream& PiExpr::stream(Tab& tab, std::ostream& os) const { std::ostream& LamExpr::stream(Tab& tab, std::ostream& os) const { return print(os, "{};", S(tab, lam())); } std::ostream& AppExpr::stream(Tab& tab, std::ostream& os) const { - return print(os, "{} {}", S(tab, callee()), S(tab, arg())); + return print(os, "{} {} {}", S(tab, callee()), is_explicit() ? "@" : "", S(tab, arg())); } std::ostream& RetExpr::stream(Tab& tab, std::ostream& os) const { @@ -204,6 +204,9 @@ std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return os << ';'; } +std::ostream& CFun::stream(Tab& tab, std::ostream& os) const { + return print(os, ".cfun {} {}: {}", dbg(), S(tab, dom()), S(tab, codom())); +} /* * Module */ diff --git a/src/thorin/check.cpp b/src/thorin/check.cpp index 4979a84705..61b7d94695 100644 --- a/src/thorin/check.cpp +++ b/src/thorin/check.cpp @@ -226,10 +226,19 @@ void Arr::check() { auto t = body()->unfold_type(); if (!Check::alpha(t, type())) error(type()->loc(), "declared sort '{}' of array does not match inferred one '{}'", type(), t); + if (t != type()) set_type(t); +} + +Ref Sigma::infer(World& w, Defs ops) { + if (ops.size() == 0) return w.type<1>(); + auto kinds = DefVec(ops.size(), [ops](size_t i) { return ops[i]->unfold_type(); }); + return w.umax(kinds); } void Sigma::check() { - // TODO + auto t = infer(world(), ops()); + // TODO check + if (t != type()) set_type(t); } void Lam::check() { @@ -255,6 +264,7 @@ void Pi::check() { auto t = infer(dom(), codom()); if (!Check::alpha(t, type())) error(type()->loc(), "declared sort '{}' of function type does not match inferred one '{}'", type(), t); + if (t != type()) set_type(t); } #ifndef DOXYGEN diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 7854bb8292..3777bba550 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -133,12 +133,13 @@ int main(int argc, char** argv) { if (input[0] == '-' || input.substr(0, 2) == "--") throw std::invalid_argument("error: unknown option " + input); + auto ast = ast::load_plugins(world, plugins); try { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); - auto ast = ast::AST(world); auto parser = ast::Parser(ast); auto mod = parser.import(driver.sym(input), os[Md]); + mod->compile(ast); if (auto s = os[AST]) { @@ -169,10 +170,7 @@ int main(int argc, char** argv) { switch (opt) { case 0: break; case 1: Phase::run(world); break; - case 2: - parser.import("opt"); - optimize(world); - break; + case 2: optimize(world); break; default: error("illegal optimization level '{}'", opt); } diff --git a/src/thorin/def.cpp b/src/thorin/def.cpp index 4c63475992..480e65f4cd 100644 --- a/src/thorin/def.cpp +++ b/src/thorin/def.cpp @@ -300,8 +300,10 @@ Def* Def::set_type(const Def* type) { void Def::unset_type() { if (type_) { invalidate(); - assert(type_->uses_.contains(Use(this, Use::Type))); - type_->uses_.erase(Use(this, Use::Type)); + if (!type_->dep_const()) { + assert(type_->uses_.contains(Use(this, Use::Type))); + type_->uses_.erase(Use(this, Use::Type)); + } type_ = nullptr; } } diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 793e2479de..53a0550dfc 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -228,7 +228,7 @@ Ref World::sigma(Defs ops) { if (n == 0) return sigma(); if (n == 1) return ops[0]; if (auto uni = Check::is_uniform(ops)) return arr(n, uni); - return unify(ops.size(), umax(ops), ops); + return unify(ops.size(), Sigma::infer(*this, ops), ops); } Ref World::tuple(Defs ops) { From ea541aef34c282818498525efb587b4a8ab2776c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 19 Apr 2024 05:06:49 +0200 Subject: [PATCH 56/95] fixing bugs --- include/thorin/ast/ast.h | 2 +- include/thorin/ast/parser.h | 1 + lit/annex.thorin | 8 +-- lit/recursive_uniform_bug.thorin | 2 +- lit/regex/match_manual.thorin | 94 +++++++++++++++----------------- src/thorin/ast/ast.cpp | 2 +- src/thorin/ast/parser.cpp | 9 ++- src/thorin/cli/main.cpp | 30 ++++++---- src/thorin/dump.cpp | 1 - src/thorin/world.cpp | 3 +- 10 files changed, 81 insertions(+), 71 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 484dd7d44c..07c4344762 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -863,7 +863,7 @@ class CFun : public ValDecl { class Import : public Node { public: - Import(Loc loc, Dbg dbg, Tok::Tag tag, Ptr&& module) + Import(Loc loc, Tok::Tag tag, Dbg dbg, Ptr&& module) : Node(loc) , dbg_(dbg) , tag_(tag) diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index aa0913c3f2..4f991fb956 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -40,6 +40,7 @@ class Parser : public fe::Parser { Ptr import(Sym, std::ostream* md = nullptr); Ptr import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); Ptr plugin(Sym); + Ptr plugin(const std::string& s) { return plugin(driver().sym(s)); } Ptr plugin(const char* name) { return plugin(driver().sym(name)); } private: diff --git a/lit/annex.thorin b/lit/annex.thorin index 96fbeff87e..2ef8ba53ab 100644 --- a/lit/annex.thorin +++ b/lit/annex.thorin @@ -2,9 +2,9 @@ .plugin math; -.Sigma %annex.Vec3.xyz: *, 3 = [x: %math.F64, y: %math.F64, z: %math.F64]; -.Sigma %annex.Vec3.rgb: *, 3 = [r: %math.F64, g: %math.F64, w: %math.F64]; -.Pi %annex.Vec3.rec: □ = Π %annex.Vec3.xyz -> %annex.Vec3.rec; -.let %annex.Vec3.zero = 0; +.let %annex.Vec3.xyz = [x: %math.F64, y: %math.F64, z: %math.F64]; +.let %annex.Vec3.rgb = [r: %math.F64, g: %math.F64, w: %math.F64]; +.rec %annex.Vec3.rec: □ = Π %annex.Vec3.xyz -> %annex.Vec3.rec; +.let %annex.Vec3.zero = 0; // CHECK: zero = 0x8f3c66400000003 diff --git a/lit/recursive_uniform_bug.thorin b/lit/recursive_uniform_bug.thorin index b5efd28484..02eca6138d 100644 --- a/lit/recursive_uniform_bug.thorin +++ b/lit/recursive_uniform_bug.thorin @@ -1,5 +1,5 @@ // RUN: %thorin %s -o - -.Sigma Triple: □, 3 = [T: *, U: *, V: *]; +.let Triple = [T: *, U: *, V: *]; .ax %bug.Box: Triple -> *; .ax %bug.test: Π [n: .Nat] [Ss: «n; Triple», X: Triple] -> %bug.Box X; diff --git a/lit/regex/match_manual.thorin b/lit/regex/match_manual.thorin index 14ac8b5d7f..056258bdbf 100644 --- a/lit/regex/match_manual.thorin +++ b/lit/regex/match_manual.thorin @@ -14,68 +14,64 @@ // matches (a|b)+a -.con .extern main[mem: %mem.M, argc: .I32, argv: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), exit : .Cn [%mem.M, .I32]] = { - .con accept [mem:%mem.M, .I32] = exit (mem, 1I32); - .con reject [mem:%mem.M, .Idx Top] = exit (mem, 0I32); +.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 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); + .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); + start (mem, 0I32) .where - .con error(mem: %mem.M, i : .I32) = reject (mem, 0I32); + .con start(mem: %mem.M, i : .I32) = { + .let ptr = %mem.lea (Top, <⊤:.Nat; .I8>, 0) (to_match, i); + .let (`mem, c) = %mem.load (mem, ptr); + .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); + .let is_end = %core.icmp.e (c, '\0'); + (not_end, error)#is_end (mem, new_i) .where - .con state1(mem: %mem.M, i : .I32); - .con state2(mem: %mem.M, i : .I32); + .con not_end(mem: %mem.M, i : .I32) = + .let is_match_a_or_b = %core.bit2.or_ 2 (%core.icmp.e (c, 'a'), %core.icmp.e (c, 'b')); + (error, state1)#is_match_a_or_b (mem, i) .where + .con state1(mem: %mem.M, i : .I32) = { + .let ptr = %mem.lea (Top, , 0) (to_match, i); + .let (`mem, c) = %mem.load (mem, ptr); + .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); + .let is_end = %core.icmp.e (c, '\0'); + (not_end, error)#is_end (mem, new_i) .where - .con start(mem: %mem.M, i : .I32) = - .let ptr = %mem.lea (Top, <⊤:.Nat; .I8>, 0) (to_match, i); - .let (`mem, c) = %mem.load (mem, ptr); - .let new_i = %core.wrap.add %core.mode.nuw (i, 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); - .con not_end(mem: %mem.M, i : .I32) = - .let is_match_a_or_b = %core.bit2.or_ 2 (%core.icmp.e (c, 'a'), %core.icmp.e (c, 'b')); - (error, state1)#is_match_a_or_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) .where - .let is_end = %core.icmp.e (c, '\0'); - (not_end, error)#is_end (mem, new_i); + .con state2(mem: %mem.M, i : .I32) = + .let ptr = %mem.lea (Top, , 0) (to_match, i); + .let (`mem, c) = %mem.load (mem, ptr); + .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); - .con state1(mem: %mem.M, i : .I32) = - .let ptr = %mem.lea (Top, , 0) (to_match, i); - .let (`mem, c) = %mem.load (mem, ptr); - .let new_i = %core.wrap.add %core.mode.nuw (i, 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); - .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 not_end(mem: %mem.M, i : .I32) = - .let is_match_a = %core.icmp.e (c, 'a'); - (not_a, state2)#is_match_a (mem, i); + .let is_end = %core.icmp.e (c, '\0'); + (not_end, accept)#is_end (mem, new_i) .where + .con accept [mem:%mem.M, .I32] = exit (mem, 1I32); + }; + }; - .let is_end = %core.icmp.e (c, '\0'); - (not_end, error)#is_end (mem, new_i); - .con state2(mem: %mem.M, i : .I32) = - .let ptr = %mem.lea (Top, , 0) (to_match, i); - .let (`mem, c) = %mem.load (mem, ptr); - .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); + .con error(mem: %mem.M, i : .I32) = + reject (mem, 0I32) .where + .con reject [mem:%mem.M, .Idx Top] = exit (mem, 0I32); - .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); - - .let is_end = %core.icmp.e (c, '\0'); - (not_end, accept)#is_end (mem, new_i); - - start(mem, 0I32) - }; - - (exit, match_argument) # (%core.icmp.ug (argc, 1I32)) (mem, 0I32) -}; // CHECK-NOT: %regex. diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 81561f6d42..de43cca726 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -53,7 +53,7 @@ AST load_plugins(World& world, View plugins) { for (auto plugin : plugins) if (auto mod = parser.import(plugin)) - imports.emplace_back(ast.ptr(mod->loc(), Dbg(Loc(), plugin), tag, std::move(mod))); + imports.emplace_back(ast.ptr(mod->loc(), tag, Dbg(Loc(), plugin), std::move(mod))); if (!plugins.empty()) { auto mod = ast.ptr(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs()); diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index ca58f623f7..e392b7e23f 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -78,8 +78,10 @@ Ptr Parser::parse_import_or_plugin() { auto track = tracker(); auto tag = lex().tag(); auto name = expect(Tag::M_id, "{} name", tag == Tag::K_import ? "import" : "plugin"); + auto sym = name.sym(); expect(Tag::T_semicolon, "end of {}", tag == Tag::K_import ? "import" : "plugin"); - if (auto module = import(name.sym())) return ptr(track, name.dbg(), tag, std::move(module)); + if (auto module = tag == Tag::K_import ? import(sym) : plugin(sym)) + return ptr(track, tag, name.dbg(), std::move(module)); return {}; } @@ -211,6 +213,7 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::K_I8: case Tag::K_I16: case Tag::K_I32: + case Tag::K_I64: case Tag::T_star: case Tag::T_box: return ptr(lex()); @@ -617,10 +620,10 @@ Ptr Parser::parse_lam_decl() { } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : nullptr; - if (tag == Tag::K_fn || tag == Tag::K_fun) doms.back()->add_ret(ast(), std::move(codom)); - auto body = accept(Tag::T_assign) ? parse_expr("body of a "s + entity) : nullptr; + expect(Tag::T_assign, "body of a "s + entity); + auto body = parse_expr("body of a "s + entity); return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index c44b7b24b0..8de3ad9ece 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -32,7 +32,7 @@ int main(int argc, char** argv) { bool dot_all_annexes = false; std::string input, prefix; std::string clang = sys::find_cmd("clang"); - std::vector plugins, search_paths; + std::vector inputs, search_paths; #ifdef THORIN_ENABLE_CHECKS std::vector breakpoints; #endif @@ -48,7 +48,7 @@ int main(int argc, char** argv) { | lyra::opt(show_version )["-v"]["--version" ]("Display version info and exit.") | lyra::opt(list_search_paths )["-l"]["--list-search-paths" ]("List search paths in order and exit.") | lyra::opt(clang, "clang" )["-c"]["--clang" ]("Path to clang executable (default: '" THORIN_WHICH " clang').") - | lyra::opt(plugins, "plugin" )["-p"]["--plugin" ]("Dynamically load plugin.") + | lyra::opt(inputs, "plugin" )["-p"]["--plugin" ]("Dynamically load plugin.") | lyra::opt(search_paths, "path" )["-P"]["--plugin-path" ]("Path to search for plugins.") | lyra::opt(inc_verbose )["-V"]["--verbose" ]("Verbose mode. Multiple -V options increase the verbosity. The maximum is 4.").cardinality(0, 4) | lyra::opt(opt, "level" )["-O"]["--optimize" ]("Optimization level (default: 2).") @@ -123,23 +123,33 @@ int main(int argc, char** argv) { } } - // we always need standard plugins, as long as we are not in bootstrap mode - if (!flags.bootstrap) plugins.insert(plugins.end(), {"compile", "opt"}); - - if (!plugins.empty()) - for (const auto& plugin : plugins) driver.load(plugin); - if (input.empty()) throw std::invalid_argument("error: no input given"); if (input[0] == '-' || input.substr(0, 2) == "--") throw std::invalid_argument("error: unknown option " + input); - auto ast = ast::load_plugins(world, plugins); + // we always need standard plugins, as long as we are not in bootstrap mode + if (!flags.bootstrap) { + inputs.insert(inputs.begin(), "compile"s); + if (opt >= 2) inputs.emplace_back("opt"s); + } + + inputs.emplace_back(input); + try { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); + + auto ast = ast::AST(world); auto parser = ast::Parser(ast); - auto mod = parser.import(driver.sym(input), os[Md]); + ast::Ptrs imports; + for (size_t i = 0, e = inputs.size(); i != e; ++i) { + auto input = inputs[i]; + auto tag = i + 1 == e ? ast::Tok::Tag::K_import : ast::Tok::Tag::K_plugin; + auto mod = i + 1 == e ? parser.import(input) : parser.plugin(input); + imports.emplace_back(ast.ptr(Loc(), tag, Dbg(Loc(), driver.sym(input)), std::move(mod))); + } + auto mod = ast.ptr(imports.back()->loc(), std::move(imports), ast::Ptrs()); mod->compile(ast); if (auto s = os[AST]) { diff --git a/src/thorin/dump.cpp b/src/thorin/dump.cpp index 7fd1c8a352..3b649bd3e9 100644 --- a/src/thorin/dump.cpp +++ b/src/thorin/dump.cpp @@ -180,7 +180,6 @@ std::ostream& operator<<(std::ostream& os, Inline u) { } else if (auto var = u->isa()) { return print(os, "{}", var->unique_name()); } else if (auto pi = u->isa()) { - return os << "TODO"; if (Pi::isa_cn(pi)) return print(os, ".Cn {}", pi->dom()); if (auto mut = pi->isa_mut(); mut && mut->var()) return print(os, "Π {}: {} {} {}", mut->var(), pi->dom(), arw, pi->codom()); diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 53a0550dfc..87fa9182dd 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -78,7 +78,8 @@ Sym World::sym(std::string_view s) { return driver().sym(s); } Sym World::sym(const std::string& s) { return driver().sym(s); } const Def* World::register_annex(flags_t f, const Def* def) { - DLOG("register: 0x{f} -> {}", f, def); + // TODO enable again + // DLOG("register: 0x{f} -> {}", f, def); auto plugin = Annex::demangle(driver(), f); if (driver().is_loaded(plugin)) { assert_emplace(move_.annexes, f, def); From 2fd3ee03ae5e50faf4c7388d2004181549ce06e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 19 Apr 2024 22:06:09 +0200 Subject: [PATCH 57/95] more bug fixes + .grp decl --- include/thorin/ast/ast.h | 19 +++- include/thorin/ast/parser.h | 2 +- include/thorin/ast/tok.h | 4 +- lit/core/pow.thorin | 12 +-- lit/direct/mut_dom_bug.thorin | 2 + lit/fun.thorin | 2 + lit/lam_body_sigma.thorin | 2 +- lit/matrix/print_prod2.thorin | 33 +++--- lit/pow_pe.thorin | 2 +- lit/ptrn.thorin | 2 +- lit/regex/fold_star_plus.thorin | 2 +- lit/regex/match_manual.thorin | 101 +++++++++--------- src/thorin/ast/bind.cpp | 8 +- src/thorin/ast/emit.cpp | 33 +++--- src/thorin/ast/parser.cpp | 181 ++++++++++++++++++++------------ src/thorin/ast/stream.cpp | 8 +- src/thorin/world.cpp | 2 +- 17 files changed, 249 insertions(+), 166 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 07c4344762..2f76e7f23b 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -666,6 +666,17 @@ class InferExpr : public Expr { * Decls */ +/// `.grp` +class GrpDecl : public ValDecl { +public: + GrpDecl(Loc loc) + : ValDecl(loc) {} + + void bind_decl(Scopes&) const override; + void emit_decl(Emitter&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; +}; + /// `.let ptrn: type = value;` class LetDecl : public ValDecl { public: @@ -836,15 +847,17 @@ class LamDecl : public RecDecl { }; /// `.cfun dbg dom -> codom` -class CFun : public ValDecl { +class CDecl : public ValDecl { public: - CFun(Loc loc, Dbg dbg, Ptr&& dom, Ptr&& codom) + CDecl(Loc loc, Tok::Tag tag, Dbg dbg, Ptr&& dom, Ptr&& codom) : ValDecl(loc) + , tag_(tag) , dbg_(dbg) , dom_(std::move(dom)) , codom_(std::move(codom)) {} Dbg dbg() const { return dbg_; } + Tok::Tag tag() const { return tag_; } const Ptrn* dom() const { return dom_.get(); } const Expr* codom() const { return codom_.get(); } @@ -853,10 +866,12 @@ class CFun : public ValDecl { std::ostream& stream(Tab&, std::ostream&) const override; private: + Tok::Tag tag_; Dbg dbg_; Ptr dom_; Ptr codom_; }; + /* * Module */ diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 4f991fb956..f4e27a6619 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -113,7 +113,7 @@ class Parser : public fe::Parser { Ptrs parse_decls(); Ptr parse_axiom_decl(); Ptr parse_let_decl(); - Ptr parse_cfun_decl(); + Ptr parse_c_decl(); Ptr parse_lam_decl(); Ptr parse_rec_decl(); ///@} diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 175a7c0ec7..5fc0654c36 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -15,11 +15,12 @@ namespace ast { m(K_import, ".import") \ m(K_plugin, ".plugin") \ m(K_ax, ".ax" ) \ - m(K_def, ".def" ) \ m(K_let, ".let" ) \ + m(K_grp, ".grp" ) \ m(K_rec, ".rec" ) \ m(K_ret, ".ret" ) \ m(K_where, ".where" ) \ + m(K_end, ".end" ) \ m(K_Nat, ".Nat" ) \ m(K_Idx, ".Idx" ) \ m(K_extern, ".extern") \ @@ -30,6 +31,7 @@ namespace ast { m(K_con, ".con" ) \ m(K_fun, ".fun" ) \ m(K_lam, ".lam" ) \ + m(K_ccon, ".ccon" ) \ m(K_cfun, ".cfun" ) \ m(K_cn, ".cn" ) \ m(K_fn, ".fn" ) \ diff --git a/lit/core/pow.thorin b/lit/core/pow.thorin index 2ec48e7a74..29722a4fb3 100644 --- a/lit/core/pow.thorin +++ b/lit/core/pow.thorin @@ -41,13 +41,13 @@ // CHECK-DAG: .con pow_then_{{[0-9_]+}} []{{(@.*)?}}= { // CHECK-DAG: _{{[0-9_]+}} 1I32 -// CHECK-DAG: .con pow_cont_{{[0-9_]+}} _{{[0-9_]+}}: .I32{{(@.*)?}}= { -// CHECK-DAG: .let _{{[0-9_]+}}: .I32 = %core.wrap.mul .i32 0 (42I32, _{{[0-9_]+}}); +// CHECK-DAG: .con pow_cont_{{[0-9_]+}} v_{{[0-9_]+}}: .I32{{(@.*)?}}= { +// CHECK-DAG: .let _{{[0-9_]+}}: .I32 = %core.wrap.mul .i32 0 (42I32, v_{{[0-9_]+}}); // CHECK-DAG: _{{[0-9_]+}} _{{[0-9_]+}} // CHECK-DAG: .con pow_else_{{[0-9_]+}} []{{(@.*)?}}= { -// CHECK-DAG: .let _{{[0-9_]+}}: .I32 = %core.wrap.add .i32 0 (4294967295I32, b_{{[0-9_]+}}); -// CHECK-DAG: pow_{{[0-9_]+}} (_{{[0-9_]+}}, pow_cont_{{[0-9_]+}}) +// CHECK-DAG: .let b_1_{{[0-9_]+}}: .I32 = %core.wrap.add .i32 0 (4294967295I32, b_{{[0-9_]+}}); +// CHECK-DAG: pow_{{[0-9_]+}} (b_1_{{[0-9_]+}}, pow_cont_{{[0-9_]+}}) -// CHECK-DAG: .let _{{[0-9_]+}}: .Bool = %core.icmp.xyglE .i32 (0I32, b_{{[0-9_]+}}); -// CHECK-DAG: (pow_else_{{[0-9_]+}}, pow_then_{{[0-9_]+}})#_{{[0-9_]+}} () +// CHECK-DAG: .let cmp_{{[0-9_]+}}: .Bool = %core.icmp.xyglE .i32 (0I32, b_{{[0-9_]+}}); +// CHECK-DAG: (pow_else_{{[0-9_]+}}, pow_then_{{[0-9_]+}})#cmp_{{[0-9_]+}} () diff --git a/lit/direct/mut_dom_bug.thorin b/lit/direct/mut_dom_bug.thorin index 61f7e285ee..3242d72fe4 100644 --- a/lit/direct/mut_dom_bug.thorin +++ b/lit/direct/mut_dom_bug.thorin @@ -3,6 +3,8 @@ .lam ForBody [n: .Nat] = [%mem.M, .Idx n] -> %mem.M; +.next + .lam For .[n: .Nat] [start: .Idx n, end: .Idx n] [mem: %mem.M] [it: ForBody n]: %mem.M = { .lam loop [mem: %mem.M, i: .Idx n] @(%core.pe.known i) : [%mem.M, .Idx n] = { .let `mem = it (mem, i); diff --git a/lit/fun.thorin b/lit/fun.thorin index 001557b41d..676776cc8d 100644 --- a/lit/fun.thorin +++ b/lit/fun.thorin @@ -3,6 +3,8 @@ .lam Ptr(T: *): * = %mem.Ptr (T, 0); +.let _ = 23; + .fun foo(mem: %mem.M, x: .I32)@(%core.icmp.e (x, 23I32)): [%mem.M, .I32] = return (mem, %core.wrap.add 0 (x, 1I32)); diff --git a/lit/lam_body_sigma.thorin b/lit/lam_body_sigma.thorin index c834de32d9..ef12a1b42a 100644 --- a/lit/lam_body_sigma.thorin +++ b/lit/lam_body_sigma.thorin @@ -1,5 +1,5 @@ // RUN: %thorin %s -o - -.Sigma S = [ +.rec S = [ n: .Nat, a: «n; .Nat» ]; diff --git a/lit/matrix/print_prod2.thorin b/lit/matrix/print_prod2.thorin index d3d0635488..9bdc0a0640 100644 --- a/lit/matrix/print_prod2.thorin +++ b/lit/matrix/print_prod2.thorin @@ -10,33 +10,30 @@ .let MT1 = (2, (2,4), %math.F64); .let MT2 = (2, (4,3), %math.F64); -.con print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; -.con print_double_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), %math.F64), return : .Cn [%mem.M]]; +.ccon print_int_matrix [mem: %mem.M, k l: .Nat, m: %matrix.Mat (2, (⊤:.Nat, ⊤:.Nat), .I32), .Cn %mem.M]; +.ccon print_double_matrix[mem: %mem.M, k l: .Nat, m: %matrix.Mat (2, (⊤:.Nat, ⊤:.Nat), %math.F64), .Cn %mem.M]; -.con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return : .Cn [%mem.M]] = { +.con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return: .Cn %mem.M] = .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat),.I32)) m; - print_int_matrix(mem, k, l, m2, return) -}; + print_int_matrix (mem, k, l, m2, return); -.con print_double_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), %math.F64), return : .Cn [%mem.M]] = { +.con print_double_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), %math.F64), return: .Cn %mem.M] = .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat), %math.F64)) m; - print_double_matrix(mem, k, l, m2, return) -}; - - -.con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr (%mem.Ptr (.I8, 0), 0), return : .Cn [%mem.M, .I32]] = { - .con return_cont [mem:%mem.M] = return (mem, 0I32); + print_double_matrix (mem, k, l, m2, return); +.con .extern main[mem: %mem.M, argc: .I32, argv: %mem.Ptr (%mem.Ptr (.I8, 0), 0), return: .Cn [%mem.M, .I32]] = .let c = 3.0:%math.F64; .let d = 5.0:%math.F64; - .let (mem2,m1) = %matrix.constMat MT1 (mem,c); - .let (mem3,m2) = %matrix.constMat MT2 (mem2,d); - .let (mem4,m1_2) = %matrix.insert MT1 (mem3,m1, (.ff,2:(.Idx 4)), 4.0:%math.F64); - .let (mem5,m2_2) = %matrix.insert MT2 (mem4,m2, (1:(.Idx 4),2:(.Idx 3)), 6.0:%math.F64); - .let (mem6, mP) = %matrix.prod (2,4,3, %math.f64) (mem5, m1_2, m2_2); + .let (mem2, m1 ) = %matrix.constMat MT1 (mem,c); + .let (mem3, m2 ) = %matrix.constMat MT2 (mem2,d); + .let (mem4, m1_2) = %matrix.insert MT1 (mem3,m1, (0_2, 2_4), 4.0:%math.F64); + .let (mem5, m2_2) = %matrix.insert MT2 (mem4,m2, (1_4, 2_3), 6.0:%math.F64); + .let (mem6, mP ) = %matrix.prod (2, 4, 3, %math.f64) (mem5, m1_2, m2_2); print_double_matrix_wrap (mem6, 2, 3, mP, return_cont) -}; + .where + .con return_cont [mem: %mem.M] = return (mem, 0I32); + .end // CHECK: 65.00, 65.00, 68.00, // CHECK: 60.00, 60.00, 63.00, diff --git a/lit/pow_pe.thorin b/lit/pow_pe.thorin index e114ad03e3..7efb254096 100644 --- a/lit/pow_pe.thorin +++ b/lit/pow_pe.thorin @@ -4,7 +4,7 @@ .lam pow(a b: .Nat)@(%core.pe.known b): .Nat = (%core.nat.mul (a, pow(a, %core.nat.sub (b, 1))), 1)#(%core.ncmp.e (b, 0)); -.let _ = 23; // HACK +.grp .lam f(n: .Nat, x: <<%core.nat.mul (n, %core.nat.mul (n, n)); .Nat>>): [] = (); .lam g(m: .Nat, y: <>): [] = f (m, y); diff --git a/lit/ptrn.thorin b/lit/ptrn.thorin index d14e6e61b5..dc92f2a937 100644 --- a/lit/ptrn.thorin +++ b/lit/ptrn.thorin @@ -4,6 +4,6 @@ .lam PtrN(n: .Nat, T: *): * = (PtrN (%core.nat.sub (n, 1), %mem.Ptr0 T), T)#(%core.ncmp.e (n, 0)); -.let _ = 23; // HACK +.grp .fun .extern foo(mem: %mem.M, p: PtrN (4, .I32)): [%mem.M, PtrN (3, .I32)] = return (%mem.load (mem, p)); diff --git a/lit/regex/fold_star_plus.thorin b/lit/regex/fold_star_plus.thorin index ce7cb44fdf..19500f1d5e 100644 --- a/lit/regex/fold_star_plus.thorin +++ b/lit/regex/fold_star_plus.thorin @@ -1,6 +1,6 @@ // RUN: %thorin %s -o - -P %S | FileCheck %s -.import mem; +.plugin mem; .plugin regex; .import dont_compile.thorin; diff --git a/lit/regex/match_manual.thorin b/lit/regex/match_manual.thorin index 056258bdbf..59962ea879 100644 --- a/lit/regex/match_manual.thorin +++ b/lit/regex/match_manual.thorin @@ -15,63 +15,68 @@ // matches (a|b)+a .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 - + (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 arg1 = %mem.lea (Top, ‹Top; %mem.Ptr («⊤:.Nat; .I8», 0)›, 0) (argv, 1I32); .let (`mem, to_match) = %mem.load (mem, arg1); - start (mem, 0I32) .where - - .con start(mem: %mem.M, i : .I32) = { - .let ptr = %mem.lea (Top, <⊤:.Nat; .I8>, 0) (to_match, i); + start (mem, 0I32) + .where + .con start(mem: %mem.M, i: .I32) = + .let ptr = %mem.lea (Top, <⊤:.Nat; .I8>, 0) (to_match, i); .let (`mem, c) = %mem.load (mem, ptr); - .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); - .let is_end = %core.icmp.e (c, '\0'); - (not_end, error)#is_end (mem, new_i) .where - - .con not_end(mem: %mem.M, i : .I32) = + .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); + .let is_end = %core.icmp.e (c, '\0'); + (not_end, error)#is_end (mem, new_i) + .where + .con not_end(mem: %mem.M, i: .I32) = .let is_match_a_or_b = %core.bit2.or_ 2 (%core.icmp.e (c, 'a'), %core.icmp.e (c, 'b')); - (error, state1)#is_match_a_or_b (mem, i) .where - - .con state1(mem: %mem.M, i : .I32) = { - .let ptr = %mem.lea (Top, , 0) (to_match, i); + (error, state1)#is_match_a_or_b (mem, i) + .where + .con state1(mem: %mem.M, i: .I32) = + .let ptr = %mem.lea (Top, , 0) (to_match, i); .let (`mem, c) = %mem.load (mem, ptr); - .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); - .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 new_i = %core.wrap.add %core.mode.nuw (i, 1I32); + .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) = + .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) .where - - .con state2(mem: %mem.M, i : .I32) = - .let ptr = %mem.lea (Top, , 0) (to_match, i); + (not_a, state2)#is_match_a (mem, i) + .where + .con state2(mem: %mem.M, i: .I32) = + .let ptr = %mem.lea (Top, , 0) (to_match, i); .let (`mem, c) = %mem.load (mem, ptr); - .let new_i = %core.wrap.add %core.mode.nuw (i, 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); - - .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); - - .let is_end = %core.icmp.e (c, '\0'); - (not_end, accept)#is_end (mem, new_i) .where - .con accept [mem:%mem.M, .I32] = exit (mem, 1I32); - }; - }; - - - .con error(mem: %mem.M, i : .I32) = - reject (mem, 0I32) .where - .con reject [mem:%mem.M, .Idx Top] = exit (mem, 0I32); - - + .let new_i = %core.wrap.add %core.mode.nuw (i, 1I32); + .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); + .end + .end + .end + .end + .end + .end + .end // CHECK-NOT: %regex. diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 12d0eb39f0..5d464325ec 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -274,6 +274,8 @@ void AxiomDecl::bind_decl(Scopes& s) const { } } +void GrpDecl::bind_decl(Scopes&) const {} + void LetDecl::bind_decl(Scopes& s) const { value()->bind(s); ptrn()->bind(s); @@ -348,11 +350,11 @@ void LamDecl::bind_body(Scopes& s) const { s.pop(); } -void CFun::bind_decl(Scopes& s) const { +void CDecl::bind_decl(Scopes& s) const { s.push(); dom()->bind(s); - s.pop(); - codom()->bind(s); // we don't allow dependency here on dom + s.pop(); // we don't allow codom to depent on dom + if (codom()) codom()->bind(s); s.bind(dbg(), this); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index b6976389bf..8ece123b88 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -1,5 +1,3 @@ -#include "thorin/rewrite.h" - #include "thorin/ast/ast.h" using namespace std::literals; @@ -46,7 +44,7 @@ class Emitter { */ Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } -Ref InferExpr::emit(Emitter& e) const { return e.world().type_infer_univ(); } +Ref InferExpr::emit(Emitter& e) const { return e.world().mut_infer_type(); } Ref IdExpr::emit(Emitter&) const { assert(decl()); @@ -331,13 +329,6 @@ void DeclsBlock::emit(Emitter& e) const { } } -void LetDecl::emit_decl(Emitter& e) const { - auto v = value()->emit(e); - def_ = ptrn()->emit_value(e, v); - - if (auto id = ptrn()->isa()) e.register_if_annex(id->dbg(), def_); -} - void AxiomDecl::Alias::emit(Emitter& e, const Axiom* axiom) const { const auto& id = axiom_->id_; def_ = axiom; @@ -383,7 +374,8 @@ void AxiomDecl::emit_decl(Emitter& e) const { sub_t s = i + offset; auto norm = e.driver().normalizer(id_.plugin, id_.tag, s); auto& aliases = annex.subs.emplace_back(std::deque()); - auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, s)->set(dbg()); + auto name = e.world().sym(dbg().sym.str() + "."s + sub(i).front()->dbg().sym.str()); + auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, s)->set(name); e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64) | flags_t(s), axiom); for (const auto& alias : sub(i)) { alias->sub_ = s; @@ -394,6 +386,15 @@ void AxiomDecl::emit_decl(Emitter& e) const { } } +void GrpDecl::emit_decl(Emitter&) const {} + +void LetDecl::emit_decl(Emitter& e) const { + auto v = value()->emit(e); + def_ = ptrn()->emit_value(e, v); + + if (auto id = ptrn()->isa()) e.register_if_annex(id->dbg(), def_); +} + void RecDecl::emit_decl(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); def_ = body()->emit_decl(e, t); @@ -453,10 +454,14 @@ void LamDecl::emit_body(Emitter& e) const { e.register_if_annex(dbg(), def_); } -void CFun::emit_decl(Emitter& e) const { +void CDecl::emit_decl(Emitter& e) const { auto dom_t = dom()->emit_type(e); - auto ret_t = codom()->emit(e); - def_ = e.world().mut_fun(dom_t, ret_t)->set(dbg()); + if (tag() == Tag::K_cfun) { + auto ret_t = codom()->emit(e); + def_ = e.world().mut_fun(dom_t, ret_t)->set(dbg()); + } else { + def_ = e.world().mut_con(dom_t)->set(dbg()); + } } } // namespace thorin::ast diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index e392b7e23f..922ea99480 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -5,6 +5,78 @@ #include "thorin/driver.h" +// clang-format off +#define PRIMARY \ + Tag::K_Univ: \ + case Tag::K_Nat: \ + case Tag::K_Idx: \ + case Tag::K_Bool: \ + case Tag::K_ff: \ + case Tag::K_tt: \ + case Tag::K_i1: \ + case Tag::K_i8: \ + case Tag::K_i16: \ + case Tag::K_i32: \ + case Tag::K_i64: \ + case Tag::K_I1: \ + case Tag::K_I8: \ + case Tag::K_I16: \ + case Tag::K_I32: \ + case Tag::K_I64: \ + case Tag::T_star: \ + case Tag::T_box + +#define ID \ + Tag::M_anx: \ + case Tag::M_id + +#define LIT \ + Tag::T_bot: \ + case Tag::T_top: \ + case Tag::L_str: \ + case Tag::L_c: \ + case Tag::L_s: \ + case Tag::L_u: \ + case Tag::L_f: \ + case Tag::L_i + +#define DECL \ + Tag::K_ax: \ + case Tag::K_grp: \ + case Tag::K_let: \ + case Tag::K_rec: \ + case Tag::K_lam: \ + case Tag::K_con: \ + case Tag::K_fun: \ + case Tag::K_ccon: \ + case Tag::K_cfun + +#define PI \ + Tag::T_Pi: \ + case Tag::K_Cn: \ + case Tag::K_Fn + +#define LAM \ + Tag::T_lm: \ + case Tag::K_cn: \ + case Tag::K_fn +// clang-format on + +#define EXPR \ +PRIMARY: \ + case ID: \ + case LIT: \ + case DECL: \ + case LAM: \ + case Tag::K_Type: /*TypeExpr*/ \ + case Tag::K_ins: /*InsertExpr*/ \ + case Tag::K_ret: /*RetExpr*/ \ + case Tag::D_angle_l: /*PackExpr*/ \ + case Tag::D_brace_l: /*BlockExpr*/ \ + case Tag::D_brckt_l: /*SigmaExpr*/ \ + case Tag::D_paren_l: /*TupleExpr*/ \ + case Tag::D_quote_l /*ArrExpr*/ + using namespace std::string_literals; namespace thorin::ast { @@ -127,7 +199,7 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec cur auto [l, r] = Tok::prec(Tok::Prec::Arrow); if (l < curr_prec) break; lex(); - auto rhs = parse_expr("right-hand side of an function type", r); + auto rhs = parse_expr("right-hand side of a function type", r); lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); } else if (ahead().isa(Tag::K_where)) { auto [l, r] = Tok::prec(Tok::Prec::Where); @@ -135,14 +207,22 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec cur lex(); auto decls = parse_decls(); lhs = ptr(track, std::move(decls), std::move(lhs), true); + lhs->dump(); + outln("--"); + expect(Tag::K_end, "end of a .where declaration block"); } else { auto [l, r] = Tok::prec(Tok::Prec::App); if (l < curr_prec) break; bool is_explicit = (bool)accept(Tag::T_at); - if (auto rhs = parse_expr({}, r)) // if we can parse an expression, it's an App - lhs = ptr(track.loc(), is_explicit, std::move(lhs), std::move(rhs)); - else - return lhs; + switch (ahead().tag()) { + case EXPR: { + auto rhs + = parse_expr("argument to an application", r); // if we can parse an expression, it's an App + lhs = ptr(track.loc(), is_explicit, std::move(lhs), std::move(rhs)); + continue; + } + default: return lhs; + } } } @@ -174,21 +254,12 @@ Ptr Parser::parse_insert_expr() { Ptr Parser::parse_primary_expr(std::string_view ctxt) { // clang-format off switch (ahead().tag()) { - case Tag::K_Cn: - case Tag::K_Fn: - case Tag::T_Pi: return parse_pi_expr(); - - case Tag::K_cn: - case Tag::K_fn: - case Tag::T_lm: return parse_lam_expr(); - - case Tag::K_ax: - case Tag::K_let: - case Tag::K_rec: - case Tag::K_con: - case Tag::K_fun: - case Tag::K_lam: return parse_decl_expr(); - + case PRIMARY: return ptr(lex()); + case ID: return ptr(lex().dbg()); + case LIT: return parse_lit_expr(); + case DECL: return parse_decl_expr(); + case PI: return parse_pi_expr(); + case LAM: return parse_lam_expr(); case Tag::K_ins: return parse_insert_expr(); case Tag::K_ret: return parse_ret_expr(); case Tag::D_quote_l: return parse_arr_or_pack_expr(); @@ -197,36 +268,6 @@ Ptr Parser::parse_primary_expr(std::string_view ctxt) { case Tag::D_paren_l: return parse_tuple_expr(); case Tag::D_brace_l: return parse_block_expr(); case Tag::K_Type: return parse_type_expr(); - - case Tag::K_Univ: - case Tag::K_Nat: - case Tag::K_Idx: - case Tag::K_Bool: - case Tag::K_ff: - case Tag::K_tt: - case Tag::K_i1: - case Tag::K_i8: - case Tag::K_i16: - case Tag::K_i32: - case Tag::K_i64: - case Tag::K_I1: - case Tag::K_I8: - case Tag::K_I16: - case Tag::K_I32: - case Tag::K_I64: - case Tag::T_star: - case Tag::T_box: return ptr(lex()); - - case Tag::T_bot: - case Tag::T_top: - case Tag::L_str: - case Tag::L_c: - case Tag::L_s: - case Tag::L_u: - case Tag::L_f: - case Tag::L_i: return parse_lit_expr(); - case Tag::M_anx: - case Tag::M_id: return ptr(lex().dbg()); default: if (ctxt.empty()) return nullptr; syntax_err("primary expression", ctxt); @@ -258,7 +299,7 @@ template Ptr Parser::parse_arr_or_pack_expr() { Ptr Parser::parse_block_expr() { auto track = tracker(); eat(Tag::D_brace_l); - auto expr = parse_expr("final expression in a block expressoin"); + auto expr = parse_expr("final expression in a block expression"); expect(Tag::D_brace_r, "block expression"); return ptr(track, std::move(expr)); } @@ -266,7 +307,9 @@ Ptr Parser::parse_block_expr() { Ptr Parser::parse_decl_expr() { auto track = tracker(); auto decls = parse_decls(); - auto expr = parse_expr("final expression of a delcaration expression"); + auto expr = parse_expr("final expression of a declaration expression"); + if (expr->isa()) + for (const auto& decl : decls) ast().note(decl->loc(), "declaration belonging to this declaration expression"); return ptr(track, std::move(decls), std::move(expr), false); } @@ -321,7 +364,7 @@ Ptr Parser::parse_pi_expr() { ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) : nullptr; - if (tag == Tag::K_Fn) doms.back()->add_ret(ast(), std::move(codom)); + if (tag == Tag::K_Fn) doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr(prev_)); return ptr(track.loc(), tag, std::move(doms), std::move(codom)); } @@ -512,13 +555,15 @@ Ptrs Parser::parse_decls() { // clang-format off switch (ahead().tag()) { case Tag::T_semicolon: lex(); break; // eat up stray semicolons - case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break; - case Tag::K_cfun: decls.emplace_back(parse_cfun_decl()); break; - case Tag::K_let: decls.emplace_back(parse_let_decl()); break; - case Tag::K_rec: decls.emplace_back(parse_rec_decl()); break; + case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break; + case Tag::K_grp: decls.emplace_back(ptr(lex().loc())); break; + case Tag::K_ccon: + case Tag::K_cfun: decls.emplace_back(parse_c_decl()); break; + case Tag::K_let: decls.emplace_back(parse_let_decl()); break; + case Tag::K_rec: decls.emplace_back(parse_rec_decl()); break; case Tag::K_con: case Tag::K_fun: - case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break; + case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break; default: return decls; } // clang-format on @@ -620,7 +665,8 @@ Ptr Parser::parse_lam_decl() { } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : nullptr; - if (tag == Tag::K_fn || tag == Tag::K_fun) doms.back()->add_ret(ast(), std::move(codom)); + if (tag == Tag::K_fn || tag == Tag::K_fun) + doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr(prev_)); expect(Tag::T_assign, "body of a "s + entity); auto body = parse_expr("body of a "s + entity); @@ -628,14 +674,17 @@ Ptr Parser::parse_lam_decl() { return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); } -Ptr Parser::parse_cfun_decl() { +Ptr Parser::parse_c_decl() { auto track = tracker(); - eat(Tag::K_cfun); - auto id = expect(Tag::M_id, "C function declaration"); - auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Tok::Prec::App); - expect(Tag::T_colon, "codomain of a C function"); - auto codom = parse_expr("codomain of a C function"); - return ptr(track, id.dbg(), std::move(dom), std::move(codom)); + auto tag = lex().tag(); + auto id = expect(Tag::M_id, "C function declaration"); + auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Tok::Prec::App); + Ptr codom; + if (tag == Tag::K_cfun) { + expect(Tag::T_colon, "codomain of a C function"); + codom = parse_expr("codomain of a C function"); + } + return ptr(track, tag, id.dbg(), std::move(dom), std::move(codom)); } } // namespace thorin::ast diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 32a19e9c2c..749d8fb07e 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -169,6 +169,8 @@ std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { return os << ";"; } +std::ostream& GrpDecl::stream(Tab&, std::ostream& os) const { return os << ".grp"; } + std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); } @@ -204,8 +206,10 @@ std::ostream& LamDecl::stream(Tab& tab, std::ostream& os) const { return os << ';'; } -std::ostream& CFun::stream(Tab& tab, std::ostream& os) const { - return print(os, ".cfun {} {}: {}", dbg(), S(tab, dom()), S(tab, codom())); +std::ostream& CDecl::stream(Tab& tab, std::ostream& os) const { + print(os, "{} {} {}", dbg(), tag(), S(tab, dom()), S(tab, codom())); + if (tag() == Tag::K_cfun) print(os, ": {}", S(tab, codom())); + return os; } /* * Module diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 87fa9182dd..e44de9e2d6 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -195,7 +195,7 @@ Ref World::app(Ref callee, Ref arg) { .note(arg->loc(), "argument: '{}'", arg) .note(arg->loc(), "type: '{}'", arg->type()) .note(callee->loc(), "callee: '{}'", callee) - .note(callee->loc(), "type: '{}'", pi); + .note(callee->loc(), "domain type: '{}'", pi->dom()); } if (auto imm = callee->isa_imm()) return imm->body(); From 789a0b5073a441b1043753ee5811145fdb7d69c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 20 Apr 2024 03:20:01 +0200 Subject: [PATCH 58/95] wip: make rec sigma work --- include/thorin/ast/ast.h | 2 ++ lit/ext_names.thorin | 5 +++-- lit/matrix/get_shape.thorin | 2 +- lit/sigma.thorin | 30 +++++++++++++++------------- src/thorin/ast/bind.cpp | 13 +++++++++--- src/thorin/ast/emit.cpp | 25 +++++++++++++++++------ src/thorin/dump.cpp | 4 ++-- src/thorin/plug/matrix/matrix.thorin | 6 +++--- 8 files changed, 56 insertions(+), 31 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 2f76e7f23b..f73ec63e38 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -242,6 +242,8 @@ class TuplePtrn : public Ptrn { void bind_body(Scopes&) const; Ref emit_value(Emitter&, Ref) const override; Ref emit_type(Emitter&) const override; + Ref emit_decl(Emitter&, Ref type) const; + Ref emit_body(Emitter&, Ref decl) const; std::ostream& stream(Tab&, std::ostream&) const override; private: diff --git a/lit/ext_names.thorin b/lit/ext_names.thorin index f8b62f6ed4..14532017f3 100644 --- a/lit/ext_names.thorin +++ b/lit/ext_names.thorin @@ -3,9 +3,10 @@ .plugin core; -.Sigma %foo.Shape: □, 3 = [n: .Nat, S: «n; .Nat», T: *]; -.ax %foo.len: %foo.Shape -> .Nat, normalize_len; +.rec %foo.Shape = [n: .Nat, S: «n; .Nat», T: *]; +.ax %foo.len: %foo.Shape -> .Nat, normalize_len; .lam %foo.Ptr s: %foo.Shape: * = %mem.Ptr0 «%foo.len s; s#T»; .lam %foo.Idx s: %foo.Shape: * = .Idx (%foo.len s); +.grp .lam get(s: %foo.Shape)(mem: %mem.M, p: %foo.Ptr s, i: %foo.Idx s): [%mem.M, s#T] = (mem, .bot:(s#T) /* dummy impl */); diff --git a/lit/matrix/get_shape.thorin b/lit/matrix/get_shape.thorin index 905b14888a..0069faca3d 100644 --- a/lit/matrix/get_shape.thorin +++ b/lit/matrix/get_shape.thorin @@ -5,7 +5,7 @@ .plugin matrix; .con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr (%mem.Ptr (.I8, 0), 0), return : .Cn [%mem.M, .I32]] = { - .let MT = (2, (3,5), .I32); + .let MT = (2, (3, 5), .I32); .let c = 5I32; .let (`mem, m) = %matrix.constMat MT (mem,c); .let d = %matrix.shape MT (m, 0_2); diff --git a/lit/sigma.thorin b/lit/sigma.thorin index f7a4d09b9a..e03a093aae 100644 --- a/lit/sigma.thorin +++ b/lit/sigma.thorin @@ -2,25 +2,27 @@ // RUN: %thorin %s -o - .plugin math; -.Sigma Vec1 = [x: %math.F64]; -.Sigma vec1 = [X: %math.F64]; -.Sigma Vec3: *, 3; -.Sigma Vec3: *, 3 = [x: %math.F64, y: %math.F64, z: %math.F64]; -.Sigma Vec2 = [x: %math.F64, y: %math.F64]; -.Sigma Vec4; -.Sigma Vec4 = [x: %math.F64, y: %math.F64, z: %math.F64, w: %math.F64]; +.rec Vec1 = [x: %math.F64]; +.rec vec1 = [X: %math.F64]; +.rec Vec3 = [x: %math.F64, y: %math.F64, z: %math.F64]; +.rec Vec2 = [x: %math.F64, y: %math.F64]; +.rec Vec4 = [x: %math.F64, y: %math.F64, z: %math.F64, w: %math.F64]; -.Sigma Foo = [ +.rec Foo = [ x: %math.F64, y: %math.F64, - .Sigma Bar = [ - n: .Nat, - b: .Bool, - ]; - bar: Bar, + bar: + .rec Bar = [ + n: .Nat, + b: .Bool, + ]; + Bar ]; -.Pi F = |~| .Nat -> F; +.rec F: * = |~| .Nat -> F; // TODO make inference for F work again + +.grp + .lam .extern f1 v: Vec1: %math.F64 = v#x; .lam .extern F1 v: vec1: %math.F64 = v#X; .lam .extern f2 v: Vec2: %math.F64 = v#y; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 5d464325ec..861a7eb4d0 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -309,14 +309,21 @@ void LamDecl::Dom::bind(Scopes& s, bool quiet) const { void LamDecl::bind_decl(Scopes& s) const { s.push(); - for (const auto& dom : doms()) dom->bind(s); + for (size_t i = 0, e = num_doms(); i != e; ++i) { + if (auto bang = dom(i)->bang(); bang && i + 1 != e) { + s.ast().warn( + bang.loc(), + "'!' superfluous as the last curried function group of a '{}' receives a '.tt'-filter by default", + tag()); + } + dom(i)->bind(s); + } if (auto bang = doms().back()->bang()) { if (tag() == Tag::K_lam || tag() == Tag::T_lm) s.ast().warn( bang.loc(), - "'!' superfluous as the last curried function group of a '{}' receives a '.tt'-filter by default", - tag()); + "'!' superfluous as all but the last curried function groups receive a '.tt'-filter by default", tag()); } if (auto filter = doms().back()->filter()) { if (auto pe = filter->isa()) { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 8ece123b88..38cc5f610d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -134,10 +134,17 @@ Ref IdPtrn::emit_type(Emitter& e) const { return type() ? type()->emit(e) : e.wo Ref GroupPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } -Ref TuplePtrn::emit_type(Emitter& e) const { - auto n = num_ptrns(); - auto type = e.world().type_infer_univ(); - auto sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); +Ref TuplePtrn::emit_type(Emitter& e) const { return emit_body(e, {}); } + +Ref TuplePtrn::emit_body(Emitter& e, Ref decl) const { + auto n = num_ptrns(); + Sigma* sigma; + if (decl) { + sigma = decl->as_mut(); + } else { + auto type = e.world().type_infer_univ(); + sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); + } auto var = sigma->var()->set(dbg()); auto& sym2idx = e.sigma2sym2idx[sigma]; @@ -151,6 +158,11 @@ Ref TuplePtrn::emit_type(Emitter& e) const { return sigma; } +Ref TuplePtrn::emit_decl(Emitter& e, Ref type) const { + type = type ? type : e.world().type_infer_univ(); + return e.world().mut_sigma(type, num_ptrns())->set(loc(), dbg().sym); +} + /* * Expr */ @@ -241,8 +253,9 @@ Ref RetExpr::emit(Emitter& e) const { c->type()); } -Ref SigmaExpr::emit_decl(Emitter&, Ref) const { return {}; } -void SigmaExpr::emit_body(Emitter&, Ref) const {} +Ref SigmaExpr::emit_decl(Emitter& e, Ref type) const { return ptrn()->emit_decl(e, type); } + +void SigmaExpr::emit_body(Emitter& e, Ref decl) const { ptrn()->emit_body(e, decl); } Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } diff --git a/src/thorin/dump.cpp b/src/thorin/dump.cpp index 3b649bd3e9..2bf5e299f7 100644 --- a/src/thorin/dump.cpp +++ b/src/thorin/dump.cpp @@ -189,16 +189,16 @@ std::ostream& operator<<(std::ostream& os, Inline u) { } else if (auto app = u->isa()) { if (auto size = Idx::size(app)) { if (auto l = Lit::isa(size)) { + // clang-format off switch (*l) { - // clang-format off case 0x0'0000'0002_n: return os << ".Bool"; case 0x0'0000'0100_n: return os << ".I8"; case 0x0'0001'0000_n: return os << ".I16"; case 0x1'0000'0000_n: return os << ".I32"; case 0_n: return os << ".I64"; default: break; - // clang-format on } + // clang-format on } } return print(os, "{} {}", LPrec(app->callee(), app), RPrec(app, app->arg())); diff --git a/src/thorin/plug/matrix/matrix.thorin b/src/thorin/plug/matrix/matrix.thorin index b70203ce36..b0b57921b5 100644 --- a/src/thorin/plug/matrix/matrix.thorin +++ b/src/thorin/plug/matrix/matrix.thorin @@ -142,7 +142,7 @@ /// ### product /// /// Follow the principle `ij <- ik, kj` (`out[i, j] = sum_k in1[i, k] * in2[k, j]`) by using mulplication as combination function and addition as reduction function. -.fun .extern internal_mapRed_matrix_prod!(m k l: .Nat, pe: «2; .Nat») +.fun .extern internal_mapRed_matrix_prod (m k l: .Nat, pe: «2; .Nat») !(mem: %mem.M, M: %matrix.Mat (2, (m, k), %math.F pe), N: %matrix.Mat (2, (k, l), %math.F pe)) :[ %mem.M, %matrix.Mat (2, (m, l), %math.F pe)] = @@ -173,7 +173,7 @@ /// Transpose a matrix by iterating the indices in swapped order. // TODO: check code for 1-matrix edge case // TODO: would this automatically be handled by read(transpose) ? -.fun .extern internal_mapRed_matrix_transpose!((k l: .Nat), T: *) +.fun .extern internal_mapRed_matrix_transpose((k l: .Nat), T: *) !(mem: %mem.M, M: %matrix.Mat (2, (k, l), T)) : [ %mem.M, %matrix.Mat (2, (l, k), T)] = .let zero = ⊥:T; // TODO: use generalized zero @@ -198,7 +198,7 @@ /// /// Sums up all elements of a matrix and returns a scalar. // TODO: test 0d matrix (edge cases in code) -.fun .extern internal_mapRed_matrix_sum!(n: .Nat, S: «n; .Nat», pe: «2; .Nat») +.fun .extern internal_mapRed_matrix_sum (n: .Nat, S: «n; .Nat», pe: «2; .Nat») !(mem: %mem.M, M: %matrix.Mat (n, S, %math.F pe)) :[%mem.M, %math.F pe] = .let R = %math.F pe; From de65b89cffd0c37a71275d77429adeeffff558a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 20 Apr 2024 04:08:27 +0200 Subject: [PATCH 59/95] fixing bugs --- lit/beta_equiv.thorin | 7 ++-- lit/core/ret_add.thorin | 33 +++++++++---------- lit/core/ret_and.thorin | 2 +- lit/core/ret_lshr.thorin | 2 +- lit/core/ret_nand.thorin | 2 +- lit/error/domain.thorin | 2 +- ...orin.disabled => double_extern_lam.thorin} | 2 +- lit/error/filter1.thorin | 3 +- lit/error/filter2.thorin | 3 -- lit/error/pi_decl1.thorin | 4 --- lit/error/pi_redef.thorin | 6 ++-- lit/error/redecl_pi.thorin | 4 --- lit/error/redecl_sigma.thorin | 4 --- lit/error/sigma_decl1.thorin | 4 --- lit/error/sigma_decl2.thorin | 4 --- lit/error/sigma_decl3.thorin | 4 --- lit/error/sigma_decl4.thorin | 3 -- lit/error/sigma_redef.thorin | 4 --- lit/error/unsupported_rec.thorin | 3 ++ lit/lam_body_sigma.thorin | 2 ++ lit/main_loop.thorin | 10 +++--- lit/matrix/print_const_prod.thorin | 4 +-- lit/matrix/transpose_init.thorin | 22 ++++++------- src/thorin/ast/bind.cpp | 2 +- 24 files changed, 54 insertions(+), 82 deletions(-) rename lit/error/{double_extern_lam.thorin.disabled => double_extern_lam.thorin} (66%) delete mode 100644 lit/error/filter2.thorin delete mode 100644 lit/error/pi_decl1.thorin delete mode 100644 lit/error/redecl_pi.thorin delete mode 100644 lit/error/redecl_sigma.thorin delete mode 100644 lit/error/sigma_decl1.thorin delete mode 100644 lit/error/sigma_decl2.thorin delete mode 100644 lit/error/sigma_decl3.thorin delete mode 100644 lit/error/sigma_decl4.thorin delete mode 100644 lit/error/sigma_redef.thorin create mode 100644 lit/error/unsupported_rec.thorin diff --git a/lit/beta_equiv.thorin b/lit/beta_equiv.thorin index 6170cd885a..643c0417eb 100644 --- a/lit/beta_equiv.thorin +++ b/lit/beta_equiv.thorin @@ -3,11 +3,12 @@ .plugin math; .plugin mem; -.Sigma Num: □, 2 = [T: *, add: [T, T] -> T]; - +.rec Num = [T: *, add: [T, T] -> T]; .lam my_add.(pe: «2; .Nat»)(a b: %math.F pe): %math.F pe = %math.arith.add 0 (a, b); -.let F64 = (%math.F64, my_add @%math.f64); +.grp + +.let F64 = (%math.F64, my_add @%math.f64); .ax %bug.Arr: Num -> *; .fun test [N: Num] [A: %bug.Arr N]: .Nat = return 0; diff --git a/lit/core/ret_add.thorin b/lit/core/ret_add.thorin index 9c435f8500..0cedc93b55 100644 --- a/lit/core/ret_add.thorin +++ b/lit/core/ret_add.thorin @@ -6,23 +6,22 @@ .plugin core; -.con atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; - -.con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = { - .con atoi_cont_a [mem : %mem.M, a : .I32] = { - .con atoi_cont_b [mem : %mem.M, b : .I32] = { - return (mem, %core.wrap.add 0 (a, b)) - }; - - .let argv_ptr_b = %mem.lea (⊤:.Nat, ‹⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)›, 0) (argv, 2I32); - .let argv_load_b = %mem.load (mem, argv_ptr_b); - atoi (argv_load_b#.ff, argv_load_b#.tt, atoi_cont_b) - }; - - .let argv_ptr_a = %mem.lea (⊤:.Nat, ‹⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)›, 0) (argv, 1I32); - .let argv_load_a = %mem.load (mem, argv_ptr_a); - atoi (argv_load_a#.ff, argv_load_a#.tt, atoi_cont_a) -}; +.ccon atoi[%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; + +.con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = + .let argv_ptr_a = %mem.lea (⊤:.Nat, ‹⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)›, 0) (argv, 1I32); + .let (`mem, val) = %mem.load (mem, argv_ptr_a); + atoi (mem, val, atoi_cont_a) + .where + .con atoi_cont_a [mem : %mem.M, a : .I32] = + .let argv_ptr_b = %mem.lea (⊤:.Nat, ‹⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)›, 0) (argv, 2I32); + .let (`mem, val) = %mem.load (mem, argv_ptr_b); + atoi (mem, val, atoi_cont_b) + .where + .con atoi_cont_b [mem : %mem.M, b : .I32] = + return (mem, %core.wrap.add 0 (a, b)); + .end + .end // CHECK-DAG: main _{{[0-9_]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, .I32, argv_{{[0-9]+}}: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { diff --git a/lit/core/ret_and.thorin b/lit/core/ret_and.thorin index 555fa83a0b..59a8982ccb 100644 --- a/lit/core/ret_and.thorin +++ b/lit/core/ret_and.thorin @@ -6,7 +6,7 @@ .plugin core; -.con atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; +.ccon atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; .con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = { .con atoi_cont_a [mem : %mem.M, a : .I32] = { diff --git a/lit/core/ret_lshr.thorin b/lit/core/ret_lshr.thorin index 8b1ebef52d..cc3b81530f 100644 --- a/lit/core/ret_lshr.thorin +++ b/lit/core/ret_lshr.thorin @@ -6,7 +6,7 @@ .plugin core; -.con atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; +.ccon atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; .con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = { .con atoi_cont_a [mem : %mem.M, a : .I32] = { diff --git a/lit/core/ret_nand.thorin b/lit/core/ret_nand.thorin index f34a8d1500..599064dce3 100644 --- a/lit/core/ret_nand.thorin +++ b/lit/core/ret_nand.thorin @@ -5,7 +5,7 @@ .plugin core; -.con atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; +.ccon atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; .con .extern main [mem: %mem.M, argc: .I32, argv: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return: .Cn [%mem.M, .I32]] = { .con atoi_cont_a [mem: %mem.M, a: .I32] = { diff --git a/lit/error/domain.thorin b/lit/error/domain.thorin index 59522c6f7c..c45ddaa540 100644 --- a/lit/error/domain.thorin +++ b/lit/error/domain.thorin @@ -4,4 +4,4 @@ .ax %foo.bar: .Cn [.I32, %math.F32]; .let err = %foo.bar(23:%math.F32, 42I32); -// CHECK: error: cannot pass argument +// CHECK: error: cannot apply diff --git a/lit/error/double_extern_lam.thorin.disabled b/lit/error/double_extern_lam.thorin similarity index 66% rename from lit/error/double_extern_lam.thorin.disabled rename to lit/error/double_extern_lam.thorin index 30af235384..0f67c5eaaf 100644 --- a/lit/error/double_extern_lam.thorin.disabled +++ b/lit/error/double_extern_lam.thorin @@ -1,4 +1,4 @@ // RUN: (! %thorin %s 2>&1) | FileCheck %s .lam .extern a() = (); .lam .extern a() = (); -// CHECK: error: symbol 'a' already declared +// CHECK: error: redeclaration diff --git a/lit/error/filter1.thorin b/lit/error/filter1.thorin index 3f14842eb0..295a0454b0 100644 --- a/lit/error/filter1.thorin +++ b/lit/error/filter1.thorin @@ -1,3 +1,4 @@ // RUN: (! %thorin %s 2>&1) | FileCheck %s .lam f!()@(.tt) = .tt; -// CHECK: error: filter already specified +// CHECK: error: explicit filter specified on top of +// CHECK: warning: '!' superfluous diff --git a/lit/error/filter2.thorin b/lit/error/filter2.thorin deleted file mode 100644 index 9918087114..0000000000 --- a/lit/error/filter2.thorin +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.lam f!(): []; -// CHECK: error: cannot specify filter of a function declaration diff --git a/lit/error/pi_decl1.thorin b/lit/error/pi_decl1.thorin deleted file mode 100644 index a0fdd18e1e..0000000000 --- a/lit/error/pi_decl1.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Pi F: □; -.Pi F = .Nat -> .Nat; -// CHECK: error: {{.*}}with a different type diff --git a/lit/error/pi_redef.thorin b/lit/error/pi_redef.thorin index 9fa37cda36..b5b33eb372 100644 --- a/lit/error/pi_redef.thorin +++ b/lit/error/pi_redef.thorin @@ -1,4 +1,4 @@ // RUN: (! %thorin %s 2>&1) | FileCheck %s -.Pi F = |~| .Nat -> .Nat; -.Pi F = |~| .Nat -> .Nat; -// CHECK: error: redefinition +.rec F = |~| .Nat -> .Nat; +.rec F = |~| .Nat -> .Nat; +// CHECK: error: redeclaration diff --git a/lit/error/redecl_pi.thorin b/lit/error/redecl_pi.thorin deleted file mode 100644 index 273bde61b4..0000000000 --- a/lit/error/redecl_pi.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Pi F: *; -.Sigma F: *, 2 = [.Nat, .Nat]; -// CHECK: error: 'F' has not been declared diff --git a/lit/error/redecl_sigma.thorin b/lit/error/redecl_sigma.thorin deleted file mode 100644 index e4174dc5b4..0000000000 --- a/lit/error/redecl_sigma.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Sigma F: *, 2; -.Pi F: * = .Nat -> .Nat; -// CHECK: error: 'F' has not been declared diff --git a/lit/error/sigma_decl1.thorin b/lit/error/sigma_decl1.thorin deleted file mode 100644 index 973ba24054..0000000000 --- a/lit/error/sigma_decl1.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Sigma S: □; -.Sigma S = [.Nat, .Nat]; -// CHECK: error: {{.*}}with a different type diff --git a/lit/error/sigma_decl2.thorin b/lit/error/sigma_decl2.thorin deleted file mode 100644 index 6c7c0cac2e..0000000000 --- a/lit/error/sigma_decl2.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Sigma S: *, 3; -.Sigma S: *, 2 = [.Nat]; -// CHECK: error: {{.*}}with a different arity diff --git a/lit/error/sigma_decl3.thorin b/lit/error/sigma_decl3.thorin deleted file mode 100644 index 8927c0f33a..0000000000 --- a/lit/error/sigma_decl3.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Pi S: *; -.Sigma S = [x: .Nat, .Nat]; -// CHECK: error: {{.*}}has not been declared as a sigma diff --git a/lit/error/sigma_decl4.thorin b/lit/error/sigma_decl4.thorin deleted file mode 100644 index 488f4e7e36..0000000000 --- a/lit/error/sigma_decl4.thorin +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Sigma S = {.Nat}; -// CHECK: error: {{.*}}expected{{.*}}while parsing diff --git a/lit/error/sigma_redef.thorin b/lit/error/sigma_redef.thorin deleted file mode 100644 index 81cd3270f1..0000000000 --- a/lit/error/sigma_redef.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.Sigma S: *, 2 = [x: .Nat, .Nat]; -.Sigma S: *, 2 = [x: .Nat, .Nat]; -// CHECK: error: redefinition diff --git a/lit/error/unsupported_rec.thorin b/lit/error/unsupported_rec.thorin new file mode 100644 index 0000000000..304752a4e2 --- /dev/null +++ b/lit/error/unsupported_rec.thorin @@ -0,0 +1,3 @@ +// RUN: (! %thorin %s 2>&1) | FileCheck %s +.rec S = {.Nat}; +// CHECK: error: unsupported expression diff --git a/lit/lam_body_sigma.thorin b/lit/lam_body_sigma.thorin index ef12a1b42a..40b5297f7b 100644 --- a/lit/lam_body_sigma.thorin +++ b/lit/lam_body_sigma.thorin @@ -4,4 +4,6 @@ a: «n; .Nat» ]; +.grp + .lam f(): S = (3, (0, 1, 2)); diff --git a/lit/main_loop.thorin b/lit/main_loop.thorin index ba728680d2..701b548eed 100644 --- a/lit/main_loop.thorin +++ b/lit/main_loop.thorin @@ -23,13 +23,13 @@ // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] // CHECK-DAG: .con loop_[[loopId]] _{{[0-9_]+}}::[mem_[[loopMemId:[0-9_]+]]: %mem.M, i_[[iterId:[0-9_]+]]: .I32, acc_[[accId:[0-9_]+]]: .I32]{{(@.*)?}}= { -// CHECK-DAG: _[[condId:[0-9_]+]]: .Bool = %core.icmp.XygLe .i32 (i_[[iterId]], {{.*}}); -// CHECK-DAG: (_[[exitId:[0-9_]+]], body_[[bodyId:[0-9_]+]])#_[[condId]] mem_[[loopMemId]] +// CHECK-DAG: cond_[[condId:[0-9_]+]]: .Bool = %core.icmp.XygLe .i32 (i_[[iterId]], {{.*}}); +// CHECK-DAG: (_[[exitId:[0-9_]+]], body_[[bodyId:[0-9_]+]])#cond_[[condId]] mem_[[loopMemId]] // CHECK-DAG: .con _[[exitId]] [[mExitVarId:[0-9a-z_]+]]: %mem.M{{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId]] ([[mExitVarId]], acc_[[accId]]) // CHECK-DAG: .con body_[[bodyId]] [[mBodyVarId:[0-9a-z_]+]]: %mem.M{{(@.*)?}}= { -// CHECK-DAG: _[[addIterId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (1I32, i_[[iterId]]); -// CHECK-DAG: _[[addAccId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (i_[[iterId]], acc_[[accId]]); -// CHECK-DAG: loop_[[loopId]] ([[mBodyVarId]], _[[addIterId]], _[[addAccId]]) +// CHECK-DAG: inc_[[addIterId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (1I32, i_[[iterId]]); +// CHECK-DAG: acci_[[addAccId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (i_[[iterId]], acc_[[accId]]); +// CHECK-DAG: loop_[[loopId]] ([[mBodyVarId]], inc_[[addIterId]], acci_[[addAccId]]) diff --git a/lit/matrix/print_const_prod.thorin b/lit/matrix/print_const_prod.thorin index d9a55d3ab3..e8940f366c 100644 --- a/lit/matrix/print_const_prod.thorin +++ b/lit/matrix/print_const_prod.thorin @@ -10,8 +10,8 @@ .let MT1 = (2, (2,4), %math.F64); .let MT2 = (2, (4,3), %math.F64); -.con print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; -.con print_double_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), %math.F64), return : .Cn [%mem.M]]; +.ccon print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; +.ccon print_double_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), %math.F64), return : .Cn [%mem.M]]; .con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return : .Cn [%mem.M]] = .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat),.I32)) m; diff --git a/lit/matrix/transpose_init.thorin b/lit/matrix/transpose_init.thorin index b26509d5a1..9acaeca24c 100644 --- a/lit/matrix/transpose_init.thorin +++ b/lit/matrix/transpose_init.thorin @@ -4,11 +4,11 @@ .plugin core; .plugin matrix; -.lam ex_internal_mapRed_matrix_transpose![[k: .Nat, l: .Nat], T:*]: .Cn[[%mem.M, %matrix.Mat (2,(k, l),T)], .Cn [%mem.M, %matrix.Mat (2,(l, k),T)] ] = +.lam ex_internal_mapRed_matrix_transpose![[k l: .Nat], T:*]: .Cn[[%mem.M, %matrix.Mat (2,(k, l),T)], .Cn [%mem.M, %matrix.Mat (2,(l, k),T)] ] = // TODO: or use generalized addition function // ignore acc .con transpose_comb [[mem:%mem.M, acc:T, [a:T]], ret:.Cn[%mem.M,T]] = ret (mem, a); - .con inner_matrix_transpose![[mem: %mem.M, M: %matrix.Mat (2,(k, l),T)], ret: .Cn[%mem.M,%matrix.Mat (2,(l, k),T)]] = + .con inner_matrix_transpose![[mem: %mem.M, M: %matrix.Mat (2,(k, l),T)], ret: .Cn[%mem.M, %matrix.Mat (2,(l, k),T)]] = // TODO: use generalized zero .let zero = (⊥:T); ret ( @@ -17,7 +17,7 @@ 1, 2, T, - (k,l) + (k, l) ) ( mem, @@ -30,15 +30,15 @@ ); inner_matrix_transpose; -.con .extern f [mem : %mem.M, [k:.Nat, l:.Nat], return: .Cn[%mem.M]] = - // M:%matrix.Mat (2,(k,m),.I32), - // N:%matrix.Mat (2,(m,l),.I32), - // return: .Cn[%mem.M, %matrix.Mat (2,(k,l),.I32)]] = { +.con .extern f [mem : %mem.M, [k l:.Nat], return: .Cn %mem.M] = + // M:%matrix.Mat (2,(k, m), .I32), + // N:%matrix.Mat (2,(m, l), .I32), + // return: .Cn[%mem.M, %matrix.Mat (2,(k, l), .I32)]] = { - .let (mem2, M) = %matrix.constMat (2,(k,l),.I32) (mem, 42I32); - // .let (mem3, N) = %matrix.constMat (2,(m,l),.I32) (mem2, 44I32; + .let (mem2, M) = %matrix.constMat (2,(k, l), .I32) (mem, 42I32); + // .let (mem3, N) = %matrix.constMat (2,(m, l), .I32) (mem2, 44I32; - .con cont [mem: %mem.M, N: %matrix.Mat (2,(l, k),.I32)] = return mem; - ex_internal_mapRed_matrix_transpose ((k,l),.I32) ((mem, M),cont); + .con cont [mem: %mem.M, N: %matrix.Mat (2,(l, k), .I32)] = return mem; + ex_internal_mapRed_matrix_transpose ((k, l), .I32) ((mem, M), cont); // CHECK-NOT: %matrix. diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 861a7eb4d0..972f019d7b 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -323,7 +323,7 @@ void LamDecl::bind_decl(Scopes& s) const { if (tag() == Tag::K_lam || tag() == Tag::T_lm) s.ast().warn( bang.loc(), - "'!' superfluous as all but the last curried function groups receive a '.tt'-filter by default", tag()); + "'!' superfluous as all but the last curried function groups receive a '.tt'-filter by default"); } if (auto filter = doms().back()->filter()) { if (auto pe = filter->isa()) { From 20241699fd0ed403f48379ee026ee4ac4bb1a656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 00:33:28 +0200 Subject: [PATCH 60/95] fixing bugs --- lit/clos/recursiveLoop.thorin | 6 +++--- src/thorin/check.cpp | 9 +++++++-- src/thorin/dump.cpp | 1 + src/thorin/tuple.cpp | 1 - 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lit/clos/recursiveLoop.thorin b/lit/clos/recursiveLoop.thorin index bc171e2686..0aa2a9dd49 100644 --- a/lit/clos/recursiveLoop.thorin +++ b/lit/clos/recursiveLoop.thorin @@ -7,9 +7,9 @@ .let i8 = .I8; .let pb_type = .Cn [%mem.M, .Cn [%mem.M]]; -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; -.con printIntegerNL [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; -.con printNL [mem: %mem.M, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printIntegerNL [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printNL [mem: %mem.M, return : .Cn [%mem.M]]; .let size = 10; diff --git a/src/thorin/check.cpp b/src/thorin/check.cpp index 61b7d94695..dab185f699 100644 --- a/src/thorin/check.cpp +++ b/src/thorin/check.cpp @@ -237,8 +237,13 @@ Ref Sigma::infer(World& w, Defs ops) { void Sigma::check() { auto t = infer(world(), ops()); - // TODO check - if (t != type()) set_type(t); + if (t != type()) { + // TODO HACK + if (Check::alpha(t, type())) set_type(t); + world().WLOG("incorrect type '{}' for '{}'. Correct one would be: '{}'. I'll keep this one nevertheless due to " + "bugs in clos-conv", + type(), this, t); + } } void Lam::check() { diff --git a/src/thorin/dump.cpp b/src/thorin/dump.cpp index 2bf5e299f7..0f6618087a 100644 --- a/src/thorin/dump.cpp +++ b/src/thorin/dump.cpp @@ -180,6 +180,7 @@ std::ostream& operator<<(std::ostream& os, Inline u) { } else if (auto var = u->isa()) { return print(os, "{}", var->unique_name()); } else if (auto pi = u->isa()) { + /*return os << "TODO";*/ if (Pi::isa_cn(pi)) return print(os, ".Cn {}", pi->dom()); if (auto mut = pi->isa_mut(); mut && mut->var()) return print(os, "Π {}: {} {} {}", mut->var(), pi->dom(), arw, pi->codom()); diff --git a/src/thorin/tuple.cpp b/src/thorin/tuple.cpp index ba52cc085d..dd426c1474 100644 --- a/src/thorin/tuple.cpp +++ b/src/thorin/tuple.cpp @@ -2,7 +2,6 @@ #include -#include "thorin/rewrite.h" #include "thorin/world.h" // TODO this code needs to be rewritten From 7f7c8417446d128f1ad5fe15562de8c8f930fa37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 00:53:09 +0200 Subject: [PATCH 61/95] bug fixes --- include/thorin/ast/ast.h | 4 ++-- lit/affine/dynamic_for.thorin | 2 +- lit/clos/bind.thorin | 2 +- lit/clos/loopDiff.thorin | 8 ++++---- lit/clos/loopDiff2.thorin | 8 ++++---- lit/clos/loopDiffSave.thorin | 2 +- lit/clos/loopError.thorin | 2 +- lit/clos/pass_through_return.thorin | 2 +- lit/clos/using_c_function.thorin | 5 ++--- lit/core/normalize_add.thorin | 2 +- lit/core/normalize_and_ff_tt.thorin | 2 +- lit/core/normalize_and_icmps_lit.thorin | 2 +- lit/core/normalize_and_tree.thorin | 4 ++-- lit/core/normalize_and_tt_tt.thorin | 4 ++-- lit/core/normalize_icmp.thorin | 2 +- src/thorin/ast/bind.cpp | 2 +- src/thorin/ast/emit.cpp | 4 ++-- src/thorin/ast/parser.cpp | 2 +- src/thorin/ast/stream.cpp | 2 +- src/thorin/check.cpp | 11 +++++++---- 20 files changed, 37 insertions(+), 35 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index f73ec63e38..bd3c9716c2 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -203,9 +203,9 @@ class IdPtrn : public Ptrn { }; /// `dbg_0 ... dbg_n-2 id` where `id` = `dbg_n-1: type` -class GroupPtrn : public Ptrn { +class GrpPtrn : public Ptrn { public: - GroupPtrn(Dbg dbg, const IdPtrn* id) + GrpPtrn(Dbg dbg, const IdPtrn* id) : Ptrn(dbg.loc, false, dbg) , id_(id) {} diff --git a/lit/affine/dynamic_for.thorin b/lit/affine/dynamic_for.thorin index 205d1f4da1..8f4b6d3ff0 100644 --- a/lit/affine/dynamic_for.thorin +++ b/lit/affine/dynamic_for.thorin @@ -7,7 +7,7 @@ .plugin core; .plugin affine; -.con atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; +.ccon atoi [%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; .con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = { .con for_body [i : .I32, [acc_a : .I32, acc_b : .I32], continue : .Cn [.I32, .I32]] = { diff --git a/lit/clos/bind.thorin b/lit/clos/bind.thorin index 1886e45fc3..0e6e51cf58 100644 --- a/lit/clos/bind.thorin +++ b/lit/clos/bind.thorin @@ -8,7 +8,7 @@ .let pb_type = .Cn [%mem.M, .Cn [%mem.M]]; -.con println_i32 [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon println_i32 [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; .let size = 100; diff --git a/lit/clos/loopDiff.thorin b/lit/clos/loopDiff.thorin index b26cd0a747..aa2b90b1d2 100644 --- a/lit/clos/loopDiff.thorin +++ b/lit/clos/loopDiff.thorin @@ -5,10 +5,10 @@ .let void_ptr = %mem.Ptr («⊤:.Nat; []», 0); -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; -.con printNL [mem: %mem.M, return : .Cn [%mem.M]]; -.con time [mem: %mem.M, return : .Cn [%mem.M, void_ptr]]; -.con print_time_diff [mem: %mem.M, t1: void_ptr, t2: void_ptr, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printNL [mem: %mem.M, return : .Cn [%mem.M]]; +.ccon time [mem: %mem.M, return : .Cn [%mem.M, void_ptr]]; +.ccon print_time_diff [mem: %mem.M, t1: void_ptr, t2: void_ptr, return : .Cn [%mem.M]]; .let size = 100; diff --git a/lit/clos/loopDiff2.thorin b/lit/clos/loopDiff2.thorin index 8141e049c4..5c4b298b67 100644 --- a/lit/clos/loopDiff2.thorin +++ b/lit/clos/loopDiff2.thorin @@ -5,10 +5,10 @@ .let void_ptr = %mem.Ptr («⊤:.Nat; []», 0); -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; -.con printNL [mem: %mem.M, return : .Cn [%mem.M]]; -.con time [mem: %mem.M, return : .Cn [%mem.M, void_ptr]]; -.con print_time_diff [mem: %mem.M, t1: void_ptr, t2: void_ptr, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printNL [mem: %mem.M, return : .Cn [%mem.M]]; +.ccon time [mem: %mem.M, return : .Cn [%mem.M, void_ptr]]; +.ccon print_time_diff [mem: %mem.M, t1: void_ptr, t2: void_ptr, return : .Cn [%mem.M]]; .let size = 100000; diff --git a/lit/clos/loopDiffSave.thorin b/lit/clos/loopDiffSave.thorin index 3474eb73db..b919870115 100644 --- a/lit/clos/loopDiffSave.thorin +++ b/lit/clos/loopDiffSave.thorin @@ -3,7 +3,7 @@ .plugin core; -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; .con init [mem: %mem.M, arr : %mem.Ptr (<<4; .I32>>, 0), return : .Cn [%mem.M]] = { diff --git a/lit/clos/loopError.thorin b/lit/clos/loopError.thorin index c47e672761..2446c65b04 100644 --- a/lit/clos/loopError.thorin +++ b/lit/clos/loopError.thorin @@ -3,7 +3,7 @@ .plugin core; -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; .con init [mem: %mem.M, return : .Cn [%mem.M]] = { .let arr_size = ⊤:.Nat; diff --git a/lit/clos/pass_through_return.thorin b/lit/clos/pass_through_return.thorin index 1427eadbc4..7e40ea5a01 100644 --- a/lit/clos/pass_through_return.thorin +++ b/lit/clos/pass_through_return.thorin @@ -10,7 +10,7 @@ return (mem) }; -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; .con .extern main [mem: %mem.M, argc: .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = { .con callback (mem: %mem.M) = return (mem, 1I32); diff --git a/lit/clos/using_c_function.thorin b/lit/clos/using_c_function.thorin index 3316ad74c6..9940909766 100644 --- a/lit/clos/using_c_function.thorin +++ b/lit/clos/using_c_function.thorin @@ -11,12 +11,11 @@ .plugin core; .plugin direct; -.let pb_type = .Cn [%mem.M]; +.let pb_type = .Cn %mem.M; -.con printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; +.ccon printInteger [mem: %mem.M, val: .I32, return : .Cn [%mem.M]]; .con .extern main [mem: %mem.M, argc: .I32, argv : %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return : .Cn [%mem.M, .I32]] = { - .con end [mem: %mem.M] = return (mem, 99I32); .con init22 [mem: %mem.M] = { diff --git a/lit/core/normalize_add.thorin b/lit/core/normalize_add.thorin index a3520584b5..d1d2e28287 100644 --- a/lit/core/normalize_add.thorin +++ b/lit/core/normalize_add.thorin @@ -15,7 +15,7 @@ .con .extern add_lit [return : .Cn .I8] = return (%core.wrap.add 0 (6I8, 0I8)); -// CHECK-DAG: add_lit _[[retId:[0-9_]+]]: .Cn .I8 +// CHECK-DAG: add_lit return_[[retId:[0-9_]+]]: .Cn .I8 // CHECK-DAG: _[[etaId:[0-9_]+]] 6I8 // CHECK-DAG: _[[etaId]] _[[etaVar:[0-9_]+]]: .I8 diff --git a/lit/core/normalize_and_ff_tt.thorin b/lit/core/normalize_and_ff_tt.thorin index e4d89969f6..bc91bce43d 100644 --- a/lit/core/normalize_and_ff_tt.thorin +++ b/lit/core/normalize_and_ff_tt.thorin @@ -7,7 +7,7 @@ return (%core.bit2.and_ 0 (.ff, .tt)) }; -// CHECK-DAG: and_lit_ff_tt _[[retId_ff_tt:[0-9_]+]]: .Cn .Bool +// CHECK-DAG: and_lit_ff_tt return_[[retId_ff_tt:[0-9_]+]]: .Cn .Bool // CHECK-DAG: _[[etaId_ff_tt:[0-9_]+]] .ff // CHECK-DAG: _[[etaId_ff_tt]] _[[etaVar_ff_tt:[0-9_]+]]: .Bool diff --git a/lit/core/normalize_and_icmps_lit.thorin b/lit/core/normalize_and_icmps_lit.thorin index 6a7235f2c8..3df75d4bc0 100644 --- a/lit/core/normalize_and_icmps_lit.thorin +++ b/lit/core/normalize_and_icmps_lit.thorin @@ -9,7 +9,7 @@ .con .extern and_lit2 [in: .I8, return : .Cn .Bool] = return (%core.bit2.and_ 0 (%core.icmp.uge (in, 'a'), %core.icmp.ule (in, 'a'))); -// CHECK-DAG: and_lit _[[retId:[0-9_]+]]: .Cn .Bool +// CHECK-DAG: and_lit return_[[retId:[0-9_]+]]: .Cn .Bool // CHECK-DAG: _[[etaId:[0-9_]+]] .tt // CHECK-DAG: _[[etaId]] _[[etaVar:[0-9_]+]]: .Bool diff --git a/lit/core/normalize_and_tree.thorin b/lit/core/normalize_and_tree.thorin index 673b88eb8d..28420a462a 100644 --- a/lit/core/normalize_and_tree.thorin +++ b/lit/core/normalize_and_tree.thorin @@ -14,8 +14,8 @@ %core.bit2.and_ 0 (.tt, .ff)))) }; -// CHECK-DAG: .con .extern and_lit _[[retId:[0-9_]+]]: .Cn .Bool{{(@.*)?}}= { +// CHECK-DAG: .con .extern and_lit return_[[retId:[0-9_]+]]: .Cn .Bool{{(@.*)?}}= { // CHECK-DAG: _[[etaId:[0-9_]+]] .ff -// CHECK-DAG: .con _[[etaId]] _[[etaVar:[0-9_]+]]: .Bool{{(@.*)?}}= { +// CHECK-DAG: .con return_[[etaId]] _[[etaVar:[0-9_]+]]: .Bool{{(@.*)?}}= { // CHECK-DAG: _[[retId]] _[[etaVar]] diff --git a/lit/core/normalize_and_tt_tt.thorin b/lit/core/normalize_and_tt_tt.thorin index 792e5e1323..760109fab4 100644 --- a/lit/core/normalize_and_tt_tt.thorin +++ b/lit/core/normalize_and_tt_tt.thorin @@ -7,8 +7,8 @@ return (%core.bit2.and_ 0 (.tt, .tt)) }; -// CHECK-DAG: .con .extern and_lit_tt_tt _[[retId:[0-9_]+]]: .Cn .Bool{{(@.*)?}}= { +// CHECK-DAG: .con .extern and_lit_tt_tt return_[[retId:[0-9_]+]]: .Cn .Bool{{(@.*)?}}= { // CHECK-DAG: _[[etaId:[0-9_]+]] .tt -// CHECK-DAG: .con _[[etaId]] _[[etaVar:[0-9_]+]]: .Bool{{(@.*)?}}= { +// CHECK-DAG: .con return_[[etaId]] _[[etaVar:[0-9_]+]]: .Bool{{(@.*)?}}= { // CHECK-DAG: _[[retId]] _[[etaVar]] diff --git a/lit/core/normalize_icmp.thorin b/lit/core/normalize_icmp.thorin index e65def31de..4a2dce1021 100644 --- a/lit/core/normalize_icmp.thorin +++ b/lit/core/normalize_icmp.thorin @@ -7,7 +7,7 @@ return (%core.icmp.e (%core.icmp.uge (.tt, .ff), %core.icmp.ug (.tt, .ff))) }; -// CHECK-DAG: icmp_lit _[[retId:[0-9_]+]]: .Cn .Bool{{(@.*)?}}= { +// CHECK-DAG: icmp_lit return_[[retId:[0-9_]+]]: .Cn .Bool{{(@.*)?}}= { // CHECK-DAG: _[[etaId:[0-9_]+]] .tt // CHECK-DAG: _[[etaId]] _[[etaVar:[0-9_]+]]: .Bool{{(@.*)?}}= { diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 972f019d7b..d2010cd789 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -122,7 +122,7 @@ void TuplePtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } -void GroupPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } +void GrpPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } /* * Expr diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 38cc5f610d..2c216c37e7 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -124,7 +124,7 @@ Ref TuplePtrn::emit_value(Emitter& e, Ref def) const { return def_ = def->set(dbg()); } -Ref GroupPtrn::emit_value(Emitter&, Ref def) const { return def_ = def; } +Ref GrpPtrn::emit_value(Emitter&, Ref def) const { return def_ = def->set(dbg()); } /* * Ptrn::emit_Type @@ -132,7 +132,7 @@ Ref GroupPtrn::emit_value(Emitter&, Ref def) const { return def_ = def; } Ref IdPtrn::emit_type(Emitter& e) const { return type() ? type()->emit(e) : e.world().mut_infer_type()->set(loc()); } -Ref GroupPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } +Ref GrpPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } Ref TuplePtrn::emit_type(Emitter& e) const { return emit_body(e, {}); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 922ea99480..c3844e85e3 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -505,7 +505,7 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { auto id = ptr(dbg.loc + type->loc().finis, false, dbg, std::move(type)); for (auto dbg : dbgs | std::views::take(dbgs.size() - 1)) - ptrns.emplace_back(ptr(dbg, id.get())); + ptrns.emplace_back(ptr(dbg, id.get())); ptrns.emplace_back(std::move(id)); return; } diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 749d8fb07e..bc0800c2b6 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -47,7 +47,7 @@ std::ostream& IdPtrn::stream(Tab& tab, std::ostream& os) const { return os << ""; } -std::ostream& GroupPtrn::stream(Tab&, std::ostream& os) const { return os << dbg(); } +std::ostream& GrpPtrn::stream(Tab&, std::ostream& os) const { return os << dbg(); } std::ostream& TuplePtrn::stream(Tab& tab, std::ostream& os) const { if (dbg()) print(os, "{}::", dbg()); diff --git a/src/thorin/check.cpp b/src/thorin/check.cpp index dab185f699..6005d535d3 100644 --- a/src/thorin/check.cpp +++ b/src/thorin/check.cpp @@ -239,10 +239,13 @@ void Sigma::check() { auto t = infer(world(), ops()); if (t != type()) { // TODO HACK - if (Check::alpha(t, type())) set_type(t); - world().WLOG("incorrect type '{}' for '{}'. Correct one would be: '{}'. I'll keep this one nevertheless due to " - "bugs in clos-conv", - type(), this, t); + if (Check::alpha(t, type())) + set_type(t); + else + world().WLOG( + "incorrect type '{}' for '{}'. Correct one would be: '{}'. I'll keep this one nevertheless due to " + "bugs in clos-conv", + type(), this, t); } } From c0144f35846524116ffb00b59474e4a4d639a939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 01:06:24 +0200 Subject: [PATCH 62/95] more bug fixes --- gtest/restricted_dep_types.cpp | 6 ++---- gtest/test.cpp | 1 + src/thorin/ast/ast.cpp | 2 +- src/thorin/world.cpp | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/gtest/restricted_dep_types.cpp b/gtest/restricted_dep_types.cpp index df58281d4b..ad5f6b92dc 100644 --- a/gtest/restricted_dep_types.cpp +++ b/gtest/restricted_dep_types.cpp @@ -216,10 +216,8 @@ TEST(RestrictedDependentTypes, join_singleton) { TEST(RestrictedDependentTypes, ll) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math"}) parser.plugin(plugin); + World& w = driver.world(); + ast::load_plugins(w, {"compile"s, "mem"s, "core"s, "math"s}); auto mem_t = w.annex(); auto i32_t = w.type_i32(); diff --git a/gtest/test.cpp b/gtest/test.cpp index c61cd4815f..09e104bb77 100644 --- a/gtest/test.cpp +++ b/gtest/test.cpp @@ -83,6 +83,7 @@ TEST(Annex, split) { TEST(trait, idx) { Driver driver; + driver.log().set(Log::Level::Debug).set(&std::cerr); World& w = driver.world(); ast::load_plugins(w, "core"); diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index de43cca726..5a22da3b12 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -57,7 +57,7 @@ AST load_plugins(World& world, View plugins) { if (!plugins.empty()) { auto mod = ast.ptr(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs()); - // TODO return mod + mod->compile(ast); } return ast; diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index e44de9e2d6..c30d4aca49 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -79,7 +79,7 @@ Sym World::sym(const std::string& s) { return driver().sym(s); } const Def* World::register_annex(flags_t f, const Def* def) { // TODO enable again - // DLOG("register: 0x{f} -> {}", f, def); + /*DLOG("register: 0x{f} -> {}", f, def);*/ auto plugin = Annex::demangle(driver(), f); if (driver().is_loaded(plugin)) { assert_emplace(move_.annexes, f, def); From 7c49eb545a6de8bc1212162220df8e6fcbfd426e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 01:20:40 +0200 Subject: [PATCH 63/95] polish --- src/thorin/plug/matrix/matrix.thorin | 2 +- src/thorin/world.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/thorin/plug/matrix/matrix.thorin b/src/thorin/plug/matrix/matrix.thorin index b0b57921b5..9594390cf8 100644 --- a/src/thorin/plug/matrix/matrix.thorin +++ b/src/thorin/plug/matrix/matrix.thorin @@ -173,7 +173,7 @@ /// Transpose a matrix by iterating the indices in swapped order. // TODO: check code for 1-matrix edge case // TODO: would this automatically be handled by read(transpose) ? -.fun .extern internal_mapRed_matrix_transpose((k l: .Nat), T: *) +.fun .extern internal_mapRed_matrix_transpose ((k l: .Nat), T: *) !(mem: %mem.M, M: %matrix.Mat (2, (k, l), T)) : [ %mem.M, %matrix.Mat (2, (l, k), T)] = .let zero = ⊥:T; // TODO: use generalized zero diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index c30d4aca49..208609ff37 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -193,9 +193,9 @@ Ref World::app(Ref callee, Ref arg) { throw Error() .error(arg->loc(), "cannot apply argument to callee") .note(arg->loc(), "argument: '{}'", arg) - .note(arg->loc(), "type: '{}'", arg->type()) .note(callee->loc(), "callee: '{}'", callee) - .note(callee->loc(), "domain type: '{}'", pi->dom()); + .note(arg->loc(), "'{}' <--- argument type", arg->type()) + .note(callee->loc(), "'{}' <--- domain type", pi->dom()); } if (auto imm = callee->isa_imm()) return imm->body(); From 02e594b2e9c448a6e206743da561d8fb03c2dcd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 01:43:44 +0200 Subject: [PATCH 64/95] World: wip: push/pop emit loc --- include/thorin/world.h | 28 ++++++++++++++++++---- src/thorin/ast/emit.cpp | 52 +++++++++++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/include/thorin/world.h b/include/thorin/world.h index 20c2af1a9b..b186aea020 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -51,7 +51,7 @@ class World { #endif friend void swap(State& s1, State& s2) noexcept { using std::swap; - assert((!s1.pod.loc || !s2.pod.loc) && "Why is emit_loc() still set?"); + assert((!s1.pod.loc || !s2.pod.loc) && "Why is get_loc() still set?"); swap(s1.pod, s2.pod); #ifdef THORIN_ENABLE_CHECKS swap(s1.breakpoints, s2.breakpoints); @@ -91,8 +91,28 @@ class World { /// Retrive compile Flags. Flags& flags(); + ///@} - Loc& emit_loc() { return state_.pod.loc; } + /// @name Loc + ///@{ + struct ScopedLoc { + ScopedLoc(World& world, Loc old_loc) + : world_(world) + , old_loc_(old_loc) {} + ~ScopedLoc() { world_.set_loc(old_loc_); } + + private: + World& world_; + Loc old_loc_; + }; + + Loc get_loc() const { return state_.pod.loc; } + void set_loc(Loc loc = {}) { state_.pod.loc = loc; } + ScopedLoc push(Loc loc) { + auto sl = ScopedLoc(*this, get_loc()); + set_loc(loc); + return sl; + } ///@} /// @name Sym @@ -533,7 +553,7 @@ class World { template const T* unify(size_t num_ops, Args&&... args) { auto state = move_.arena.state(); auto def = allocate(num_ops, std::forward(args)...); - if (auto loc = emit_loc()) def->set(loc); + if (auto loc = get_loc()) def->set(loc); assert(!def->isa_mut()); #ifdef THORIN_ENABLE_CHECKS if (flags().trace_gids) outln("{}: {} - {}", def->node_name(), def->gid(), def->flags()); @@ -565,7 +585,7 @@ class World { template T* insert(size_t num_ops, Args&&... args) { auto def = allocate(num_ops, std::forward(args)...); - if (auto loc = emit_loc()) def->set(loc); + if (auto loc = get_loc()) def->set(loc); #ifdef THORIN_ENABLE_CHECKS if (flags().trace_gids) outln("{}: {} - {}", def->node_name(), def->gid(), def->flags()); if (breakpoints().contains(def->gid())) fe::breakpoint(); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 2c216c37e7..3925c5294f 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -53,7 +53,7 @@ Ref IdExpr::emit(Emitter&) const { Ref TypeExpr::emit(Emitter& e) const { auto l = level()->emit(e); - return e.world().type(l)->set(loc()); + return e.world().type(l); } Ref PrimaryExpr ::emit(Emitter& e) const { @@ -83,19 +83,20 @@ Ref PrimaryExpr ::emit(Emitter& e) const { } Ref LitExpr::emit(Emitter& e) const { + auto old_loc = e.world().push(loc()); // auto t = type() ? type()->emit(e) : e.world().type<0>(); - // return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t))->set(loc()); + // return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t)); auto t = type() ? type()->emit(e) : nullptr; // clang-format off switch (tag()){ case Tag::L_f: case Tag::L_s: - case Tag::L_u: return (t ? e.world().lit(t, tok().lit_u()) : e.world().lit_nat(tok().lit_u()))->set(loc()); + case Tag::L_u: return t ? e.world().lit(t, tok().lit_u()) : e.world().lit_nat(tok().lit_u()); case Tag::L_i: return tok().lit_i(); case Tag::L_c: return e.world().lit_i8(tok().lit_c()); - case Tag::L_str: return e.world().tuple(tok().sym())->set(loc()); - case Tag::T_bot: return t ? e.world().bot(t)->set(loc()) : *e.world().type_bot(); - case Tag::T_top: return t ? e.world().top(t)->set(loc()) : *e.world().type_top(); + case Tag::L_str: return e.world().tuple(tok().sym()); + case Tag::T_bot: return t ? e.world().bot(t) : e.world().type_bot(); + case Tag::T_top: return t ? e.world().top(t) : e.world().type_top(); default: fe::unreachable(); } // clang-format on @@ -107,6 +108,7 @@ void Module::emit(AST& ast) const { } void Module::emit(Emitter& e) const { + auto _ = e.world().push(loc()); for (const auto& import : imports()) import->emit(e); decls_.emit(e); } @@ -130,20 +132,24 @@ Ref GrpPtrn::emit_value(Emitter&, Ref def) const { return def_ = def->set(dbg()) * Ptrn::emit_Type */ -Ref IdPtrn::emit_type(Emitter& e) const { return type() ? type()->emit(e) : e.world().mut_infer_type()->set(loc()); } +Ref IdPtrn::emit_type(Emitter& e) const { + auto _ = e.world().push(loc()); + return type() ? type()->emit(e) : e.world().mut_infer_type(); +} Ref GrpPtrn::emit_type(Emitter& e) const { return id()->emit_type(e); } Ref TuplePtrn::emit_type(Emitter& e) const { return emit_body(e, {}); } Ref TuplePtrn::emit_body(Emitter& e, Ref decl) const { + auto _ = e.world().push(loc()); auto n = num_ptrns(); Sigma* sigma; if (decl) { sigma = decl->as_mut(); } else { auto type = e.world().type_infer_univ(); - sigma = e.world().mut_sigma(type, n)->set(loc(), dbg().sym); + sigma = e.world().mut_sigma(type, n)->set(dbg().sym); } auto var = sigma->var()->set(dbg()); auto& sym2idx = e.sigma2sym2idx[sigma]; @@ -159,8 +165,9 @@ Ref TuplePtrn::emit_body(Emitter& e, Ref decl) const { } Ref TuplePtrn::emit_decl(Emitter& e, Ref type) const { - type = type ? type : e.world().type_infer_univ(); - return e.world().mut_sigma(type, num_ptrns())->set(loc(), dbg().sym); + auto _ = e.world().push(loc()); + type = type ? type : e.world().type_infer_univ(); + return e.world().mut_sigma(type, num_ptrns())->set(dbg().sym); } /* @@ -175,9 +182,10 @@ Ref DeclExpr::emit(Emitter& e) const { Ref BlockExpr::emit(Emitter& e) const { return expr()->emit(e); } Ref ArrowExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); auto d = dom()->emit(e); auto c = codom()->emit(e); - return e.world().pi(d, c)->set(loc()); + return e.world().pi(d, c); } void PiExpr::Dom::emit_type(Emitter& e) const { @@ -233,12 +241,14 @@ Ref LamExpr::emit(Emitter& e) const { } Ref AppExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); auto c = callee()->emit(e); auto a = arg()->emit(e); - return (is_explicit() ? e.world().app(c, a) : e.world().iapp(c, a))->set(loc()); + return is_explicit() ? e.world().app(c, a) : e.world().iapp(c, a); } Ref RetExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); auto c = callee()->emit(e); if (auto cn = Pi::ret_pi(c->type())) { auto con = e.world().mut_lam(cn); @@ -260,11 +270,13 @@ void SigmaExpr::emit_body(Emitter& e, Ref decl) const { ptrn()->emit_body(e, dec Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } Ref TupleExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); DefVec elems(num_elems(), [&](size_t i) { return elem(i)->emit(e); }); - return e.world().tuple(elems)->set(loc()); + return e.world().tuple(elems); } template Ref ArrOrPackExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); auto s = shape()->emit_type(e); if (shape()->is_anon()) { // immutable auto b = body()->emit(e); @@ -297,6 +309,7 @@ template Ref ArrOrPackExpr::emit(Emitter&) const; template Ref ArrOrPackExpr::emit(Emitter&) const; Ref ExtractExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); auto tup = tuple()->emit(e); if (auto dbg = std::get_if(&index())) { if (auto sigma = tup->type()->isa_mut()) { @@ -304,24 +317,25 @@ Ref ExtractExpr::emit(Emitter& e) const { auto sigma = i->first->as_mut(); const auto& sym2idx = i->second; if (auto i = sym2idx.find(dbg->sym); i != sym2idx.end()) - return e.world().extract(tup, sigma->num_ops(), i->second)->set(loc()); + return e.world().extract(tup, sigma->num_ops(), i->second); } } - if (decl()) return e.world().extract(tup, decl()->def())->set(loc()); + if (decl()) return e.world().extract(tup, decl()->def()); error(dbg->loc, "cannot resolve index '{}' for extraction", dbg); } auto expr = std::get>(index()).get(); auto i = expr->emit(e); - return e.world().extract(tup, i)->set(loc()); + return e.world().extract(tup, i); } Ref InsertExpr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); auto t = tuple()->emit(e); auto i = index()->emit(e); auto v = value()->emit(e); - return e.world().insert(t, i, v)->set(loc()); + return e.world().insert(t, i, v); } /* @@ -434,6 +448,8 @@ Lam* LamDecl::Dom::emit_value(Emitter& e) const { } void LamDecl::emit_decl(Emitter& e) const { + auto _ = e.world().push(loc()); + // Iterate over all doms: Build a Lam for cur dom, by furst building a curried Pi for the remaining doms. for (size_t i = 0, n = num_doms(); i != n; ++i) { for (const auto& dom : doms() | std::ranges::views::drop(i)) dom->emit_type(e); @@ -455,7 +471,7 @@ void LamDecl::emit_decl(Emitter& e) const { lam->set_filter(f); if (i == 0) - def_ = lam->set(loc(), dbg().sym); + def_ = lam->set(dbg().sym); else dom(i - 1)->lam_->set_body(lam); } From fcfdf8a8199fca7c8607cb70672b0d9b6198aff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 20:38:24 +0200 Subject: [PATCH 65/95] bug fixes --- include/thorin/world.h | 2 +- lit/direct/mut_dom_bug.thorin | 2 +- lit/matrix/test_write.thorin | 2 +- lit/mem/alloc_load_store.thorin | 4 ++-- lit/mem/malloc_load_store.thorin | 4 ++-- lit/mem/mslot_load_store.thorin | 4 ++-- src/thorin/plug/clos/clos.cpp | 6 +++++- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/thorin/world.h b/include/thorin/world.h index b186aea020..e3cea31e97 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -261,7 +261,7 @@ class World { /// Pi with codom thorin::Bot%tom ///@{ // clang-format off - const Pi* cn( bool implicit = false) { return cn(sigma( ), implicit); } + const Pi* cn( ) { return cn(sigma( ), false); } const Pi* cn(Ref dom, bool implicit = false) { return pi( dom , type_bot(), implicit); } const Pi* cn(Defs dom, bool implicit = false) { return cn(sigma(dom), implicit); } const Pi* fn(Ref dom, Ref codom, bool implicit = false) { return cn({ dom , cn(codom)}, implicit); } diff --git a/lit/direct/mut_dom_bug.thorin b/lit/direct/mut_dom_bug.thorin index 3242d72fe4..780832ab13 100644 --- a/lit/direct/mut_dom_bug.thorin +++ b/lit/direct/mut_dom_bug.thorin @@ -3,7 +3,7 @@ .lam ForBody [n: .Nat] = [%mem.M, .Idx n] -> %mem.M; -.next +.grp .lam For .[n: .Nat] [start: .Idx n, end: .Idx n] [mem: %mem.M] [it: ForBody n]: %mem.M = { .lam loop [mem: %mem.M, i: .Idx n] @(%core.pe.known i) : [%mem.M, .Idx n] = { diff --git a/lit/matrix/test_write.thorin b/lit/matrix/test_write.thorin index 59748e4abf..9a9a445b03 100644 --- a/lit/matrix/test_write.thorin +++ b/lit/matrix/test_write.thorin @@ -8,7 +8,7 @@ .let MT = (2, (2,4), .I32); -.con print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; +.ccon print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; .con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return : .Cn [%mem.M]] = .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat),.I32)) m; diff --git a/lit/mem/alloc_load_store.thorin b/lit/mem/alloc_load_store.thorin index 91d6971b8b..e52f042e14 100644 --- a/lit/mem/alloc_load_store.thorin +++ b/lit/mem/alloc_load_store.thorin @@ -18,10 +18,10 @@ // CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .I32, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { // CHECK-DAG: _[[appAllocId:[0-9_]+]]: [%mem.M, %mem.Ptr (.I32, 0)] = %mem.malloc (.I32, 0) (mem_[[mainMemId]], 4); // CHECK-DAG: _[[appStoreId:[0-9_]+]]: %mem.M = %mem.store (.I32, 0) (_[[appAllocId]]#.ff, _[[appAllocId]]#.tt, argc_[[argcId]]); -// CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .I32] = %mem.load (.I32, 0) (_[[appStoreId]], _[[appAllocId]]#.tt); +// CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .I32] = %mem.load (.I32, 0) (mem_[[appStoreId]], _[[appAllocId]]#.tt); // CHECK-DAG: _[[appFreeId:[0-9_]+]]: %mem.M = %mem.free (.I32, 0) (_[[appLoadId]]#.ff, _[[appAllocId]]#.tt); -// CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (_[[appFreeId]], _[[appLoadId]]#.tt) +// CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (mem_[[appFreeId]], _[[appLoadId]]#.tt) // CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .I32]{{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/mem/malloc_load_store.thorin b/lit/mem/malloc_load_store.thorin index 1e9c142d80..12da776b37 100644 --- a/lit/mem/malloc_load_store.thorin +++ b/lit/mem/malloc_load_store.thorin @@ -18,10 +18,10 @@ // CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .I32, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { // CHECK-DAG: _[[appMallocId:[0-9_]+]]: [%mem.M, %mem.Ptr (.I32, 0)] = %mem.malloc (.I32, 0) (mem_[[mainMemId]], 4); // CHECK-DAG: _[[appStoreId:[0-9_]+]]: %mem.M = %mem.store (.I32, 0) (_[[appMallocId]]#.ff, _[[appMallocId]]#.tt, argc_[[argcId]]); -// CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .I32] = %mem.load (.I32, 0) (_[[appStoreId]], _[[appMallocId]]#.tt); +// CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .I32] = %mem.load (.I32, 0) (mem_[[appStoreId]], _[[appMallocId]]#.tt); // CHECK-DAG: _[[appFreeId:[0-9_]+]]: %mem.M = %mem.free (.I32, 0) (_[[appLoadId]]#.ff, _[[appMallocId]]#.tt); -// CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (_[[appFreeId]], _[[appLoadId]]#.tt) +// CHECK-DAG: return_[[returnEtaId:[0-9_]+]] (mem_[[appFreeId]], _[[appLoadId]]#.tt) // CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .I32]{{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/lit/mem/mslot_load_store.thorin b/lit/mem/mslot_load_store.thorin index ed278f32ea..0c200eb073 100644 --- a/lit/mem/mslot_load_store.thorin +++ b/lit/mem/mslot_load_store.thorin @@ -17,8 +17,8 @@ // CHECK-DAG: .con .extern main _{{[0-9_]+}}::[mem_[[mainMemId:[_0-9]*]]: %mem.M, argc_[[argcId:[0-9_]+]]: .I32, %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), return_[[returnId:[_0-9]*]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { // CHECK-DAG: _[[appMSlotId:[0-9_]+]]: [%mem.M, %mem.Ptr (.I32, 0)] = %mem.mslot (.I32, 0) (mem_[[mainMemId]], 4, 0); // CHECK-DAG: _[[appStoreId:[0-9_]+]]: %mem.M = %mem.store (.I32, 0) (_[[appMSlotId]]#.ff, _[[appMSlotId]]#.tt, argc_[[argcId]]); -// CHECK-DAG: _[[appLoadId:[0-9_]+]]: [%mem.M, .I32] = %mem.load (.I32, 0) (_[[appStoreId]], _[[appMSlotId]]#.tt); -// CHECK-DAG: return_[[returnEtaId:[0-9_]+]] _[[appLoadId]] +// CHECK-DAG: ld_[[appLoadId:[0-9_]+]]: [%mem.M, .I32] = %mem.load (.I32, 0) (mem_[[appStoreId]], _[[appMSlotId]]#.tt); +// CHECK-DAG: return_[[returnEtaId:[0-9_]+]] ld_[[appLoadId]] // CHECK-DAG: return_[[returnEtaId]] _[[returnEtaVarId:[0-9_]+]]: [%mem.M, .I32]{{(@.*)?}}= { // CHECK-DAG: return_[[returnId]] _[[returnEtaVarId]] diff --git a/src/thorin/plug/clos/clos.cpp b/src/thorin/plug/clos/clos.cpp index 9f4a19b9bc..462454ae25 100644 --- a/src/thorin/plug/clos/clos.cpp +++ b/src/thorin/plug/clos/clos.cpp @@ -118,7 +118,11 @@ const Sigma* isa_clos_type(Ref def) { return (pi && Pi::isa_cn(pi) && pi->num_ops() > 1_u64 && pi->dom(Clos_Env_Param) == var) ? sig : nullptr; } -Sigma* clos_type(const Pi* pi) { return ctype(pi->world(), pi->doms(), nullptr)->as_mut(); } +Sigma* clos_type(const Pi* pi) { + auto& w = pi->world(); + auto doms = pi->doms(); + return ctype(w, doms, nullptr)->as_mut(); +} const Pi* clos_type_to_pi(Ref ct, Ref new_env_type) { assert(isa_clos_type(ct)); From 2dc3b3a8bbc39b5bbbe5142e57d83dbae5188ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 21 Apr 2024 21:58:25 +0200 Subject: [PATCH 66/95] bug fixes --- lit/matrix/map_reduce.thorin | 4 ++-- src/thorin/ast/emit.cpp | 11 ++++++----- src/thorin/world.cpp | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/lit/matrix/map_reduce.thorin b/lit/matrix/map_reduce.thorin index 5f6db4b38a..1ce9113311 100644 --- a/lit/matrix/map_reduce.thorin +++ b/lit/matrix/map_reduce.thorin @@ -4,8 +4,8 @@ .plugin core; .plugin matrix; -.fun identity(mem: %mem.M, a: .I32): [%mem.M, .I32] = return (mem, a); -.fun addition(mem: %mem.M, a b :.I32): [%mem.M, .I32] = return (mem, %core.wrap.add 0 (a,b)); +.fun identity(mem: %mem.M, a: .I32): [%mem.M, .I32] = return (mem, a); +.fun addition(mem: %mem.M, a b: .I32): [%mem.M, .I32] = return (mem, %core.wrap.add 0 (a, b)); .fun .extern f(mem: %mem.M, k l: .Nat, M: %matrix.Mat (2, (k, l), .I32)): [%mem.M, %matrix.Mat (2, (l, k), .I32)] = .let MT = %matrix.map_reduce diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 3925c5294f..4f6697fc6f 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -448,7 +448,8 @@ Lam* LamDecl::Dom::emit_value(Emitter& e) const { } void LamDecl::emit_decl(Emitter& e) const { - auto _ = e.world().push(loc()); + auto _ = e.world().push(loc()); + bool is_cps = tag_ == Tag::K_cn || tag_ == Tag::K_con || tag_ == Tag::K_fn || tag_ == Tag::K_fun; // Iterate over all doms: Build a Lam for cur dom, by furst building a curried Pi for the remaining doms. for (size_t i = 0, n = num_doms(); i != n; ++i) { @@ -464,10 +465,10 @@ void LamDecl::emit_decl(Emitter& e) const { auto cur = dom(i); auto lam = cur->emit_value(e); - auto f = cur->has_bang() ? e.world().lit_tt() - : cur->filter() ? cur->filter()->emit(e) - : (tag() == Tag::T_lm || tag() == Tag::K_lam) ? e.world().lit_tt() - : e.world().lit_ff(); + auto f = cur->has_bang() ? e.world().lit_tt() + : cur->filter() ? cur->filter()->emit(e) + : i + 1 == n && is_cps ? e.world().lit_ff() + : e.world().lit_tt(); lam->set_filter(f); if (i == 0) diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 208609ff37..65e47fa000 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -188,7 +188,11 @@ Ref World::app(Ref callee, Ref arg) { Infer::eliminate(Vector{&callee, &arg}); auto pi = callee->type()->isa(); - if (!pi) error(callee->loc(), "called expression '{}' : '{}' is not of function type", callee, callee->type()); + if (!pi) { + throw Error() + .error(callee->loc(), "called expression not of function type") + .error(callee->loc(), "'{}' <--- callee type", callee->type()); + } if (!Check::assignable(pi->dom(), arg)) { throw Error() .error(arg->loc(), "cannot apply argument to callee") @@ -355,9 +359,13 @@ Ref World::insert(Ref d, Ref index, Ref val) { error(index->loc(), "index '{}' does not fit within arity '{}'", index, type->arity()); if (lidx) { - auto target_type = type->proj(*lidx); - if (!Check::assignable(target_type, val)) - error(val->loc(), "value of type {} is not assignable to type {}", val->type(), target_type); + auto elem_type = type->proj(*lidx); + if (!Check::assignable(elem_type, val)) { + throw Error() + .error(val->loc(), "value to be inserted not assignable to element") + .note(val->loc(), "'{}' <--- value type", val->type()) + .note(val->loc(), "'{}' <--- element type", elem_type); + } } if (auto l = Lit::isa(size); l && *l == 1) From 34e334553b2d332d823ba80f8cdb13b1c222e207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 22 Apr 2024 03:05:24 +0200 Subject: [PATCH 67/95] more bug fixes --- src/thorin/ast/emit.cpp | 41 +++++++++++++++++++---------------------- src/thorin/world.cpp | 10 +++++----- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 4f6697fc6f..5e36052750 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -189,25 +189,24 @@ Ref ArrowExpr::emit(Emitter& e) const { } void PiExpr::Dom::emit_type(Emitter& e) const { - pi_ = decl_ ? decl_ : e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); - auto type = ptrn()->emit_type(e); + pi_ = decl_ ? decl_ : e.world().mut_pi(e.world().type_infer_univ(), is_implicit()); + auto dom_t = ptrn()->emit_type(e); if (ret()) { - auto ret_t = e.world().cn(ret()->emit_type(e)); - auto sigma_t = e.world().umax({type, ret_t}); - auto sigma = e.world().mut_sigma(sigma_t, 2)->set(ret()->loc()); - auto var = sigma->var()->set(ret()->loc().anew_begin()); - sigma->set(0, type); + auto sigma = e.world().mut_sigma(2)->set(loc()); + auto var = sigma->var()->set(ret()->loc().anew_begin()); + sigma->set(0, dom_t); ptrn()->emit_value(e, var->proj(2, 0)); + auto ret_t = e.world().cn(ret()->emit_type(e)); sigma->set(1, ret_t); if (auto imm = sigma->immutabilize()) - type = imm; + dom_t = imm; else - type = sigma; - pi_->set_dom(type); + dom_t = sigma; + pi_->set_dom(dom_t); } else { - pi_->set_dom(type); + pi_->set_dom(dom_t); ptrn()->emit_value(e, pi_->var()); } } @@ -451,25 +450,23 @@ void LamDecl::emit_decl(Emitter& e) const { auto _ = e.world().push(loc()); bool is_cps = tag_ == Tag::K_cn || tag_ == Tag::K_con || tag_ == Tag::K_fn || tag_ == Tag::K_fun; - // Iterate over all doms: Build a Lam for cur dom, by furst building a curried Pi for the remaining doms. + // Iterate over all doms: Build a Lam for cur dom, by first building a curried Pi for the remaining doms. for (size_t i = 0, n = num_doms(); i != n; ++i) { for (const auto& dom : doms() | std::ranges::views::drop(i)) dom->emit_type(e); - auto cod = codom() ? codom()->emit(e) - : (tag() == Tag::T_lm || tag() == Tag::K_lam) ? e.world().mut_infer_type() - : e.world().type_bot(); + auto cod = codom() ? codom()->emit(e) : is_cps ? e.world().type_bot() : e.world().mut_infer_type(); for (const auto& dom : doms() | std::ranges::views::drop(i) | std::ranges::views::reverse) { dom->pi_->set_codom(cod); cod = dom->pi_; } - auto cur = dom(i); - auto lam = cur->emit_value(e); - auto f = cur->has_bang() ? e.world().lit_tt() - : cur->filter() ? cur->filter()->emit(e) - : i + 1 == n && is_cps ? e.world().lit_ff() - : e.world().lit_tt(); - lam->set_filter(f); + auto cur = dom(i); + auto lam = cur->emit_value(e); + auto filter = cur->has_bang() ? e.world().lit_tt() + : cur->filter() ? cur->filter()->emit(e) + : i + 1 == n && is_cps ? e.world().lit_ff() + : e.world().lit_tt(); + lam->set_filter(filter); if (i == 0) def_ = lam->set(dbg().sym); diff --git a/src/thorin/world.cpp b/src/thorin/world.cpp index 65e47fa000..4768307233 100644 --- a/src/thorin/world.cpp +++ b/src/thorin/world.cpp @@ -196,10 +196,10 @@ Ref World::app(Ref callee, Ref arg) { if (!Check::assignable(pi->dom(), arg)) { throw Error() .error(arg->loc(), "cannot apply argument to callee") - .note(arg->loc(), "argument: '{}'", arg) .note(callee->loc(), "callee: '{}'", callee) - .note(arg->loc(), "'{}' <--- argument type", arg->type()) - .note(callee->loc(), "'{}' <--- domain type", pi->dom()); + .note(arg->loc(), "argument: '{}'", arg) + .note(callee->loc(), "vvv domain type vvv\n'{}'\n'{}'", pi->dom(), arg->type()) + .note(arg->loc(), "^^^ argument type ^^^"); } if (auto imm = callee->isa_imm()) return imm->body(); @@ -363,8 +363,8 @@ Ref World::insert(Ref d, Ref index, Ref val) { if (!Check::assignable(elem_type, val)) { throw Error() .error(val->loc(), "value to be inserted not assignable to element") - .note(val->loc(), "'{}' <--- value type", val->type()) - .note(val->loc(), "'{}' <--- element type", elem_type); + .note(val->loc(), "vvv value type vvv \n'{}'\n'{}'", val->type(), elem_type) + .note(val->loc(), "^^^ element type ^^^", elem_type); } } From cd5cc03231d318459554aa90bf745544a423f980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Mon, 22 Apr 2024 03:09:03 +0200 Subject: [PATCH 68/95] bug fixes --- lit/matrix/print_const.thorin | 2 +- lit/matrix/print_const_dyn_mat.thorin | 4 ++-- lit/matrix/print_id_mat.thorin | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lit/matrix/print_const.thorin b/lit/matrix/print_const.thorin index 090c4bbd98..a83add0403 100644 --- a/lit/matrix/print_const.thorin +++ b/lit/matrix/print_const.thorin @@ -8,7 +8,7 @@ .let MT = (2, (2,4), .I32); -.con print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; +.ccon print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; .con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return : .Cn [%mem.M]] = { .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat),.I32)) m; diff --git a/lit/matrix/print_const_dyn_mat.thorin b/lit/matrix/print_const_dyn_mat.thorin index ebdd2a2906..bbb46ffafd 100644 --- a/lit/matrix/print_const_dyn_mat.thorin +++ b/lit/matrix/print_const_dyn_mat.thorin @@ -11,8 +11,8 @@ .let u8 = .I8; .let String = %mem.Ptr («⊤:.Nat; .I8», 0); -.con atoi [%mem.M, String, .Cn [%mem.M, .I32]]; -.con print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; +.ccon atoi [%mem.M, String, .Cn [%mem.M, .I32]]; +.ccon print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; .con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return : .Cn [%mem.M]] = { .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat),.I32)) m; diff --git a/lit/matrix/print_id_mat.thorin b/lit/matrix/print_id_mat.thorin index e720f833ea..668197c074 100644 --- a/lit/matrix/print_id_mat.thorin +++ b/lit/matrix/print_id_mat.thorin @@ -9,8 +9,8 @@ .let MT1 = (2, (2,4), %math.F64); // .let MT2 = (2, (4,3), %math.F64); -.con print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; -.con print_double_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), %math.F64), return : .Cn [%mem.M]]; +.ccon print_int_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), .I32), return : .Cn [%mem.M]]; +.ccon print_double_matrix [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (⊤:.Nat,⊤:.Nat), %math.F64), return : .Cn [%mem.M]]; .con print_int_matrix_wrap [mem: %mem.M, k: .Nat, l: .Nat, m: %matrix.Mat (2, (k,l), .I32), return : .Cn [%mem.M]] = { .let m2 = %core.bitcast (%matrix.Mat (2,(⊤:.Nat,⊤:.Nat),.I32)) m; From 8488db377b1d2762e353d8818314c1238d933273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 23 Apr 2024 00:31:17 +0200 Subject: [PATCH 69/95] simplify ast::Prec madness --- include/thorin/ast/parser.h | 7 +- include/thorin/ast/tok.h | 46 ++++--------- lit/regex/match_mail.thorin | 2 +- src/thorin/ast/parser.cpp | 132 +++++++++++++++++++----------------- src/thorin/ast/tok.cpp | 10 --- src/thorin/dump.cpp | 36 ++++++++-- 6 files changed, 120 insertions(+), 113 deletions(-) diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index f4e27a6619..9ca6456478 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -74,10 +74,9 @@ class Parser : public fe::Parser { /// @name parse exprs ///@{ - Ptr parse_expr(std::string_view ctxt, Tok::Prec = Tok::Prec::Bot); + Ptr parse_expr(std::string_view ctxt, Prec = Prec::Bot); Ptr parse_primary_expr(std::string_view ctxt); - Ptr parse_infix_expr(Tracker, Ptr&& lhs, Tok::Prec = Tok::Prec::Bot); - Ptr parse_extract_expr(Tracker, Ptr&&, Tok::Prec); + Ptr parse_infix_expr(Tracker, Ptr&& lhs, Prec = Prec::Bot); ///@} /// @name parse primary exprs @@ -100,7 +99,7 @@ class Parser : public fe::Parser { ///@{ /// Depending on @p tag, this parses a `()`-style (Tok::Tag::D_paren_l) or `[]`-style (Tok::Tag::D_brckt_l) Ptrn. - Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Tok::Prec = Tok::Prec::Bot, bool allow_annex = false); + Ptr parse_ptrn(Tok::Tag tag, std::string_view ctxt, Prec = Prec::Bot, bool allow_annex = false); Ptr parse_tuple_ptrn(bool rebind, Dbg); ///@} diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 5fc0654c36..609f0fc364 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -103,40 +103,24 @@ constexpr auto Num_Keys = size_t(0) THORIN_KEY(CODE); m(".top", T_top ) \ m(".insert", K_ins ) \ -#define THORIN_PREC(m) \ - /* left prec, right */ \ - m(Nil, Bot, Nil ) \ - m(Nil, Nil, Nil ) \ - m(Nil, Where, Where ) \ - m(Lam, Arrow, Arrow ) \ - m(Nil, Lam, Pi ) \ - m(Nil, Pi, App ) \ - m(App, App, Extract ) \ - m(Extract, Extract, Lit ) \ - m(Nil, Lit, Lit ) \ +/// @name Precedence +///@{ +enum class Prec { + Err, + Bot, + Where, + Arrow, + Pi, + App, + Extract, + Lit, +}; + +inline constexpr bool is_rassoc(Prec p) { return p == Prec::Arrow; } +///@} class Tok { public: - /// @name Precedence - ///@{ - enum class Prec { -#define CODE(l, p, r) p, - THORIN_PREC(CODE) -#undef CODE - }; - - static constexpr std::array prec(Prec p) { - switch (p) { -#define CODE(l, p, r) \ - case Prec::p: return {Prec::l, Prec::r}; - default: fe::unreachable(); - THORIN_PREC(CODE) -#undef CODE - } - } - static Prec prec(const Def*); - ///@} - /// @name Tag ///@{ enum class Tag { diff --git a/lit/regex/match_mail.thorin b/lit/regex/match_mail.thorin index e6e88e55b6..89950d4c8f 100644 --- a/lit/regex/match_mail.thorin +++ b/lit/regex/match_mail.thorin @@ -65,7 +65,7 @@ letter, %regex.quant.plus letter); -.con strlen[%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; +.ccon strlen[%mem.M, %mem.Ptr («⊤:.Nat; .I8», 0), .Cn [%mem.M, .I32]]; .con .extern main[mem: %mem.M, argc: .I32, argv: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), exit : .Cn [%mem.M, .I32]] = { .con match_argument[mem: %mem.M, .I32] = { diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index c3844e85e3..4106571d3f 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -83,6 +83,19 @@ namespace thorin::ast { using Tag = Tok::Tag; +// clang-format off +Prec tag2prec(Tag tag) { + switch (tag) { + case Tag::K_where: return Prec::Where; + case Tag::T_arrow: return Prec::Arrow; + case Tag::T_extract: return Prec::Extract; + case Tag::T_at: + case EXPR: return Prec::App; + default: return Prec::Err; + } +} +// clang-format on + /* * entry points */ @@ -171,7 +184,7 @@ Dbg Parser::parse_name(std::string_view ctxt) { } Ptr Parser::parse_type_ascr(std::string_view ctxt) { - if (accept(Tag::T_colon)) return parse_expr(ctxt, Tok::Prec::Bot); + if (accept(Tag::T_colon)) return parse_expr(ctxt); if (ctxt.empty()) return nullptr; syntax_err("':'", ctxt); return ptr(prev_); @@ -181,61 +194,58 @@ Ptr Parser::parse_type_ascr(std::string_view ctxt) { * exprs */ -Ptr Parser::parse_expr(std::string_view ctxt, Tok::Prec curr_prec) { +Ptr Parser::parse_expr(std::string_view ctxt, Prec curr_prec) { auto track = tracker(); auto lhs = parse_primary_expr(ctxt); return parse_infix_expr(track, std::move(lhs), curr_prec); } -Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Tok::Prec curr_prec) { +Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_prec) { while (true) { // If operator in ahead has less left precedence: reduce (break). - if (ahead().isa(Tag::T_extract)) { - if (auto extract = parse_extract_expr(track, std::move(lhs), curr_prec)) - lhs = std::move(extract); - else - break; - } else if (ahead().isa(Tag::T_arrow)) { - auto [l, r] = Tok::prec(Tok::Prec::Arrow); - if (l < curr_prec) break; - lex(); - auto rhs = parse_expr("right-hand side of a function type", r); - lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); - } else if (ahead().isa(Tag::K_where)) { - auto [l, r] = Tok::prec(Tok::Prec::Where); - if (l < curr_prec) break; - lex(); - auto decls = parse_decls(); - lhs = ptr(track, std::move(decls), std::move(lhs), true); - lhs->dump(); - outln("--"); - expect(Tag::K_end, "end of a .where declaration block"); - } else { - auto [l, r] = Tok::prec(Tok::Prec::App); - if (l < curr_prec) break; - bool is_explicit = (bool)accept(Tag::T_at); - switch (ahead().tag()) { - case EXPR: { - auto rhs - = parse_expr("argument to an application", r); // if we can parse an expression, it's an App - lhs = ptr(track.loc(), is_explicit, std::move(lhs), std::move(rhs)); - continue; + switch (ahead().tag()) { + case Tag::T_extract: { + if (curr_prec >= Prec::Extract) return lhs; + lex(); + if (auto tok = accept(Tag::M_id)) + lhs = ptr(track.loc(), std::move(lhs), tok.dbg()); + else { + auto rhs = parse_expr("right-hand side of an extract", Prec::Extract); + lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); } - default: return lhs; + continue; } + case Tag::T_arrow: { + if (curr_prec > Prec::Arrow) return lhs; // ">" - Arrow is rassoc + lex(); + auto rhs = parse_expr("right-hand side of a function type", Prec::Arrow); + lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); + continue; + } + case Tag::K_where: { + if (curr_prec >= Prec::Where) return lhs; + lex(); + auto decls = parse_decls(); + lhs = ptr(track, std::move(decls), std::move(lhs), true); + expect(Tag::K_end, "end of a .where declaration block"); + continue; + } + case Tag::T_at: { + if (curr_prec >= Prec::App) return lhs; + lex(); + auto rhs = parse_expr("explicit argument to an application", Prec::App); + lhs = ptr(track.loc(), true, std::move(lhs), std::move(rhs)); + continue; + } + case EXPR: { + if (curr_prec >= Prec::App) return lhs; + auto rhs = parse_expr("argument to an application", Prec::App); + lhs = ptr(track.loc(), false, std::move(lhs), std::move(rhs)); + continue; + } + default: return lhs; } } - - return lhs; -} - -Ptr Parser::parse_extract_expr(Tracker track, Ptr&& lhs, Tok::Prec curr_prec) { - auto [l, r] = Tok::prec(Tok::Prec::Extract); - if (l < curr_prec) return nullptr; - lex(); - if (auto tok = accept(Tag::M_id)) return ptr(track.loc(), std::move(lhs), tok.dbg()); - auto rhs = parse_expr("right-hand side of an extract", r); - return ptr(track.loc(), std::move(lhs), std::move(rhs)); } Ptr Parser::parse_insert_expr() { @@ -314,10 +324,9 @@ Ptr Parser::parse_decl_expr() { } Ptr Parser::parse_lit_expr() { - auto track = tracker(); - auto tok = lex(); - auto [_, r] = Tok::prec(Tok::Prec::Lit); - auto type = accept(Tag::T_colon) ? parse_expr("literal", r) : nullptr; + auto track = tracker(); + auto tok = lex(); + auto type = accept(Tag::T_colon) ? parse_expr("literal", Prec::Lit) : nullptr; return ptr(track, tok, std::move(type)); } @@ -333,8 +342,7 @@ Ptr Parser::parse_tuple_expr() { Ptr Parser::parse_type_expr() { auto track = tracker(); eat(Tag::K_Type); - auto [l, r] = Tok::prec(Tok::Prec::App); - auto level = parse_expr("type level", r); + auto level = parse_expr("type level", Prec::App); return ptr(track, std::move(level)); } @@ -354,15 +362,14 @@ Ptr Parser::parse_pi_expr() { do { auto track = tracker(); auto implicit = (bool)accept(Tag::T_dot); - auto prec = tag == Tag::K_Cn ? Tok::Prec::Bot : Tok::Prec::App; + auto prec = tag == Tag::K_Cn ? Prec::Bot : Prec::Pi; auto ptrn = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec); doms.emplace_back(ptr(track, implicit, std::move(ptrn))); } while (ahead().isa(Tag::T_dot) || ahead().isa(Tag::D_brckt_l) || ahead().isa(Tag::T_backtick) || (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon_colon))); - auto codom = tag != Tag::K_Cn - ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Tok::Prec::Arrow)) - : nullptr; + auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Prec::Arrow)) + : nullptr; if (tag == Tag::K_Fn) doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr(prev_)); @@ -388,7 +395,7 @@ Ptr Parser::parse_ret_expr() { * ptrns */ -Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Tok::Prec prec, bool allow_annex) { +Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool allow_annex) { auto track = tracker(); auto dbg = Dbg(ahead().loc(), Sym()); bool p = delim_l == Tag::D_paren_l; @@ -516,9 +523,8 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { auto rhs = ptr(dbg); lhs = ptr(track, false, std::move(lhs), std::move(rhs)); } - auto [_, r] = Tok::prec(Tok::Prec::App); - auto expr = parse_infix_expr(track, std::move(lhs), r); - ptrn = IdPtrn::mk_type(ast(), std::move(expr)); + auto expr = parse_infix_expr(track, std::move(lhs), Prec::App); + ptrn = IdPtrn::mk_type(ast(), std::move(expr)); } else { ptrn = parse_ptrn(delim_l, "element of a tuple pattern"); @@ -609,7 +615,7 @@ Ptr Parser::parse_axiom_decl() { Ptr Parser::parse_let_decl() { auto track = tracker(); eat(Tag::K_let); - auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration", Tok::Prec::Bot, true); + auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a let declaration", Prec::Bot, true); expect(Tag::T_assign, "let"); auto type = parse_type_ascr(); auto value = parse_expr("value of a let declaration"); @@ -629,7 +635,7 @@ Ptr Parser::parse_rec_decl() { Ptr Parser::parse_lam_decl() { auto track = tracker(); auto tag = lex().tag(); - auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Tok::Prec::Bot : Tok::Prec::Pi; + auto prec = tag == Tag::K_cn || tag == Tag::K_con ? Prec::Bot : Prec::Pi; bool external = (bool)accept(Tag::K_extern); bool decl; @@ -664,7 +670,7 @@ Ptr Parser::parse_lam_decl() { doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); - auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Tok::Prec::Arrow) : nullptr; + auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Prec::Arrow) : nullptr; if (tag == Tag::K_fn || tag == Tag::K_fun) doms.back()->add_ret(ast(), codom ? std::move(codom) : ptr(prev_)); @@ -678,7 +684,7 @@ Ptr Parser::parse_c_decl() { auto track = tracker(); auto tag = lex().tag(); auto id = expect(Tag::M_id, "C function declaration"); - auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Tok::Prec::App); + auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Prec::App); Ptr codom; if (tag == Tag::K_cfun) { expect(Tag::T_colon, "codomain of a C function"); diff --git a/src/thorin/ast/tok.cpp b/src/thorin/ast/tok.cpp index 3324f98f4c..383e091bc8 100644 --- a/src/thorin/ast/tok.cpp +++ b/src/thorin/ast/tok.cpp @@ -33,14 +33,4 @@ std::ostream& operator<<(std::ostream& os, Tok tok) { } ///@} -// clang-format off -Tok::Prec Tok::prec(const Def* def) { - if (def->isa()) return Tok::Prec::Arrow; - if (def->isa()) return Tok::Prec::App; - if (def->isa()) return Tok::Prec::Extract; - if (def->isa()) return Tok::Prec::Lit; - return Tok::Prec::Bot; -} -// clang-format on - } // namespace thorin::ast diff --git a/src/thorin/dump.cpp b/src/thorin/dump.cpp index 0f6618087a..ed1cfec13d 100644 --- a/src/thorin/dump.cpp +++ b/src/thorin/dump.cpp @@ -78,6 +78,36 @@ struct Inline { friend std::ostream& operator<<(std::ostream&, Inline); }; +#define MY_PREC(m) \ + /* left prec, right */ \ + m(Nil, Bot, Nil) m(Nil, Nil, Nil) m(Lam, Arrow, Arrow) m(Nil, Lam, Pi) m(Nil, Pi, App) m(App, App, Extract) \ + m(Extract, Extract, Lit) m(Nil, Lit, Lit) + +enum class MyPrec { +#define CODE(l, p, r) p, + MY_PREC(CODE) +#undef CODE +}; + +static constexpr std::array my_prec(MyPrec p) { + switch (p) { +#define CODE(l, p, r) \ + case MyPrec::p: return {MyPrec::l, MyPrec::r}; + default: fe::unreachable(); MY_PREC(CODE) +#undef CODE + } +} + +// clang-format off +MyPrec my_prec(const Def* def) { + if (def->isa()) return MyPrec::Arrow; + if (def->isa()) return MyPrec::App; + if (def->isa()) return MyPrec::Extract; + if (def->isa()) return MyPrec::Lit; + return MyPrec::Bot; +} +// clang-format on + // TODO prec is currently broken template struct LRPrec { LRPrec(const Def* l, const Def* r) @@ -90,12 +120,10 @@ template struct LRPrec { friend std::ostream& operator<<(std::ostream& os, const LRPrec& p) { if constexpr (L) { - if (Inline(p.l) && ast::Tok::prec(ast::Tok::prec(p.r))[0] > ast::Tok::prec(p.r)) - return print(os, "({})", p.l); + if (Inline(p.l) && my_prec(my_prec(p.r))[0] > my_prec(p.r)) return print(os, "({})", p.l); return print(os, "{}", p.l); } else { - if (Inline(p.r) && ast::Tok::prec(p.l) > ast::Tok::prec(ast::Tok::prec(p.l))[1]) - return print(os, "({})", p.r); + if (Inline(p.r) && my_prec(p.l) > my_prec(my_prec(p.l))[1]) return print(os, "({})", p.r); return print(os, "{}", p.r); } } From 6cde3d7ff15f5674acdd88a1fe3d4e1b362d2faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 23 Apr 2024 02:36:02 +0200 Subject: [PATCH 70/95] bug fix --- lit/regex/match_manual.thorin | 3 +-- src/thorin/ast/parser.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lit/regex/match_manual.thorin b/lit/regex/match_manual.thorin index 59962ea879..5716b989be 100644 --- a/lit/regex/match_manual.thorin +++ b/lit/regex/match_manual.thorin @@ -20,8 +20,7 @@ .con error(mem: %mem.M, i : .I32) = reject (mem, 0I32) .where - .con reject[mem: %mem.M, .Idx Top] = - exit (mem, 0I32); + .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); diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 4106571d3f..50e9975346 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -228,7 +228,7 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre auto decls = parse_decls(); lhs = ptr(track, std::move(decls), std::move(lhs), true); expect(Tag::K_end, "end of a .where declaration block"); - continue; + return lhs; } case Tag::T_at: { if (curr_prec >= Prec::App) return lhs; From 4cefe87eacdc8d18f6aff0eda4017fb029e95114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 23 Apr 2024 14:46:49 +0200 Subject: [PATCH 71/95] moving stuff around --- src/thorin/ast/parser.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 50e9975346..2e15ffdc57 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -222,14 +222,6 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre lhs = ptr(track.loc(), std::move(lhs), std::move(rhs)); continue; } - case Tag::K_where: { - if (curr_prec >= Prec::Where) return lhs; - lex(); - auto decls = parse_decls(); - lhs = ptr(track, std::move(decls), std::move(lhs), true); - expect(Tag::K_end, "end of a .where declaration block"); - return lhs; - } case Tag::T_at: { if (curr_prec >= Prec::App) return lhs; lex(); @@ -243,6 +235,14 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre lhs = ptr(track.loc(), false, std::move(lhs), std::move(rhs)); continue; } + case Tag::K_where: { + if (curr_prec >= Prec::Where) return lhs; + lex(); + auto decls = parse_decls(); + lhs = ptr(track, std::move(decls), std::move(lhs), true); + expect(Tag::K_end, "end of a .where declaration block"); + return lhs; + } default: return lhs; } } From 5f33ecea952a14accaa7ef82393e68d6bdb9e3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 23 Apr 2024 16:41:58 +0200 Subject: [PATCH 72/95] all tests working again --- gtest/automaton.cpp | 33 ++++++++++++--------------------- include/thorin/ast/parser.h | 12 ++++++------ src/thorin/ast/emit.cpp | 1 + src/thorin/ast/parser.cpp | 24 ++++++++++++++---------- src/thorin/pass/optimize.cpp | 10 +--------- 5 files changed, 34 insertions(+), 46 deletions(-) diff --git a/gtest/automaton.cpp b/gtest/automaton.cpp index 2aeb04eaf8..4043bb3ceb 100644 --- a/gtest/automaton.cpp +++ b/gtest/automaton.cpp @@ -8,7 +8,7 @@ #include -#include +#include #include #include @@ -155,10 +155,8 @@ TEST(Automaton, NFAAorBplusA) { TEST(Automaton, Regex2NFA) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); + World& w = driver.world(); + ast::load_plugins(w, {"compile", "mem", "core", "math", "regex"}); auto pattern = w.call( 2, w.tuple({w.call(w.lit_i8('a')), w.call(w.lit_i8('b'))})); // (a & b) @@ -169,10 +167,8 @@ TEST(Automaton, Regex2NFA) { TEST(Automaton, Regex2NFAAorBplusA) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); + World& w = driver.world(); + ast::load_plugins(w, {"compile", "mem", "core", "math", "regex"}); auto pattern = w.call( 2, w.tuple({w.call(regex::quant::plus, w.call(2, w.tuple({w.call(w.lit_i8('a')), @@ -189,10 +185,9 @@ TEST(Automaton, Regex2NFAAorBplusA) { TEST(Automaton, Regex2NFA1or5or9) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); + World& w = driver.world(); + auto ast = ast::AST(w); + ast::load_plugins(w, {"compile", "mem", "core", "math", "regex"}); // %regex.disj 2 (%regex.disj 2 (%regex.range ‹2; 49I8›, %regex.range ‹2; 53I8›), %regex.range ‹2; // 57I8›) @@ -210,10 +205,8 @@ TEST(Automaton, Regex2NFA1or5or9) { TEST(Automaton, Regex2NFANot1or5or9) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); + World& w = driver.world(); + ast::load_plugins(w, {"compile", "mem", "core", "math", "regex"}); // %regex.not_ (%regex.disj 2 (%regex.disj 2 (%regex.range ‹2; 49I8›, %regex.range ‹2; 53I8›), // %regex.range ‹2; 57I8›)) @@ -232,10 +225,8 @@ TEST(Automaton, Regex2NFANot1or5or9) { TEST(Automaton, Regex2NFANotwds) { Driver driver; - World& w = driver.world(); - auto ast = ast::AST(w); - auto parser = ast::Parser(ast); - for (auto plugin : {"compile", "mem", "core", "math", "regex"}) parser.plugin(plugin); + World& w = driver.world(); + ast::load_plugins(w, {"compile", "mem", "core", "math", "regex"}); // %regex.not_ (%regex.conj 3 (%regex.cls.w, %regex.cls.d, %regex.cls.s)) auto pattern = w.call( diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index 9ca6456478..c590416393 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -36,12 +36,12 @@ class Parser : public fe::Parser { AST& ast() { return ast_; } Driver& driver() { return ast().driver(); } - Ptr import(std::string_view sv) { return import(driver().sym(sv)); } - Ptr import(Sym, std::ostream* md = nullptr); - Ptr import(std::istream&, const fs::path* = nullptr, std::ostream* md = nullptr); - Ptr plugin(Sym); - Ptr plugin(const std::string& s) { return plugin(driver().sym(s)); } - Ptr plugin(const char* name) { return plugin(driver().sym(name)); } + Ptr import(std::string_view sv) { return import({Loc(), driver().sym(sv)}); } + Ptr import(Dbg, std::ostream* md = nullptr); + Ptr import(std::istream&, Loc = {}, const fs::path* = nullptr, std::ostream* md = nullptr); + Ptr plugin(Dbg); + Ptr plugin(const std::string& s) { return plugin({Loc(), driver().sym(s)}); } + Ptr plugin(const char* name) { return plugin({Loc(), driver().sym(name)}); } private: template auto ptr(Args&&... args) { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 5e36052750..b57b20065f 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -424,6 +424,7 @@ void LetDecl::emit_decl(Emitter& e) const { void RecDecl::emit_decl(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); def_ = body()->emit_decl(e, t); + def_->set(dbg()); } void RecDecl::emit_body(Emitter& e) const { diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 2e15ffdc57..0a916e4b50 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -115,9 +115,10 @@ Ptr Parser::parse_module() { return ptr(track, std::move(imports), std::move(decls)); } -Ptr Parser::import(Sym name, std::ostream* md) { - driver().VLOG("import: {}", name); +Ptr Parser::import(Dbg dbg, std::ostream* md) { + auto name = dbg.sym; auto filename = fs::path(name.view()); + driver().VLOG("import: {}", name); if (!filename.has_extension()) filename.replace_extension("thorin"); // TODO error cases @@ -132,14 +133,17 @@ Ptr Parser::import(Sym name, std::ostream* md) { if (auto path = driver().add_import(std::move(rel_path), name)) { auto ifs = std::ifstream(*path); - return import(ifs, path, md); + return import(ifs, dbg.loc, path, md); } return {}; } -Ptr Parser::import(std::istream& is, const fs::path* path, std::ostream* md) { +Ptr Parser::import(std::istream& is, Loc loc, const fs::path* path, std::ostream* md) { driver().VLOG("reading: {}", path ? path->string() : ""s); - if (!is) return {}; + if (!is) { + ast().error(loc, "cannot read file {}", *path); + return {}; + } auto state = std::tuple(prev_, ahead_, lexer_); auto lexer = Lexer(ast(), is, path, md); @@ -150,9 +154,9 @@ Ptr Parser::import(std::istream& is, const fs::path* path, std::ostream* return mod; } -Ptr Parser::plugin(Sym name) { - if (!driver().flags().bootstrap && !driver().is_loaded(name)) driver().load(name); - return import(name); +Ptr Parser::plugin(Dbg dbg) { + if (!driver().flags().bootstrap && !driver().is_loaded(dbg.sym)) driver().load(dbg.sym); + return import(dbg); } /* @@ -163,9 +167,9 @@ Ptr Parser::parse_import_or_plugin() { auto track = tracker(); auto tag = lex().tag(); auto name = expect(Tag::M_id, "{} name", tag == Tag::K_import ? "import" : "plugin"); - auto sym = name.sym(); + auto dbg = name.dbg(); expect(Tag::T_semicolon, "end of {}", tag == Tag::K_import ? "import" : "plugin"); - if (auto module = tag == Tag::K_import ? import(sym) : plugin(sym)) + if (auto module = tag == Tag::K_import ? import(dbg) : plugin(dbg)) return ptr(track, tag, name.dbg(), std::move(module)); return {}; } diff --git a/src/thorin/pass/optimize.cpp b/src/thorin/pass/optimize.cpp index f239088080..43318a46a5 100644 --- a/src/thorin/pass/optimize.cpp +++ b/src/thorin/pass/optimize.cpp @@ -1,17 +1,8 @@ #include "thorin/pass/optimize.h" -#include - #include "thorin/driver.h" -#include "thorin/pass/beta_red.h" -#include "thorin/pass/eta_exp.h" -#include "thorin/pass/eta_red.h" -#include "thorin/pass/lam_spec.h" #include "thorin/pass/pipelinebuilder.h" -#include "thorin/pass/ret_wrap.h" -#include "thorin/pass/scalarize.h" -#include "thorin/pass/tail_rec_elim.h" #include "thorin/phase/phase.h" namespace thorin { @@ -26,6 +17,7 @@ void optimize(World& world) { compilation_->make_internal(); } } + // make all functions `[] -> Pipeline` internal auto externals = world.externals(); // copy for (auto [_, def] : externals) { From 866ba3a2937b0923fe585b6ff5733094f54eaad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 23 Apr 2024 17:55:35 +0200 Subject: [PATCH 73/95] fix md output + refactoring * proper getters/setters for Dbg --- include/thorin/ast/ast.h | 9 ++++----- include/thorin/def.h | 33 ++++++++++++++++----------------- include/thorin/util/dbg.h | 31 +++++++++++++++++++++++++------ src/thorin/ast/ast.cpp | 4 ++-- src/thorin/ast/bind.cpp | 29 ++++++++++++++--------------- src/thorin/ast/emit.cpp | 32 ++++++++++++++++---------------- src/thorin/ast/parser.cpp | 10 +++++----- src/thorin/cli/main.cpp | 4 ++-- src/thorin/def.cpp | 11 ++--------- 9 files changed, 86 insertions(+), 77 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index bd3c9716c2..686ffdf792 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -160,7 +160,6 @@ class Ptrn : public Decl { bool rebind() const { return rebind_; } Dbg dbg() const { return dbg_; } - bool is_anon() const { return !dbg().sym || dbg().sym == '_'; } virtual void bind(Scopes&, bool quiet = false) const = 0; virtual Ref emit_value(Emitter&, Ref) const = 0; @@ -188,7 +187,7 @@ class IdPtrn : public Ptrn { return ast.ptr(loc, false, Dbg(loc, ast.sym_anon()), std::move(type)); } static Ptr mk_id(AST& ast, Dbg dbg, Ptr&& type) { - auto loc = (type && dbg) ? dbg.loc + type->loc() : type ? type->loc() : dbg.loc; + auto loc = (type && dbg) ? dbg.loc() + type->loc() : type ? type->loc() : dbg.loc(); return ast.ptr(loc, false, dbg, std::move(type)); } @@ -206,7 +205,7 @@ class IdPtrn : public Ptrn { class GrpPtrn : public Ptrn { public: GrpPtrn(Dbg dbg, const IdPtrn* id) - : Ptrn(dbg.loc, false, dbg) + : Ptrn(dbg.loc(), false, dbg) , id_(id) {} const IdPtrn* id() const { return id_; } @@ -259,7 +258,7 @@ class TuplePtrn : public Ptrn { class IdExpr : public Expr { public: IdExpr(Dbg dbg) - : Expr(dbg.loc) + : Expr(dbg.loc()) , dbg_(dbg) {} Dbg dbg() const { return dbg_; } @@ -705,7 +704,7 @@ class AxiomDecl : public ValDecl { class Alias : public Decl { public: Alias(Dbg dbg) - : Decl(dbg.loc) + : Decl(dbg.loc()) , dbg_(dbg) {} Dbg dbg() const { return dbg_; } diff --git a/include/thorin/def.h b/include/thorin/def.h index befaf615e6..bc2916d678 100644 --- a/include/thorin/def.h +++ b/include/thorin/def.h @@ -10,7 +10,6 @@ #include "thorin/util/dbg.h" #include "thorin/util/hash.h" #include "thorin/util/pool.h" -#include "thorin/util/print.h" #include "thorin/util/util.h" #include "thorin/util/vector.h" @@ -172,20 +171,20 @@ THORIN_ENUM_OPERATORS(Dep) // clang-format off /// Use as mixin to declare setters for Def::loc \& Def::name using a *covariant* return type. -#define THORIN_SETTERS_(T) \ -public: \ - template const T* set(Loc l ) const { if (Ow || !dbg_.loc) dbg_.loc = l; return this; } \ - template T* set(Loc l ) { if (Ow || !dbg_.loc) dbg_.loc = l; return this; } \ - template const T* set( Sym s ) const { if (Ow || !dbg_.sym) dbg_.sym = s; return this; } \ - template T* set( Sym s ) { if (Ow || !dbg_.sym) dbg_.sym = s; return this; } \ - template const T* set( std::string s) const { set(sym(std::move(s))); return this; } \ - template T* set( std::string s) { set(sym(std::move(s))); return this; } \ - template const T* set(Loc l, Sym s ) const { set(l); set(s); return this; } \ - template T* set(Loc l, Sym s ) { set(l); set(s); return this; } \ - template const T* set(Loc l, std::string s) const { set(l); set(sym(std::move(s))); return this; } \ - template T* set(Loc l, std::string s) { set(l); set(sym(std::move(s))); return this; } \ - template const T* set(Dbg d) const { set(d.loc, d.sym); return this; } \ - template T* set(Dbg d) { set(d.loc, d.sym); return this; } +#define THORIN_SETTERS_(T) \ +public: \ + template const T* set(Loc l ) const { if (Ow || !dbg_.loc()) dbg_.set(l); return this; } \ + template T* set(Loc l ) { if (Ow || !dbg_.loc()) dbg_.set(l); return this; } \ + template const T* set( Sym s ) const { if (Ow || !dbg_.sym()) dbg_.set(s); return this; } \ + template T* set( Sym s ) { if (Ow || !dbg_.sym()) dbg_.set(s); return this; } \ + template const T* set( std::string s) const { set(sym(std::move(s))); return this; } \ + template T* set( std::string s) { set(sym(std::move(s))); return this; } \ + template const T* set(Loc l, Sym s ) const { set(l); set(s); return this; } \ + template T* set(Loc l, Sym s ) { set(l); set(s); return this; } \ + template const T* set(Loc l, std::string s) const { set(l); set(sym(std::move(s))); return this; } \ + template T* set(Loc l, std::string s) { set(l); set(sym(std::move(s))); return this; } \ + template const T* set(Dbg d) const { set(d.loc(), d.sym()); return this; } \ + template T* set(Dbg d) { set(d.loc(), d.sym()); return this; } // clang-format on #ifdef DOXYGEN @@ -465,8 +464,8 @@ class Def : public fe::RuntimeCast { /// @name Dbg Getters ///@{ Dbg dbg() const { return dbg_; } - Loc loc() const { return dbg_.loc; } - Sym sym() const { return dbg_.sym; } + Loc loc() const { return dbg_.loc(); } + Sym sym() const { return dbg_.sym(); } std::string unique_name() const; ///< name + "_" + Def::gid ///@} diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index 464322bde7..caf5b0ba89 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -134,21 +134,40 @@ template [[noreturn]] void error(Loc loc, const char* f, Args&&.. ///@} struct Dbg { +public: + /// @name Constructors + ///@{ constexpr Dbg() noexcept = default; constexpr Dbg(const Dbg&) noexcept = default; constexpr Dbg(Loc loc, Sym sym) noexcept - : loc(loc) - , sym(sym) {} + : loc_(loc) + , sym_(sym) {} constexpr Dbg(Loc loc) noexcept : Dbg(loc, {}) {} + constexpr Dbg(Sym sym) noexcept + : Dbg({}, sym) {} Dbg& operator=(const Dbg&) noexcept = default; + ///@} - Loc loc; - Sym sym; + /// @name Getters + ///@{ + Sym sym() const { return sym_; } + Loc loc() const { return loc_; } + bool is_anon() const { return !sym() || sym() == '_'; } + explicit operator bool() const { return sym().operator bool(); } + ///@} - explicit operator bool() const { return sym.operator bool(); } + /// @name Setters + ///@{ + Dbg& set(Sym sym) { return sym_ = sym, *this; } + Dbg& set(Loc loc) { return loc_ = loc, *this; } + ///@} + +private: + Loc loc_; + Sym sym_; - friend std::ostream& operator<<(std::ostream& os, const Dbg& dbg) { return os << dbg.sym; } + friend std::ostream& operator<<(std::ostream& os, const Dbg& dbg) { return os << dbg.sym(); } }; } // namespace thorin diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 5a22da3b12..60a882e858 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -52,8 +52,8 @@ AST load_plugins(World& world, View plugins) { auto imports = Ptrs(); for (auto plugin : plugins) - if (auto mod = parser.import(plugin)) - imports.emplace_back(ast.ptr(mod->loc(), tag, Dbg(Loc(), plugin), std::move(mod))); + if (auto mod = parser.import(plugin, nullptr)) + imports.emplace_back(ast.ptr(mod->loc(), tag, Dbg(plugin), std::move(mod))); if (!plugins.empty()) { auto mod = ast.ptr(imports.front()->loc() + imports.back()->loc(), std::move(imports), Ptrs()); diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index d2010cd789..11f4c47a37 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -37,28 +37,27 @@ class Scopes { } const Decl* find(Dbg dbg, bool quiet = false) { - if (!dbg || dbg.sym == '_') return nullptr; + if (dbg.is_anon()) return nullptr; for (auto& scope : scopes_ | std::ranges::views::reverse) - if (auto i = scope.find(dbg.sym); i != scope.end()) return i->second.second; + if (auto i = scope.find(dbg.sym()); i != scope.end()) return i->second.second; if (!quiet) { - ast().error(dbg.loc, "'{}' not found", dbg.sym); + ast().error(dbg.loc(), "'{}' not found", dbg.sym()); bind(dbg, dummy()); // put into scope to prevent further errors } return nullptr; } void bind(Dbg dbg, const Decl* decl, bool rebind = false, bool quiet = false) { - auto [loc, sym] = dbg; - if (!sym || sym == '_') return; // don't do anything with '_' + if (dbg.is_anon()) return; if (rebind) { - top()[sym] = std::pair(loc, decl); - } else if (auto [i, ins] = top().emplace(sym, std::pair(loc, decl)); !ins) { + top()[dbg.sym()] = std::pair(dbg.loc(), decl); + } else if (auto [i, ins] = top().emplace(dbg.sym(), std::pair(dbg.loc(), decl)); !ins) { auto [prev_loc, prev_decl] = i->second; if (!quiet && !prev_decl->isa()) { // if prev_decl stems from an error - don't complain - ast().error(loc, "redeclaration of '{}'", sym); + ast().error(dbg.loc(), "redeclaration of '{}'", dbg); ast().note(prev_loc, "previous declaration here"); } } @@ -241,22 +240,22 @@ void DeclsBlock::bind(Scopes& s) const { void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { axiom_ = axiom; - auto sym = s.ast().sym(axiom->dbg().sym.str() + "."s + dbg().sym.str()); - full_ = Dbg(dbg().loc, sym); + auto sym = s.ast().sym(axiom->dbg().sym().str() + "."s + dbg().sym().str()); + full_ = Dbg(dbg().loc(), sym); s.bind(full_, this); } void AxiomDecl::bind_decl(Scopes& s) const { type()->bind(s); - std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym); + std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym()); if (auto p = Annex::mangle(sym_.plugin)) id_.plugin = *p; else - s.ast().error(dbg().loc, "invalid axiom name '{}'", dbg()); + s.ast().error(dbg().loc(), "invalid axiom name '{}'", dbg()); - if (sym_.sub) error(dbg().loc, "axiom '{}' must not have a subtag", dbg().sym); + if (sym_.sub) error(dbg().loc(), "axiom '{}' must not have a subtag", dbg().sym()); if (num_subs() == 0) { s.bind(dbg(), this); @@ -264,8 +263,8 @@ void AxiomDecl::bind_decl(Scopes& s) const { if (auto old = s.find(dbg(), true)) { if (auto old_ax = old->isa()) { if (old_ax->num_subs() == 0) { - s.ast().error(dbg().loc, "redeclared sub-less axiom '{}' with subs", dbg()); - s.ast().note(old_ax->dbg().loc, "previous location here"); + s.ast().error(dbg().loc(), "redeclared sub-less axiom '{}' with subs", dbg()); + s.ast().note(old_ax->dbg().loc(), "previous location here"); } } } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index b57b20065f..8413dcdb10 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -18,10 +18,10 @@ class Emitter { absl::node_hash_map, GIDHash, GIDEq> sigma2sym2idx; void register_if_annex(Dbg dbg, Ref def) { - if (dbg && dbg.sym.front() == '%') { - auto [plugin, tag, sub] = Annex::split(driver(), dbg.sym); + if (dbg && dbg.sym().front() == '%') { + auto [plugin, tag, sub] = Annex::split(driver(), dbg.sym()); auto name = world().sym("%"s + plugin.str() + "."s + tag.str()); - auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc); + auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc()); plugin_t p = *Annex::mangle(plugin); tag_t t = annex.tag_id; sub_t s = annex.subs.size(); @@ -149,7 +149,7 @@ Ref TuplePtrn::emit_body(Emitter& e, Ref decl) const { sigma = decl->as_mut(); } else { auto type = e.world().type_infer_univ(); - sigma = e.world().mut_sigma(type, n)->set(dbg().sym); + sigma = e.world().mut_sigma(type, n)->set(dbg().sym()); } auto var = sigma->var()->set(dbg()); auto& sym2idx = e.sigma2sym2idx[sigma]; @@ -157,7 +157,7 @@ Ref TuplePtrn::emit_body(Emitter& e, Ref decl) const { for (size_t i = 0; i != n; ++i) { sigma->set(i, ptrn(i)->emit_type(e)); ptrn(i)->emit_value(e, var->proj(n, i)); - sym2idx[ptrn(i)->dbg().sym] = i; + sym2idx[ptrn(i)->dbg().sym()] = i; } if (auto imm = sigma->immutabilize()) return imm; @@ -167,7 +167,7 @@ Ref TuplePtrn::emit_body(Emitter& e, Ref decl) const { Ref TuplePtrn::emit_decl(Emitter& e, Ref type) const { auto _ = e.world().push(loc()); type = type ? type : e.world().type_infer_univ(); - return e.world().mut_sigma(type, num_ptrns())->set(dbg().sym); + return e.world().mut_sigma(type, num_ptrns())->set(dbg().sym()); } /* @@ -277,7 +277,7 @@ Ref TupleExpr::emit(Emitter& e) const { template Ref ArrOrPackExpr::emit(Emitter& e) const { auto _ = e.world().push(loc()); auto s = shape()->emit_type(e); - if (shape()->is_anon()) { // immutable + if (shape()->dbg().is_anon()) { // immutable auto b = body()->emit(e); return arr ? e.world().arr(s, b) : e.world().pack(s, b); } @@ -315,13 +315,13 @@ Ref ExtractExpr::emit(Emitter& e) const { if (auto i = e.sigma2sym2idx.find(sigma); i != e.sigma2sym2idx.end()) { auto sigma = i->first->as_mut(); const auto& sym2idx = i->second; - if (auto i = sym2idx.find(dbg->sym); i != sym2idx.end()) + if (auto i = sym2idx.find(dbg->sym()); i != sym2idx.end()) return e.world().extract(tup, sigma->num_ops(), i->second); } } if (decl()) return e.world().extract(tup, decl()->def()); - error(dbg->loc, "cannot resolve index '{}' for extraction", dbg); + error(dbg->loc(), "cannot resolve index '{}' for extraction", dbg); } auto expr = std::get>(index()).get(); @@ -361,8 +361,8 @@ void AxiomDecl::Alias::emit(Emitter& e, const Axiom* axiom) const { } void AxiomDecl::emit_decl(Emitter& e) const { - auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym); - auto&& [annex, is_new] = e.driver().name2annex(dbg().sym, plugin_s, tag_s, dbg().loc); + auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym()); + auto&& [annex, is_new] = e.driver().name2annex(dbg().sym(), plugin_s, tag_s, dbg().loc()); thorin_type_ = type()->emit(e); auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); @@ -383,11 +383,11 @@ void AxiomDecl::emit_decl(Emitter& e) const { } if (!is_new && annex.pi != (thorin_type_->isa() != nullptr)) - error(dbg().loc, "all declarations of annex '{}' have to be function types if any is", dbg().sym); + error(dbg().loc(), "all declarations of annex '{}' have to be function types if any is", dbg().sym()); id_.tag = annex.tag_id; annex.pi = thorin_type_->isa() != nullptr; - annex.normalizer = normalizer().sym; + annex.normalizer = normalizer().sym(); if (num_subs() == 0) { auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); @@ -400,13 +400,13 @@ void AxiomDecl::emit_decl(Emitter& e) const { sub_t s = i + offset; auto norm = e.driver().normalizer(id_.plugin, id_.tag, s); auto& aliases = annex.subs.emplace_back(std::deque()); - auto name = e.world().sym(dbg().sym.str() + "."s + sub(i).front()->dbg().sym.str()); + auto name = e.world().sym(dbg().sym().str() + "."s + sub(i).front()->dbg().sym().str()); auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, s)->set(name); e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64) | flags_t(s), axiom); for (const auto& alias : sub(i)) { alias->sub_ = s; alias->emit(e, axiom); - aliases.emplace_back(alias->dbg().sym); + aliases.emplace_back(alias->dbg().sym()); } } } @@ -470,7 +470,7 @@ void LamDecl::emit_decl(Emitter& e) const { lam->set_filter(filter); if (i == 0) - def_ = lam->set(dbg().sym); + def_ = lam->set(dbg().sym()); else dom(i - 1)->lam_->set_body(lam); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 0a916e4b50..a898e9d9f4 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -116,7 +116,7 @@ Ptr Parser::parse_module() { } Ptr Parser::import(Dbg dbg, std::ostream* md) { - auto name = dbg.sym; + auto name = dbg.sym(); auto filename = fs::path(name.view()); driver().VLOG("import: {}", name); @@ -133,7 +133,7 @@ Ptr Parser::import(Dbg dbg, std::ostream* md) { if (auto path = driver().add_import(std::move(rel_path), name)) { auto ifs = std::ifstream(*path); - return import(ifs, dbg.loc, path, md); + return import(ifs, dbg.loc(), path, md); } return {}; } @@ -155,7 +155,7 @@ Ptr Parser::import(std::istream& is, Loc loc, const fs::path* path, std: } Ptr Parser::plugin(Dbg dbg) { - if (!driver().flags().bootstrap && !driver().is_loaded(dbg.sym)) driver().load(dbg.sym); + if (!driver().flags().bootstrap && !driver().is_loaded(dbg.sym())) driver().load(dbg.sym()); return import(dbg); } @@ -459,7 +459,7 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool if (ahead().isa(Tag::D_paren_l) || ahead().isa(Tag::D_brckt_l)) return parse_tuple_ptrn(rebind, dbg); else - syntax_err("tuple pattern after '" + dbg.sym.str() + "::'", ctxt); + syntax_err("tuple pattern after '" + dbg.sym().str() + "::'", ctxt); } else if (ahead(1).isa(Tag::T_colon)) { // p -> s: e b -> s: e // p -> 's: e b -> 's: e @@ -513,7 +513,7 @@ Ptr Parser::parse_tuple_ptrn(bool rebind, Dbg dbg) { if (accept(Tag::T_colon)) { // identifier group: x y x: T auto dbg = dbgs.back(); auto type = parse_expr("type of an identifier group within a tuple pattern"); - auto id = ptr(dbg.loc + type->loc().finis, false, dbg, std::move(type)); + auto id = ptr(dbg.loc() + type->loc().finis, false, dbg, std::move(type)); for (auto dbg : dbgs | std::views::take(dbgs.size() - 1)) ptrns.emplace_back(ptr(dbg, id.get())); diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 8de3ad9ece..0c8098b9f7 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -145,8 +145,8 @@ int main(int argc, char** argv) { for (size_t i = 0, e = inputs.size(); i != e; ++i) { auto input = inputs[i]; auto tag = i + 1 == e ? ast::Tok::Tag::K_import : ast::Tok::Tag::K_plugin; - auto mod = i + 1 == e ? parser.import(input) : parser.plugin(input); - imports.emplace_back(ast.ptr(Loc(), tag, Dbg(Loc(), driver.sym(input)), std::move(mod))); + auto mod = i + 1 == e ? parser.import(driver.sym(input), os[Md]) : parser.plugin(input); + imports.emplace_back(ast.ptr(Loc(), tag, Dbg(driver.sym(input)), std::move(mod))); } auto mod = ast.ptr(imports.back()->loc(), std::move(imports), ast::Ptrs()); diff --git a/src/thorin/def.cpp b/src/thorin/def.cpp index 480e65f4cd..bf493f27fc 100644 --- a/src/thorin/def.cpp +++ b/src/thorin/def.cpp @@ -447,15 +447,8 @@ Defs Def::extended_ops() const { } #ifndef NDEBUG -const Def* Def::debug_prefix(std::string prefix) const { - dbg_.sym = world().sym(prefix + sym().str()); - return this; -} - -const Def* Def::debug_suffix(std::string suffix) const { - dbg_.sym = world().sym(sym().str() + suffix); - return this; -} +const Def* Def::debug_prefix(std::string prefix) const { return dbg_.set(world().sym(prefix + sym().str())), this; } +const Def* Def::debug_suffix(std::string suffix) const { return dbg_.set(world().sym(sym().str() + suffix)), this; } #endif // clang-format off From f06aed4836c8172a27f7c2a477a65da0c51c36f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Tue, 23 Apr 2024 23:34:35 +0200 Subject: [PATCH 74/95] removed !-filter * Filter: @(expr) -> @expr * old: .fun f!(A): B * new: .fun f(A)@.tt: B * Fix some bugs regarding utf8 output in lexer --- include/thorin/ast/ast.h | 6 +----- include/thorin/ast/tok.h | 1 - lit/core/unary_tuple.thorin | 22 ++------------------- lit/direct/ds2cps_ax_cps2ds_twice.thorin | 11 +++-------- lit/error/filter1.thorin | 4 ---- lit/matrix/transpose_init.thorin | 4 ++-- lit/mem/no_mem.thorin | 3 +-- src/thorin/ast/bind.cpp | 25 ++---------------------- src/thorin/ast/emit.cpp | 3 +-- src/thorin/ast/lexer.cpp | 8 +++++--- src/thorin/ast/parser.cpp | 11 ++--------- src/thorin/ast/stream.cpp | 1 - src/thorin/plug/autodiff/autodiff.thorin | 12 ++++++------ src/thorin/plug/matrix/matrix.thorin | 20 +++++++++---------- 14 files changed, 35 insertions(+), 96 deletions(-) delete mode 100644 lit/error/filter1.thorin diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 686ffdf792..ea44c9c879 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -797,13 +797,10 @@ class LamDecl : public RecDecl { public: class Dom : public PiExpr::Dom { public: - Dom(Loc loc, Tok bang, bool is_implicit, Ptr&& ptrn, Ptr&& filter) + Dom(Loc loc, bool is_implicit, Ptr&& ptrn, Ptr&& filter) : PiExpr::Dom(loc, is_implicit, std::move(ptrn)) - , bang_(bang) , filter_(std::move(filter)) {} - Tok bang() const { return bang_; } - bool has_bang() const { return (bool)bang(); } const Expr* filter() const { return filter_.get(); } void bind(Scopes& scopes, bool quiet = false) const override; @@ -811,7 +808,6 @@ class LamDecl : public RecDecl { std::ostream& stream(Tab&, std::ostream&) const override; private: - Tok bang_; Ptr filter_; mutable Lam* lam_; diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 609f0fc364..139fc02b03 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -83,7 +83,6 @@ constexpr auto Num_Keys = size_t(0) THORIN_KEY(CODE); m(T_assign, "=") \ m(T_at, "@") \ m(T_backtick, "`") \ - m(T_bang, "!") \ m(T_bot, "⊥") \ m(T_top, "⊤") \ m(T_box, "□") \ diff --git a/lit/core/unary_tuple.thorin b/lit/core/unary_tuple.thorin index 43d1acce75..3051694092 100644 --- a/lit/core/unary_tuple.thorin +++ b/lit/core/unary_tuple.thorin @@ -3,25 +3,7 @@ .plugin core; -.con g ![ - n:.Nat, - i:.Idx n, - t:<< n; [.I32,.I32]>>, - return:.Cn[.I32]] = { - - return (t#i#(.tt)) -}; - - -.con .extern f [return:.Cn[.I32]] = { - g ( - 1, - (0:(.Idx 1)), - ( - (42I32, 43I32) - ), - return - ) -}; +.con g(n: .Nat, i: .Idx n, t: << n; [.I32,.I32]>>, return: .Cn .I32)@.tt = return (t#i#(.tt)); +.con .extern f(return: .Cn .I32) = g (1, 0_1, ((42I32, 43I32)), return); // CHECK-DAG: {{[0-9_]+}} 43I32 diff --git a/lit/direct/ds2cps_ax_cps2ds_twice.thorin b/lit/direct/ds2cps_ax_cps2ds_twice.thorin index 937ff1e128..91397690e1 100644 --- a/lit/direct/ds2cps_ax_cps2ds_twice.thorin +++ b/lit/direct/ds2cps_ax_cps2ds_twice.thorin @@ -4,18 +4,13 @@ .plugin core; .plugin direct; -.con f ![a:.I32, return: .Cn .I32] = { - .let b = %core.wrap.add 0 (2I32, a); - return b -}; +.con f(a: .I32, return: .Cn .I32)@.tt = return (%core.wrap.add 0 (2I32, a)); - -.con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr (%mem.Ptr (.I8, 0), 0), return : .Cn [%mem.M, .I32]] = { +.con .extern main(mem: %mem.M, argc: .I32, argv: %mem.Ptr (%mem.Ptr (.I8, 0), 0), return: .Cn [%mem.M, .I32]) = .let g = %direct.cps2ds (.I32,.I32) f; .let c1 = g 38I32; .let h = %direct.cps2ds (.I32,.I32) f; .let c2 = h (c1); - return (mem, c2) -}; + return (mem, c2); // CHECK-DAG: return{{.*}}42 diff --git a/lit/error/filter1.thorin b/lit/error/filter1.thorin deleted file mode 100644 index 295a0454b0..0000000000 --- a/lit/error/filter1.thorin +++ /dev/null @@ -1,4 +0,0 @@ -// RUN: (! %thorin %s 2>&1) | FileCheck %s -.lam f!()@(.tt) = .tt; -// CHECK: error: explicit filter specified on top of -// CHECK: warning: '!' superfluous diff --git a/lit/matrix/transpose_init.thorin b/lit/matrix/transpose_init.thorin index 9acaeca24c..b7840d69b7 100644 --- a/lit/matrix/transpose_init.thorin +++ b/lit/matrix/transpose_init.thorin @@ -4,11 +4,11 @@ .plugin core; .plugin matrix; -.lam ex_internal_mapRed_matrix_transpose![[k l: .Nat], T:*]: .Cn[[%mem.M, %matrix.Mat (2,(k, l),T)], .Cn [%mem.M, %matrix.Mat (2,(l, k),T)] ] = +.lam ex_internal_mapRed_matrix_transpose[[k l: .Nat], T:*]@.tt: .Cn[[%mem.M, %matrix.Mat (2,(k, l),T)], .Cn [%mem.M, %matrix.Mat (2,(l, k),T)] ] = // TODO: or use generalized addition function // ignore acc .con transpose_comb [[mem:%mem.M, acc:T, [a:T]], ret:.Cn[%mem.M,T]] = ret (mem, a); - .con inner_matrix_transpose![[mem: %mem.M, M: %matrix.Mat (2,(k, l),T)], ret: .Cn[%mem.M, %matrix.Mat (2,(l, k),T)]] = + .con inner_matrix_transpose[[mem: %mem.M, M: %matrix.Mat (2,(k, l),T)], ret: .Cn[%mem.M, %matrix.Mat (2,(l, k),T)]]@.tt = // TODO: use generalized zero .let zero = (⊥:T); ret ( diff --git a/lit/mem/no_mem.thorin b/lit/mem/no_mem.thorin index 404ed208bc..76b7c02a10 100644 --- a/lit/mem/no_mem.thorin +++ b/lit/mem/no_mem.thorin @@ -3,8 +3,7 @@ .plugin core; -.fun f!(a: .I32): .I32 = - return (%core.wrap.mul 0 (a, a)); +.fun f(a: .I32)@.tt: .I32 = return (%core.wrap.mul 0 (a, a)); .con .extern main [mem : %mem.M, argc : .I32, argv : %mem.Ptr (%mem.Ptr (.I8, 0), 0), return : .Cn [%mem.M, .I32]] = .con ret_cont(r: .I32) = diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 11f4c47a37..0dbcd9797f 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -296,34 +296,13 @@ void RecDecl::bind_body(Scopes& s) const { body()->bind(s); } void LamDecl::Dom::bind(Scopes& s, bool quiet) const { PiExpr::Dom::bind(s, quiet); - if (filter() && !quiet) { - if (has_bang()) { - s.ast().error(filter()->loc(), "explicit filter specified on top of '!' annotation"); - s.ast().note(bang().loc(), "'!' here"); - } - - filter()->bind(s); - } + if (filter() && !quiet) filter()->bind(s); } void LamDecl::bind_decl(Scopes& s) const { s.push(); - for (size_t i = 0, e = num_doms(); i != e; ++i) { - if (auto bang = dom(i)->bang(); bang && i + 1 != e) { - s.ast().warn( - bang.loc(), - "'!' superfluous as the last curried function group of a '{}' receives a '.tt'-filter by default", - tag()); - } - dom(i)->bind(s); - } + for (size_t i = 0, e = num_doms(); i != e; ++i) dom(i)->bind(s); - if (auto bang = doms().back()->bang()) { - if (tag() == Tag::K_lam || tag() == Tag::T_lm) - s.ast().warn( - bang.loc(), - "'!' superfluous as all but the last curried function groups receive a '.tt'-filter by default"); - } if (auto filter = doms().back()->filter()) { if (auto pe = filter->isa()) { if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm)) diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 8413dcdb10..ea9eec4b29 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -463,8 +463,7 @@ void LamDecl::emit_decl(Emitter& e) const { auto cur = dom(i); auto lam = cur->emit_value(e); - auto filter = cur->has_bang() ? e.world().lit_tt() - : cur->filter() ? cur->filter()->emit(e) + auto filter = cur->filter() ? cur->filter()->emit(e) : i + 1 == n && is_cps ? e.world().lit_ff() : e.world().lit_tt(); lam->set_filter(filter); diff --git a/src/thorin/ast/lexer.cpp b/src/thorin/ast/lexer.cpp index 2d7c59da2b..e088528fd2 100644 --- a/src/thorin/ast/lexer.cpp +++ b/src/thorin/ast/lexer.cpp @@ -39,7 +39,10 @@ Tok Lexer::lex() { if (accept(utf8::EoF)) return tok(Tag::EoF); if (accept(utf8::isspace)) continue; - if (accept(utf8::Null)) ast().error(loc_, "invalid UTF-8 character"); + if (accept(utf8::Null)) { + ast().error(loc_, "invalid UTF-8 character"); + continue; + } // clang-format off // delimiters @@ -70,7 +73,6 @@ Tok Lexer::lex() { if (accept(U'→')) return tok(Tag::T_arrow); if (accept( '@')) return tok(Tag::T_at); if (accept( '=')) return tok(Tag::T_assign); - if (accept( '!')) return tok(Tag::T_bang); if (accept(U'⊥')) return tok(Tag::T_bot); if (accept(U'⊤')) return tok(Tag::T_top); if (accept(U'□')) return tok(Tag::T_box); @@ -166,7 +168,7 @@ Tok Lexer::lex() { continue; } - ast().error({loc_.path, peek_}, "invalid input char '{x}'", (uint32_t)utf8::Char32(ahead()).c); + ast().error({loc_.path, peek_}, "invalid input char '{}'", utf8::Char32(ahead())); next(); } } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index a898e9d9f4..7eaac05da1 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -660,18 +660,11 @@ Ptr Parser::parse_lam_decl() { Ptrs doms; do { auto track = tracker(); - auto bang = accept(Tag::T_bang); bool implicit = (bool)accept(Tag::T_dot); auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); + auto filter = accept(Tag::T_at) ? parse_expr("filter") : nullptr; - Ptr filter; - if (auto tok = accept(Tag::T_at)) { - expect(Tag::D_paren_l, "opening parenthesis of a filter"); - filter = parse_expr("filter"); - expect(Tag::D_paren_r, "closing parenthesis of a filter"); - } - - doms.emplace_back(ptr(track, bang, implicit, std::move(ptrn), std::move(filter))); + doms.emplace_back(ptr(track, implicit, std::move(ptrn), std::move(filter))); } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Prec::Arrow) : nullptr; diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index bc0800c2b6..329bd2209c 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -182,7 +182,6 @@ std::ostream& RecDecl::stream(Tab& tab, std::ostream& os) const { } std::ostream& LamDecl::Dom::stream(Tab& tab, std::ostream& os) const { - if (has_bang()) os << '!'; print(os, "{}{}", is_implicit() ? "." : "", S(tab, ptrn())); if (filter()) print(os, "@({})", S(tab, filter())); if (ret()) print(os, ": {}", S(tab, ret()->type())); diff --git a/src/thorin/plug/autodiff/autodiff.thorin b/src/thorin/plug/autodiff/autodiff.thorin index daee9533aa..6e28f358e0 100644 --- a/src/thorin/plug/autodiff/autodiff.thorin +++ b/src/thorin/plug/autodiff/autodiff.thorin @@ -109,19 +109,19 @@ /// /// The comparison pullback exists formally but is not used. /// -.fun .extern internal_diff_core_icmp_xYgLE.(s: .Nat)!(ab: «2; .Idx s»): [.Bool, .Cn[.Bool, .Cn«2; .Idx s»]] = - return (%core.icmp.sle ab, .fn ![.Bool]: «2; .Idx s» = return ‹2; 0:(.Idx s)›); +.fun .extern internal_diff_core_icmp_xYgLE.(s: .Nat)(ab: «2; .Idx s»)@.tt: [.Bool, .Cn[.Bool, .Cn«2; .Idx s»]] = + return (%core.icmp.sle ab, .fn [.Bool]@.tt: «2; .Idx s» = return ‹2; 0:(.Idx s)›); /// /// ### %core.wrap.add /// /// s ↦ (s, s) /// -.fun .extern internal_diff_core_wrap_add.(s: .Nat)(m: .Nat)!(ab: «2; .Idx s»): [.Idx s, .Cn[.Idx s, .Cn«2; .Idx s»]] = - return (%core.wrap.add m ab, .fn !(i: .Idx s): «2; .Idx s» = return ‹2; i›); +.fun .extern internal_diff_core_wrap_add.(s: .Nat)(m: .Nat)(ab: «2; .Idx s»)@.tt: [.Idx s, .Cn[.Idx s, .Cn«2; .Idx s»]] = + return (%core.wrap.add m ab, .fn (i: .Idx s)@.tt: «2; .Idx s» = return ‹2; i›); /// /// ### %core.wrap.mul /// /// s ↦ (s*b, s*a) /// -.fun .extern internal_diff_core_wrap_mul.(s: .Nat)(m: .Nat)!ab::(a b: .Idx s): [.Idx s, .Cn[.Idx s, .Cn«2; .Idx s»]] = - return (%core.wrap.mul m ab, .fn !(i: .Idx s): «2; .Idx s» = return (%core.wrap.mul m (i, b), %core.wrap.mul m (i, a))); +.fun .extern internal_diff_core_wrap_mul.(s: .Nat)(m: .Nat)ab::(a b: .Idx s)@.tt: [.Idx s, .Cn[.Idx s, .Cn«2; .Idx s»]] = + return (%core.wrap.mul m ab, .fn (i: .Idx s)@.tt: «2; .Idx s» = return (%core.wrap.mul m (i, b), %core.wrap.mul m (i, a))); diff --git a/src/thorin/plug/matrix/matrix.thorin b/src/thorin/plug/matrix/matrix.thorin index 9594390cf8..3c9ac125ba 100644 --- a/src/thorin/plug/matrix/matrix.thorin +++ b/src/thorin/plug/matrix/matrix.thorin @@ -142,10 +142,10 @@ /// ### product /// /// Follow the principle `ij <- ik, kj` (`out[i, j] = sum_k in1[i, k] * in2[k, j]`) by using mulplication as combination function and addition as reduction function. -.fun .extern internal_mapRed_matrix_prod (m k l: .Nat, pe: «2; .Nat») - !(mem: %mem.M, M: %matrix.Mat (2, (m, k), %math.F pe), - N: %matrix.Mat (2, (k, l), %math.F pe)) - :[ %mem.M, %matrix.Mat (2, (m, l), %math.F pe)] = +.fun .extern internal_mapRed_matrix_prod(m k l: .Nat, pe: «2; .Nat») + (mem: %mem.M, M: %matrix.Mat (2, (m, k), %math.F pe), + N: %matrix.Mat (2, (k, l), %math.F pe))@.tt + : [ %mem.M, %matrix.Mat (2, (m, l), %math.F pe)] = .let R = %math.F pe; .let zero_real = %math.conv.f2f pe 0.0:%math.F64; return ( @@ -173,9 +173,9 @@ /// Transpose a matrix by iterating the indices in swapped order. // TODO: check code for 1-matrix edge case // TODO: would this automatically be handled by read(transpose) ? -.fun .extern internal_mapRed_matrix_transpose ((k l: .Nat), T: *) - !(mem: %mem.M, M: %matrix.Mat (2, (k, l), T)) : - [ %mem.M, %matrix.Mat (2, (l, k), T)] = +.fun .extern internal_mapRed_matrix_transpose((k l: .Nat), T: *) + (mem: %mem.M, M: %matrix.Mat (2, (k, l), T))@.tt + : [ %mem.M, %matrix.Mat (2, (l, k), T)] = .let zero = ⊥:T; // TODO: use generalized zero return ( %matrix.map_reduce @@ -198,9 +198,9 @@ /// /// Sums up all elements of a matrix and returns a scalar. // TODO: test 0d matrix (edge cases in code) -.fun .extern internal_mapRed_matrix_sum (n: .Nat, S: «n; .Nat», pe: «2; .Nat») - !(mem: %mem.M, M: %matrix.Mat (n, S, %math.F pe)) - :[%mem.M, %math.F pe] = +.fun .extern internal_mapRed_matrix_sum(n: .Nat, S: «n; .Nat», pe: «2; .Nat») + (mem: %mem.M, M: %matrix.Mat (n, S, %math.F pe))@.tt + : [%mem.M, %math.F pe] = .let R = %math.F pe; // TODO: use generalized zero .let zero_64 = 0.0:(%math.F (52,11)); From 1176a4e8a37f577ad557336530aa2a9f08dccad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 00:41:41 +0200 Subject: [PATCH 75/95] cleanup --- include/thorin/ast/ast.h | 8 -------- src/thorin/ast/bind.cpp | 13 ++----------- src/thorin/plug/matrix/matrix.cpp | 1 - 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index ea44c9c879..482909ca64 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -101,8 +101,6 @@ class Expr : public Node { public: virtual void bind(Scopes&) const = 0; - virtual void bind_decl(Scopes&) const { fe::unreachable(); } - virtual void bind_body(Scopes&) const { fe::unreachable(); } virtual Ref emit(Emitter&) const = 0; virtual Ref emit_decl(Emitter&, Ref /*type*/) const { fe::unreachable(); } virtual void emit_body(Emitter&, Ref /*decl*/) const { fe::unreachable(); } @@ -447,8 +445,6 @@ class PiExpr : public Expr { const Expr* codom() const { return codom_.get(); } void bind(Scopes&) const override; - void bind_decl(Scopes&) const override; - void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const override; void emit_body(Emitter&, Ref decl) const override; @@ -468,8 +464,6 @@ class LamExpr : public Expr { const LamDecl* lam() const { return lam_.get(); } void bind(Scopes&) const override; - void bind_decl(Scopes&) const override; - void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const override; void emit_body(Emitter&, Ref decl) const override; @@ -539,8 +533,6 @@ class SigmaExpr : public Expr { const TuplePtrn* ptrn() const { return ptrn_.get(); } void bind(Scopes&) const override; - void bind_decl(Scopes&) const override; - void bind_body(Scopes&) const override; Ref emit(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const override; void emit_body(Emitter&, Ref decl) const override; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 0dbcd9797f..d8386e5cf5 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -148,9 +148,6 @@ void PiExpr::Dom::bind(Scopes& s, bool quiet) const { if (ret()) ret()->bind(s, quiet); } -void PiExpr::bind_decl(Scopes&) const {} -void PiExpr::bind_body(Scopes&) const {} - void PiExpr::bind(Scopes& s) const { s.push(); for (const auto& dom : doms()) dom->bind(s); @@ -161,12 +158,9 @@ void PiExpr::bind(Scopes& s) const { s.pop(); } -void LamExpr::bind_decl(Scopes& s) const { lam()->bind_decl(s); } -void LamExpr::bind_body(Scopes& s) const { lam()->bind_body(s); } - void LamExpr::bind(Scopes& s) const { - bind_decl(s); - bind_body(s); + lam()->bind_decl(s); + lam()->bind_body(s); } void AppExpr::bind(Scopes& s) const { @@ -181,9 +175,6 @@ void RetExpr::bind(Scopes& s) const { body()->bind(s); } -void SigmaExpr::bind_decl(Scopes& s) const { ptrn()->bind_decl(s); } -void SigmaExpr::bind_body(Scopes& s) const { ptrn()->bind_body(s); } - void SigmaExpr::bind(Scopes& s) const { s.push(); ptrn()->bind(s); diff --git a/src/thorin/plug/matrix/matrix.cpp b/src/thorin/plug/matrix/matrix.cpp index baf60c8063..c64c605bd0 100644 --- a/src/thorin/plug/matrix/matrix.cpp +++ b/src/thorin/plug/matrix/matrix.cpp @@ -1,4 +1,3 @@ - #include "thorin/plug/matrix/matrix.h" #include From 2b5c3a69bb8f8b7dcf804a1702b5a25a9afd40f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 00:43:37 +0200 Subject: [PATCH 76/95] cleanup --- include/thorin/ast/ast.h | 3 --- src/thorin/ast/bind.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 482909ca64..a883da490a 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -195,7 +195,6 @@ class IdPtrn : public Ptrn { std::ostream& stream(Tab&, std::ostream&) const override; private: - bool rebind_; Ptr type_; }; @@ -235,8 +234,6 @@ class TuplePtrn : public Ptrn { size_t num_ptrns() const { return ptrns().size(); } void bind(Scopes&, bool quiet = false) const override; - void bind_decl(Scopes&) const; - void bind_body(Scopes&) const; Ref emit_value(Emitter&, Ref) const override; Ref emit_type(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index d8386e5cf5..9ba36551b8 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -113,9 +113,6 @@ void IdPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), quiet); } -void TuplePtrn::bind_decl(Scopes& s) const {} -void TuplePtrn::bind_body(Scopes& s) const {} - void TuplePtrn::bind(Scopes& s, bool quiet) const { for (const auto& ptrn : ptrns()) ptrn->bind(s, quiet); s.bind(dbg(), this, rebind(), quiet); From ac9ce24252e9be79661a197323629cbfb9eaffc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 02:05:55 +0200 Subject: [PATCH 77/95] cleanup --- include/thorin/ast/ast.h | 97 ++++++++++++++--------- src/thorin/ast/bind.cpp | 38 ++++----- src/thorin/ast/emit.cpp | 162 ++++++++++++++++++-------------------- src/thorin/ast/stream.cpp | 21 ++--- 4 files changed, 168 insertions(+), 150 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index a883da490a..b0c332d5da 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -100,10 +100,13 @@ class Expr : public Node { : Node(loc) {} public: + Ref emit(Emitter&) const; virtual void bind(Scopes&) const = 0; - virtual Ref emit(Emitter&) const = 0; virtual Ref emit_decl(Emitter&, Ref /*type*/) const { fe::unreachable(); } virtual void emit_body(Emitter&, Ref /*decl*/) const { fe::unreachable(); } + +private: + virtual Ref emit_(Emitter&) const = 0; }; class Decl : public Node { @@ -249,6 +252,30 @@ class TuplePtrn : public Ptrn { * Expr */ +class ErrorExpr : public Expr { +public: + ErrorExpr(Loc loc) + : Expr(loc) {} + + void bind(Scopes&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Ref emit_(Emitter&) const override; +}; + +class InferExpr : public Expr { +public: + InferExpr(Loc loc) + : Expr(loc) {} + + void bind(Scopes&) const override; + std::ostream& stream(Tab&, std::ostream&) const override; + +private: + Ref emit_(Emitter&) const override; +}; + /// `sym` class IdExpr : public Expr { public: @@ -260,10 +287,11 @@ class IdExpr : public Expr { const Decl* decl() const { return decl_; } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Dbg dbg_; mutable const Decl* decl_ = nullptr; }; @@ -280,10 +308,11 @@ class PrimaryExpr : public Expr { Tok::Tag tag() const { return tag_; } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Tok::Tag tag_; }; @@ -300,10 +329,11 @@ class LitExpr : public Expr { const Expr* type() const { return type_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Tok tok_; Ptr type_; }; @@ -319,10 +349,11 @@ class BlockExpr : public Expr { const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr expr_; }; @@ -339,10 +370,11 @@ class DeclExpr : public Expr { const Expr* expr() const { return expr_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + DeclsBlock decls_; Ptr expr_; bool where_; @@ -358,10 +390,11 @@ class TypeExpr : public Expr { const Expr* level() const { return level_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr level_; }; @@ -380,10 +413,11 @@ class ArrowExpr : public Expr { const Expr* codom() const { return codom_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr dom_; Ptr codom_; }; @@ -442,12 +476,13 @@ class PiExpr : public Expr { const Expr* codom() const { return codom_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const override; void emit_body(Emitter&, Ref decl) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Tok::Tag tag_; mutable Ptrs doms_; Ptr codom_; @@ -461,12 +496,13 @@ class LamExpr : public Expr { const LamDecl* lam() const { return lam_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const override; void emit_body(Emitter&, Ref decl) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr lam_; }; @@ -484,10 +520,11 @@ class AppExpr : public Expr { const Expr* arg() const { return arg_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + bool is_explicit_; Ptr callee_; Ptr arg_; @@ -509,10 +546,11 @@ class RetExpr : public Expr { const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr ptrn_; Ptr callee_; Ptr arg_; @@ -530,12 +568,13 @@ class SigmaExpr : public Expr { const TuplePtrn* ptrn() const { return ptrn_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const override; void emit_body(Emitter&, Ref decl) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr ptrn_; friend Ptr Ptrn::to_ptrn(Ptr&&); @@ -553,10 +592,11 @@ class TupleExpr : public Expr { size_t num_elems() const { return elems().size(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptrs elems_; }; @@ -572,10 +612,11 @@ template class ArrOrPackExpr : public Expr { const Expr* body() const { return body_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr shape_; Ptr body_; }; @@ -600,10 +641,11 @@ class ExtractExpr : public Expr { const Decl* decl() const { return decl_; } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr tuple_; std::variant, Dbg> index_; mutable const Decl* decl_ = nullptr; @@ -623,35 +665,16 @@ class InsertExpr : public Expr { const Expr* value() const { return value_.get(); } void bind(Scopes&) const override; - Ref emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: + Ref emit_(Emitter&) const override; + Ptr tuple_; Ptr index_; Ptr value_; }; -class ErrorExpr : public Expr { -public: - ErrorExpr(Loc loc) - : Expr(loc) {} - - void bind(Scopes&) const override; - Ref emit(Emitter&) const override; - std::ostream& stream(Tab&, std::ostream&) const override; -}; - -class InferExpr : public Expr { -public: - InferExpr(Loc loc) - : Expr(loc) {} - - void bind(Scopes&) const override; - Ref emit(Emitter&) const override; - std::ostream& stream(Tab&, std::ostream&) const override; -}; - /* * Decls */ diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 9ba36551b8..e8c7607b48 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -71,27 +71,9 @@ class Scopes { }; /* - * AST + * Module */ -// clang-format off -void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } -void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } -void ErrorExpr ::bind(Scopes&) const {} -void InferExpr ::bind(Scopes&) const {} -void PrimaryExpr::bind(Scopes&) const {} -// clang-format on - -void LitExpr::bind(Scopes& s) const { - if (type()) { - type()->bind(s); - if (tag() == Tag::L_str || tag() == Tag::L_c || tag() == Tag::L_i) - s.ast().error(type()->loc(), "a {} shall not have a type annotation", tag()); - } else { - if (tag() == Tag::L_f) s.ast().error(loc(), "type annotation mandatory for floating point literal"); - } -} - void Module::bind(AST& ast) const { auto scopes = Scopes(ast); bind(scopes); @@ -124,6 +106,24 @@ void GrpPtrn::bind(Scopes& s, bool quiet) const { s.bind(dbg(), this, rebind(), * Expr */ +// clang-format off +void IdExpr ::bind(Scopes& s) const { decl_ = s.find(dbg()); } +void TypeExpr ::bind(Scopes& s) const { level()->bind(s); } +void ErrorExpr ::bind(Scopes&) const {} +void InferExpr ::bind(Scopes&) const {} +void PrimaryExpr::bind(Scopes&) const {} +// clang-format on + +void LitExpr::bind(Scopes& s) const { + if (type()) { + type()->bind(s); + if (tag() == Tag::L_str || tag() == Tag::L_c || tag() == Tag::L_i) + s.ast().error(type()->loc(), "a {} shall not have a type annotation", tag()); + } else { + if (tag() == Tag::L_f) s.ast().error(loc(), "type annotation mandatory for floating point literal"); + } +} + void DeclExpr::bind(Scopes& s) const { decls_.bind(s); expr()->bind(s); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index ea9eec4b29..f24822c51d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -40,68 +40,9 @@ class Emitter { }; /* - * AST + * Module */ -Ref ErrorExpr::emit(Emitter&) const { fe::unreachable(); } -Ref InferExpr::emit(Emitter& e) const { return e.world().mut_infer_type(); } - -Ref IdExpr::emit(Emitter&) const { - assert(decl()); - return decl()->def(); -} - -Ref TypeExpr::emit(Emitter& e) const { - auto l = level()->emit(e); - return e.world().type(l); -} - -Ref PrimaryExpr ::emit(Emitter& e) const { - switch (tag()) { - // clang-format off - case Tag::K_Univ: return e.world().univ(); - case Tag::K_Nat: return e.world().type_nat(); - case Tag::K_Idx: return e.world().type_idx(); - case Tag::K_Bool: return e.world().type_bool(); - case Tag::K_ff: return e.world().lit_ff(); - case Tag::K_tt: return e.world().lit_tt(); - case Tag::K_i1: return e.world().lit_i1(); - case Tag::K_i8: return e.world().lit_i8(); - case Tag::K_i16: return e.world().lit_i16(); - case Tag::K_i32: return e.world().lit_i32(); - case Tag::K_i64: return e.world().lit_i64(); - case Tag::K_I1: return e.world().type_i1(); - case Tag::K_I8: return e.world().type_i8(); - case Tag::K_I16: return e.world().type_i16(); - case Tag::K_I32: return e.world().type_i32(); - case Tag::K_I64: return e.world().type_i64(); - case Tag::T_star: return e.world().type<0>(); - case Tag::T_box: return e.world().type<1>(); - default: fe::unreachable(); - // clang-format on - } -} - -Ref LitExpr::emit(Emitter& e) const { - auto old_loc = e.world().push(loc()); - // auto t = type() ? type()->emit(e) : e.world().type<0>(); - // return (tag() == Tag::T_bot ? e.world().bot(t) : e.world().top(t)); - auto t = type() ? type()->emit(e) : nullptr; - // clang-format off - switch (tag()){ - case Tag::L_f: - case Tag::L_s: - case Tag::L_u: return t ? e.world().lit(t, tok().lit_u()) : e.world().lit_nat(tok().lit_u()); - case Tag::L_i: return tok().lit_i(); - case Tag::L_c: return e.world().lit_i8(tok().lit_c()); - case Tag::L_str: return e.world().tuple(tok().sym()); - case Tag::T_bot: return t ? e.world().bot(t) : e.world().type_bot(); - case Tag::T_top: return t ? e.world().top(t) : e.world().type_top(); - default: fe::unreachable(); - } - // clang-format on -} - void Module::emit(AST& ast) const { auto emitter = Emitter(ast); emit(emitter); @@ -122,6 +63,7 @@ void Import::emit(Emitter& e) const { module()->emit(e); } Ref IdPtrn::emit_value(Emitter&, Ref def) const { return def_ = def->set(dbg()); } Ref TuplePtrn::emit_value(Emitter& e, Ref def) const { + auto _ = e.world().push(loc()); for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_value(e, def->proj(n, i)); return def_ = def->set(dbg()); } @@ -174,15 +116,75 @@ Ref TuplePtrn::emit_decl(Emitter& e, Ref type) const { * Expr */ -Ref DeclExpr::emit(Emitter& e) const { +Ref Expr::emit(Emitter& e) const { + auto _ = e.world().push(loc()); + return emit_(e); +} + +Ref ErrorExpr::emit_(Emitter&) const { fe::unreachable(); } +Ref InferExpr::emit_(Emitter& e) const { return e.world().mut_infer_type(); } + +Ref IdExpr::emit_(Emitter&) const { + assert(decl()); + return decl()->def(); +} + +Ref TypeExpr::emit_(Emitter& e) const { + auto l = level()->emit(e); + return e.world().type(l); +} + +Ref PrimaryExpr ::emit_(Emitter& e) const { + // clang-format off + switch (tag()) { + case Tag::K_Univ: return e.world().univ(); + case Tag::K_Nat: return e.world().type_nat(); + case Tag::K_Idx: return e.world().type_idx(); + case Tag::K_Bool: return e.world().type_bool(); + case Tag::K_ff: return e.world().lit_ff(); + case Tag::K_tt: return e.world().lit_tt(); + case Tag::K_i1: return e.world().lit_i1(); + case Tag::K_i8: return e.world().lit_i8(); + case Tag::K_i16: return e.world().lit_i16(); + case Tag::K_i32: return e.world().lit_i32(); + case Tag::K_i64: return e.world().lit_i64(); + case Tag::K_I1: return e.world().type_i1(); + case Tag::K_I8: return e.world().type_i8(); + case Tag::K_I16: return e.world().type_i16(); + case Tag::K_I32: return e.world().type_i32(); + case Tag::K_I64: return e.world().type_i64(); + case Tag::T_star: return e.world().type<0>(); + case Tag::T_box: return e.world().type<1>(); + default: fe::unreachable(); + } + // clang-format on +} + +Ref LitExpr::emit_(Emitter& e) const { + auto t = type() ? type()->emit(e) : nullptr; + // clang-format off + switch (tag()) { + case Tag::L_f: + case Tag::L_s: + case Tag::L_u: return t ? e.world().lit(t, tok().lit_u()) : e.world().lit_nat(tok().lit_u()); + case Tag::L_i: return tok().lit_i(); + case Tag::L_c: return e.world().lit_i8(tok().lit_c()); + case Tag::L_str: return e.world().tuple(tok().sym()); + case Tag::T_bot: return t ? e.world().bot(t) : e.world().type_bot(); + case Tag::T_top: return t ? e.world().top(t) : e.world().type_top(); + default: fe::unreachable(); + } + // clang-format on +} + +Ref DeclExpr::emit_(Emitter& e) const { decls_.emit(e); return expr()->emit(e); } -Ref BlockExpr::emit(Emitter& e) const { return expr()->emit(e); } +Ref BlockExpr::emit_(Emitter& e) const { return expr()->emit(e); } -Ref ArrowExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +Ref ArrowExpr::emit_(Emitter& e) const { auto d = dom()->emit(e); auto c = codom()->emit(e); return e.world().pi(d, c); @@ -213,12 +215,12 @@ void PiExpr::Dom::emit_type(Emitter& e) const { Ref PiExpr::emit_decl(Emitter& e, Ref type) const { const auto& first = doms().front(); - return first->decl_ = e.world().mut_pi(type, first->is_implicit()); + return first->decl_ = e.world().mut_pi(type, first->is_implicit())->set(loc()); } void PiExpr::emit_body(Emitter& e, Ref) const { emit(e); } -Ref PiExpr::emit(Emitter& e) const { +Ref PiExpr::emit_(Emitter& e) const { for (const auto& dom : doms()) dom->emit_type(e); auto cod = codom() ? codom()->emit(e) : e.world().type_bot(); @@ -233,21 +235,19 @@ Ref PiExpr::emit(Emitter& e) const { Ref LamExpr::emit_decl(Emitter& e, Ref) const { return lam()->emit_decl(e), lam()->def(); } void LamExpr::emit_body(Emitter& e, Ref) const { lam()->emit_body(e); } -Ref LamExpr::emit(Emitter& e) const { +Ref LamExpr::emit_(Emitter& e) const { auto res = emit_decl(e, {}); emit_body(e, {}); return res; } -Ref AppExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +Ref AppExpr::emit_(Emitter& e) const { auto c = callee()->emit(e); auto a = arg()->emit(e); return is_explicit() ? e.world().app(c, a) : e.world().iapp(c, a); } -Ref RetExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +Ref RetExpr::emit_(Emitter& e) const { auto c = callee()->emit(e); if (auto cn = Pi::ret_pi(c->type())) { auto con = e.world().mut_lam(cn); @@ -263,19 +263,15 @@ Ref RetExpr::emit(Emitter& e) const { } Ref SigmaExpr::emit_decl(Emitter& e, Ref type) const { return ptrn()->emit_decl(e, type); } - void SigmaExpr::emit_body(Emitter& e, Ref decl) const { ptrn()->emit_body(e, decl); } +Ref SigmaExpr::emit_(Emitter& e) const { return ptrn()->emit_type(e); } -Ref SigmaExpr::emit(Emitter& e) const { return ptrn()->emit_type(e); } - -Ref TupleExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +Ref TupleExpr::emit_(Emitter& e) const { DefVec elems(num_elems(), [&](size_t i) { return elem(i)->emit(e); }); return e.world().tuple(elems); } -template Ref ArrOrPackExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +template Ref ArrOrPackExpr::emit_(Emitter& e) const { auto s = shape()->emit_type(e); if (shape()->dbg().is_anon()) { // immutable auto b = body()->emit(e); @@ -304,11 +300,10 @@ template Ref ArrOrPackExpr::emit(Emitter& e) const { } } -template Ref ArrOrPackExpr::emit(Emitter&) const; -template Ref ArrOrPackExpr::emit(Emitter&) const; +template Ref ArrOrPackExpr::emit_(Emitter&) const; +template Ref ArrOrPackExpr::emit_(Emitter&) const; -Ref ExtractExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +Ref ExtractExpr::emit_(Emitter& e) const { auto tup = tuple()->emit(e); if (auto dbg = std::get_if(&index())) { if (auto sigma = tup->type()->isa_mut()) { @@ -329,8 +324,7 @@ Ref ExtractExpr::emit(Emitter& e) const { return e.world().extract(tup, i); } -Ref InsertExpr::emit(Emitter& e) const { - auto _ = e.world().push(loc()); +Ref InsertExpr::emit_(Emitter& e) const { auto t = tuple()->emit(e); auto i = index()->emit(e); auto v = value()->emit(e); diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index 329bd2209c..d9167d474c 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -34,6 +34,17 @@ void Node::dump() const { stream(tab, std::cout) << std::endl; } +/* + * Module + */ + +std::ostream& Import::stream(Tab& tab, std::ostream& os) const { return tab.println(os, "{} '{}';", tag(), "TODO"); } + +std::ostream& Module::stream(Tab& tab, std::ostream& os) const { + for (const auto& import : imports()) import->stream(tab, os); + return decls_.stream(tab, os); +} + /* * Ptrn */ @@ -210,15 +221,5 @@ std::ostream& CDecl::stream(Tab& tab, std::ostream& os) const { if (tag() == Tag::K_cfun) print(os, ": {}", S(tab, codom())); return os; } -/* - * Module - */ - -std::ostream& Import::stream(Tab& tab, std::ostream& os) const { return tab.println(os, "{} '{}';", tag(), "TODO"); } - -std::ostream& Module::stream(Tab& tab, std::ostream& os) const { - for (const auto& import : imports()) import->stream(tab, os); - return decls_.stream(tab, os); -} } // namespace thorin::ast From 344ab4408bbd5008dffd97ca5ad1299407920e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 15:13:41 +0200 Subject: [PATCH 78/95] make let in ptrns work --- include/thorin/ast/ast.h | 11 ++++++----- lit/let_ptrn.thorin | 11 +++++++++++ src/thorin/ast/emit.cpp | 11 ++++++----- 3 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 lit/let_ptrn.thorin diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index b0c332d5da..62fda04806 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -163,13 +163,15 @@ class Ptrn : public Decl { Dbg dbg() const { return dbg_; } virtual void bind(Scopes&, bool quiet = false) const = 0; - virtual Ref emit_value(Emitter&, Ref) const = 0; - virtual Ref emit_type(Emitter&) const = 0; + Ref emit_value(Emitter&, Ref) const; + virtual Ref emit_type(Emitter&) const = 0; [[nodiscard]] static Ptr to_expr(AST&, Ptr&&); [[nodiscard]] static Ptr to_ptrn(Ptr&&); private: + virtual void emit_value_(Emitter&, Ref) const {} + Dbg dbg_; bool rebind_; }; @@ -193,7 +195,6 @@ class IdPtrn : public Ptrn { } void bind(Scopes&, bool quiet = false) const override; - Ref emit_value(Emitter&, Ref) const override; Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -211,7 +212,6 @@ class GrpPtrn : public Ptrn { const IdPtrn* id() const { return id_; } void bind(Scopes&, bool quiet = false) const override; - Ref emit_value(Emitter&, Ref) const override; Ref emit_type(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; @@ -237,13 +237,14 @@ class TuplePtrn : public Ptrn { size_t num_ptrns() const { return ptrns().size(); } void bind(Scopes&, bool quiet = false) const override; - Ref emit_value(Emitter&, Ref) const override; Ref emit_type(Emitter&) const override; Ref emit_decl(Emitter&, Ref type) const; Ref emit_body(Emitter&, Ref decl) const; std::ostream& stream(Tab&, std::ostream&) const override; private: + void emit_value_(Emitter&, Ref) const override; + Tok::Tag delim_l_; Ptrs ptrns_; }; diff --git a/lit/let_ptrn.thorin b/lit/let_ptrn.thorin new file mode 100644 index 0000000000..149b9e99f8 --- /dev/null +++ b/lit/let_ptrn.thorin @@ -0,0 +1,11 @@ +// RUN: %thorin %s -o - +.ax %foo.F: * -> *; +.ax %foo.f: |~| T: * -> .Nat -> %foo.F T; + +.fun .extern f( + T: *, + U: .let F = %foo.F T; F, + V: F + )( + W: F + ): F = return (%foo.f T 23); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index f24822c51d..55fd1bb049 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -60,15 +60,16 @@ void Import::emit(Emitter& e) const { module()->emit(e); } * Ptrn::emit_value */ -Ref IdPtrn::emit_value(Emitter&, Ref def) const { return def_ = def->set(dbg()); } - -Ref TuplePtrn::emit_value(Emitter& e, Ref def) const { +Ref Ptrn::emit_value(Emitter& e, Ref def) const { auto _ = e.world().push(loc()); - for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_value(e, def->proj(n, i)); + emit_type(e); + emit_value_(e, def); return def_ = def->set(dbg()); } -Ref GrpPtrn::emit_value(Emitter&, Ref def) const { return def_ = def->set(dbg()); } +void TuplePtrn::emit_value_(Emitter& e, Ref def) const { + for (size_t i = 0, n = num_ptrns(); i != n; ++i) ptrn(i)->emit_value(e, def->proj(n, i)); +} /* * Ptrn::emit_Type From ef6fcd3c29f5e999cd8aac1ce1e08eccd9403614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 22:19:58 +0200 Subject: [PATCH 79/95] cleanup --- src/thorin/ast/parser.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 7eaac05da1..23f3a21f78 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -83,19 +83,6 @@ namespace thorin::ast { using Tag = Tok::Tag; -// clang-format off -Prec tag2prec(Tag tag) { - switch (tag) { - case Tag::K_where: return Prec::Where; - case Tag::T_arrow: return Prec::Arrow; - case Tag::T_extract: return Prec::Extract; - case Tag::T_at: - case EXPR: return Prec::App; - default: return Prec::Err; - } -} -// clang-format on - /* * entry points */ @@ -386,11 +373,11 @@ Ptr Parser::parse_ret_expr() { auto track = tracker(); eat(Tag::K_ret); auto ptrn = parse_ptrn(Tag::D_paren_l, "binding pattern of a ret expression"); - expect(Tag::T_assign, "let expression"); + expect(Tag::T_assign, "ret expression"); auto callee = parse_expr("continuation expression of a ret expression"); expect(Tag::T_dollar, "separator of a ret expression"); auto arg = parse_expr("argument of ret expression"); - expect(Tag::T_semicolon, "let expression"); + expect(Tag::T_semicolon, "ret expression"); auto body = parse_expr("body of a ret expression"); return ptr(track, std::move(ptrn), std::move(callee), std::move(arg), std::move(body)); } @@ -416,8 +403,8 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool } } - // p -> (p, ..., p) - // p -> [b, ..., b] b -> [b, ..., b] + // p -> (p, ..., p) + // p -> [b, ..., b] b -> [b, ..., b] // p -> s::(p, ..., p) // p -> s::[b, ..., b] b -> s::[b, ..., b] // p -> s: e b -> s: e From 8da1efcfa35e7b45e29558f10f1e9b4854a8ee75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 22:31:27 +0200 Subject: [PATCH 80/95] added warnings + hints --- src/thorin/ast/parser.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 23f3a21f78..6f07b30741 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -222,6 +222,15 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre } case EXPR: { if (curr_prec >= Prec::App) return lhs; + switch (ahead().tag()) { + case DECL: + ast().warn(ahead().loc(), "you are passing a declaration expression as argument"); + ast().note(lhs->loc(), "to this expression"); + ast().note(ahead().loc(), + "if this was your intention, parenthesize the declaration expression"); + ast().note(lhs->loc().anew_finis(), "otherwise, you are probably missing a ';'"); + default: break; + } auto rhs = parse_expr("argument to an application", Prec::App); lhs = ptr(track.loc(), false, std::move(lhs), std::move(rhs)); continue; From f4a21a51e20a095b3ece4dd0c91dd6dd471430e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 23:10:04 +0200 Subject: [PATCH 81/95] polish --- lit/regex/match_wds.thorin | 24 ++++++++++-------------- src/thorin/ast/parser.cpp | 4 +--- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/lit/regex/match_wds.thorin b/lit/regex/match_wds.thorin index c5584acf56..d0a0661420 100644 --- a/lit/regex/match_wds.thorin +++ b/lit/regex/match_wds.thorin @@ -11,20 +11,16 @@ .let Top = ⊤:.Nat; .let re = %regex.conj 2 (%regex.cls.w, %regex.conj 2 (%regex.cls.d, %regex.cls.s)); -.con .extern main[mem: %mem.M, argc: .I32, argv: %mem.Ptr («⊤:.Nat; %mem.Ptr («⊤:.Nat; .I8», 0)», 0), exit : .Cn [%mem.M, .I32]] = { - .con handle_match [mem: %mem.M, matched: .Bool, match: %mem.Ptr(«Top; .I8», 0)] = { - - exit (mem, %core.conv.u .i32 matched) - }; - - .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); - .let (`mem, matched, pos) = re (mem, to_match, 0:(.Idx Top)); - exit (mem, %core.conv.u .i32 matched) - }; - +.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 handle_match [mem: %mem.M, matched: .Bool, match: %mem.Ptr(«Top; .I8», 0)] = + exit (mem, %core.conv.u .i32 matched); + .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); + .let (`mem, matched, pos) = re (mem, to_match, 0:(.Idx Top)); + exit (mem, %core.conv.u .i32 matched); + .end // CHECK-NOT: %regex. diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 6f07b30741..4b9b3b7c2d 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -318,8 +318,6 @@ Ptr Parser::parse_decl_expr() { auto track = tracker(); auto decls = parse_decls(); auto expr = parse_expr("final expression of a declaration expression"); - if (expr->isa()) - for (const auto& decl : decls) ast().note(decl->loc(), "declaration belonging to this declaration expression"); return ptr(track, std::move(decls), std::move(expr), false); } @@ -330,7 +328,7 @@ Ptr Parser::parse_lit_expr() { return ptr(track, tok, std::move(type)); } -Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, Dbg(ahead().loc(), Sym()))); } +Ptr Parser::parse_sigma_expr() { return ptr(parse_tuple_ptrn(false, Dbg(ahead().loc()))); } Ptr Parser::parse_tuple_expr() { auto track = tracker(); From 6933c2b602938015e6d9a8e3e070ba4c8a8a07c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Wed, 24 Apr 2024 23:17:49 +0200 Subject: [PATCH 82/95] fix endless loops in parse_pi_expr/parse_lam_decl --- src/thorin/ast/parser.cpp | 50 ++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 4b9b3b7c2d..952c5b5228 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -357,14 +357,20 @@ Ptr Parser::parse_pi_expr() { } Ptrs doms; - do { + while (true) { auto track = tracker(); auto implicit = (bool)accept(Tag::T_dot); auto prec = tag == Tag::K_Cn ? Prec::Bot : Prec::Pi; auto ptrn = parse_ptrn(Tag::D_brckt_l, "domain of a "s + entity, prec); doms.emplace_back(ptr(track, implicit, std::move(ptrn))); - } while (ahead().isa(Tag::T_dot) || ahead().isa(Tag::D_brckt_l) || ahead().isa(Tag::T_backtick) - || (ahead(0).isa(Tag::M_id) && ahead(1).isa(Tag::T_colon_colon))); + + switch (ahead().tag()) { + case EXPR: + case Tag::T_backtick: continue; + default: break; + } + break; + } auto codom = tag != Tag::K_Cn ? (expect(Tag::T_arrow, entity), parse_expr("codomain of a "s + entity, Prec::Arrow)) : nullptr; @@ -415,11 +421,11 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool // p -> s::(p, ..., p) // p -> s::[b, ..., b] b -> s::[b, ..., b] // p -> s: e b -> s: e - // p -> s b -> e - // p -> 's::(p, ..., p) - // p -> 's::[b, ..., b] b -> 's::[b, ..., b] - // p -> 's: e b -> 's: e - // p -> 's + // p -> s b -> e + // p -> `s::(p, ..., p) + // p -> `s::[b, ..., b] b -> `s::[b, ..., b] + // p -> `s: e b -> `s: e + // p -> `s if (p && ahead().isa(Tag::D_paren_l)) { // p -> (p, ..., p) @@ -437,10 +443,10 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool // p -> s::[b, ..., b] b -> s::[b, ..., b] // p -> s: e b -> s: e // p -> s b -> e where e == id - // p -> 's::(p, ..., p) - // p -> 's::[b, ..., b] b -> 's::[b, ..., b] - // p -> 's: e b -> 's: e - // p -> 's + // p -> `s::(p, ..., p) + // p -> `s::[b, ..., b] b -> `s::[b, ..., b] + // p -> `s: e b -> `s: e + // p -> `s if (ahead(1).isa(Tag::T_colon_colon)) { dbg = eat(Tag::M_id).dbg(); eat(Tag::T_colon_colon); @@ -448,25 +454,25 @@ Ptr Parser::parse_ptrn(Tag delim_l, std::string_view ctxt, Prec prec, bool ast().error(ahead().loc(), "switching from []-style patterns to ()-style patterns is not allowed"); // b -> s::(p, ..., p) // b -> s::[b, ..., b] b -> s::[b, ..., b] - // b -> 's::(p, ..., p) - // b -> 's::[b, ..., b] b -> 's::[b, ..., b] + // b -> `s::(p, ..., p) + // b -> `s::[b, ..., b] b -> `s::[b, ..., b] if (ahead().isa(Tag::D_paren_l) || ahead().isa(Tag::D_brckt_l)) return parse_tuple_ptrn(rebind, dbg); else syntax_err("tuple pattern after '" + dbg.sym().str() + "::'", ctxt); } else if (ahead(1).isa(Tag::T_colon)) { // p -> s: e b -> s: e - // p -> 's: e b -> 's: e + // p -> `s: e b -> `s: e dbg = eat(Tag::M_id).dbg(); eat(Tag::T_colon); auto type = parse_expr(ctxt, prec); return ptr(track, rebind, dbg, std::move(type)); } else { // p -> s b -> e where e == id - // p -> 's + // p -> `s if (p) { // p -> s - // p -> 's + // p -> `s dbg = eat(Tag::M_id).dbg(); return ptr(track, rebind, dbg, nullptr); } else { @@ -652,14 +658,20 @@ Ptr Parser::parse_lam_decl() { auto dbg = decl ? parse_name(entity) : Dbg(); Ptrs doms; - do { + while (true) { auto track = tracker(); bool implicit = (bool)accept(Tag::T_dot); auto ptrn = parse_ptrn(Tag::D_paren_l, "domain pattern of a "s + entity, prec); auto filter = accept(Tag::T_at) ? parse_expr("filter") : nullptr; doms.emplace_back(ptr(track, implicit, std::move(ptrn), std::move(filter))); - } while (!ahead().isa(Tag::T_colon) && !ahead().isa(Tag::T_assign) && !ahead().isa(Tag::T_semicolon)); + switch (ahead().tag()) { + case EXPR: + case Tag::T_backtick: continue; + default: break; + } + break; + } auto codom = accept(Tag::T_colon) ? parse_expr("codomain of a "s + entity, Prec::Arrow) : nullptr; if (tag == Tag::K_fn || tag == Tag::K_fun) From 2ce91c0af8f546a99b2c5c52c0c3e2a4d5d9d719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 25 Apr 2024 16:19:15 +0200 Subject: [PATCH 83/95] rework decls to explicitly use .and for mutal recursion --- include/thorin/ast/ast.h | 80 ++++++++++++--------------- include/thorin/ast/parser.h | 3 +- include/thorin/ast/tok.h | 4 +- lit/beta_equiv.thorin | 2 - lit/direct/mut_dom_bug.thorin | 2 - lit/ext_names.thorin | 2 - lit/lam_body_sigma.thorin | 2 - lit/pow_pe.thorin | 2 - lit/ptrn.thorin | 2 - lit/rec.thorin | 3 +- lit/sigma.thorin | 2 - src/thorin/ast/bind.cpp | 41 +++++--------- src/thorin/ast/emit.cpp | 31 ++++------- src/thorin/ast/parser.cpp | 100 +++++++++++++++++++--------------- src/thorin/ast/stream.cpp | 15 ++--- 15 files changed, 124 insertions(+), 167 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 62fda04806..95338b2a26 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -127,25 +127,8 @@ class ValDecl : public Decl { : Decl(loc) {} public: - virtual void bind_decl(Scopes&) const = 0; - virtual void emit_decl(Emitter&) const = 0; -}; - -class DeclsBlock { -public: - DeclsBlock(Ptrs&& decls) - : decls_(std::move(decls)) {} - - const auto& decls() const { return decls_; } - const ValDecl* decl(size_t i) const { return decls_[i].get(); } - size_t num_decls() const { return decls_.size(); } - - std::ostream& stream(Tab&, std::ostream&) const; - void bind(Scopes&) const; - void emit(Emitter&) const; - -private: - Ptrs decls_; + virtual void bind(Scopes&) const = 0; + virtual void emit(Emitter&) const = 0; }; /* @@ -367,6 +350,7 @@ class DeclExpr : public Expr { , expr_(std::move(expr)) , where_(where) {} + const auto& decls() const { return decls_; } bool where() const { return where_; } const Expr* expr() const { return expr_.get(); } @@ -376,7 +360,7 @@ class DeclExpr : public Expr { private: Ref emit_(Emitter&) const override; - DeclsBlock decls_; + Ptrs decls_; Ptr expr_; bool where_; }; @@ -680,17 +664,6 @@ class InsertExpr : public Expr { * Decls */ -/// `.grp` -class GrpDecl : public ValDecl { -public: - GrpDecl(Loc loc) - : ValDecl(loc) {} - - void bind_decl(Scopes&) const override; - void emit_decl(Emitter&) const override; - std::ostream& stream(Tab&, std::ostream&) const override; -}; - /// `.let ptrn: type = value;` class LetDecl : public ValDecl { public: @@ -702,8 +675,8 @@ class LetDecl : public ValDecl { const Ptrn* ptrn() const { return ptrn_.get(); } const Expr* value() const { return value_.get(); } - void bind_decl(Scopes&) const override; - void emit_decl(Emitter&) const override; + void bind(Scopes&) const override; + void emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -753,8 +726,8 @@ class AxiomDecl : public ValDecl { Tok curry() const { return curry_; } Tok trip() const { return trip_; } - void bind_decl(Scopes&) const override; - void emit_decl(Emitter&) const override; + void bind(Scopes&) const override; + void emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -777,26 +750,33 @@ class AxiomDecl : public ValDecl { /// `.rec dbg: type = body` class RecDecl : public ValDecl { public: - RecDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body) + RecDecl(Loc loc, Dbg dbg, Ptr&& type, Ptr&& body, Ptr&& next) : ValDecl(loc) , dbg_(dbg) , type_(std::move(type)) - , body_(std::move(body)) {} + , body_(std::move(body)) + , next_(std::move(next)) {} Dbg dbg() const { return dbg_; } const Expr* type() const { return type_.get(); } const Expr* body() const { return body_.get(); } + const RecDecl* next() const { return next_.get(); } - void bind_decl(Scopes&) const override; - void emit_decl(Emitter&) const override; + void bind(Scopes&) const override; + virtual void bind_decl(Scopes&) const; virtual void bind_body(Scopes&) const; + + void emit(Emitter&) const override; + virtual void emit_decl(Emitter&) const; virtual void emit_body(Emitter&) const; + std::ostream& stream(Tab&, std::ostream&) const override; private: Dbg dbg_; Ptr type_; Ptr body_; + Ptr next_; }; /// One of: @@ -827,8 +807,15 @@ class LamDecl : public RecDecl { friend class LamDecl; }; - LamDecl(Loc loc, Tok::Tag tag, bool is_external, Dbg dbg, Ptrs&& doms, Ptr&& codom, Ptr&& body) - : RecDecl(loc, dbg, nullptr, std::move(body)) + LamDecl(Loc loc, + Tok::Tag tag, + bool is_external, + Dbg dbg, + Ptrs&& doms, + Ptr&& codom, + Ptr&& body, + Ptr&& next) + : RecDecl(loc, dbg, nullptr, std::move(body), std::move(next)) , tag_(tag) , is_external_(is_external) , doms_(std::move(doms)) @@ -845,8 +832,8 @@ class LamDecl : public RecDecl { void bind_decl(Scopes&) const override; void bind_body(Scopes&) const override; - void emit_decl(Emitter& e) const override; - void emit_body(Emitter& e) const override; + void emit_decl(Emitter&) const override; + void emit_body(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -871,8 +858,8 @@ class CDecl : public ValDecl { const Ptrn* dom() const { return dom_.get(); } const Expr* codom() const { return codom_.get(); } - void bind_decl(Scopes&) const override; - void emit_decl(Emitter&) const override; + void bind(Scopes&) const override; + void emit(Emitter&) const override; std::ostream& stream(Tab&, std::ostream&) const override; private: @@ -923,6 +910,7 @@ class Module : public Node { , decls_(std::move(decls)) {} const auto& imports() const { return imports_; } + const auto& decls() const { return decls_; } void compile(AST&) const; void bind(AST&) const; @@ -933,7 +921,7 @@ class Module : public Node { private: Ptrs imports_; - DeclsBlock decls_; + Ptrs decls_; }; AST load_plugins(World&, View); diff --git a/include/thorin/ast/parser.h b/include/thorin/ast/parser.h index c590416393..87aa83684d 100644 --- a/include/thorin/ast/parser.h +++ b/include/thorin/ast/parser.h @@ -114,7 +114,8 @@ class Parser : public fe::Parser { Ptr parse_let_decl(); Ptr parse_c_decl(); Ptr parse_lam_decl(); - Ptr parse_rec_decl(); + Ptr parse_rec_decl(bool first); + Ptr parse_and_decl(); ///@} /// @name error messages diff --git a/include/thorin/ast/tok.h b/include/thorin/ast/tok.h index 139fc02b03..ad147303b3 100644 --- a/include/thorin/ast/tok.h +++ b/include/thorin/ast/tok.h @@ -14,13 +14,13 @@ namespace ast { m(K_module, ".module") \ m(K_import, ".import") \ m(K_plugin, ".plugin") \ + m(K_and, ".and" ) \ m(K_ax, ".ax" ) \ m(K_let, ".let" ) \ - m(K_grp, ".grp" ) \ m(K_rec, ".rec" ) \ m(K_ret, ".ret" ) \ m(K_where, ".where" ) \ - m(K_end, ".end" ) \ + m(K_end, ".end" ) \ m(K_Nat, ".Nat" ) \ m(K_Idx, ".Idx" ) \ m(K_extern, ".extern") \ diff --git a/lit/beta_equiv.thorin b/lit/beta_equiv.thorin index 643c0417eb..4fcc5e4a89 100644 --- a/lit/beta_equiv.thorin +++ b/lit/beta_equiv.thorin @@ -6,8 +6,6 @@ .rec Num = [T: *, add: [T, T] -> T]; .lam my_add.(pe: «2; .Nat»)(a b: %math.F pe): %math.F pe = %math.arith.add 0 (a, b); -.grp - .let F64 = (%math.F64, my_add @%math.f64); .ax %bug.Arr: Num -> *; diff --git a/lit/direct/mut_dom_bug.thorin b/lit/direct/mut_dom_bug.thorin index 780832ab13..61f7e285ee 100644 --- a/lit/direct/mut_dom_bug.thorin +++ b/lit/direct/mut_dom_bug.thorin @@ -3,8 +3,6 @@ .lam ForBody [n: .Nat] = [%mem.M, .Idx n] -> %mem.M; -.grp - .lam For .[n: .Nat] [start: .Idx n, end: .Idx n] [mem: %mem.M] [it: ForBody n]: %mem.M = { .lam loop [mem: %mem.M, i: .Idx n] @(%core.pe.known i) : [%mem.M, .Idx n] = { .let `mem = it (mem, i); diff --git a/lit/ext_names.thorin b/lit/ext_names.thorin index 14532017f3..fd8868b288 100644 --- a/lit/ext_names.thorin +++ b/lit/ext_names.thorin @@ -7,6 +7,4 @@ .ax %foo.len: %foo.Shape -> .Nat, normalize_len; .lam %foo.Ptr s: %foo.Shape: * = %mem.Ptr0 «%foo.len s; s#T»; .lam %foo.Idx s: %foo.Shape: * = .Idx (%foo.len s); -.grp - .lam get(s: %foo.Shape)(mem: %mem.M, p: %foo.Ptr s, i: %foo.Idx s): [%mem.M, s#T] = (mem, .bot:(s#T) /* dummy impl */); diff --git a/lit/lam_body_sigma.thorin b/lit/lam_body_sigma.thorin index 40b5297f7b..ef12a1b42a 100644 --- a/lit/lam_body_sigma.thorin +++ b/lit/lam_body_sigma.thorin @@ -4,6 +4,4 @@ a: «n; .Nat» ]; -.grp - .lam f(): S = (3, (0, 1, 2)); diff --git a/lit/pow_pe.thorin b/lit/pow_pe.thorin index 7efb254096..4f7bea55fa 100644 --- a/lit/pow_pe.thorin +++ b/lit/pow_pe.thorin @@ -4,7 +4,5 @@ .lam pow(a b: .Nat)@(%core.pe.known b): .Nat = (%core.nat.mul (a, pow(a, %core.nat.sub (b, 1))), 1)#(%core.ncmp.e (b, 0)); -.grp - .lam f(n: .Nat, x: <<%core.nat.mul (n, %core.nat.mul (n, n)); .Nat>>): [] = (); .lam g(m: .Nat, y: <>): [] = f (m, y); diff --git a/lit/ptrn.thorin b/lit/ptrn.thorin index dc92f2a937..20184e123f 100644 --- a/lit/ptrn.thorin +++ b/lit/ptrn.thorin @@ -4,6 +4,4 @@ .lam PtrN(n: .Nat, T: *): * = (PtrN (%core.nat.sub (n, 1), %mem.Ptr0 T), T)#(%core.ncmp.e (n, 0)); -.grp - .fun .extern foo(mem: %mem.M, p: PtrN (4, .I32)): [%mem.M, PtrN (3, .I32)] = return (%mem.load (mem, p)); diff --git a/lit/rec.thorin b/lit/rec.thorin index 5fee6a85f8..3f4307ce20 100644 --- a/lit/rec.thorin +++ b/lit/rec.thorin @@ -1,7 +1,8 @@ // RUN: %thorin %s --output-ll %t.ll -o - | FileCheck %s .plugin core; -.lam is_even(i: .Nat): .Bool = (is_odd (%core.nat.sub (i, 1)), .tt)#(%core.ncmp.e (i, 0)); +.lam is_even(i: .Nat): .Bool = (is_odd (%core.nat.sub (i, 1)), .tt)#(%core.ncmp.e (i, 0)) +.and .lam is_odd (i: .Nat): .Bool = (is_even(%core.nat.sub (i, 1)), .ff)#(%core.ncmp.e (i, 0)); .fun .extern f(): .Bool = return (is_even 4); diff --git a/lit/sigma.thorin b/lit/sigma.thorin index e03a093aae..41594bcaae 100644 --- a/lit/sigma.thorin +++ b/lit/sigma.thorin @@ -21,8 +21,6 @@ .rec F: * = |~| .Nat -> F; // TODO make inference for F work again -.grp - .lam .extern f1 v: Vec1: %math.F64 = v#x; .lam .extern F1 v: vec1: %math.F64 = v#X; .lam .extern f2 v: Vec2: %math.F64 = v#y; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index e8c7607b48..2c1f5464b3 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -81,7 +81,7 @@ void Module::bind(AST& ast) const { void Module::bind(Scopes& s) const { for (const auto& import : imports()) import->bind(s); - decls_.bind(s); + for (const auto& decl : decls()) decl->bind(s); } void Import::bind(Scopes& s) const { module()->bind(s); } @@ -125,7 +125,7 @@ void LitExpr::bind(Scopes& s) const { } void DeclExpr::bind(Scopes& s) const { - decls_.bind(s); + for (const auto& decl : decls()) decl->bind(s); expr()->bind(s); } @@ -212,20 +212,6 @@ void InsertExpr::bind(Scopes& s) const { * Decl */ -void DeclsBlock::bind(Scopes& s) const { - for (size_t i = 0, e = num_decls(), r = 0; true; ++i) { - if (i < e && decl(i)->isa()) { - if (!decl(r)->isa()) r = i; - } else if (r < e && decl(r)->isa()) { - for (size_t j = r; j != i; ++j) decl(j)->as()->bind_body(s); - r = i; - } - - if (i == e) break; - decl(i)->bind_decl(s); - } -} - void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { axiom_ = axiom; auto sym = s.ast().sym(axiom->dbg().sym().str() + "."s + dbg().sym().str()); @@ -233,7 +219,7 @@ void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { s.bind(full_, this); } -void AxiomDecl::bind_decl(Scopes& s) const { +void AxiomDecl::bind(Scopes& s) const { type()->bind(s); std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym()); @@ -261,22 +247,25 @@ void AxiomDecl::bind_decl(Scopes& s) const { } } -void GrpDecl::bind_decl(Scopes&) const {} - -void LetDecl::bind_decl(Scopes& s) const { +void LetDecl::bind(Scopes& s) const { value()->bind(s); ptrn()->bind(s); } +void RecDecl::bind(Scopes& s) const { + for (auto curr = this; curr; curr = curr->next()) curr->bind_decl(s); + for (auto curr = this; curr; curr = curr->next()) curr->bind_body(s); +} + void RecDecl::bind_decl(Scopes& s) const { - if (type()) type()->bind(s); + if (auto t = type()) t->bind(s); if (!type()->isa() && body()->isa()) s.ast().warn(type()->loc(), "type of recursive declaration ignored for function expression"); - s.bind(dbg(), this); - if (!body()->isa() && !body()->isa() && !body()->isa()) s.ast().error(body()->loc(), "unsupported expression for a recursive declaration"); + + s.bind(dbg(), this); } void RecDecl::bind_body(Scopes& s) const { body()->bind(s); } @@ -296,12 +285,12 @@ void LamDecl::bind_decl(Scopes& s) const { if (pe->tag() == Tag::K_tt && (tag() == Tag::K_lam || tag() == Tag::T_lm)) s.ast().warn(filter->loc(), "'.tt'-filter superfluous as the last curried function group of a '{}' receives a " - "'.tt' filter by default", + "'.tt'-filter by default", tag()); if (pe->tag() == Tag::K_ff && (tag() != Tag::K_lam && tag() != Tag::T_lm)) s.ast().warn(filter->loc(), "'.ff'-filter superfluous as the last curried function group of a '{}' receives a " - "'.ff' filter by default", + "'.ff'-filter by default", tag()); } } @@ -323,7 +312,7 @@ void LamDecl::bind_body(Scopes& s) const { s.pop(); } -void CDecl::bind_decl(Scopes& s) const { +void CDecl::bind(Scopes& s) const { s.push(); dom()->bind(s); s.pop(); // we don't allow codom to depent on dom diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 55fd1bb049..d25e63703f 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -51,7 +51,7 @@ void Module::emit(AST& ast) const { void Module::emit(Emitter& e) const { auto _ = e.world().push(loc()); for (const auto& import : imports()) import->emit(e); - decls_.emit(e); + for (const auto& decl : decls()) decl->emit(e); } void Import::emit(Emitter& e) const { module()->emit(e); } @@ -179,7 +179,7 @@ Ref LitExpr::emit_(Emitter& e) const { } Ref DeclExpr::emit_(Emitter& e) const { - decls_.emit(e); + for (const auto& decl : decls()) decl->emit(e); return expr()->emit(e); } @@ -336,26 +336,12 @@ Ref InsertExpr::emit_(Emitter& e) const { * Decl */ -void DeclsBlock::emit(Emitter& e) const { - for (size_t i = 0, n = num_decls(), r = 0; true; ++i) { - if (i < n && decl(i)->isa()) { - if (!decl(r)->isa()) r = i; - } else if (r < n && decl(r)->isa()) { - for (size_t j = r; j != i; ++j) decl(j)->as()->emit_body(e); - r = i; - } - - if (i == n) break; - decl(i)->emit_decl(e); - } -} - void AxiomDecl::Alias::emit(Emitter& e, const Axiom* axiom) const { const auto& id = axiom_->id_; def_ = axiom; } -void AxiomDecl::emit_decl(Emitter& e) const { +void AxiomDecl::emit(Emitter& e) const { auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym()); auto&& [annex, is_new] = e.driver().name2annex(dbg().sym(), plugin_s, tag_s, dbg().loc()); thorin_type_ = type()->emit(e); @@ -407,15 +393,18 @@ void AxiomDecl::emit_decl(Emitter& e) const { } } -void GrpDecl::emit_decl(Emitter&) const {} - -void LetDecl::emit_decl(Emitter& e) const { +void LetDecl::emit(Emitter& e) const { auto v = value()->emit(e); def_ = ptrn()->emit_value(e, v); if (auto id = ptrn()->isa()) e.register_if_annex(id->dbg(), def_); } +void RecDecl::emit(Emitter& e) const { + for (auto curr = this; curr; curr = curr->next()) curr->emit_decl(e); + for (auto curr = this; curr; curr = curr->next()) curr->emit_body(e); +} + void RecDecl::emit_decl(Emitter& e) const { auto t = type() ? type()->emit(e) : e.world().type_infer_univ(); def_ = body()->emit_decl(e, t); @@ -476,7 +465,7 @@ void LamDecl::emit_body(Emitter& e) const { e.register_if_annex(dbg(), def_); } -void CDecl::emit_decl(Emitter& e) const { +void CDecl::emit(Emitter& e) const { auto dom_t = dom()->emit_type(e); if (tag() == Tag::K_cfun) { auto ret_t = codom()->emit(e); diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index 952c5b5228..b981747bf0 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -6,7 +6,7 @@ #include "thorin/driver.h" // clang-format off -#define PRIMARY \ +#define TAG__PRIMARY \ Tag::K_Univ: \ case Tag::K_Nat: \ case Tag::K_Idx: \ @@ -26,11 +26,11 @@ case Tag::T_star: \ case Tag::T_box -#define ID \ +#define TAG__ID \ Tag::M_anx: \ case Tag::M_id -#define LIT \ +#define TAG__LIT \ Tag::T_bot: \ case Tag::T_top: \ case Tag::L_str: \ @@ -40,34 +40,35 @@ case Tag::L_f: \ case Tag::L_i -#define DECL \ +#define TAG__LAM \ + Tag::K_lam: \ + case Tag::K_con: \ + case Tag::K_fun + +#define TAG__DECL \ Tag::K_ax: \ - case Tag::K_grp: \ case Tag::K_let: \ case Tag::K_rec: \ - case Tag::K_lam: \ - case Tag::K_con: \ - case Tag::K_fun: \ case Tag::K_ccon: \ - case Tag::K_cfun + case Tag::K_cfun: \ + case TAG__LAM -#define PI \ +#define TAG__PI \ Tag::T_Pi: \ case Tag::K_Cn: \ case Tag::K_Fn -#define LAM \ +#define TAG__LM \ Tag::T_lm: \ case Tag::K_cn: \ case Tag::K_fn -// clang-format on -#define EXPR \ -PRIMARY: \ - case ID: \ - case LIT: \ - case DECL: \ - case LAM: \ +#define TAG__EXPR \ + TAG__PRIMARY: \ + case TAG__ID: \ + case TAG__LIT: \ + case TAG__DECL: \ + case TAG__LM: \ case Tag::K_Type: /*TypeExpr*/ \ case Tag::K_ins: /*InsertExpr*/ \ case Tag::K_ret: /*RetExpr*/ \ @@ -76,6 +77,7 @@ PRIMARY: \ case Tag::D_brckt_l: /*SigmaExpr*/ \ case Tag::D_paren_l: /*TupleExpr*/ \ case Tag::D_quote_l /*ArrExpr*/ +// clang-format on using namespace std::string_literals; @@ -220,14 +222,14 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre lhs = ptr(track.loc(), true, std::move(lhs), std::move(rhs)); continue; } - case EXPR: { + case TAG__EXPR: { if (curr_prec >= Prec::App) return lhs; switch (ahead().tag()) { - case DECL: + case TAG__DECL: ast().warn(ahead().loc(), "you are passing a declaration expression as argument"); ast().note(lhs->loc(), "to this expression"); ast().note(ahead().loc(), - "if this was your intention, parenthesize the declaration expression"); + "if this was your intention, consider to parenthesize the declaration expression"); ast().note(lhs->loc().anew_finis(), "otherwise, you are probably missing a ';'"); default: break; } @@ -264,12 +266,12 @@ Ptr Parser::parse_insert_expr() { Ptr Parser::parse_primary_expr(std::string_view ctxt) { // clang-format off switch (ahead().tag()) { - case PRIMARY: return ptr(lex()); - case ID: return ptr(lex().dbg()); - case LIT: return parse_lit_expr(); - case DECL: return parse_decl_expr(); - case PI: return parse_pi_expr(); - case LAM: return parse_lam_expr(); + case TAG__PRIMARY: return ptr(lex()); + case TAG__ID: return ptr(lex().dbg()); + case TAG__LIT: return parse_lit_expr(); + case TAG__DECL: return parse_decl_expr(); + case TAG__PI: return parse_pi_expr(); + case TAG__LM: return parse_lam_expr(); case Tag::K_ins: return parse_insert_expr(); case Tag::K_ret: return parse_ret_expr(); case Tag::D_quote_l: return parse_arr_or_pack_expr(); @@ -365,7 +367,7 @@ Ptr Parser::parse_pi_expr() { doms.emplace_back(ptr(track, implicit, std::move(ptrn))); switch (ahead().tag()) { - case EXPR: + case TAG__EXPR: case Tag::T_backtick: continue; default: break; } @@ -566,11 +568,10 @@ Ptrs Parser::parse_decls() { switch (ahead().tag()) { case Tag::T_semicolon: lex(); break; // eat up stray semicolons case Tag::K_ax: decls.emplace_back(parse_axiom_decl()); break; - case Tag::K_grp: decls.emplace_back(ptr(lex().loc())); break; case Tag::K_ccon: case Tag::K_cfun: decls.emplace_back(parse_c_decl()); break; case Tag::K_let: decls.emplace_back(parse_let_decl()); break; - case Tag::K_rec: decls.emplace_back(parse_rec_decl()); break; + case Tag::K_rec: decls.emplace_back(parse_rec_decl(true)); break; case Tag::K_con: case Tag::K_fun: case Tag::K_lam: decls.emplace_back(parse_lam_decl()); break; @@ -626,14 +627,28 @@ Ptr Parser::parse_let_decl() { return ptr(track, std::move(ptrn), std::move(value)); } -Ptr Parser::parse_rec_decl() { +Ptr Parser::parse_c_decl() { + auto track = tracker(); + auto tag = lex().tag(); + auto id = expect(Tag::M_id, "C function declaration"); + auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Prec::App); + Ptr codom; + if (tag == Tag::K_cfun) { + expect(Tag::T_colon, "codomain of a C function"); + codom = parse_expr("codomain of a C function"); + } + return ptr(track, tag, id.dbg(), std::move(dom), std::move(codom)); +} + +Ptr Parser::parse_rec_decl(bool first) { auto track = tracker(); - eat(Tag::K_rec); + eat(first ? Tag::K_rec : Tag::K_and); auto dbg = parse_name("recursive declaration"); auto type = accept(Tag::T_colon) ? parse_expr("type of a recursive declaration") : ptr(prev_); expect(Tag::T_assign, "recursive declaration"); auto body = parse_expr("body of a recursive declaration"); - return ptr(track, dbg, std::move(type), std::move(body)); + auto next = ahead().isa(Tag::K_and) ? parse_and_decl() : nullptr; + return ptr(track, dbg, std::move(type), std::move(body), std::move(next)); } Ptr Parser::parse_lam_decl() { @@ -666,7 +681,7 @@ Ptr Parser::parse_lam_decl() { doms.emplace_back(ptr(track, implicit, std::move(ptrn), std::move(filter))); switch (ahead().tag()) { - case EXPR: + case TAG__EXPR: case Tag::T_backtick: continue; default: break; } @@ -679,21 +694,16 @@ Ptr Parser::parse_lam_decl() { expect(Tag::T_assign, "body of a "s + entity); auto body = parse_expr("body of a "s + entity); + auto next = ahead().isa(Tag::K_and) ? parse_and_decl() : nullptr; - return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body)); + return ptr(track, tag, external, dbg, std::move(doms), std::move(codom), std::move(body), std::move(next)); } -Ptr Parser::parse_c_decl() { - auto track = tracker(); - auto tag = lex().tag(); - auto id = expect(Tag::M_id, "C function declaration"); - auto dom = parse_ptrn(Tag::D_brckt_l, "domain of a C function"s, Prec::App); - Ptr codom; - if (tag == Tag::K_cfun) { - expect(Tag::T_colon, "codomain of a C function"); - codom = parse_expr("codomain of a C function"); +Ptr Parser::parse_and_decl() { + switch (ahead(1).tag()) { + case TAG__LAM: return lex(), parse_lam_decl(); + default: return parse_rec_decl(false); } - return ptr(track, tag, id.dbg(), std::move(dom), std::move(codom)); } } // namespace thorin::ast diff --git a/src/thorin/ast/stream.cpp b/src/thorin/ast/stream.cpp index d9167d474c..5167278547 100644 --- a/src/thorin/ast/stream.cpp +++ b/src/thorin/ast/stream.cpp @@ -42,7 +42,8 @@ std::ostream& Import::stream(Tab& tab, std::ostream& os) const { return tab.prin std::ostream& Module::stream(Tab& tab, std::ostream& os) const { for (const auto& import : imports()) import->stream(tab, os); - return decls_.stream(tab, os); + for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); + return os; } /* @@ -92,12 +93,11 @@ std::ostream& DeclExpr::stream(Tab& tab, std::ostream& os) const { if (where()) { tab.println(os, "{} .where", S(tab, expr())); ++tab; - decls_.stream(tab, os); + for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); --tab; return os; } else { - for (const auto& decl : decls_.decls()) tab.println(os, "{}", S(tab, decl.get())); - decls_.stream(tab, os); + for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); return print(os, "{}", S(tab, expr())); } } @@ -156,11 +156,6 @@ std::ostream& InsertExpr::stream(Tab& tab, std::ostream& os) const { * Decl */ -std::ostream& DeclsBlock::stream(Tab& tab, std::ostream& os) const { - for (const auto& decl : decls()) tab.println(os, "{}", S(tab, decl.get())); - return os; -} - std::ostream& AxiomDecl::Alias::stream(Tab&, std::ostream& os) const { return os << dbg(); } std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { @@ -180,8 +175,6 @@ std::ostream& AxiomDecl::stream(Tab& tab, std::ostream& os) const { return os << ";"; } -std::ostream& GrpDecl::stream(Tab&, std::ostream& os) const { return os << ".grp"; } - std::ostream& LetDecl::stream(Tab& tab, std::ostream& os) const { return print(os, ".let {} = {};", S(tab, ptrn()), S(tab, value())); } From c9de8cfaa78d99a70b0d22ba5affa56fcc4df425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 25 Apr 2024 17:01:18 +0200 Subject: [PATCH 84/95] make .where truly upside down * better error messages --- include/thorin/ast/ast.h | 8 ++++---- lit/regex/match_manual.thorin | 29 ++++++++++++++--------------- src/thorin/ast/bind.cpp | 5 ++++- src/thorin/ast/emit.cpp | 5 ++++- src/thorin/ast/parser.cpp | 5 +++++ src/thorin/ast/stream.cpp | 2 +- 6 files changed, 32 insertions(+), 22 deletions(-) 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())); From f0ba7d4f4474ab354902f75360554929e07e6fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Thu, 25 Apr 2024 22:18:34 +0200 Subject: [PATCH 85/95] cleanup --- include/thorin/plugin.h | 22 ++++++++------- src/thorin/ast/emit.cpp | 8 +++--- src/thorin/be/h/bootstrap.cpp | 50 +++++++++++++++++------------------ src/thorin/plugin.cpp | 12 ++++----- 4 files changed, 47 insertions(+), 45 deletions(-) diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index c74daeb040..f5df0ab2ea 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -51,14 +51,16 @@ THORIN_EXPORT thorin::Plugin thorin_get_plugin(); /// Holds info about an entity defined within a Plugin (called *Annex*). struct Annex { - Annex(Sym plugin, Sym tag, flags_t tag_id) - : plugin(plugin) - , tag(tag) - , tag_id(tag_id) {} - - Sym plugin; - Sym tag; - flags_t tag_id; + Annex(Sym sym_plugin, Sym sym_tag, flags_t id_tag) + : sym{sym_plugin, sym_tag} + , id{id_tag} {} + + struct { + Sym plugin, tag; + } sym; + struct { + flags_t tag; // switch to tag_t ? + } id; std::deque> subs; ///< List of subs which is a list of aliases. Sym normalizer; bool pi = false; @@ -86,11 +88,11 @@ struct Annex { /// | 54-63: | `0`-`9` | /// The 0 is special and marks the end of the name if the name has less than 8 chars. /// @returns `std::nullopt` if encoding is not possible. - static std::optional mangle(Sym s); + static std::optional mangle(Sym plugin); /// Reverts an Axiom::mangle%d string to a Sym. /// Ignores lower 16-bit of @p u. - static Sym demangle(Driver&, plugin_t u); + static Sym demangle(Driver&, plugin_t plugin); static std::tuple split(Driver&, Sym); ///@} diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 4007fdeeef..81cd837131 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -23,7 +23,7 @@ class Emitter { auto name = world().sym("%"s + plugin.str() + "."s + tag.str()); auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc()); plugin_t p = *Annex::mangle(plugin); - tag_t t = annex.tag_id; + tag_t t = annex.id.tag; sub_t s = annex.subs.size(); if (sub) { @@ -340,8 +340,8 @@ Ref InsertExpr::emit_(Emitter& e) const { */ void AxiomDecl::Alias::emit(Emitter& e, const Axiom* axiom) const { - const auto& id = axiom_->id_; - def_ = axiom; + /*const auto& id = axiom_->id_;*/ + def_ = axiom; } void AxiomDecl::emit(Emitter& e) const { @@ -369,7 +369,7 @@ void AxiomDecl::emit(Emitter& e) const { if (!is_new && annex.pi != (thorin_type_->isa() != nullptr)) error(dbg().loc(), "all declarations of annex '{}' have to be function types if any is", dbg().sym()); - id_.tag = annex.tag_id; + id_.tag = annex.id.tag; annex.pi = thorin_type_->isa() != nullptr; annex.normalizer = normalizer().sym(); diff --git a/src/thorin/be/h/bootstrap.cpp b/src/thorin/be/h/bootstrap.cpp index dcc4c96ade..6cab054cf6 100644 --- a/src/thorin/be/h/bootstrap.cpp +++ b/src/thorin/be/h/bootstrap.cpp @@ -3,7 +3,6 @@ #include #include -#include "thorin/axiom.h" #include "thorin/driver.h" namespace thorin { @@ -21,53 +20,53 @@ void bootstrap(Driver& driver, Sym plugin, std::ostream& h) { plugin_t plugin_id = *Annex::mangle(plugin); std::vector normalizers, outer_namespace; - tab.print(h << std::hex, "static constexpr plugin_t Plugin_Id = 0x{};\n\n", plugin_id); + tab.print(h, "static constexpr plugin_t Plugin_Id = 0x{x};\n\n", plugin_id); const auto& unordered = driver.plugin2annxes(plugin); std::deque> infos(unordered.begin(), unordered.end()); - std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.tag_id < p2.second.tag_id; }); + std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; }); // clang-format off - for (const auto& [key, ax] : infos) { - if (ax.plugin != plugin) continue; // this is from an import + for (const auto& [key, annex] : infos) { + if (annex.sym.plugin != plugin) continue; // this is from an import - tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, ax.tag); + tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, annex.sym.tag); tab.print(h, "#ifdef DOXYGEN // see https://github.com/doxygen/doxygen/issues/9668\n"); - tab.print(h, "enum {} : flags_t {{\n", ax.tag); + tab.print(h, "enum {} : flags_t {{\n", annex.sym.tag); tab.print(h, "#else\n"); - tab.print(h, "enum class {} : flags_t {{\n", ax.tag); + tab.print(h, "enum class {} : flags_t {{\n", annex.sym.tag); tab.print(h, "#endif\n"); ++tab; - flags_t ax_id = plugin_id | (ax.tag_id << 8u); + flags_t ax_id = plugin_id | (annex.id.tag << 8u); auto& os = outer_namespace.emplace_back(); - print(os << std::hex, "template<> constexpr flags_t Annex::Base = 0x{};\n", plugin, ax.tag, ax_id); + print(os, "template<> constexpr flags_t Annex::Base = 0x{x};\n", plugin, annex.sym.tag, ax_id); - if (auto& subs = ax.subs; !subs.empty()) { + if (auto& subs = annex.subs; !subs.empty()) { for (const auto& aliases : subs) { const auto& sub = aliases.front(); - tab.print(h, "{} = 0x{},\n", sub, ax_id++); + tab.print(h, "{} = 0x{x},\n", sub, ax_id++); for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub); - if (ax.normalizer) - print(normalizers.emplace_back(), "normalizers[flags_t({}::{})] = &{}<{}::{}>;", ax.tag, sub, - ax.normalizer, ax.tag, sub); + if (annex.normalizer) + print(normalizers.emplace_back(), "normalizers[flags_t({}::{})] = &{}<{}::{}>;", annex.sym.tag, sub, + annex.normalizer, annex.sym.tag, sub); } } else { - if (ax.normalizer) - print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", ax.tag, ax.normalizer); + if (annex.normalizer) + print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", annex.sym.tag, annex.normalizer); } --tab; tab.print(h, "}};\n\n"); - if (!ax.subs.empty()) tab.print(h, "THORIN_ENUM_OPERATORS({})\n", ax.tag); - print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, ax.tag, ax.subs.size()); + if (!annex.subs.empty()) tab.print(h, "THORIN_ENUM_OPERATORS({})\n", annex.sym.tag); + print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, annex.sym.tag, annex.subs.size()); - if (ax.normalizer) { - if (auto& subs = ax.subs; !subs.empty()) { - tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", ax.tag, ax.normalizer); + if (annex.normalizer) { + if (auto& subs = annex.subs; !subs.empty()) { + tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", annex.sym.tag, annex.normalizer); } else { - tab.print(h, "Ref {}(Ref, Ref, Ref);\n", ax.normalizer); + tab.print(h, "Ref {}(Ref, Ref, Ref);\n", annex.normalizer); } } tab.print(h, "///@}}\n\n"); @@ -94,8 +93,9 @@ void bootstrap(Driver& driver, Sym plugin, std::ostream& h) { // emit helpers for non-function axiom for (const auto& [tag, ax] : infos) { - if (ax.pi || ax.plugin != plugin) continue; // from function or other plugin? - tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", ax.plugin, ax.tag); + if (ax.pi || ax.sym.plugin != plugin) continue; // from function or other plugin? + tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", ax.sym.plugin, + ax.sym.tag); } tab.print(h, "#endif\n"); diff --git a/src/thorin/plugin.cpp b/src/thorin/plugin.cpp index 7861ec09c7..503160d02e 100644 --- a/src/thorin/plugin.cpp +++ b/src/thorin/plugin.cpp @@ -6,8 +6,8 @@ using namespace std::literals; namespace thorin { -std::optional Annex::mangle(Sym s) { - auto n = s.size(); +std::optional Annex::mangle(Sym plugin) { + auto n = plugin.size(); if (n > Max_Plugin_Size) return {}; u64 result = 0; @@ -15,7 +15,7 @@ std::optional Annex::mangle(Sym s) { u64 u = '\0'; if (i < n) { - auto c = s[i]; + auto c = plugin[i]; if (c == '_') u = 1; else if ('a' <= c && c <= 'z') @@ -34,10 +34,10 @@ std::optional Annex::mangle(Sym s) { return result << 16_u64; } -Sym Annex::demangle(Driver& driver, plugin_t u) { +Sym Annex::demangle(Driver& driver, plugin_t plugin) { std::string result; for (size_t i = 0; i != Max_Plugin_Size; ++i) { - u64 c = (u & 0xfc00000000000000_u64) >> 58_u64; + u64 c = (plugin & 0xfc00000000000000_u64) >> 58_u64; if (c == 0) return driver.sym(result); else if (c == 1) @@ -49,7 +49,7 @@ Sym Annex::demangle(Driver& driver, plugin_t u) { else result += '0' + ((char)c - 54); - u <<= 6_u64; + plugin <<= 6_u64; } return driver.sym(result); From 2d57ac2783cf004565e9b04f60b2c2618f7f55f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 26 Apr 2024 01:11:13 +0200 Subject: [PATCH 86/95] make actual input root module again --- include/thorin/ast/ast.h | 4 ++++ src/thorin/ast/bind.cpp | 1 + src/thorin/ast/emit.cpp | 3 ++- src/thorin/cli/main.cpp | 25 ++++++++++++------------- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 8b28607e0f..454e92766b 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -909,9 +909,12 @@ class Module : public Node { , imports_(std::move(imports)) , decls_(std::move(decls)) {} + const auto& implicit_imports() const { return implicit_imports_; } const auto& imports() const { return imports_; } const auto& decls() const { return decls_; } + void add_implicit_imports(Ptrs&& imports) const { implicit_imports_ = std::move(imports); } + void compile(AST&) const; void bind(AST&) const; void bind(Scopes&) const; @@ -920,6 +923,7 @@ class Module : public Node { std::ostream& stream(Tab&, std::ostream&) const override; private: + mutable Ptrs implicit_imports_; Ptrs imports_; Ptrs decls_; }; diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 6a345391f8..71be50ba47 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -80,6 +80,7 @@ void Module::bind(AST& ast) const { } void Module::bind(Scopes& s) const { + for (const auto& import : implicit_imports()) import->bind(s); for (const auto& import : imports()) import->bind(s); for (const auto& decl : decls()) decl->bind(s); } diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 81cd837131..42bd09380c 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -50,6 +50,7 @@ void Module::emit(AST& ast) const { void Module::emit(Emitter& e) const { auto _ = e.world().push(loc()); + for (const auto& import : implicit_imports()) import->emit(e); for (const auto& import : imports()) import->emit(e); for (const auto& decl : decls()) decl->emit(e); } @@ -339,7 +340,7 @@ Ref InsertExpr::emit_(Emitter& e) const { * Decl */ -void AxiomDecl::Alias::emit(Emitter& e, const Axiom* axiom) const { +void AxiomDecl::Alias::emit(Emitter&, const Axiom* axiom) const { /*const auto& id = axiom_->id_;*/ def_ = axiom; } diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 0c8098b9f7..1ddb062913 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -32,7 +32,7 @@ int main(int argc, char** argv) { bool dot_all_annexes = false; std::string input, prefix; std::string clang = sys::find_cmd("clang"); - std::vector inputs, search_paths; + std::vector plugins, search_paths; #ifdef THORIN_ENABLE_CHECKS std::vector breakpoints; #endif @@ -48,7 +48,7 @@ int main(int argc, char** argv) { | lyra::opt(show_version )["-v"]["--version" ]("Display version info and exit.") | lyra::opt(list_search_paths )["-l"]["--list-search-paths" ]("List search paths in order and exit.") | lyra::opt(clang, "clang" )["-c"]["--clang" ]("Path to clang executable (default: '" THORIN_WHICH " clang').") - | lyra::opt(inputs, "plugin" )["-p"]["--plugin" ]("Dynamically load plugin.") + | lyra::opt(plugins, "plugin" )["-p"]["--plugin" ]("Dynamically load plugin.") | lyra::opt(search_paths, "path" )["-P"]["--plugin-path" ]("Path to search for plugins.") | lyra::opt(inc_verbose )["-V"]["--verbose" ]("Verbose mode. Multiple -V options increase the verbosity. The maximum is 4.").cardinality(0, 4) | lyra::opt(opt, "level" )["-O"]["--optimize" ]("Optimization level (default: 2).") @@ -129,12 +129,10 @@ int main(int argc, char** argv) { // we always need standard plugins, as long as we are not in bootstrap mode if (!flags.bootstrap) { - inputs.insert(inputs.begin(), "compile"s); - if (opt >= 2) inputs.emplace_back("opt"s); + plugins.insert(plugins.begin(), "compile"s); + if (opt >= 2) plugins.emplace_back("opt"s); } - inputs.emplace_back(input); - try { auto path = fs::path(input); world.set(path.filename().replace_extension().string()); @@ -142,14 +140,15 @@ int main(int argc, char** argv) { auto ast = ast::AST(world); auto parser = ast::Parser(ast); ast::Ptrs imports; - for (size_t i = 0, e = inputs.size(); i != e; ++i) { - auto input = inputs[i]; - auto tag = i + 1 == e ? ast::Tok::Tag::K_import : ast::Tok::Tag::K_plugin; - auto mod = i + 1 == e ? parser.import(driver.sym(input), os[Md]) : parser.plugin(input); - imports.emplace_back(ast.ptr(Loc(), tag, Dbg(driver.sym(input)), std::move(mod))); - } - auto mod = ast.ptr(imports.back()->loc(), std::move(imports), ast::Ptrs()); + for (const auto& plugin : plugins) { + auto mod = parser.plugin(plugin); + auto import + = ast.ptr(Loc(), ast::Tok::Tag::K_plugin, Dbg(driver.sym(plugin)), std::move(mod)); + imports.emplace_back(std::move(import)); + } + auto mod = parser.import(driver.sym(input), os[Md]); + mod->add_implicit_imports(std::move(imports)); mod->compile(ast); if (auto s = os[AST]) { From 16e96b05c9647ed3487b888e21e98540971008a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 26 Apr 2024 01:47:10 +0200 Subject: [PATCH 87/95] move bootstrap stuff to AST --- include/thorin/ast/ast.h | 9 +++ include/thorin/be/h/bootstrap.h | 13 ---- include/thorin/driver.h | 7 --- src/thorin/CMakeLists.txt | 1 - src/thorin/ast/ast.cpp | 108 ++++++++++++++++++++++++++++++++ src/thorin/ast/emit.cpp | 4 +- src/thorin/be/h/bootstrap.cpp | 105 ------------------------------- src/thorin/cli/main.cpp | 7 ++- src/thorin/driver.cpp | 9 --- 9 files changed, 123 insertions(+), 140 deletions(-) delete mode 100644 include/thorin/be/h/bootstrap.h delete mode 100644 src/thorin/be/h/bootstrap.cpp diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 454e92766b..029234c75b 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -63,6 +63,14 @@ class AST { // clang-format on ///@} + /// @name Manage Annex + ///@{ + std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); + const auto& plugin2annxes(Sym plugin) { return plugin2annexes_[plugin]; } + ///@} + + void bootstrap(Sym plugin, std::ostream& h); + friend void swap(AST& a1, AST& a2) noexcept { using std::swap; // clang-format off @@ -76,6 +84,7 @@ class AST { World* world_ = nullptr; fe::Arena arena_; mutable Error err_; + fe::SymMap> plugin2annexes_; }; class Node : public fe::RuntimeCast { diff --git a/include/thorin/be/h/bootstrap.h b/include/thorin/be/h/bootstrap.h deleted file mode 100644 index a0820affb6..0000000000 --- a/include/thorin/be/h/bootstrap.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -#include "thorin/util/dbg.h" - -namespace thorin { - -class Driver; - -void bootstrap(Driver&, Sym, std::ostream&); - -} // namespace thorin diff --git a/include/thorin/driver.h b/include/thorin/driver.h index 2449732934..bd6a16f514 100644 --- a/include/thorin/driver.h +++ b/include/thorin/driver.h @@ -76,12 +76,6 @@ class Driver : public fe::SymPool { auto backend(std::string_view name) { return lookup(backends_, name); } ///@} - /// @name Manage Annex - ///@{ - const auto& plugin2annxes(Sym plugin) { return plugin2annexes_[plugin]; } - std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); - ///@} - private: // This must go *first* so plugins will be unloaded *last* in the d'tor; otherwise funny things might happen ... absl::node_hash_map plugins_; @@ -94,7 +88,6 @@ class Driver : public fe::SymPool { Passes passes_; Normalizers normalizers_; std::deque> imports_; - fe::SymMap> plugin2annexes_; }; #define GET_FUN_PTR(plugin, f) get_fun_ptr(plugin, #f) diff --git a/src/thorin/CMakeLists.txt b/src/thorin/CMakeLists.txt index 039c20647b..b74d02589a 100644 --- a/src/thorin/CMakeLists.txt +++ b/src/thorin/CMakeLists.txt @@ -20,7 +20,6 @@ target_sources(libthorin analyses/looptree.cpp analyses/schedule.cpp analyses/scope.cpp - be/h/bootstrap.cpp ast/ast.cpp ast/bind.cpp ast/emit.cpp diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 60a882e858..28b1268b64 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -10,6 +10,114 @@ AST::~AST() { driver().WLOG("{} warning(s) encountered while compiling module\n{}", error().num_warnings(), error()); } +std::pair AST::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { + auto& annexes = plugin2annexes_[plugin]; + if (annexes.size() > std::numeric_limits::max()) + error(loc, "exceeded maxinum number of axioms in current plugin"); + + auto [it, is_new] = annexes.emplace(sym, Annex{plugin, tag, annexes.size()}); + return {it->second, is_new}; +} + +void AST::bootstrap(Sym plugin, std::ostream& h) { + Tab tab; + tab.print(h, "#pragma once\n\n"); + tab.print(h, "#include \n" + "#include \n\n"); + + tab.print(h, "/// @namespace thorin::plug::{} @ref {} \n", plugin, plugin); + tab.print(h, "namespace thorin {{\n"); + tab.print(h, "namespace plug::{} {{\n\n", plugin); + + plugin_t plugin_id = *Annex::mangle(plugin); + std::vector normalizers, outer_namespace; + + tab.print(h, "static constexpr plugin_t Plugin_Id = 0x{x};\n\n", plugin_id); + + const auto& unordered = plugin2annxes(plugin); + std::deque> infos(unordered.begin(), unordered.end()); + std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; }); + + // clang-format off + for (const auto& [key, annex] : infos) { + if (annex.sym.plugin != plugin) continue; // this is from an import + + tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, annex.sym.tag); + tab.print(h, "#ifdef DOXYGEN // see https://github.com/doxygen/doxygen/issues/9668\n"); + tab.print(h, "enum {} : flags_t {{\n", annex.sym.tag); + tab.print(h, "#else\n"); + tab.print(h, "enum class {} : flags_t {{\n", annex.sym.tag); + tab.print(h, "#endif\n"); + ++tab; + flags_t ax_id = plugin_id | (annex.id.tag << 8u); + + auto& os = outer_namespace.emplace_back(); + print(os, "template<> constexpr flags_t Annex::Base = 0x{x};\n", plugin, annex.sym.tag, ax_id); + + if (auto& subs = annex.subs; !subs.empty()) { + for (const auto& aliases : subs) { + const auto& sub = aliases.front(); + tab.print(h, "{} = 0x{x},\n", sub, ax_id++); + for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub); + + if (annex.normalizer) + print(normalizers.emplace_back(), "normalizers[flags_t({}::{})] = &{}<{}::{}>;", annex.sym.tag, sub, + annex.normalizer, annex.sym.tag, sub); + } + } else { + if (annex.normalizer) + print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", annex.sym.tag, annex.normalizer); + } + --tab; + tab.print(h, "}};\n\n"); + + if (!annex.subs.empty()) tab.print(h, "THORIN_ENUM_OPERATORS({})\n", annex.sym.tag); + print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, annex.sym.tag, annex.subs.size()); + + if (annex.normalizer) { + if (auto& subs = annex.subs; !subs.empty()) { + tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", annex.sym.tag, annex.normalizer); + } else { + tab.print(h, "Ref {}(Ref, Ref, Ref);\n", annex.normalizer); + } + } + tab.print(h, "///@}}\n\n"); + } + // clang-format on + + if (!normalizers.empty()) { + tab.print(h, "void register_normalizers(Normalizers& normalizers);\n\n"); + tab.print(h, "#define THORIN_{}_NORMALIZER_IMPL \\\n", plugin); + ++tab; + tab.print(h, "void register_normalizers(Normalizers& normalizers) {{\\\n"); + ++tab; + for (const auto& normalizer : normalizers) tab.print(h, "{} \\\n", normalizer.str()); + --tab; + tab.print(h, "}}\n"); + --tab; + } + + tab.print(h, "}} // namespace plug::{}\n\n", plugin); + + tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n"); + for (const auto& line : outer_namespace) tab.print(h, "{}", line.str()); + tab.print(h, "\n"); + + // emit helpers for non-function axiom + for (const auto& [tag, ax] : infos) { + if (ax.pi || ax.sym.plugin != plugin) continue; // from function or other plugin? + tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", ax.sym.plugin, + ax.sym.tag); + } + + tab.print(h, "#endif\n"); + tab.print(h, "}} // namespace thorin\n"); +} + +/* + * Other + */ + LamExpr::LamExpr(Ptr&& lam) : Expr(lam->loc()) , lam_(std::move(lam)) {} diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 42bd09380c..a2643961dd 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -21,7 +21,7 @@ class Emitter { if (dbg && dbg.sym().front() == '%') { auto [plugin, tag, sub] = Annex::split(driver(), dbg.sym()); auto name = world().sym("%"s + plugin.str() + "."s + tag.str()); - auto&& [annex, is_new] = driver().name2annex(name, plugin, tag, dbg.loc()); + auto&& [annex, is_new] = ast().name2annex(name, plugin, tag, dbg.loc()); plugin_t p = *Annex::mangle(plugin); tag_t t = annex.id.tag; sub_t s = annex.subs.size(); @@ -347,7 +347,7 @@ void AxiomDecl::Alias::emit(Emitter&, const Axiom* axiom) const { void AxiomDecl::emit(Emitter& e) const { auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym()); - auto&& [annex, is_new] = e.driver().name2annex(dbg().sym(), plugin_s, tag_s, dbg().loc()); + auto&& [annex, is_new] = e.ast().name2annex(dbg().sym(), plugin_s, tag_s, dbg().loc()); thorin_type_ = type()->emit(e); auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); diff --git a/src/thorin/be/h/bootstrap.cpp b/src/thorin/be/h/bootstrap.cpp deleted file mode 100644 index 6cab054cf6..0000000000 --- a/src/thorin/be/h/bootstrap.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "thorin/be/h/bootstrap.h" - -#include -#include - -#include "thorin/driver.h" - -namespace thorin { - -void bootstrap(Driver& driver, Sym plugin, std::ostream& h) { - Tab tab; - tab.print(h, "#pragma once\n\n"); - tab.print(h, "#include \n" - "#include \n\n"); - - tab.print(h, "/// @namespace thorin::plug::{} @ref {} \n", plugin, plugin); - tab.print(h, "namespace thorin {{\n"); - tab.print(h, "namespace plug::{} {{\n\n", plugin); - - plugin_t plugin_id = *Annex::mangle(plugin); - std::vector normalizers, outer_namespace; - - tab.print(h, "static constexpr plugin_t Plugin_Id = 0x{x};\n\n", plugin_id); - - const auto& unordered = driver.plugin2annxes(plugin); - std::deque> infos(unordered.begin(), unordered.end()); - std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; }); - - // clang-format off - for (const auto& [key, annex] : infos) { - if (annex.sym.plugin != plugin) continue; // this is from an import - - tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, annex.sym.tag); - tab.print(h, "#ifdef DOXYGEN // see https://github.com/doxygen/doxygen/issues/9668\n"); - tab.print(h, "enum {} : flags_t {{\n", annex.sym.tag); - tab.print(h, "#else\n"); - tab.print(h, "enum class {} : flags_t {{\n", annex.sym.tag); - tab.print(h, "#endif\n"); - ++tab; - flags_t ax_id = plugin_id | (annex.id.tag << 8u); - - auto& os = outer_namespace.emplace_back(); - print(os, "template<> constexpr flags_t Annex::Base = 0x{x};\n", plugin, annex.sym.tag, ax_id); - - if (auto& subs = annex.subs; !subs.empty()) { - for (const auto& aliases : subs) { - const auto& sub = aliases.front(); - tab.print(h, "{} = 0x{x},\n", sub, ax_id++); - for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub); - - if (annex.normalizer) - print(normalizers.emplace_back(), "normalizers[flags_t({}::{})] = &{}<{}::{}>;", annex.sym.tag, sub, - annex.normalizer, annex.sym.tag, sub); - } - } else { - if (annex.normalizer) - print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", annex.sym.tag, annex.normalizer); - } - --tab; - tab.print(h, "}};\n\n"); - - if (!annex.subs.empty()) tab.print(h, "THORIN_ENUM_OPERATORS({})\n", annex.sym.tag); - print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, annex.sym.tag, annex.subs.size()); - - if (annex.normalizer) { - if (auto& subs = annex.subs; !subs.empty()) { - tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", annex.sym.tag, annex.normalizer); - } else { - tab.print(h, "Ref {}(Ref, Ref, Ref);\n", annex.normalizer); - } - } - tab.print(h, "///@}}\n\n"); - } - // clang-format on - - if (!normalizers.empty()) { - tab.print(h, "void register_normalizers(Normalizers& normalizers);\n\n"); - tab.print(h, "#define THORIN_{}_NORMALIZER_IMPL \\\n", plugin); - ++tab; - tab.print(h, "void register_normalizers(Normalizers& normalizers) {{\\\n"); - ++tab; - for (const auto& normalizer : normalizers) tab.print(h, "{} \\\n", normalizer.str()); - --tab; - tab.print(h, "}}\n"); - --tab; - } - - tab.print(h, "}} // namespace plug::{}\n\n", plugin); - - tab.print(h, "#ifndef DOXYGEN // don't include in Doxygen documentation\n"); - for (const auto& line : outer_namespace) tab.print(h, "{}", line.str()); - tab.print(h, "\n"); - - // emit helpers for non-function axiom - for (const auto& [tag, ax] : infos) { - if (ax.pi || ax.sym.plugin != plugin) continue; // from function or other plugin? - tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", ax.sym.plugin, - ax.sym.tag); - } - - tab.print(h, "#endif\n"); - tab.print(h, "}} // namespace thorin\n"); -} - -} // namespace thorin diff --git a/src/thorin/cli/main.cpp b/src/thorin/cli/main.cpp index 1ddb062913..e672c9b2d4 100644 --- a/src/thorin/cli/main.cpp +++ b/src/thorin/cli/main.cpp @@ -10,7 +10,6 @@ #include "thorin/driver.h" #include "thorin/ast/parser.h" -#include "thorin/be/h/bootstrap.h" #include "thorin/pass/optimize.h" #include "thorin/phase/phase.h" #include "thorin/util/sys.h" @@ -171,8 +170,10 @@ int main(int argc, char** argv) { } if (flags.bootstrap) { - if (auto h = os[H]) - bootstrap(driver, world.sym(fs::path{path}.filename().replace_extension().string()), *h); + if (auto h = os[H]) { + auto plugin = world.sym(fs::path{path}.filename().replace_extension().string()); + ast.bootstrap(plugin, *h); + } opt = std::min(opt, 1); } diff --git a/src/thorin/driver.cpp b/src/thorin/driver.cpp index e90621999e..cb498d0728 100644 --- a/src/thorin/driver.cpp +++ b/src/thorin/driver.cpp @@ -93,13 +93,4 @@ void* Driver::get_fun_ptr(Sym plugin, const char* name) { return nullptr; } -std::pair Driver::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { - auto& annexes = plugin2annexes_[plugin]; - if (annexes.size() > std::numeric_limits::max()) - error(loc, "exceeded maxinum number of axioms in current plugin"); - - auto [it, is_new] = annexes.emplace(sym, Annex{plugin, tag, annexes.size()}); - return {it->second, is_new}; -} - } // namespace thorin From 3d55ecd43bed53a02faa5a2b2f58e0314c17f285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 26 Apr 2024 12:00:19 +0200 Subject: [PATCH 88/95] cleanup --- include/thorin/ast/ast.h | 4 ++-- include/thorin/driver.h | 4 ++-- include/thorin/plugin.h | 4 ++-- src/thorin/ast/ast.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 029234c75b..a4f6af32b3 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -66,7 +66,7 @@ class AST { /// @name Manage Annex ///@{ std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); - const auto& plugin2annxes(Sym plugin) { return plugin2annexes_[plugin]; } + const auto& plugin2annexes(Sym plugin) { return plugin2sym2annex_[plugin]; } ///@} void bootstrap(Sym plugin, std::ostream& h); @@ -84,7 +84,7 @@ class AST { World* world_ = nullptr; fe::Arena arena_; mutable Error err_; - fe::SymMap> plugin2annexes_; + absl::node_hash_map> plugin2sym2annex_; }; class Node : public fe::RuntimeCast { diff --git a/include/thorin/driver.h b/include/thorin/driver.h index bd6a16f514..f91bf696d6 100644 --- a/include/thorin/driver.h +++ b/include/thorin/driver.h @@ -2,14 +2,14 @@ #include +#include + #include "thorin/flags.h" #include "thorin/plugin.h" #include "thorin/world.h" #include "thorin/util/log.h" -#include "absl/container/node_hash_map.h" - namespace thorin { /// Some "global" variables needed all over the place. diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index f5df0ab2ea..3d691249c4 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -51,7 +51,7 @@ THORIN_EXPORT thorin::Plugin thorin_get_plugin(); /// Holds info about an entity defined within a Plugin (called *Annex*). struct Annex { - Annex(Sym sym_plugin, Sym sym_tag, flags_t id_tag) + Annex(Sym sym_plugin, Sym sym_tag, tag_t id_tag) : sym{sym_plugin, sym_tag} , id{id_tag} {} @@ -59,7 +59,7 @@ struct Annex { Sym plugin, tag; } sym; struct { - flags_t tag; // switch to tag_t ? + tag_t tag; } id; std::deque> subs; ///< List of subs which is a list of aliases. Sym normalizer; diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 28b1268b64..e2c4eadb8b 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -11,7 +11,7 @@ AST::~AST() { } std::pair AST::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { - auto& annexes = plugin2annexes_[plugin]; + auto& annexes = plugin2sym2annex_[plugin]; if (annexes.size() > std::numeric_limits::max()) error(loc, "exceeded maxinum number of axioms in current plugin"); @@ -34,7 +34,7 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { tab.print(h, "static constexpr plugin_t Plugin_Id = 0x{x};\n\n", plugin_id); - const auto& unordered = plugin2annxes(plugin); + const auto& unordered = plugin2annexes(plugin); std::deque> infos(unordered.begin(), unordered.end()); std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; }); From fcd88847ba11911144f4abaf4c722401bb436864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Fri, 26 Apr 2024 23:21:26 +0200 Subject: [PATCH 89/95] wip: cleanup annex magic --- include/thorin/ast/ast.h | 14 +++------- include/thorin/plugin.h | 11 +++++--- src/thorin/ast/ast.cpp | 29 ++++++++++++++++++++- src/thorin/ast/bind.cpp | 11 ++------ src/thorin/ast/emit.cpp | 56 +++++++++++++++++----------------------- 5 files changed, 64 insertions(+), 57 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index a4f6af32b3..21d2f82068 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -48,6 +48,7 @@ class AST { Sym sym(const std::string& s) { return driver().sym(s); } Sym sym_anon() { return sym("_"); } ///< `"_"`. Sym sym_return() { return sym("return"); } ///< `"return"`. + Sym sym_error() { return sym("_error_"); } ///< `"_error_"`. ///@} template auto ptr(Args&&... args) { @@ -65,6 +66,7 @@ class AST { /// @name Manage Annex ///@{ + Annex& name2annex(Dbg dbg); std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); const auto& plugin2annexes(Sym plugin) { return plugin2sym2annex_[plugin]; } ///@} @@ -705,14 +707,11 @@ class AxiomDecl : public ValDecl { Dbg dbg() const { return dbg_; } void bind(Scopes&, const AxiomDecl*) const; - void emit(Emitter&, const Axiom*) const; std::ostream& stream(Tab&, std::ostream&) const override; private: Dbg dbg_; mutable Dbg full_; - mutable const AxiomDecl* axiom_ = nullptr; - mutable sub_t sub_ = 0; friend class AxiomDecl; }; @@ -745,14 +744,7 @@ class AxiomDecl : public ValDecl { Ptr type_; Dbg normalizer_; Tok curry_, trip_; - mutable struct { - Sym plugin, tag, sub; - } sym_; - mutable struct { - plugin_t plugin = 0; - tag_t tag = 0; - uint8_t curry, trip; - } id_; + mutable Annex* annex_ = nullptr; mutable Ref thorin_type_; }; diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index 3d691249c4..5db190ad29 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -51,19 +51,24 @@ THORIN_EXPORT thorin::Plugin thorin_get_plugin(); /// Holds info about an entity defined within a Plugin (called *Annex*). struct Annex { - Annex(Sym sym_plugin, Sym sym_tag, tag_t id_tag) + Annex(Sym sym_plugin, Sym sym_tag, plugin_t id_plugin, tag_t id_tag) : sym{sym_plugin, sym_tag} - , id{id_tag} {} + , id{id_plugin, id_tag, 0, 0} { + assert(mangle(sym_plugin) == id_plugin); + } struct { Sym plugin, tag; } sym; struct { + plugin_t plugin; tag_t tag; + uint8_t curry, trip; } id; std::deque> subs; ///< List of subs which is a list of aliases. Sym normalizer; - bool pi = false; + bool pi = false; + bool fresh = true; /// @name Mangling Plugin Name ///@{ diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index e2c4eadb8b..0cdf6f6c6b 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -10,12 +10,39 @@ AST::~AST() { driver().WLOG("{} warning(s) encountered while compiling module\n{}", error().num_warnings(), error()); } +Annex& AST::name2annex(Dbg dbg) { + auto [plugin_s, tag_s, sub_s] = Annex::split(driver(), dbg.sym()); + auto& sym2annex = plugin2sym2annex_[plugin_s]; + auto tag_id = sym2annex.size(); + + if (plugin_s == sym_error()) error(dbg.loc(), "plugin name '{}' is reserved", dbg); + if (tag_id > std::numeric_limits::max()) + error(dbg.loc(), "exceeded maxinum number of annexes in current plugin"); + + plugin_t plugin_id; + if (auto p = Annex::mangle(plugin_s)) + plugin_id = *p; + else { + error(dbg.loc(), "invalid annex name '{}'", dbg); + plugin_s = sym_error(); + plugin_id = *Annex::mangle(plugin_s); + } + + if (sub_s) error(dbg.loc(), "annex '{}' must not have a subtag", dbg); + + auto [i, fresh] = sym2annex.emplace(dbg.sym(), Annex{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()}); + auto& annex = i->second; + if (!fresh) annex.fresh = false; + return annex; +} + std::pair AST::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { auto& annexes = plugin2sym2annex_[plugin]; if (annexes.size() > std::numeric_limits::max()) error(loc, "exceeded maxinum number of axioms in current plugin"); - auto [it, is_new] = annexes.emplace(sym, Annex{plugin, tag, annexes.size()}); + auto plugin_id = *Annex::mangle(plugin); + auto [it, is_new] = annexes.emplace(sym, Annex{plugin, tag, plugin_id, (tag_t)annexes.size()}); return {it->second, is_new}; } diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 71be50ba47..a2c80e7ba5 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -217,7 +217,6 @@ void InsertExpr::bind(Scopes& s) const { */ void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { - axiom_ = axiom; auto sym = s.ast().sym(axiom->dbg().sym().str() + "."s + dbg().sym().str()); full_ = Dbg(dbg().loc(), sym); s.bind(full_, this); @@ -225,15 +224,9 @@ void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { void AxiomDecl::bind(Scopes& s) const { type()->bind(s); + annex_ = &s.ast().name2annex(dbg()); - std::tie(sym_.plugin, sym_.tag, sym_.sub) = Annex::split(s.driver(), dbg().sym()); - - if (auto p = Annex::mangle(sym_.plugin)) - id_.plugin = *p; - else - s.ast().error(dbg().loc(), "invalid axiom name '{}'", dbg()); - - if (sym_.sub) error(dbg().loc(), "axiom '{}' must not have a subtag", dbg().sym()); + annex_->normalizer = normalizer().sym(); // TODO error checking if (num_subs() == 0) { s.bind(dbg(), this); diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index a2643961dd..42017c5e1d 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -340,57 +340,47 @@ Ref InsertExpr::emit_(Emitter& e) const { * Decl */ -void AxiomDecl::Alias::emit(Emitter&, const Axiom* axiom) const { - /*const auto& id = axiom_->id_;*/ - def_ = axiom; -} - void AxiomDecl::emit(Emitter& e) const { - auto [plugin_s, tag_s, sub_s] = Annex::split(e.driver(), dbg().sym()); - auto&& [annex, is_new] = e.ast().name2annex(dbg().sym(), plugin_s, tag_s, dbg().loc()); - thorin_type_ = type()->emit(e); - auto [i_curry, i_trip] = Axiom::infer_curry_and_trip(thorin_type_); + thorin_type_ = type()->emit(e); + annex_->pi = thorin_type_->isa() != nullptr; + auto& id = annex_->id; + std::tie(id.curry, id.trip) = Axiom::infer_curry_and_trip(thorin_type_); if (curry_) { - id_.curry = curry_.lit_u(); - if (id_.curry > i_curry) error(curry_.loc(), "curry counter cannot be greater than {}", (int)i_curry); - } else { - id_.curry = i_curry; + if (curry_.lit_u() > id.curry) + error(curry_.loc(), "curry counter cannot be greater than {}", id.curry); + else + id.curry = curry_.lit_u(); } if (trip_) { - id_.trip = trip_.lit_u(); - if (id_.trip > id_.curry) - error(curry_.loc(), "trip counter '{}' cannot be greater than curry counter '{}'", (int)id_.trip, - (int)id_.curry); - } else { - id_.trip = i_trip; + if (trip_.lit_u() > id.curry) + error(trip_.loc(), "trip counter cannot be greater than curry counter '{}'", (int)id.curry); + else + id.trip = trip_.lit_u(); } +#if 0 if (!is_new && annex.pi != (thorin_type_->isa() != nullptr)) error(dbg().loc(), "all declarations of annex '{}' have to be function types if any is", dbg().sym()); - - id_.tag = annex.id.tag; - annex.pi = thorin_type_->isa() != nullptr; - annex.normalizer = normalizer().sym(); +#endif if (num_subs() == 0) { - auto norm = e.driver().normalizer(id_.plugin, id_.tag, 0); - auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, 0)->set(dbg()); + auto norm = e.driver().normalizer(id.plugin, id.tag, 0); + auto axiom = e.world().axiom(norm, id.curry, id.trip, thorin_type_, id.plugin, id.tag, 0)->set(dbg()); def_ = axiom; - e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64), axiom); + e.world().register_annex(id.plugin | (flags_t(id.tag) << 8_u64), axiom); } else { - sub_t offset = annex.subs.size(); + sub_t offset = annex_->subs.size(); for (sub_t i = 0, n = num_subs(); i != n; ++i) { + auto& aliases = annex_->subs.emplace_back(std::deque()); sub_t s = i + offset; - auto norm = e.driver().normalizer(id_.plugin, id_.tag, s); - auto& aliases = annex.subs.emplace_back(std::deque()); + auto norm = e.driver().normalizer(id.plugin, id.tag, s); auto name = e.world().sym(dbg().sym().str() + "."s + sub(i).front()->dbg().sym().str()); - auto axiom = e.world().axiom(norm, id_.curry, id_.trip, thorin_type_, id_.plugin, id_.tag, s)->set(name); - e.world().register_annex(id_.plugin | (flags_t(id_.tag) << 8_u64) | flags_t(s), axiom); + auto axiom = e.world().axiom(norm, id.curry, id.trip, thorin_type_, id.plugin, id.tag, s)->set(name); + e.world().register_annex(id.plugin | (flags_t(id.tag) << 8_u64) | flags_t(s), axiom); for (const auto& alias : sub(i)) { - alias->sub_ = s; - alias->emit(e, axiom); + alias->def_ = axiom; aliases.emplace_back(alias->dbg().sym()); } } From caf78d9d5de9eb6172c96f1a6b965238cba87f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 27 Apr 2024 01:31:41 +0200 Subject: [PATCH 90/95] deprecated BlockExpr * added warning * polished error handling --- include/thorin/util/dbg.h | 25 +++++--------- src/thorin/ast/ast.cpp | 6 ++-- src/thorin/ast/bind.cpp | 2 ++ src/thorin/ast/parser.cpp | 2 ++ src/thorin/plug/clos/clos.thorin | 48 ++++++++++++-------------- src/thorin/plug/compile/compile.thorin | 16 ++++----- src/thorin/plug/direct/direct.thorin | 13 ++++--- src/thorin/plug/matrix/matrix.thorin | 13 ++++--- src/thorin/plug/mem/mem.thorin | 11 +++--- src/thorin/plug/opt/opt.thorin | 32 ++++++++--------- src/thorin/util/dbg.cpp | 20 +++++++++++ 11 files changed, 97 insertions(+), 91 deletions(-) diff --git a/include/thorin/util/dbg.h b/include/thorin/util/dbg.h index caf5b0ba89..45c40d802b 100644 --- a/include/thorin/util/dbg.h +++ b/include/thorin/util/dbg.h @@ -60,21 +60,6 @@ class Error : std::exception { size_t num_notes() const { return num_notes_; } ///@} - void clear() { - num_errors_ = 0; - num_warnings_ = 0; - num_notes_ = 0; - msgs_.clear(); - } - - /// If errors occured, claim them and throw. - void ack() { - if (num_errors() != 0) { - auto errors = std::move(*this); - throw errors; - } - } - /// @name Add formatted message ///@{ template Error& msg(Loc loc, Tag tag, const char* s, Args&&... args) { @@ -89,7 +74,14 @@ class Error : std::exception { assert(num_errors() > 0 || num_warnings() > 0); /* */ ++num_notes_; return msg(loc, Tag::Note, s, std::forward(args)...); } // clang-format on - //@} + ///@} + + /// @name Handle Errors/Warnings + ///@{ + void clear(); + /// If errors occured, claim them and throw; if warnings occured, claim them and report to @p os. + void ack(std::ostream& os = std::cerr); + ///@} friend std::ostream& operator<<(std::ostream& o, Tag tag) { // clang-format off @@ -109,7 +101,6 @@ class Error : std::exception { friend void swap(Error& e1, Error& e2) noexcept { using std::swap; - ; // clang-format off swap(e1.msgs_, e2.msgs_); swap(e1.num_errors_, e2.num_errors_); diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 0cdf6f6c6b..948fc9e437 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -5,9 +5,8 @@ namespace thorin::ast { AST::~AST() { - assert(error().num_errors() == 0 && "please encounter any errors before destroying this class"); - if (error().num_warnings() != 0) - driver().WLOG("{} warning(s) encountered while compiling module\n{}", error().num_warnings(), error()); + assert(error().num_errors() == 0 && error().num_warnings() == 0 + && "please encounter any errors before destroying this class"); } Annex& AST::name2annex(Dbg dbg) { @@ -173,6 +172,7 @@ void Module::compile(AST& ast) const { bind(ast); ast.error().ack(); emit(ast); + if (ast.error().num_warnings() != 0) std::cerr << ast.error(); } AST load_plugins(World& world, View plugins) { diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index a2c80e7ba5..0bc6f21636 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -245,7 +245,9 @@ void AxiomDecl::bind(Scopes& s) const { } void LetDecl::bind(Scopes& s) const { + s.push(); value()->bind(s); + s.pop(); ptrn()->bind(s); } diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index a8220673fa..a4b3b66abe 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -318,6 +318,8 @@ Ptr Parser::parse_block_expr() { eat(Tag::D_brace_l); auto expr = parse_expr("final expression in a block expression"); expect(Tag::D_brace_r, "block expression"); + ast().warn(track, "block expression is deprecated; use a (possibly parenthesized) declaration expression instead"); + return ptr(track, std::move(expr)); } diff --git a/src/thorin/plug/clos/clos.thorin b/src/thorin/plug/clos/clos.thorin index a2bdc06337..20660cbb8a 100644 --- a/src/thorin/plug/clos/clos.thorin +++ b/src/thorin/plug/clos/clos.thorin @@ -42,28 +42,28 @@ .ax %clos.clos_conv_phase: %compile.Phase; .ax %clos.lower_typed_clos_phase: %compile.Phase; -.let clos_opt1_phase = { - .let eta_red = %clos.eta_red_bool_pass .tt; - .let eta_exp = %compile.eta_exp_pass eta_red; - %compile.pass_phase (%compile.pass_list - eta_red - eta_exp - (%compile.scalerize_pass eta_exp) - ) -}; -.let clos_opt2_phase = { - .let nullptr = %compile.nullptr_pass; - %compile.pass_phase (%compile.pass_list - nullptr - (%compile.scalerize_pass nullptr) - %clos.branch_clos_pass - (%mem.copy_prop_pass (nullptr, nullptr, .tt)) - %clos.lower_typed_clos_prep_pass - %clos.clos2sjlj_pass - ) -}; -.let clos_phases = { - .let nullptr = %compile.nullptr_pass; +.let clos_opt1_phase = + .let eta_red = %clos.eta_red_bool_pass .tt; + .let eta_exp = %compile.eta_exp_pass eta_red; + %compile.pass_phase (%compile.pass_list + eta_red + eta_exp + (%compile.scalerize_pass eta_exp) + ); + +.let clos_opt2_phase = + .let nullptr = %compile.nullptr_pass; + %compile.pass_phase + (%compile.pass_list + nullptr + (%compile.scalerize_pass nullptr) + %clos.branch_clos_pass + (%mem.copy_prop_pass (nullptr, nullptr, .tt)) + %clos.lower_typed_clos_prep_pass + %clos.clos2sjlj_pass); + +.let clos_phases = + .let nullptr = %compile.nullptr_pass; %compile.combined_phase (%compile.phase_list (%compile.single_pass_phase nullptr) @@ -75,6 +75,4 @@ %clos.clos_conv_phase clos_opt1_phase clos_opt2_phase - %clos.lower_typed_clos_phase - ) -}; + %clos.lower_typed_clos_phase); diff --git a/src/thorin/plug/compile/compile.thorin b/src/thorin/plug/compile/compile.thorin index 08a99749af..2b0530129b 100644 --- a/src/thorin/plug/compile/compile.thorin +++ b/src/thorin/plug/compile/compile.thorin @@ -116,7 +116,7 @@ /// ### Phases /// // TODO: allow functions by inlining them first -.let optimization_pass_list = { +.let optimization_pass_list = .let eta_red = %compile.eta_red_pass; .let eta_exp = %compile.eta_exp_pass eta_red; %compile.pass_list @@ -124,15 +124,13 @@ eta_red eta_exp (%compile.scalerize_pass eta_exp) - (%compile.tail_rec_elim_pass eta_red) -}; -.let optimization_phase = { - %compile.pass_phase optimization_pass_list -}; + (%compile.tail_rec_elim_pass eta_red); + +.let optimization_phase = %compile.pass_phase optimization_pass_list; /// /// ### Pipelines /// -.let default_core_pipeline = { +.let default_core_pipeline = .let nullptr = %compile.nullptr_pass; %compile.pipe (%compile.single_pass_phase nullptr) @@ -142,8 +140,8 @@ optimization_phase (%compile.single_pass_phase %compile.internal_cleanup_pass) (%compile.single_pass_phase %compile.lam_spec_pass) - (%compile.single_pass_phase %compile.ret_wrap_pass) -}; + (%compile.single_pass_phase %compile.ret_wrap_pass); + .lam .extern _fallback_compile(): %compile.Pipeline = default_core_pipeline; /// /// ### Dependent Passes and Phases diff --git a/src/thorin/plug/direct/direct.thorin b/src/thorin/plug/direct/direct.thorin index c66c56db73..9f3a303353 100644 --- a/src/thorin/plug/direct/direct.thorin +++ b/src/thorin/plug/direct/direct.thorin @@ -36,10 +36,9 @@ /// /// ### Phases /// -.let direct_phases = { - %compile.combined_phase (%compile.phase_list - (%compile.single_pass_phase %direct.ds2cps_pass) - (%compile.single_pass_phase %direct.cps2ds_pass) - optimization_phase - ) -}; +.let direct_phases = + %compile.combined_phase + (%compile.phase_list + (%compile.single_pass_phase %direct.ds2cps_pass) + (%compile.single_pass_phase %direct.cps2ds_pass) + optimization_phase); diff --git a/src/thorin/plug/matrix/matrix.thorin b/src/thorin/plug/matrix/matrix.thorin index 3c9ac125ba..b4dc20be47 100644 --- a/src/thorin/plug/matrix/matrix.thorin +++ b/src/thorin/plug/matrix/matrix.thorin @@ -236,15 +236,14 @@ /// /// ### Phases /// -.let matrix_lower_phase = { +.let matrix_lower_phase = %compile.phases_to_phase (⊤:.Nat) ( - (%compile.pass_phase (%compile.pass_list - %matrix.lower_matrix_high_level_map_reduce - %matrix.lower_matrix_medium_level - )), + (%compile.pass_phase + (%compile.pass_list + %matrix.lower_matrix_high_level_map_reduce + %matrix.lower_matrix_medium_level)), // TODO: only in map_red namespace %compile.single_pass_phase %matrix.internal_map_reduce_cleanup, %matrix.lower_matrix_low_level - ) -}; + ); diff --git a/src/thorin/plug/mem/mem.thorin b/src/thorin/plug/mem/mem.thorin index 5a138ac233..96dbd0b0aa 100644 --- a/src/thorin/plug/mem/mem.thorin +++ b/src/thorin/plug/mem/mem.thorin @@ -116,7 +116,7 @@ /// .ax %mem.add_mem_phase: %compile.Phase; -.let mem_opt_pass_list = { +.let mem_opt_pass_list = .let beta_red = %compile.beta_red_pass; .let eta_red = %compile.eta_red_pass; .let eta_exp = %compile.eta_exp_pass eta_red; @@ -125,10 +125,7 @@ eta_red eta_exp (%mem.ssa_pass eta_exp) - (%mem.copy_prop_pass (beta_red, eta_exp, .ff)) -}; + (%mem.copy_prop_pass (beta_red, eta_exp, .ff)); + .let mem_opt_phase = %compile.pass_phase mem_opt_pass_list; -.let mem_prep_phase = %compile.passes_to_phase (⊤:.Nat) ( - %mem.remem_elim_pass, - %mem.alloc2malloc_pass - ); +.let mem_prep_phase = %compile.passes_to_phase (⊤:.Nat) (%mem.remem_elim_pass, %mem.alloc2malloc_pass); diff --git a/src/thorin/plug/opt/opt.thorin b/src/thorin/plug/opt/opt.thorin index 3591c5a18e..95a8a60ef3 100644 --- a/src/thorin/plug/opt/opt.thorin +++ b/src/thorin/plug/opt/opt.thorin @@ -22,7 +22,7 @@ /// /// ### Pipelines /// -.lam .extern _default_compile []: %compile.Pipeline = { +.lam .extern _default_compile []: %compile.Pipeline = .let nullptr = %compile.nullptr_pass; .let nullphase = %compile.single_pass_phase nullptr; %compile.pipe @@ -41,20 +41,21 @@ mem_opt_pass_list )) ) - (plugin_cond_phase (%compile.autodiff_plugin, - %compile.combined_phase (%compile.phase_list - (%compile.single_pass_phase %autodiff.ad_eval_pass) - // optimization_phase - (%compile.single_pass_phase %autodiff.ad_zero_pass) - ) - )) + (plugin_cond_phase + (%compile.autodiff_plugin, + %compile.combined_phase + (%compile.phase_list + (%compile.single_pass_phase %autodiff.ad_eval_pass) + // optimization_phase + (%compile.single_pass_phase %autodiff.ad_zero_pass)))) (plugin_cond_phase (%compile.direct_plugin, direct_phases)) - (plugin_cond_phase (%compile.matrix_plugin, - %compile.combined_phase (%compile.phase_list - matrix_lower_phase - (plugin_cond_phase (%compile.direct_plugin, direct_phases)) - (plugin_cond_phase (%compile.affine_plugin, %compile.single_pass_phase %affine.lower_for_pass)) - ))) + (plugin_cond_phase + (%compile.matrix_plugin, + %compile.combined_phase + (%compile.phase_list + matrix_lower_phase + (plugin_cond_phase (%compile.direct_plugin, direct_phases)) + (plugin_cond_phase (%compile.affine_plugin, %compile.single_pass_phase %affine.lower_for_pass))))) (%compile.single_pass_phase %compile.internal_cleanup_pass) (plugin_cond_phase (%compile.clos_plugin, clos_phases)) (%compile.single_pass_phase %compile.lam_spec_pass) @@ -72,5 +73,4 @@ %compile.pass_list (plugin_cond_pass (%compile.refly_plugin, %refly.remove_dbg_perm_pass)) )) - ) -}; + ); diff --git a/src/thorin/util/dbg.cpp b/src/thorin/util/dbg.cpp index 59ea0409d2..c60623f631 100644 --- a/src/thorin/util/dbg.cpp +++ b/src/thorin/util/dbg.cpp @@ -1 +1,21 @@ +#include "thorin/util/dbg.h" + #include + +namespace thorin { + +void Error::clear() { + num_errors_ = 0; + num_warnings_ = 0; + num_notes_ = 0; + msgs_.clear(); +} + +/// If errors occured, claim them and throw; if warnings occured, claim them and report to @p os. +void Error::ack(std::ostream& os) { + auto e = std::move(*this); + if (e.num_errors() != 0) throw e; + if (e.num_warnings() != 0) print(os, "{} warning(s) encountered\n{}", e.num_warnings(), e); +} + +} // namespace thorin From 7751e47a7c24b14acc57b233c39be52a0567546e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 27 Apr 2024 01:54:27 +0200 Subject: [PATCH 91/95] Split Annex into Annex and ast::AnnexInfo --- include/thorin/ast/ast.h | 29 +++++++++++++++++++++++++---- include/thorin/plugin.h | 19 +------------------ src/thorin/ast/ast.cpp | 10 +++++----- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 21d2f82068..3f4f3bc595 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -22,6 +22,27 @@ template using Ptr = fe::Arena::Ptr; template using Ptrs = std::deque>; /* */ using Dbgs = std::deque; +struct AnnexInfo { + AnnexInfo(Sym sym_plugin, Sym sym_tag, plugin_t id_plugin, tag_t id_tag) + : sym{sym_plugin, sym_tag} + , id{id_plugin, id_tag, 0, 0} { + assert(Annex::mangle(sym_plugin) == id_plugin); + } + + struct { + Sym plugin, tag; + } sym; + struct { + plugin_t plugin; + tag_t tag; + uint8_t curry, trip; + } id; + std::deque> subs; ///< List of subs which is a list of aliases. + Sym normalizer; + bool pi = false; + bool fresh = true; +}; + class AST { public: AST() = default; @@ -66,8 +87,8 @@ class AST { /// @name Manage Annex ///@{ - Annex& name2annex(Dbg dbg); - std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); + AnnexInfo& name2annex(Dbg dbg); + std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); const auto& plugin2annexes(Sym plugin) { return plugin2sym2annex_[plugin]; } ///@} @@ -86,7 +107,7 @@ class AST { World* world_ = nullptr; fe::Arena arena_; mutable Error err_; - absl::node_hash_map> plugin2sym2annex_; + absl::node_hash_map> plugin2sym2annex_; }; class Node : public fe::RuntimeCast { @@ -744,7 +765,7 @@ class AxiomDecl : public ValDecl { Ptr type_; Dbg normalizer_; Tok curry_, trip_; - mutable Annex* annex_ = nullptr; + mutable AnnexInfo* annex_ = nullptr; mutable Ref thorin_type_; }; diff --git a/include/thorin/plugin.h b/include/thorin/plugin.h index 5db190ad29..57b3b1263f 100644 --- a/include/thorin/plugin.h +++ b/include/thorin/plugin.h @@ -51,24 +51,7 @@ THORIN_EXPORT thorin::Plugin thorin_get_plugin(); /// Holds info about an entity defined within a Plugin (called *Annex*). struct Annex { - Annex(Sym sym_plugin, Sym sym_tag, plugin_t id_plugin, tag_t id_tag) - : sym{sym_plugin, sym_tag} - , id{id_plugin, id_tag, 0, 0} { - assert(mangle(sym_plugin) == id_plugin); - } - - struct { - Sym plugin, tag; - } sym; - struct { - plugin_t plugin; - tag_t tag; - uint8_t curry, trip; - } id; - std::deque> subs; ///< List of subs which is a list of aliases. - Sym normalizer; - bool pi = false; - bool fresh = true; + Annex() = delete; /// @name Mangling Plugin Name ///@{ diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 948fc9e437..949aa864f6 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -9,7 +9,7 @@ AST::~AST() { && "please encounter any errors before destroying this class"); } -Annex& AST::name2annex(Dbg dbg) { +AnnexInfo& AST::name2annex(Dbg dbg) { auto [plugin_s, tag_s, sub_s] = Annex::split(driver(), dbg.sym()); auto& sym2annex = plugin2sym2annex_[plugin_s]; auto tag_id = sym2annex.size(); @@ -29,19 +29,19 @@ Annex& AST::name2annex(Dbg dbg) { if (sub_s) error(dbg.loc(), "annex '{}' must not have a subtag", dbg); - auto [i, fresh] = sym2annex.emplace(dbg.sym(), Annex{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()}); + auto [i, fresh] = sym2annex.emplace(dbg.sym(), AnnexInfo{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()}); auto& annex = i->second; if (!fresh) annex.fresh = false; return annex; } -std::pair AST::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { +std::pair AST::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { auto& annexes = plugin2sym2annex_[plugin]; if (annexes.size() > std::numeric_limits::max()) error(loc, "exceeded maxinum number of axioms in current plugin"); auto plugin_id = *Annex::mangle(plugin); - auto [it, is_new] = annexes.emplace(sym, Annex{plugin, tag, plugin_id, (tag_t)annexes.size()}); + auto [it, is_new] = annexes.emplace(sym, AnnexInfo{plugin, tag, plugin_id, (tag_t)annexes.size()}); return {it->second, is_new}; } @@ -61,7 +61,7 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { tab.print(h, "static constexpr plugin_t Plugin_Id = 0x{x};\n\n", plugin_id); const auto& unordered = plugin2annexes(plugin); - std::deque> infos(unordered.begin(), unordered.end()); + std::deque> infos(unordered.begin(), unordered.end()); std::ranges::sort(infos, [&](const auto& p1, const auto& p2) { return p1.second.id.tag < p2.second.id.tag; }); // clang-format off From 4cfc9e4b5d979aee1a643e16b059254002e247f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 27 Apr 2024 02:05:59 +0200 Subject: [PATCH 92/95] cleanup --- include/thorin/ast/ast.h | 3 +-- src/thorin/ast/ast.cpp | 25 ++++++++----------------- src/thorin/ast/bind.cpp | 4 +++- src/thorin/ast/emit.cpp | 14 ++++++-------- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 3f4f3bc595..6978d47939 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -87,8 +87,7 @@ class AST { /// @name Manage Annex ///@{ - AnnexInfo& name2annex(Dbg dbg); - std::pair name2annex(Sym sym, Sym plugin, Sym tag, Loc loc); + std::pair name2annex(Dbg dbg); const auto& plugin2annexes(Sym plugin) { return plugin2sym2annex_[plugin]; } ///@} diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 949aa864f6..3d8525ad85 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -2,6 +2,8 @@ #include "thorin/ast/parser.h" +using namespace std::literals; + namespace thorin::ast { AST::~AST() { @@ -9,8 +11,9 @@ AST::~AST() { && "please encounter any errors before destroying this class"); } -AnnexInfo& AST::name2annex(Dbg dbg) { +std::pair AST::name2annex(Dbg dbg) { auto [plugin_s, tag_s, sub_s] = Annex::split(driver(), dbg.sym()); + auto plugin_tag = driver().sym("%"s + plugin_s.str() + "."s + tag_s.str()); auto& sym2annex = plugin2sym2annex_[plugin_s]; auto tag_id = sym2annex.size(); @@ -27,22 +30,10 @@ AnnexInfo& AST::name2annex(Dbg dbg) { plugin_id = *Annex::mangle(plugin_s); } - if (sub_s) error(dbg.loc(), "annex '{}' must not have a subtag", dbg); - - auto [i, fresh] = sym2annex.emplace(dbg.sym(), AnnexInfo{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()}); - auto& annex = i->second; - if (!fresh) annex.fresh = false; - return annex; -} - -std::pair AST::name2annex(Sym sym, Sym plugin, Sym tag, Loc loc) { - auto& annexes = plugin2sym2annex_[plugin]; - if (annexes.size() > std::numeric_limits::max()) - error(loc, "exceeded maxinum number of axioms in current plugin"); - - auto plugin_id = *Annex::mangle(plugin); - auto [it, is_new] = annexes.emplace(sym, AnnexInfo{plugin, tag, plugin_id, (tag_t)annexes.size()}); - return {it->second, is_new}; + auto [i, fresh] = sym2annex.emplace(plugin_tag, AnnexInfo{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()}); + auto annex = &i->second; + if (!fresh) annex->fresh = false; + return {annex, sub_s}; } void AST::bootstrap(Sym plugin, std::ostream& h) { diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 0bc6f21636..8402f7c7d8 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -224,7 +224,9 @@ void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { void AxiomDecl::bind(Scopes& s) const { type()->bind(s); - annex_ = &s.ast().name2annex(dbg()); + Sym sub; + std::tie(annex_, sub) = s.ast().name2annex(dbg()); + if (sub) error(dbg().loc(), "annex '{}' must not have a subtag", dbg()); annex_->normalizer = normalizer().sym(); // TODO error checking diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index 42017c5e1d..ec00728eec 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -19,19 +19,17 @@ class Emitter { void register_if_annex(Dbg dbg, Ref def) { if (dbg && dbg.sym().front() == '%') { - auto [plugin, tag, sub] = Annex::split(driver(), dbg.sym()); - auto name = world().sym("%"s + plugin.str() + "."s + tag.str()); - auto&& [annex, is_new] = ast().name2annex(name, plugin, tag, dbg.loc()); - plugin_t p = *Annex::mangle(plugin); - tag_t t = annex.id.tag; - sub_t s = annex.subs.size(); + auto [annex, sub] = ast().name2annex(dbg); + const auto& sym = annex->sym; + const auto& id = annex->id; + sub_t s = annex->subs.size(); if (sub) { - auto& aliases = annex.subs.emplace_back(); + auto& aliases = annex->subs.emplace_back(); aliases.emplace_back(sub); } - world().register_annex(p | (t << 8) | s, def); + world().register_annex(id.plugin | (id.tag << 8) | s, def); } } From 3c92ef1c82d89b7443f954fe9e874a109fbd2dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 27 Apr 2024 03:30:55 +0200 Subject: [PATCH 93/95] missing errors + further polishing of annexes/axioms --- include/thorin/ast/ast.h | 14 +++++++--- include/thorin/world.h | 3 +++ src/thorin/ast/ast.cpp | 55 +++++++++++++++++++++++++--------------- src/thorin/ast/bind.cpp | 21 +++++++++++---- src/thorin/ast/emit.cpp | 41 ++++++++++++------------------ 5 files changed, 81 insertions(+), 53 deletions(-) diff --git a/include/thorin/ast/ast.h b/include/thorin/ast/ast.h index 6978d47939..ffede04c8f 100644 --- a/include/thorin/ast/ast.h +++ b/include/thorin/ast/ast.h @@ -29,6 +29,8 @@ struct AnnexInfo { assert(Annex::mangle(sym_plugin) == id_plugin); } + bool is_pi() const { return pi && *pi && bool((*pi)->isa()); } + struct { Sym plugin, tag; } sym; @@ -38,8 +40,8 @@ struct AnnexInfo { uint8_t curry, trip; } id; std::deque> subs; ///< List of subs which is a list of aliases. - Sym normalizer; - bool pi = false; + Dbg normalizer; + std::optional pi; bool fresh = true; }; @@ -87,7 +89,7 @@ class AST { /// @name Manage Annex ///@{ - std::pair name2annex(Dbg dbg); + AnnexInfo* name2annex(Dbg dbg, sub_t*); const auto& plugin2annexes(Sym plugin) { return plugin2sym2annex_[plugin]; } ///@} @@ -713,6 +715,8 @@ class LetDecl : public ValDecl { private: Ptr ptrn_; Ptr value_; + mutable AnnexInfo* annex_ = nullptr; + mutable sub_t sub_; }; /// `.ax ptrn: type = value;` @@ -798,6 +802,8 @@ class RecDecl : public ValDecl { Ptr type_; Ptr body_; Ptr next_; + mutable AnnexInfo* annex_ = nullptr; + mutable sub_t sub_; }; /// One of: @@ -862,6 +868,8 @@ class LamDecl : public RecDecl { bool is_external_; Ptrs doms_; Ptr codom_; + mutable AnnexInfo* annex_ = nullptr; + mutable sub_t sub_; }; /// `.cfun dbg dom -> codom` diff --git a/include/thorin/world.h b/include/thorin/world.h index e3cea31e97..e7810fe7e4 100644 --- a/include/thorin/world.h +++ b/include/thorin/world.h @@ -194,6 +194,9 @@ class World { template const Def* annex() { return annex(Annex::Base); } const Def* register_annex(flags_t f, const Def*); + const Def* register_annex(plugin_t p, tag_t t, sub_t s, const Def* def) { + return register_annex(p | (flags_t(t) << 8_u64) | flags_t(s), def); + } ///@} /// @name Univ, Type, Var, Proxy, Infer diff --git a/src/thorin/ast/ast.cpp b/src/thorin/ast/ast.cpp index 3d8525ad85..860a014b92 100644 --- a/src/thorin/ast/ast.cpp +++ b/src/thorin/ast/ast.cpp @@ -11,7 +11,9 @@ AST::~AST() { && "please encounter any errors before destroying this class"); } -std::pair AST::name2annex(Dbg dbg) { +AnnexInfo* AST::name2annex(Dbg dbg, sub_t* sub_id) { + if (!dbg || dbg.sym()[0] != '%') return nullptr; + auto [plugin_s, tag_s, sub_s] = Annex::split(driver(), dbg.sym()); auto plugin_tag = driver().sym("%"s + plugin_s.str() + "."s + tag_s.str()); auto& sym2annex = plugin2sym2annex_[plugin_s]; @@ -32,8 +34,19 @@ std::pair AST::name2annex(Dbg dbg) { auto [i, fresh] = sym2annex.emplace(plugin_tag, AnnexInfo{plugin_s, tag_s, plugin_id, (tag_t)sym2annex.size()}); auto annex = &i->second; + + if (sub_s) { + if (sub_id) { + *sub_id = annex->subs.size(); + auto& aliases = annex->subs.emplace_back(); + aliases.emplace_back(sub_s); + } else { + error(dbg.loc(), "annex '{}' must not have a subtag", dbg); + } + } + if (!fresh) annex->fresh = false; - return {annex, sub_s}; + return annex; } void AST::bootstrap(Sym plugin, std::ostream& h) { @@ -57,19 +70,20 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { // clang-format off for (const auto& [key, annex] : infos) { - if (annex.sym.plugin != plugin) continue; // this is from an import + const auto& sym = annex.sym; + if (sym.plugin != plugin) continue; // this is from an import - tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, annex.sym.tag); + tab.print(h, "/// @name %%{}.{}\n///@{{\n", plugin, sym.tag); tab.print(h, "#ifdef DOXYGEN // see https://github.com/doxygen/doxygen/issues/9668\n"); - tab.print(h, "enum {} : flags_t {{\n", annex.sym.tag); + tab.print(h, "enum {} : flags_t {{\n", sym.tag); tab.print(h, "#else\n"); - tab.print(h, "enum class {} : flags_t {{\n", annex.sym.tag); + tab.print(h, "enum class {} : flags_t {{\n", sym.tag); tab.print(h, "#endif\n"); ++tab; flags_t ax_id = plugin_id | (annex.id.tag << 8u); auto& os = outer_namespace.emplace_back(); - print(os, "template<> constexpr flags_t Annex::Base = 0x{x};\n", plugin, annex.sym.tag, ax_id); + print(os, "template<> constexpr flags_t Annex::Base = 0x{x};\n", plugin, sym.tag, ax_id); if (auto& subs = annex.subs; !subs.empty()) { for (const auto& aliases : subs) { @@ -77,25 +91,26 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { tab.print(h, "{} = 0x{x},\n", sub, ax_id++); for (size_t i = 1; i < aliases.size(); ++i) tab.print(h, "{} = {},\n", aliases[i], sub); - if (annex.normalizer) - print(normalizers.emplace_back(), "normalizers[flags_t({}::{})] = &{}<{}::{}>;", annex.sym.tag, sub, - annex.normalizer, annex.sym.tag, sub); + if (auto norm = annex.normalizer) { + auto& os = normalizers.emplace_back(); + print(os, "normalizers[flags_t({}::{})] = &{}<{}::{}>;", sym.tag, sub, norm, sym.tag, sub); + } } } else { - if (annex.normalizer) - print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", annex.sym.tag, annex.normalizer); + if (auto norm = annex.normalizer) + print(normalizers.emplace_back(), "normalizers[flags_t(Annex::Base<{}>)] = &{};", sym.tag, norm); } --tab; tab.print(h, "}};\n\n"); - if (!annex.subs.empty()) tab.print(h, "THORIN_ENUM_OPERATORS({})\n", annex.sym.tag); - print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, annex.sym.tag, annex.subs.size()); + if (!annex.subs.empty()) tab.print(h, "THORIN_ENUM_OPERATORS({})\n", sym.tag); + print(outer_namespace.emplace_back(), "template<> constexpr size_t Annex::Num = {};\n", plugin, sym.tag, annex.subs.size()); - if (annex.normalizer) { + if (auto norm = annex.normalizer) { if (auto& subs = annex.subs; !subs.empty()) { - tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", annex.sym.tag, annex.normalizer); + tab.print(h, "template<{}>\nRef {}(Ref, Ref, Ref);\n\n", sym.tag, norm); } else { - tab.print(h, "Ref {}(Ref, Ref, Ref);\n", annex.normalizer); + tab.print(h, "Ref {}(Ref, Ref, Ref);\n", norm); } } tab.print(h, "///@}}\n\n"); @@ -122,9 +137,9 @@ void AST::bootstrap(Sym plugin, std::ostream& h) { // emit helpers for non-function axiom for (const auto& [tag, ax] : infos) { - if (ax.pi || ax.sym.plugin != plugin) continue; // from function or other plugin? - tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", ax.sym.plugin, - ax.sym.tag); + const auto& sym = ax.sym; + if (ax.is_pi() || sym.plugin != plugin) continue; // from function or other plugin? + tab.print(h, "template<> struct Axiom::Match {{ using type = Axiom; }};\n", sym.plugin, sym.tag); } tab.print(h, "#endif\n"); diff --git a/src/thorin/ast/bind.cpp b/src/thorin/ast/bind.cpp index 8402f7c7d8..b6162be6c1 100644 --- a/src/thorin/ast/bind.cpp +++ b/src/thorin/ast/bind.cpp @@ -224,11 +224,18 @@ void AxiomDecl::Alias::bind(Scopes& s, const AxiomDecl* axiom) const { void AxiomDecl::bind(Scopes& s) const { type()->bind(s); - Sym sub; - std::tie(annex_, sub) = s.ast().name2annex(dbg()); - if (sub) error(dbg().loc(), "annex '{}' must not have a subtag", dbg()); - - annex_->normalizer = normalizer().sym(); // TODO error checking + annex_ = s.ast().name2annex(dbg(), nullptr); + + if (annex_->fresh) + annex_->normalizer = normalizer(); + else if (annex_->normalizer.sym() != normalizer().sym()) { + auto l = normalizer().loc() ? normalizer().loc() : loc().anew_finis(); + s.ast().error(l, "normalizer mismatch for axiom '{}'", dbg()); + if (auto norm = annex_->normalizer) + s.ast().note(norm.loc(), "previous normalizer '{}'", norm); + else + s.ast().note(l, "initially no normalizer specified"); + } if (num_subs() == 0) { s.bind(dbg(), this); @@ -251,11 +258,14 @@ void LetDecl::bind(Scopes& s) const { value()->bind(s); s.pop(); ptrn()->bind(s); + + if (auto id = ptrn()->isa()) annex_ = s.ast().name2annex(id->dbg(), &sub_); } void RecDecl::bind(Scopes& s) const { for (auto curr = this; curr; curr = curr->next()) curr->bind_decl(s); for (auto curr = this; curr; curr = curr->next()) curr->bind_body(s); + annex_ = s.ast().name2annex(dbg(), &sub_); } void RecDecl::bind_decl(Scopes& s) const { @@ -304,6 +314,7 @@ void LamDecl::bind_decl(Scopes& s) const { s.pop(); s.bind(dbg(), this); + annex_ = s.ast().name2annex(dbg(), &sub_); } void LamDecl::bind_body(Scopes& s) const { diff --git a/src/thorin/ast/emit.cpp b/src/thorin/ast/emit.cpp index ec00728eec..51e1ae2322 100644 --- a/src/thorin/ast/emit.cpp +++ b/src/thorin/ast/emit.cpp @@ -15,24 +15,15 @@ class Emitter { World& world() { return ast().world(); } Driver& driver() { return world().driver(); } - absl::node_hash_map, GIDHash, GIDEq> sigma2sym2idx; - - void register_if_annex(Dbg dbg, Ref def) { - if (dbg && dbg.sym().front() == '%') { - auto [annex, sub] = ast().name2annex(dbg); - const auto& sym = annex->sym; - const auto& id = annex->id; - sub_t s = annex->subs.size(); - - if (sub) { - auto& aliases = annex->subs.emplace_back(); - aliases.emplace_back(sub); - } - - world().register_annex(id.plugin | (id.tag << 8) | s, def); + void register_annex(AnnexInfo* annex, sub_t sub, Ref def) { + if (annex) { + const auto& id = annex->id; + world().register_annex(id.plugin | (id.tag << 8) | sub, def); } } + absl::node_hash_map, GIDHash, GIDEq> sigma2sym2idx; + private: AST& ast_; }; @@ -340,7 +331,6 @@ Ref InsertExpr::emit_(Emitter& e) const { void AxiomDecl::emit(Emitter& e) const { thorin_type_ = type()->emit(e); - annex_->pi = thorin_type_->isa() != nullptr; auto& id = annex_->id; std::tie(id.curry, id.trip) = Axiom::infer_curry_and_trip(thorin_type_); @@ -358,16 +348,17 @@ void AxiomDecl::emit(Emitter& e) const { id.trip = trip_.lit_u(); } -#if 0 - if (!is_new && annex.pi != (thorin_type_->isa() != nullptr)) + auto pi = thorin_type_->isa(); + if (!annex_->pi) + annex_->pi = pi; + else if (bool(pi) ^ bool(*annex_->pi)) error(dbg().loc(), "all declarations of annex '{}' have to be function types if any is", dbg().sym()); -#endif if (num_subs() == 0) { auto norm = e.driver().normalizer(id.plugin, id.tag, 0); auto axiom = e.world().axiom(norm, id.curry, id.trip, thorin_type_, id.plugin, id.tag, 0)->set(dbg()); def_ = axiom; - e.world().register_annex(id.plugin | (flags_t(id.tag) << 8_u64), axiom); + e.world().register_annex(id.plugin, id.tag, 0, axiom); } else { sub_t offset = annex_->subs.size(); for (sub_t i = 0, n = num_subs(); i != n; ++i) { @@ -376,7 +367,8 @@ void AxiomDecl::emit(Emitter& e) const { auto norm = e.driver().normalizer(id.plugin, id.tag, s); auto name = e.world().sym(dbg().sym().str() + "."s + sub(i).front()->dbg().sym().str()); auto axiom = e.world().axiom(norm, id.curry, id.trip, thorin_type_, id.plugin, id.tag, s)->set(name); - e.world().register_annex(id.plugin | (flags_t(id.tag) << 8_u64) | flags_t(s), axiom); + e.world().register_annex(id.plugin, id.tag, s, axiom); + for (const auto& alias : sub(i)) { alias->def_ = axiom; aliases.emplace_back(alias->dbg().sym()); @@ -388,8 +380,7 @@ void AxiomDecl::emit(Emitter& e) const { void LetDecl::emit(Emitter& e) const { auto v = value()->emit(e); def_ = ptrn()->emit_value(e, v); - - if (auto id = ptrn()->isa()) e.register_if_annex(id->dbg(), def_); + e.register_annex(annex_, sub_, def_); } void RecDecl::emit(Emitter& e) const { @@ -406,7 +397,7 @@ void RecDecl::emit_decl(Emitter& e) const { void RecDecl::emit_body(Emitter& e) const { body()->emit_body(e, def_); // TODO immutabilize? - e.register_if_annex(dbg(), def_); + e.register_annex(annex_, sub_, def_); } Lam* LamDecl::Dom::emit_value(Emitter& e) const { @@ -454,7 +445,7 @@ void LamDecl::emit_decl(Emitter& e) const { void LamDecl::emit_body(Emitter& e) const { doms().back()->lam_->set_body(body()->emit(e)); if (is_external()) doms().front()->lam_->make_external(); - e.register_if_annex(dbg(), def_); + e.register_annex(annex_, sub_, def_); } void CDecl::emit(Emitter& e) const { From b9dffe47999e1b0f65263cb53c775b328c5bc79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sat, 27 Apr 2024 23:53:01 +0200 Subject: [PATCH 94/95] porting main_loop to .where expr --- lit/main_loop.thorin | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lit/main_loop.thorin b/lit/main_loop.thorin index 701b548eed..cbaa7044b2 100644 --- a/lit/main_loop.thorin +++ b/lit/main_loop.thorin @@ -7,14 +7,19 @@ .plugin core; .fun .extern main(mem: %mem.M, argc: .I32, argv: %mem.Ptr0 (%mem.Ptr0 .I8)): [%mem.M, .I32] = - .con loop(mem: %mem.M, i: .I32, acc: .I32) = - .let cond = %core.icmp.ul (i, argc); - .con body m: %mem.M = - .let inc = %core.wrap.add 0 (1I32, i); - .let acci = %core.wrap.add 0 (i, acc); - loop (m, inc, acci); - (.cn m: %mem.M = return (m, acc), body)#cond mem; - loop (mem, 0I32, 0I32); + loop (mem, 0I32, 0I32) + .where + .con loop(mem: %mem.M, i: .I32, acc: .I32) = + .let cond = %core.icmp.ul (i, argc); + (exit, body)#cond mem + .where + .con body m: %mem.M = + .let inc = %core.wrap.add 0 (1I32, i); + .let `acc = %core.wrap.add 0 (i, acc); + loop (m, inc, acc); + .con exit(m: %mem.M) = return (m, acc); + .end + .end // CHECK-DAG: .con .extern main _[[mainVarId:[0-9_]+]]::[_{{[0-9]+}}::[mem_[[memId:[0-9_]+]]: %mem.M, argc_[[argcId:[0-9_]+]]: .I32, %mem.Ptr (%mem.Ptr (.I8, 0), 0)], return_[[returnId:[0-9_]+]]: .Cn [%mem.M, .I32]]{{(@.*)?}}= { // CHECK-DAG: loop_[[loopId:[0-9_]+]] ({{.*}}, 0I32, 0I32) @@ -24,12 +29,12 @@ // CHECK-DAG: .con loop_[[loopId]] _{{[0-9_]+}}::[mem_[[loopMemId:[0-9_]+]]: %mem.M, i_[[iterId:[0-9_]+]]: .I32, acc_[[accId:[0-9_]+]]: .I32]{{(@.*)?}}= { // CHECK-DAG: cond_[[condId:[0-9_]+]]: .Bool = %core.icmp.XygLe .i32 (i_[[iterId]], {{.*}}); -// CHECK-DAG: (_[[exitId:[0-9_]+]], body_[[bodyId:[0-9_]+]])#cond_[[condId]] mem_[[loopMemId]] +// CHECK-DAG: (exit_[[exitId:[0-9_]+]], body_[[bodyId:[0-9_]+]])#cond_[[condId]] mem_[[loopMemId]] -// CHECK-DAG: .con _[[exitId]] [[mExitVarId:[0-9a-z_]+]]: %mem.M{{(@.*)?}}= { +// CHECK-DAG: .con exit_[[exitId]] [[mExitVarId:[0-9a-z_]+]]: %mem.M{{(@.*)?}}= { // CHECK-DAG: return_[[returnEtaId]] ([[mExitVarId]], acc_[[accId]]) // CHECK-DAG: .con body_[[bodyId]] [[mBodyVarId:[0-9a-z_]+]]: %mem.M{{(@.*)?}}= { // CHECK-DAG: inc_[[addIterId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (1I32, i_[[iterId]]); -// CHECK-DAG: acci_[[addAccId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (i_[[iterId]], acc_[[accId]]); -// CHECK-DAG: loop_[[loopId]] ([[mBodyVarId]], inc_[[addIterId]], acci_[[addAccId]]) +// CHECK-DAG: acc_[[addAccId:[0-9_]+]]: .I32 = %core.wrap.add .i32 0 (i_[[iterId]], acc_[[accId]]); +// CHECK-DAG: loop_[[loopId]] ([[mBodyVarId]], inc_[[addIterId]], acc_[[addAccId]]) From f21a72cf7e92cedfb58aedaf0eecb2adf8c90634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Lei=C3=9Fa?= Date: Sun, 28 Apr 2024 00:15:32 +0200 Subject: [PATCH 95/95] polish --- src/thorin/ast/parser.cpp | 64 +++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/thorin/ast/parser.cpp b/src/thorin/ast/parser.cpp index a4b3b66abe..09e58d3433 100644 --- a/src/thorin/ast/parser.cpp +++ b/src/thorin/ast/parser.cpp @@ -6,8 +6,8 @@ #include "thorin/driver.h" // clang-format off -#define TAG__PRIMARY \ - Tag::K_Univ: \ +#define C_PRIMARY \ + K_Univ: \ case Tag::K_Nat: \ case Tag::K_Idx: \ case Tag::K_Bool: \ @@ -26,12 +26,12 @@ case Tag::T_star: \ case Tag::T_box -#define TAG__ID \ - Tag::M_anx: \ +#define C_ID \ + M_anx: \ case Tag::M_id -#define TAG__LIT \ - Tag::T_bot: \ +#define C_LIT \ + T_bot: \ case Tag::T_top: \ case Tag::L_str: \ case Tag::L_c: \ @@ -40,35 +40,35 @@ case Tag::L_f: \ case Tag::L_i -#define TAG__LAM \ - Tag::K_lam: \ +#define C_LAM \ + K_lam: \ case Tag::K_con: \ case Tag::K_fun -#define TAG__DECL \ - Tag::K_ax: \ +#define C_DECL \ + K_ax: \ case Tag::K_let: \ case Tag::K_rec: \ case Tag::K_ccon: \ case Tag::K_cfun: \ - case TAG__LAM + case Tag::C_LAM -#define TAG__PI \ - Tag::T_Pi: \ +#define C_PI \ + T_Pi: \ case Tag::K_Cn: \ case Tag::K_Fn -#define TAG__LM \ - Tag::T_lm: \ +#define C_LM \ + T_lm: \ case Tag::K_cn: \ case Tag::K_fn -#define TAG__EXPR \ - TAG__PRIMARY: \ - case TAG__ID: \ - case TAG__LIT: \ - case TAG__DECL: \ - case TAG__LM: \ +#define C_EXPR \ + C_PRIMARY: \ + case Tag::C_ID: \ + case Tag::C_LIT: \ + case Tag::C_DECL: \ + case Tag::C_LM: \ case Tag::K_Type: /*TypeExpr*/ \ case Tag::K_ins: /*InsertExpr*/ \ case Tag::K_ret: /*RetExpr*/ \ @@ -222,10 +222,10 @@ Ptr Parser::parse_infix_expr(Tracker track, Ptr&& lhs, Prec curr_pre lhs = ptr(track.loc(), true, std::move(lhs), std::move(rhs)); continue; } - case TAG__EXPR: { + case Tag::C_EXPR: { if (curr_prec >= Prec::App) return lhs; switch (ahead().tag()) { - case TAG__DECL: + case Tag::C_DECL: ast().warn(ahead().loc(), "you are passing a declaration expression as argument"); ast().note(lhs->loc(), "to this expression"); ast().note(ahead().loc(), @@ -271,12 +271,12 @@ Ptr Parser::parse_insert_expr() { Ptr Parser::parse_primary_expr(std::string_view ctxt) { // clang-format off switch (ahead().tag()) { - case TAG__PRIMARY: return ptr(lex()); - case TAG__ID: return ptr(lex().dbg()); - case TAG__LIT: return parse_lit_expr(); - case TAG__DECL: return parse_decl_expr(); - case TAG__PI: return parse_pi_expr(); - case TAG__LM: return parse_lam_expr(); + case Tag::C_PRIMARY: return ptr(lex()); + case Tag::C_ID: return ptr(lex().dbg()); + case Tag::C_LIT: return parse_lit_expr(); + case Tag::C_DECL: return parse_decl_expr(); + case Tag::C_PI: return parse_pi_expr(); + case Tag::C_LM: return parse_lam_expr(); case Tag::K_ins: return parse_insert_expr(); case Tag::K_ret: return parse_ret_expr(); case Tag::D_quote_l: return parse_arr_or_pack_expr(); @@ -374,7 +374,7 @@ Ptr Parser::parse_pi_expr() { doms.emplace_back(ptr(track, implicit, std::move(ptrn))); switch (ahead().tag()) { - case TAG__EXPR: + case Tag::C_EXPR: case Tag::T_backtick: continue; default: break; } @@ -688,7 +688,7 @@ Ptr Parser::parse_lam_decl() { doms.emplace_back(ptr(track, implicit, std::move(ptrn), std::move(filter))); switch (ahead().tag()) { - case TAG__EXPR: + case Tag::C_EXPR: case Tag::T_backtick: continue; default: break; } @@ -708,7 +708,7 @@ Ptr Parser::parse_lam_decl() { Ptr Parser::parse_and_decl() { switch (ahead(1).tag()) { - case TAG__LAM: return lex(), parse_lam_decl(); + case Tag::C_LAM: return lex(), parse_lam_decl(); default: return parse_rec_decl(false); } }