From 4907d865ebc62e509d301850e353c345fdef206c Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 13:38:23 +0100 Subject: [PATCH 1/8] move to C++20 --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9500adbb..552072c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,7 +25,7 @@ add_library(libartic summoner.cpp types.cpp) -set_target_properties(libartic PROPERTIES PREFIX "" CXX_STANDARD 17) +set_target_properties(libartic PROPERTIES PREFIX "" CXX_STANDARD 20) target_link_libraries(libartic PUBLIC ${Thorin_LIBRARIES}) target_include_directories(libartic PUBLIC ${Thorin_INCLUDE_DIRS} ../include) @@ -35,7 +35,7 @@ if (${COLORIZE}) endif() add_executable(artic main.cpp) -set_target_properties(artic PROPERTIES CXX_STANDARD 17) +set_target_properties(artic PROPERTIES CXX_STANDARD 20) target_compile_definitions(artic PUBLIC -DARTIC_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DARTIC_VERSION_MINOR=${PROJECT_VERSION_MINOR}) target_link_libraries(artic PUBLIC libartic) if (Thorin_HAS_JSON_SUPPORT) From 5f05a5f5a973679ecd5b51c53af451b3f9390664 Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 13:45:09 +0100 Subject: [PATCH 2/8] added dummy unique_ptr like smart pointer --- include/artic/arena.h | 41 +++++++++++++++++++++++++++++++++++++++++ include/artic/ast.h | 10 ++++++---- src/parser.cpp | 4 ++-- 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 include/artic/arena.h diff --git a/include/artic/arena.h b/include/artic/arena.h new file mode 100644 index 00000000..5cf1ebda --- /dev/null +++ b/include/artic/arena.h @@ -0,0 +1,41 @@ +#ifndef ARTIC_ARENA_H +#define ARTIC_ARENA_H + +#include + +template +/** works like unique_ptr but doesn't actually own anything */ +struct arena_ptr { + T* _ptr; + + arena_ptr() : _ptr(nullptr) {} + arena_ptr(T* ptr) : _ptr(ptr) {} + + template, bool> = true> + arena_ptr(arena_ptr& other) : _ptr(static_cast(other._ptr)) {} + + template, bool> = true> + arena_ptr(arena_ptr&& other) : _ptr(static_cast(other._ptr)) { + other._ptr = nullptr; + } + ~arena_ptr() { + _ptr = nullptr; + } + + arena_ptr& operator=(const arena_ptr& other) { _ptr = other._ptr; return *this; } + arena_ptr& operator=(arena_ptr&& other) { _ptr = other._ptr; other._ptr = nullptr; return *this; } + + T* operator->() const { return _ptr; } + T& operator*() const { return *_ptr; } + operator bool() const { return _ptr; } + + T* get() const { return _ptr; } + + void swap(arena_ptr& other) { + T* tmp = other._ptr; + other._ptr = _ptr; + _ptr = tmp; + } +}; + +#endif // ARTIC_ARENA_H diff --git a/include/artic/ast.h b/include/artic/ast.h index 401450d8..1efb43b9 100644 --- a/include/artic/ast.h +++ b/include/artic/ast.h @@ -5,6 +5,7 @@ #include #include +#include "artic/arena.h" #include "artic/loc.h" #include "artic/log.h" #include "artic/cast.h" @@ -25,11 +26,12 @@ class TypeChecker; class Emitter; class Summoner; -template using Ptr = std::unique_ptr; -template using PtrVector = std::vector>; +template using Ptr = arena_ptr; +template using PtrVector = std::vector>; template -std::unique_ptr make_ptr(Args&&... args) { - return std::make_unique(std::forward(args)...); + +Ptr make_ptr(Args&&... args) { + return Ptr(new T(std::forward(args)...)); } namespace ast { diff --git a/src/parser.cpp b/src/parser.cpp index 7ea25107..0709298b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -782,7 +782,7 @@ Ptr Parser::parse_for_expr() { auto expr = parse_expr(); auto call_loc = expr->loc; - Ptr call(expr->isa() ? expr.release()->as() : nullptr); + Ptr call(expr->isa() ? expr->as() : nullptr); if (!call) { error(ahead().loc(), "invalid for loop expression"); return make_ptr(tracker()); @@ -798,7 +798,7 @@ Ptr Parser::parse_for_expr() { // Cannot use body->loc directly because std::move(body) might be executed first auto lambda = make_ptr(lambda_loc, nullptr, std::move(ptrn), nullptr, std::move(body)); - Ptr callee(call->callee.release()); + Ptr callee(call->callee.get()); call->callee = make_ptr(call_loc, std::move(callee), std::move(lambda)); return make_ptr(tracker(), std::move(call)); } From 9e4aae0df7154fc1597ce1327c2e8de13f315175 Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 14:21:48 +0100 Subject: [PATCH 3/8] arena_ptr fixes --- include/artic/arena.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/artic/arena.h b/include/artic/arena.h index 5cf1ebda..3c48ee10 100644 --- a/include/artic/arena.h +++ b/include/artic/arena.h @@ -11,18 +11,18 @@ struct arena_ptr { arena_ptr() : _ptr(nullptr) {} arena_ptr(T* ptr) : _ptr(ptr) {} - template, bool> = true> - arena_ptr(arena_ptr& other) : _ptr(static_cast(other._ptr)) {} + // template, bool> = true> + // arena_ptr(arena_ptr& other) : _ptr(other._ptr) {} template, bool> = true> - arena_ptr(arena_ptr&& other) : _ptr(static_cast(other._ptr)) { + arena_ptr(arena_ptr&& other) : _ptr(other._ptr) { other._ptr = nullptr; } ~arena_ptr() { _ptr = nullptr; } - arena_ptr& operator=(const arena_ptr& other) { _ptr = other._ptr; return *this; } + // arena_ptr& operator=(const arena_ptr& other) { _ptr = other._ptr; return *this; } arena_ptr& operator=(arena_ptr&& other) { _ptr = other._ptr; other._ptr = nullptr; return *this; } T* operator->() const { return _ptr; } From f67593e5d28fc36cdc4bacc098f027c7d7b3962a Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 14:45:32 +0100 Subject: [PATCH 4/8] use an Arena instead of leaking memory --- include/artic/arena.h | 21 +++++ include/artic/ast.h | 13 +-- include/artic/check.h | 5 +- include/artic/emit.h | 9 +- include/artic/parser.h | 3 +- include/artic/summoner.h | 6 +- src/CMakeLists.txt | 1 + src/ast.cpp | 12 +-- src/check.cpp | 10 +-- src/emit.cpp | 47 +++++----- src/main.cpp | 10 +-- src/parser.cpp | 190 +++++++++++++++++++-------------------- src/summoner.cpp | 2 +- 13 files changed, 177 insertions(+), 152 deletions(-) diff --git a/include/artic/arena.h b/include/artic/arena.h index 3c48ee10..40e63cdc 100644 --- a/include/artic/arena.h +++ b/include/artic/arena.h @@ -2,6 +2,8 @@ #define ARTIC_ARENA_H #include +#include +#include template /** works like unique_ptr but doesn't actually own anything */ @@ -38,4 +40,23 @@ struct arena_ptr { } }; +struct Arena { + Arena(); + ~Arena(); + + template + arena_ptr make_ptr(Args&& ...args) { + void* ptr = alloc(sizeof(T)); + new (ptr) T (std::forward(args)...); + return arena_ptr(static_cast(ptr)); + } +private: + void* alloc(size_t); + void grow(); + + size_t _block_size; + size_t _available; + std::vector _data; +}; + #endif // ARTIC_ARENA_H diff --git a/include/artic/ast.h b/include/artic/ast.h index 1efb43b9..6db1f7a0 100644 --- a/include/artic/ast.h +++ b/include/artic/ast.h @@ -28,11 +28,6 @@ class Summoner; template using Ptr = arena_ptr; template using PtrVector = std::vector>; -template - -Ptr make_ptr(Args&&... args) { - return Ptr(new T(std::forward(args)...)); -} namespace ast { @@ -157,7 +152,7 @@ struct Ptrn : public Node { /// Collect patterns that bind an identifier to a value in this pattern. virtual void collect_bound_ptrns(std::vector&) const; /// Rewrites the pattern into an expression - virtual const Expr* to_expr() { return as_expr.get(); } + virtual const Expr* to_expr(Arena&) { return as_expr.get(); } /// Returns true when the pattern is trivial (e.g. always matches). virtual bool is_trivial() const = 0; /// Emits IR for the pattern, given a value to bind it to. @@ -1581,7 +1576,7 @@ struct TypedPtrn : public Ptrn { void emit(Emitter&, const thorin::Def*) const override; const artic::Type* infer(TypeChecker&) override; void bind(NameBinder&) override; - const Expr* to_expr() override; + const Expr* to_expr(Arena&) override; void resolve_summons(Summoner&) override; void print(Printer&) const override; }; @@ -1602,7 +1597,7 @@ struct IdPtrn : public Ptrn { const artic::Type* infer(TypeChecker&) override; const artic::Type* check(TypeChecker&, const artic::Type*) override; void bind(NameBinder&) override; - const Expr* to_expr() override; + const Expr* to_expr(Arena&) override; void resolve_summons(Summoner&) override; void print(Printer&) const override; }; @@ -1620,7 +1615,7 @@ struct LiteralPtrn : public Ptrn { const artic::Type* infer(TypeChecker&) override; const artic::Type* check(TypeChecker&, const artic::Type*) override; void bind(NameBinder&) override; - const Expr* to_expr() override; + const Expr* to_expr(Arena&) override; void resolve_summons(Summoner&) override {}; void print(Printer&) const override; }; diff --git a/include/artic/check.h b/include/artic/check.h index 6e57f97f..70b662b4 100644 --- a/include/artic/check.h +++ b/include/artic/check.h @@ -14,8 +14,8 @@ namespace artic { /// Utility class to perform bidirectional type checking. class TypeChecker : public Logger { public: - TypeChecker(Log& log, TypeTable& type_table) - : Logger(log), type_table(type_table) + TypeChecker(Log& log, TypeTable& type_table, Arena& arena) + : Logger(log), type_table(type_table), _arena(arena) {} TypeTable& type_table; @@ -82,6 +82,7 @@ class TypeChecker : public Logger { private: std::unordered_set decls_; + Arena& _arena; }; } // namespace artic diff --git a/include/artic/emit.h b/include/artic/emit.h index ab42c345..5de35dc8 100644 --- a/include/artic/emit.h +++ b/include/artic/emit.h @@ -19,11 +19,12 @@ struct StructType; /// Helper class for Thorin IR generation. class Emitter : public Logger { public: - Emitter(Log& log, thorin::World& world) - : Logger(log), world(world) + Emitter(Log& log, thorin::World& world, Arena& arena) + : Logger(log), world(world), arena(arena) {} thorin::World& world; + Arena& arena; struct State { const thorin::Def* mem = nullptr; @@ -147,12 +148,12 @@ class Emitter : public Logger { /// Helper function to compile a set of files and generate an AST and a thorin module. /// Errors are reported in the log, and this function returns true on success. -bool compile( +Ptr compile( const std::vector& file_names, const std::vector& file_data, bool warns_as_errors, bool enable_all_warns, - ast::ModDecl& program, + Arena& arena, thorin::World& world, Log& log); diff --git a/include/artic/parser.h b/include/artic/parser.h index 8d5c0de1..f27b6d44 100644 --- a/include/artic/parser.h +++ b/include/artic/parser.h @@ -17,7 +17,7 @@ namespace artic { /// Generates an AST from a stream of tokens. class Parser : public Logger { public: - Parser(Log& log, Lexer&); + Parser(Log& log, Lexer&, Arena&); /// Parses a program read from the Lexer object. /// Errors are reported by the Logger. @@ -208,6 +208,7 @@ class Parser : public Logger { Token ahead_[max_ahead]; Lexer& lexer_; Loc prev_; + Arena& _arena; }; } // namespace artic diff --git a/include/artic/summoner.h b/include/artic/summoner.h index 1c35de52..34312ed1 100644 --- a/include/artic/summoner.h +++ b/include/artic/summoner.h @@ -11,8 +11,8 @@ namespace artic { class Summoner : public Logger { public: - Summoner(Log& log) - : Logger(log) + Summoner(Log& log, Arena& arena) + : Logger(log), _arena(arena) {} /// Eliminates all SummonExpr from the program @@ -28,6 +28,8 @@ class Summoner : public Logger { bool error = false; std::vector> scopes; + Arena& _arena; + friend ast::SummonExpr; friend ast::ImplicitDecl; friend ast::ModDecl; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 552072c1..350fd919 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ add_library(libartic ../include/artic/symbol.h ../include/artic/token.h ../include/artic/types.h + arena.cpp ast.cpp bind.cpp check.cpp diff --git a/src/ast.cpp b/src/ast.cpp index f11eb046..2af4e41e 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -619,10 +619,10 @@ bool TypedPtrn::is_trivial() const { return !ptrn || ptrn->is_trivial(); } -const Expr* TypedPtrn::to_expr() { +const Expr* TypedPtrn::to_expr(Arena& arena) { if (!ptrn) return nullptr; - return ptrn->to_expr(); + return ptrn->to_expr(arena); } void IdPtrn::collect_bound_ptrns(std::vector& bound_ptrns) const { @@ -635,7 +635,7 @@ bool IdPtrn::is_trivial() const { return !sub_ptrn || sub_ptrn->is_trivial(); } -const Expr* IdPtrn::to_expr() { +const Expr* IdPtrn::to_expr(Arena& arena) { if (as_expr) return as_expr.get(); Identifier id = decl->id; @@ -644,7 +644,7 @@ const Expr* IdPtrn::to_expr() { Path path = Path(loc, std::move(elems)); path.start_decl = decl.get(); path.is_value = true; - as_expr = make_ptr(std::move(path)); + as_expr = arena.make_ptr(std::move(path)); return as_expr.get(); } @@ -652,10 +652,10 @@ bool LiteralPtrn::is_trivial() const { return false; } -const Expr* LiteralPtrn::to_expr() { +const Expr* LiteralPtrn::to_expr(Arena& arena) { if (as_expr) return as_expr.get(); - as_expr = make_ptr(loc, lit); + as_expr = arena.make_ptr(loc, lit); return as_expr.get(); } diff --git a/src/check.cpp b/src/check.cpp index fa6f01f9..4efbe2a2 100644 --- a/src/check.cpp +++ b/src/check.cpp @@ -150,7 +150,7 @@ inline std::pair remove_ptr(const Type* type) { const Type* TypeChecker::deref(Ptr& expr) { auto [ref_type, type] = remove_ref(infer(*expr)); if (ref_type) - expr = make_ptr(expr->loc, std::move(expr), type); + expr = _arena.make_ptr(expr->loc, std::move(expr), type); return type; } @@ -169,7 +169,7 @@ const Type* TypeChecker::coerce(Ptr& expr, const Type* expected) { if (auto implicit = expected->isa()) { // Only the empty tuple () can be coerced into a Summon[T] if (is_unit(expr)) { - Ptr summoned = make_ptr(expr->loc, Ptr()); + Ptr summoned = _arena.make_ptr(expr->loc, Ptr()); summoned->type = implicit->underlying; expr.swap(summoned); return implicit->underlying; @@ -193,7 +193,7 @@ const Type* TypeChecker::coerce(Ptr& expr, const Type* expected) { } if (auto implicit = tuple_t->args[i]->isa()) { - Ptr summoned = make_ptr(loc, Ptr()); + Ptr summoned = _arena.make_ptr(loc, Ptr()); summoned->type = implicit->underlying; args.push_back(std::move(summoned)); continue; @@ -201,13 +201,13 @@ const Type* TypeChecker::coerce(Ptr& expr, const Type* expected) { bad_arguments(loc, "non-implicit arguments", i, tuple_t->args.size()); } - expr = make_ptr(loc, std::move(args)); + expr = _arena.make_ptr(loc, std::move(args)); } auto type = expr->type ? expr->type : check(*expr, expected); if (type != expected) { if (type->subtype(expected)) { - expr = make_ptr(expr->loc, std::move(expr), expected); + expr = _arena.make_ptr(expr->loc, std::move(expr), expected); return expected; } else return incompatible_types(expr->loc, type, expected); diff --git a/src/emit.cpp b/src/emit.cpp index 83e1f7da..a3898680 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -204,7 +204,7 @@ class PtrnCompiler { assert(literal_ptrn->lit.as_string().size() + 1 == member_count); const char* str = literal_ptrn->lit.as_string().c_str(); for (size_t j = 0; j < member_count; ++j) { - auto char_ptrn = make_ptr(literal_ptrn->loc, uint8_t(str[j])); + auto char_ptrn = emitter.arena.make_ptr(literal_ptrn->loc, uint8_t(str[j])); char_ptrn->type = type->type_table.prim_type(ast::PrimType::U8); new_elems[j] = char_ptrn.get(); tmp_ptrns.emplace_back(std::move(char_ptrn)); @@ -1317,12 +1317,12 @@ const thorin::Def* ProjExpr::emit(Emitter& emitter) const { return emitter.world.extract(emitter.emit(*expr), index, emitter.debug_info(*this)); } -static inline std::pair, Ptr> dummy_case(const Loc& loc, const artic::Type* type) { +static inline std::pair, Ptr> dummy_case(const Loc& loc, const artic::Type* type, Arena& arena) { // Create a dummy wildcard pattern '_' and empty tuple '()' // for the else/break branches of an `if let`/`while let`. - auto anon_decl = make_ptr(loc, Identifier(loc, "_"), false); - auto anon_ptrn = make_ptr(loc, std::move(anon_decl), nullptr); - auto empty_tuple = make_ptr(loc, PtrVector()); + auto anon_decl = arena.make_ptr(loc, Identifier(loc, "_"), false); + auto anon_ptrn = arena.make_ptr(loc, std::move(anon_decl), nullptr); + auto empty_tuple = arena.make_ptr(loc, PtrVector()); anon_ptrn->type = type; return std::make_pair(std::move(anon_ptrn), std::move(empty_tuple)); } @@ -1348,7 +1348,7 @@ const thorin::Def* IfExpr::emit(Emitter& emitter) const { auto false_value = if_false ? emitter.emit(*if_false) : emitter.world.tuple({}); if (join) emitter.jump(join, false_value); } else { - auto [else_ptrn, empty_tuple] = dummy_case(loc, expr->type); + auto [else_ptrn, empty_tuple] = dummy_case(loc, expr->type, emitter.arena); std::vector match_cases; match_cases.emplace_back(ptrn.get(), if_true.get(), this, join); @@ -1400,7 +1400,7 @@ const thorin::Def* WhileExpr::emit(Emitter& emitter) const { emitter.emit(*body); emitter.jump(while_head); } else { - auto [else_ptrn, empty_tuple] = dummy_case(loc, expr->type); + auto [else_ptrn, empty_tuple] = dummy_case(loc, expr->type, emitter.arena); std::vector match_cases; match_cases.emplace_back(ptrn.get(), body.get(), this, while_head); @@ -2053,16 +2053,17 @@ struct MemBuf : public std::streambuf { } }; -bool compile( +Ptr compile( const std::vector& file_names, const std::vector& file_data, bool warns_as_errors, bool enable_all_warns, - ast::ModDecl& program, + Arena& arena, thorin::World& world, Log& log) { assert(file_data.size() == file_names.size()); + auto program = arena.make_ptr(); for (size_t i = 0, n = file_names.size(); i < n; ++i) { if (log.locator) log.locator->register_file(file_names[i], file_data[i]); @@ -2070,20 +2071,20 @@ bool compile( std::istream is(&mem_buf); Lexer lexer(log, file_names[i], is); - Parser parser(log, lexer); + Parser parser(log, lexer, arena); parser.warns_as_errors = warns_as_errors; auto module = parser.parse(); if (log.errors > 0) - return false; + return nullptr; - program.decls.insert( - program.decls.end(), + program->decls.insert( + program->decls.end(), std::make_move_iterator(module->decls.begin()), std::make_move_iterator(module->decls.end()) ); } - program.set_super(); + program->set_super(); NameBinder name_binder(log); name_binder.warns_as_errors = warns_as_errors; @@ -2091,17 +2092,19 @@ bool compile( name_binder.warn_on_shadowing = true; TypeTable type_table; - TypeChecker type_checker(log, type_table); + TypeChecker type_checker(log, type_table, arena); type_checker.warns_as_errors = warns_as_errors; - Summoner summoner(log); + Summoner summoner(log, arena); - if (!name_binder.run(program) || !type_checker.run(program) || !summoner.run(program)) - return false; + if (!name_binder.run(*program) || !type_checker.run(*program) || !summoner.run(*program)) + return nullptr; - Emitter emitter(log, world); + Emitter emitter(log, world, arena); emitter.warns_as_errors = warns_as_errors; - return emitter.run(program); + if (!emitter.run(*program)) + return nullptr; + return program; } } // namespace artic @@ -2117,6 +2120,6 @@ bool compile( Locator locator; log::Output out(error_stream, false); Log log(out, &locator); - ast::ModDecl program; - return artic::compile(file_names, file_data, false, false, program, world, log); + Arena arena; + return artic::compile(file_names, file_data, false, false, arena, world, log); } diff --git a/src/main.cpp b/src/main.cpp index 5cc035e5..0919900d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -321,12 +321,12 @@ int main(int argc, char** argv) { thorin.world().set(opts.log_level); thorin.world().set(std::make_shared(std::cerr)); - ast::ModDecl program; - bool success = compile( + Arena arena; + auto program = compile( opts.files, file_data, opts.warns_as_errors, opts.enable_all_warns, - program, thorin.world(), log); + arena, thorin.world(), log); log.print_summary(); @@ -336,12 +336,12 @@ int main(int argc, char** argv) { Printer p(log::out); p.show_implicit_casts = opts.show_implicit_casts; p.tab = std::string(opts.tab_width, ' '); - program.print(p); + program->print(p); log::out << '\n'; log::out.stream.flush(); } - if (!success) + if (!program) return EXIT_FAILURE; if (opts.opt_level == 1) diff --git a/src/parser.cpp b/src/parser.cpp index 0709298b..f50a3864 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6,8 +6,8 @@ namespace artic { -Parser::Parser(Log& log, Lexer& lexer) - : Logger(log), lexer_(lexer) +Parser::Parser(Log& log, Lexer& lexer, Arena& arena) + : Logger(log), lexer_(lexer), _arena(arena) { for (int i = 0; i < max_ahead; i++) ahead_[i] = Token(Loc()); @@ -20,7 +20,7 @@ Ptr Parser::parse() { PtrVector decls; while (ahead().tag() != Token::End) decls.emplace_back(parse_decl(true)); - return make_ptr(tracker(), ast::Identifier(), std::move(decls)); + return _arena.make_ptr(tracker(), ast::Identifier(), std::move(decls)); } // Declarations -------------------------------------------------------------------- @@ -62,7 +62,7 @@ Ptr Parser::parse_let_decl() { if (accept(Token::Eq)) init = parse_expr(); expect(Token::Semi); - return make_ptr(tracker(), std::move(ptrn), std::move(init)); + return _arena.make_ptr(tracker(), std::move(ptrn), std::move(init)); } Ptr Parser::parse_fn_decl() { @@ -87,7 +87,7 @@ Ptr Parser::parse_fn_decl() { Ptr ret_type; if (accept(Token::Arrow)) { if (accept(Token::Not)) - ret_type = make_ptr(prev_); + ret_type = _arena.make_ptr(prev_); else ret_type = parse_type(); } @@ -106,8 +106,8 @@ Ptr Parser::parse_fn_decl() { expect(Token::Semi); } - auto fn = make_ptr(tracker(), std::move(filter), std::move(param), std::move(ret_type), std::move(body)); - return make_ptr(tracker(), std::move(id), std::move(fn), std::move(type_params)); + auto fn = _arena.make_ptr(tracker(), std::move(filter), std::move(param), std::move(ret_type), std::move(body)); + return _arena.make_ptr(tracker(), std::move(id), std::move(fn), std::move(type_params)); } Ptr Parser::parse_field_decl(bool is_tuple_like) { @@ -119,7 +119,7 @@ Ptr Parser::parse_field_decl(bool is_tuple_like) { Ptr init; if (accept(Token::Eq)) init = parse_expr(); - return make_ptr(tracker(), std::move(id), std::move(type), std::move(init)); + return _arena.make_ptr(tracker(), std::move(id), std::move(type), std::move(init)); } Ptr Parser::parse_struct_decl() { @@ -145,7 +145,7 @@ Ptr Parser::parse_struct_decl() { expect(Token::Semi); } - return make_ptr(tracker(), std::move(id), std::move(type_params), std::move(fields), is_tuple_like); + return _arena.make_ptr(tracker(), std::move(id), std::move(type_params), std::move(fields), is_tuple_like); } Ptr Parser::parse_option_decl() { @@ -163,7 +163,7 @@ Ptr Parser::parse_option_decl() { }); has_fields = true; } - return make_ptr(tracker(), std::move(id), std::move(param), std::move(fields), has_fields); + return _arena.make_ptr(tracker(), std::move(id), std::move(param), std::move(fields), has_fields); } Ptr Parser::parse_enum_decl() { @@ -182,7 +182,7 @@ Ptr Parser::parse_enum_decl() { }); if (options.empty()) error(tracker(), "enums require at least one alternative"); - return make_ptr(tracker(), std::move(id), std::move(type_params), std::move(options)); + return _arena.make_ptr(tracker(), std::move(id), std::move(type_params), std::move(options)); } Ptr Parser::parse_type_decl() { @@ -197,7 +197,7 @@ Ptr Parser::parse_type_decl() { expect(Token::Eq); auto aliased_type = parse_type(); expect(Token::Semi); - return make_ptr(tracker(), std::move(id), std::move(type_params), std::move(aliased_type)); + return _arena.make_ptr(tracker(), std::move(id), std::move(type_params), std::move(aliased_type)); } Ptr Parser::parse_implicit_decl() { @@ -211,7 +211,7 @@ Ptr Parser::parse_implicit_decl() { expect(Token::Eq); auto value = parse_expr(true); expect(Token::Semi); - return make_ptr(tracker(), std::move(type), std::move(value)); + return _arena.make_ptr(tracker(), std::move(type), std::move(value)); } Ptr Parser::parse_static_decl() { @@ -228,13 +228,13 @@ Ptr Parser::parse_static_decl() { if (accept(Token::Eq)) init = parse_expr(); expect(Token::Semi); - return make_ptr(tracker(), std::move(id), std::move(type), std::move(init), is_mut); + return _arena.make_ptr(tracker(), std::move(id), std::move(type), std::move(init), is_mut); } Ptr Parser::parse_type_param() { Tracker tracker(this); auto id = parse_id(); - return make_ptr(tracker(), std::move(id)); + return _arena.make_ptr(tracker(), std::move(id)); } Ptr Parser::parse_type_params() { @@ -244,7 +244,7 @@ Ptr Parser::parse_type_params() { parse_list(Token::RBracket, Token::Comma, [&] { type_params.emplace_back(parse_type_param()); }); - return make_ptr(tracker(), std::move(type_params)); + return _arena.make_ptr(tracker(), std::move(type_params)); } Ptr Parser::parse_mod_decl() { @@ -256,7 +256,7 @@ Ptr Parser::parse_mod_decl() { while (ahead().tag() != Token::End && ahead().tag() != Token::RBrace) decls.emplace_back(parse_decl(true)); expect(Token::RBrace); - return make_ptr(tracker(), std::move(id), std::move(decls)); + return _arena.make_ptr(tracker(), std::move(id), std::move(decls)); } Ptr Parser::parse_use_decl() { @@ -273,14 +273,14 @@ Ptr Parser::parse_use_decl() { log::keyword_style("use"), path, log::keyword_style("as")); } - return make_ptr(tracker(), std::move(path), std::move(id)); + return _arena.make_ptr(tracker(), std::move(path), std::move(id)); } Ptr Parser::parse_error_decl() { Tracker tracker(this); error(ahead().loc(), "expected declaration, got '{}'", ahead().string()); next(); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } // Patterns ------------------------------------------------------------------------ @@ -295,7 +295,7 @@ Ptr Parser::parse_ptrn(bool allow_types, bool allow_implicits) { if (!allow_types) return parse_error_ptrn(); auto type = parse_prim_type(tag); - return make_ptr(type->loc, Ptr(), std::move(type)); + return _arena.make_ptr(type->loc, Ptr(), std::move(type)); } auto id = parse_path_elem(); if (ahead().tag() == Token::DblColon || @@ -307,8 +307,8 @@ Ptr Parser::parse_ptrn(bool allow_types, bool allow_implicits) { if (ahead().tag() == Token::LBrace) ptrn = parse_record_ptrn(std::move(path)); else if (allow_types) { - auto type = make_ptr(path.loc, std::move(path)); - return make_ptr(path.loc, Ptr(), std::move(type)); + auto type = _arena.make_ptr(path.loc, std::move(path)); + return _arena.make_ptr(path.loc, Ptr(), std::move(type)); } else ptrn = parse_ctor_ptrn(std::move(path)); } else @@ -334,7 +334,7 @@ Ptr Parser::parse_ptrn(bool allow_types, bool allow_implicits) { case Token::Fn: if (allow_types) { auto type = parse_type(); - return make_ptr(type->loc, Ptr(), std::move(type)); + return _arena.make_ptr(type->loc, Ptr(), std::move(type)); } [[fallthrough]]; case Token::Implicit: @@ -343,7 +343,7 @@ Ptr Parser::parse_ptrn(bool allow_types, bool allow_implicits) { return parse_error_ptrn(); eat(Token::Implicit); auto underlying = parse_ptrn(); - return make_ptr(underlying->loc, std::move(underlying)); + return _arena.make_ptr(underlying->loc, std::move(underlying)); } default: ptrn = parse_error_ptrn(); @@ -356,24 +356,24 @@ Ptr Parser::parse_typed_ptrn(Ptr&& ptrn) { Tracker tracker(this, ptrn->loc); if (accept(Token::Colon)) { auto type = parse_type(); - return make_ptr(tracker(), std::move(ptrn), std::move(type)); + return _arena.make_ptr(tracker(), std::move(ptrn), std::move(type)); } return std::move(ptrn); } Ptr Parser::parse_id_ptrn(ast::Identifier&& id, bool is_mut) { Tracker tracker(this, id.loc); - auto decl = make_ptr(tracker(), std::move(id), is_mut); + auto decl = _arena.make_ptr(tracker(), std::move(id), is_mut); Ptr sub_ptrn; if (accept(Token::As)) sub_ptrn = parse_ptrn(); - return make_ptr(tracker(), std::move(decl), std::move(sub_ptrn)); + return _arena.make_ptr(tracker(), std::move(decl), std::move(sub_ptrn)); } Ptr Parser::parse_literal_ptrn() { Tracker tracker(this); auto lit = parse_lit(); - return make_ptr(tracker(), lit); + return _arena.make_ptr(tracker(), lit); } Ptr Parser::parse_field_ptrn() { @@ -389,7 +389,7 @@ Ptr Parser::parse_field_ptrn() { expect(Token::Eq); ptrn = parse_ptrn(); } - return make_ptr(tracker(), std::move(id), std::move(ptrn)); + return _arena.make_ptr(tracker(), std::move(id), std::move(ptrn)); } Ptr Parser::parse_record_ptrn(ast::Path&& path) { @@ -403,7 +403,7 @@ Ptr Parser::parse_record_ptrn(ast::Path&& path) { auto etc = std::find_if(fields.begin(), fields.end(), [] (auto& field) { return field->is_etc(); }); if (etc != fields.end() && etc != fields.end() - 1) error((*etc)->loc, "'...' can only be used at the end of a record pattern"); - return make_ptr(tracker(), std::move(path), std::move(fields)); + return _arena.make_ptr(tracker(), std::move(path), std::move(fields)); } Ptr Parser::parse_ctor_ptrn(ast::Path&& path) { @@ -411,7 +411,7 @@ Ptr Parser::parse_ctor_ptrn(ast::Path&& path) { Ptr arg; if (ahead().tag() == Token::LParen) arg = parse_tuple_ptrn(); - return make_ptr(tracker(), std::move(path), std::move(arg)); + return _arena.make_ptr(tracker(), std::move(path), std::move(arg)); } Ptr Parser::parse_tuple_ptrn(bool allow_types, bool allow_implicits, Token::Tag beg, Token::Tag end) { @@ -425,7 +425,7 @@ Ptr Parser::parse_tuple_ptrn(bool allow_types, bool allow_implicits, args[0]->loc = tracker(); return std::move(args[0]); } - return make_ptr(tracker(), std::move(args)); + return _arena.make_ptr(tracker(), std::move(args)); } Ptr Parser::parse_array_ptrn() { @@ -436,14 +436,14 @@ Ptr Parser::parse_array_ptrn() { parse_list(Token::RBracket, Token::Comma, [&] { elems.emplace_back(parse_ptrn()); }); - return make_ptr(tracker(), std::move(elems), is_simd); + return _arena.make_ptr(tracker(), std::move(elems), is_simd); } Ptr Parser::parse_error_ptrn() { Tracker tracker(this); error(ahead().loc(), "expected pattern, got '{}'", ahead().string()); next(); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } // Statements ---------------------------------------------------------------------- @@ -461,19 +461,19 @@ Ptr Parser::parse_stmt() { default: return parse_expr_stmt(); } - return make_ptr(tracker(), std::move(expr)); + return _arena.make_ptr(tracker(), std::move(expr)); } Ptr Parser::parse_decl_stmt() { Tracker tracker(this); auto decl = parse_decl(); - return make_ptr(tracker(), std::move(decl)); + return _arena.make_ptr(tracker(), std::move(decl)); } Ptr Parser::parse_expr_stmt() { Tracker tracker(this); auto expr = parse_expr(); - return make_ptr(tracker(), std::move(expr)); + return _arena.make_ptr(tracker(), std::move(expr)); } // Expressions --------------------------------------------------------------------- @@ -486,18 +486,18 @@ Ptr Parser::parse_typed_expr(Ptr&& expr) { Tracker tracker(this, expr->loc); eat(Token::Colon); auto type = parse_type(); - return make_ptr(tracker(), std::move(expr), std::move(type)); + return _arena.make_ptr(tracker(), std::move(expr), std::move(type)); } Ptr Parser::parse_path_expr() { auto path = parse_path(true); - return make_ptr(std::move(path)); + return _arena.make_ptr(std::move(path)); } Ptr Parser::parse_literal_expr() { Tracker tracker(this); auto lit = parse_lit(); - return make_ptr(tracker(), lit); + return _arena.make_ptr(tracker(), lit); } Ptr Parser::parse_summon_expr() { @@ -506,7 +506,7 @@ Ptr Parser::parse_summon_expr() { expect(Token::LBracket); auto t = parse_type(); expect(Token::RBracket); - return make_ptr(tracker(), std::move(t)); + return _arena.make_ptr(tracker(), std::move(t)); } Ptr Parser::parse_field_expr() { @@ -514,7 +514,7 @@ Ptr Parser::parse_field_expr() { auto id = parse_id(); expect(Token::Eq); auto expr = parse_expr(); - return make_ptr(tracker(), std::move(id), std::move(expr)); + return _arena.make_ptr(tracker(), std::move(id), std::move(expr)); } Ptr Parser::parse_record_expr(ast::Path&& path) { @@ -523,13 +523,13 @@ Ptr Parser::parse_record_expr(ast::Path&& path) { // path.loc and std::move(path) in the argument list // (argument evaluation order is not defined). auto loc = path.loc; - auto type_app = make_ptr(loc, std::move(path)); + auto type_app = _arena.make_ptr(loc, std::move(path)); eat(Token::LBrace); PtrVector fields; parse_list(Token::RBrace, Token::Comma, [&] { fields.emplace_back(parse_field_expr()); }); - return make_ptr(tracker(), std::move(type_app), std::move(fields)); + return _arena.make_ptr(tracker(), std::move(type_app), std::move(fields)); } Ptr Parser::parse_record_expr(Ptr&& expr) { @@ -540,7 +540,7 @@ Ptr Parser::parse_record_expr(Ptr&& expr) { parse_list(Token::RBrace, Token::Comma, [&] { fields.emplace_back(parse_field_expr()); }); - return make_ptr(tracker(), std::move(expr), std::move(fields)); + return _arena.make_ptr(tracker(), std::move(expr), std::move(fields)); } Ptr Parser::parse_tuple_expr() { @@ -554,7 +554,7 @@ Ptr Parser::parse_tuple_expr() { args[0]->loc = tracker(); return std::move(args[0]); } - return make_ptr(tracker(), std::move(args)); + return _arena.make_ptr(tracker(), std::move(args)); } Ptr Parser::parse_array_expr() { @@ -567,16 +567,16 @@ Ptr Parser::parse_array_expr() { auto size = parse_array_size(); expect(Token::RBracket); if (size) - return make_ptr(tracker(), std::move(elems.front()), std::move(*size), is_simd); - return make_ptr(tracker(), std::move(elems), is_simd); + return _arena.make_ptr(tracker(), std::move(elems.front()), std::move(*size), is_simd); + return _arena.make_ptr(tracker(), std::move(elems), is_simd); } else if (accept(Token::Comma)) { parse_list(Token::RBracket, Token::Comma, [&] { elems.emplace_back(parse_expr()); }); - return make_ptr(tracker(), std::move(elems), is_simd); + return _arena.make_ptr(tracker(), std::move(elems), is_simd); } else { expect(Token::RBracket); - return make_ptr(tracker(), std::move(elems), is_simd); + return _arena.make_ptr(tracker(), std::move(elems), is_simd); } } @@ -633,7 +633,7 @@ Ptr Parser::parse_block_expr() { break; } expect(Token::RBrace); - return make_ptr(tracker(), std::move(stmts), last_semi); + return _arena.make_ptr(tracker(), std::move(stmts), last_semi); } Ptr Parser::parse_fn_expr(Ptr&& filter, bool nested) { @@ -654,10 +654,10 @@ Ptr Parser::parse_fn_expr(Ptr&& filter, bool nested) { if (args.size() == 1) { ptrn = std::move(args.front()); } else { - ptrn = make_ptr(tracker(), std::move(args)); + ptrn = _arena.make_ptr(tracker(), std::move(args)); } } else if (accept(Token::LogicOr)) - ptrn = make_ptr(tracker(), PtrVector{}); + ptrn = _arena.make_ptr(tracker(), PtrVector{}); else ptrn = parse_error_ptrn(); @@ -673,13 +673,13 @@ Ptr Parser::parse_fn_expr(Ptr&& filter, bool nested) { ret_type = parse_type(); body = parse_expr(); } - return make_ptr(tracker(), std::move(filter), std::move(ptrn), std::move(ret_type), std::move(body)); + return _arena.make_ptr(tracker(), std::move(filter), std::move(ptrn), std::move(ret_type), std::move(body)); } Ptr Parser::parse_call_expr(Ptr&& callee) { Tracker tracker(this, callee->loc); auto args = parse_tuple_expr(); - return make_ptr(tracker(), std::move(callee), std::move(args)); + return _arena.make_ptr(tracker(), std::move(callee), std::move(args)); } Ptr Parser::parse_proj_expr(Ptr&& expr) { @@ -688,10 +688,10 @@ Ptr Parser::parse_proj_expr(Ptr&& expr) { if (ahead().is_literal() && ahead().literal().is_integer()) { size_t index = ahead().literal().as_integer(); eat(Token::Lit); - return make_ptr(tracker(), std::move(expr), index); + return _arena.make_ptr(tracker(), std::move(expr), index); } else { auto id = parse_id(); - return make_ptr(tracker(), std::move(expr), std::move(id)); + return _arena.make_ptr(tracker(), std::move(expr), std::move(id)); } } @@ -719,11 +719,11 @@ Ptr Parser::parse_if_expr() { auto if_true = parse_block_expr(); auto if_false = accept_else(); - return make_ptr(tracker(), std::move(ptrn), std::move(expr), std::move(if_true), std::move(if_false)); + return _arena.make_ptr(tracker(), std::move(ptrn), std::move(expr), std::move(if_true), std::move(if_false)); } else { auto [cond, if_true] = parse_cond_and_block(); auto if_false = accept_else(); - return make_ptr(tracker(), std::move(cond), std::move(if_true), std::move(if_false)); + return _arena.make_ptr(tracker(), std::move(cond), std::move(if_true), std::move(if_false)); } } @@ -732,7 +732,7 @@ Ptr Parser::parse_case_expr() { auto ptrn = parse_ptrn(); expect(Token::FatArrow); auto expr = parse_expr(); - return make_ptr(tracker(), std::move(ptrn), std::move(expr)); + return _arena.make_ptr(tracker(), std::move(ptrn), std::move(expr)); } Ptr Parser::parse_match_expr() { @@ -744,7 +744,7 @@ Ptr Parser::parse_match_expr() { parse_list(Token::RBrace, Token::Comma, [&] { cases.emplace_back(parse_case_expr()); }); - return make_ptr(tracker(), std::move(arg), std::move(cases)); + return _arena.make_ptr(tracker(), std::move(arg), std::move(cases)); } Ptr Parser::parse_while_expr() { @@ -756,10 +756,10 @@ Ptr Parser::parse_while_expr() { auto expr = parse_expr(false); auto body = parse_block_expr(); - return make_ptr(tracker(), std::move(ptrn), std::move(expr), std::move(body)); + return _arena.make_ptr(tracker(), std::move(ptrn), std::move(expr), std::move(body)); } else { auto[cond, body] = parse_cond_and_block(); - return make_ptr(tracker(), std::move(cond), std::move(body)); + return _arena.make_ptr(tracker(), std::move(cond), std::move(body)); } } @@ -777,7 +777,7 @@ Ptr Parser::parse_for_expr() { ptrn = parse_tuple_ptrn(false, false, Token::For, Token::In); else { eat(Token::For); - ptrn = make_ptr(tracker(), PtrVector{}); + ptrn = _arena.make_ptr(tracker(), PtrVector{}); } auto expr = parse_expr(); @@ -785,7 +785,7 @@ Ptr Parser::parse_for_expr() { Ptr call(expr->isa() ? expr->as() : nullptr); if (!call) { error(ahead().loc(), "invalid for loop expression"); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } Ptr body; @@ -796,29 +796,29 @@ Ptr Parser::parse_for_expr() { auto lambda_loc = body->loc; // Cannot use body->loc directly because std::move(body) might be executed first - auto lambda = make_ptr(lambda_loc, nullptr, std::move(ptrn), nullptr, std::move(body)); + auto lambda = _arena.make_ptr(lambda_loc, nullptr, std::move(ptrn), nullptr, std::move(body)); Ptr callee(call->callee.get()); - call->callee = make_ptr(call_loc, std::move(callee), std::move(lambda)); - return make_ptr(tracker(), std::move(call)); + call->callee = _arena.make_ptr(call_loc, std::move(callee), std::move(lambda)); + return _arena.make_ptr(tracker(), std::move(call)); } Ptr Parser::parse_break_expr() { Tracker tracker(this); eat(Token::Break); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } Ptr Parser::parse_continue_expr() { Tracker tracker(this); eat(Token::Continue); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } Ptr Parser::parse_return_expr() { Tracker tracker(this); eat(Token::Return); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } Ptr Parser::parse_primary_expr(bool allow_structs, bool allow_casts) { @@ -900,14 +900,14 @@ Ptr Parser::parse_prefix_expr(bool allow_structs) { if (tag == ast::UnaryExpr::AddrOf && accept(Token::Mut)) tag = ast::UnaryExpr::AddrOfMut; auto expr = parse_primary_expr(allow_structs, false); - return make_ptr(tracker(), tag, std::move(expr)); + return _arena.make_ptr(tracker(), tag, std::move(expr)); } Ptr Parser::parse_postfix_expr(Ptr&& expr) { Tracker tracker(this, expr->loc); auto tag = ast::UnaryExpr::tag_from_token(ahead(), false); next(); - return make_ptr(tracker(), tag, std::move(expr)); + return _arena.make_ptr(tracker(), tag, std::move(expr)); } Ptr Parser::parse_binary_expr(bool allow_structs, int max_prec) { @@ -922,7 +922,7 @@ Ptr Parser::parse_binary_expr(bool allow_structs, int max_prec) { next(); auto right = parse_binary_expr(allow_structs, prec - 1); - left = make_ptr(tracker(), tag, std::move(left), std::move(right)); + left = _arena.make_ptr(tracker(), tag, std::move(left), std::move(right)); } return left; } @@ -933,7 +933,7 @@ Ptr Parser::parse_filter_expr(Ptr&& filter) { if (auto call_expr = expr->isa()) { if (call_expr->callee->isa()) warn(filter->loc, "redundant filter annotation"); - call_expr->callee = make_ptr(tracker(), std::move(filter), std::move(call_expr->callee)); + call_expr->callee = _arena.make_ptr(tracker(), std::move(filter), std::move(call_expr->callee)); } else error(expr->loc, "invalid filter expression"); return expr; @@ -943,7 +943,7 @@ Ptr Parser::parse_cast_expr(Ptr&& expr) { Tracker tracker(this, expr->loc); eat(Token::As); auto type = parse_type(); - return make_ptr(tracker(), std::move(expr), std::move(type)); + return _arena.make_ptr(tracker(), std::move(expr), std::move(type)); } Ptr Parser::parse_asm_expr() { @@ -1004,7 +1004,7 @@ Ptr Parser::parse_asm_expr() { error(ahead().loc(), "expected ':', or ')' in assembly expression"); done: - return make_ptr( + return _arena.make_ptr( tracker(), std::move(src), std::move(ins), std::move(outs), std::move(clobs), std::move(opts)); @@ -1014,7 +1014,7 @@ Ptr Parser::parse_error_expr() { Tracker tracker(this); error(ahead().loc(), "expected expression, got '{}'", ahead().string()); next(); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } // Types --------------------------------------------------------------------------- @@ -1047,7 +1047,7 @@ Ptr Parser::parse_named_type() { Ptr Parser::parse_prim_type(ast::PrimType::Tag tag) { Tracker tracker(this); next(); - return make_ptr(tracker(), tag); + return _arena.make_ptr(tracker(), tag); } Ptr Parser::parse_tuple_type() { @@ -1061,7 +1061,7 @@ Ptr Parser::parse_tuple_type() { args[0]->loc = tracker(); return std::move(args[0]); } - return make_ptr(tracker(), std::move(args)); + return _arena.make_ptr(tracker(), std::move(args)); } Ptr Parser::parse_array_type() { @@ -1074,11 +1074,11 @@ Ptr Parser::parse_array_type() { auto size = parse_array_size(); expect(Token::RBracket); if (size) - return make_ptr(tracker(), std::move(elem), std::move(*size), is_simd); - return make_ptr(tracker(), std::move(elem)); + return _arena.make_ptr(tracker(), std::move(elem), std::move(*size), is_simd); + return _arena.make_ptr(tracker(), std::move(elem)); } else { expect(Token::RBracket); - return make_ptr(tracker(), std::move(elem)); + return _arena.make_ptr(tracker(), std::move(elem)); } } @@ -1093,10 +1093,10 @@ Ptr Parser::parse_fn_type() { expect(Token::Arrow); Ptr to; if (accept(Token::Not)) - to = make_ptr(prev_); + to = _arena.make_ptr(prev_); else to = parse_type(); - return make_ptr(tracker(), std::move(from), std::move(to)); + return _arena.make_ptr(tracker(), std::move(from), std::move(to)); } Ptr Parser::parse_ptr_type() { @@ -1110,23 +1110,23 @@ Ptr Parser::parse_ptr_type() { if (ahead().tag() == Token::AddrSpace) addr_space = parse_addr_space(); auto pointee = parse_type(); - auto inner_ptr = make_ptr(tracker(), std::move(pointee), is_mut, addr_space); + auto inner_ptr = _arena.make_ptr(tracker(), std::move(pointee), is_mut, addr_space); return double_ptr - ? make_ptr(tracker(), std::move(inner_ptr), false, 0) + ? _arena.make_ptr(tracker(), std::move(inner_ptr), false, 0) : std::move(inner_ptr); } Ptr Parser::parse_type_app() { Tracker tracker(this); auto path = parse_path(); - return make_ptr(tracker(), std::move(path)); + return _arena.make_ptr(tracker(), std::move(path)); } Ptr Parser::parse_error_type() { Tracker tracker(this); error(ahead().loc(), "expected type, got '{}'", ahead().string()); next(); - return make_ptr(tracker()); + return _arena.make_ptr(tracker()); } Ptr Parser::parse_filter() { @@ -1137,7 +1137,7 @@ Ptr Parser::parse_filter() { expr = parse_expr(); expect(Token::RParen); } - return make_ptr(tracker(), std::move(expr)); + return _arena.make_ptr(tracker(), std::move(expr)); } Ptr Parser::parse_attr_list() { @@ -1148,7 +1148,7 @@ Ptr Parser::parse_attr_list() { parse_list(Token::RBracket, Token::Comma, [&] { attrs.emplace_back(parse_attr()); }); - return make_ptr(tracker(), std::move(attrs)); + return _arena.make_ptr(tracker(), std::move(attrs)); } Ptr Parser::parse_attr() { @@ -1162,13 +1162,13 @@ Ptr Parser::parse_attr() { if (ahead().tag() == Token::Lit) { auto lit = ahead().literal(); eat(Token::Lit); - return make_ptr(tracker(), std::move(name), lit); + return _arena.make_ptr(tracker(), std::move(name), lit); } else if (ahead().tag() == Token::Id) { auto path = parse_path(); - return make_ptr(tracker(), std::move(name), std::move(path)); + return _arena.make_ptr(tracker(), std::move(name), std::move(path)); } else { error(ahead().loc(), "expected attribute value, got '{}'", ahead().string()); - return make_ptr(tracker(), std::move(name), PtrVector()); + return _arena.make_ptr(tracker(), std::move(name), PtrVector()); } } else { PtrVector args; @@ -1177,7 +1177,7 @@ Ptr Parser::parse_attr() { args.emplace_back(parse_attr()); }); } - return make_ptr(tracker(), std::move(name), std::move(args)); + return _arena.make_ptr(tracker(), std::move(name), std::move(args)); } } diff --git a/src/summoner.cpp b/src/summoner.cpp index bb6ce9ed..9b8c78c6 100644 --- a/src/summoner.cpp +++ b/src/summoner.cpp @@ -220,7 +220,7 @@ void IdPtrn::resolve_summons(artic::Summoner& summoner) { } void ImplicitParamPtrn::resolve_summons(artic::Summoner& summoner) { - summoner.insert(underlying->type, underlying->to_expr()); + summoner.insert(underlying->type, underlying->to_expr(summoner._arena)); } void FieldPtrn::resolve_summons(artic::Summoner& summoner) { From 40ae7a224c2506b6ed12372de50a41d9ad122377 Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 15:45:30 +0100 Subject: [PATCH 5/8] compile() now returns a tuple of (module, success) --- include/artic/emit.h | 2 +- src/emit.cpp | 12 ++++++------ src/main.cpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/artic/emit.h b/include/artic/emit.h index 5de35dc8..b96190ea 100644 --- a/include/artic/emit.h +++ b/include/artic/emit.h @@ -148,7 +148,7 @@ class Emitter : public Logger { /// Helper function to compile a set of files and generate an AST and a thorin module. /// Errors are reported in the log, and this function returns true on success. -Ptr compile( +std::tuple, bool> compile( const std::vector& file_names, const std::vector& file_data, bool warns_as_errors, diff --git a/src/emit.cpp b/src/emit.cpp index a3898680..6a47dce7 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -2053,7 +2053,7 @@ struct MemBuf : public std::streambuf { } }; -Ptr compile( +std::tuple, bool> compile( const std::vector& file_names, const std::vector& file_data, bool warns_as_errors, @@ -2075,7 +2075,7 @@ Ptr compile( parser.warns_as_errors = warns_as_errors; auto module = parser.parse(); if (log.errors > 0) - return nullptr; + return std::make_tuple(std::move(program), false); program->decls.insert( program->decls.end(), @@ -2098,13 +2098,13 @@ Ptr compile( Summoner summoner(log, arena); if (!name_binder.run(*program) || !type_checker.run(*program) || !summoner.run(*program)) - return nullptr; + return std::make_tuple(std::move(program), false); Emitter emitter(log, world, arena); emitter.warns_as_errors = warns_as_errors; if (!emitter.run(*program)) - return nullptr; - return program; + return std::make_tuple(std::move(program), false); + return std::make_tuple(std::move(program), true); } } // namespace artic @@ -2121,5 +2121,5 @@ bool compile( log::Output out(error_stream, false); Log log(out, &locator); Arena arena; - return artic::compile(file_names, file_data, false, false, arena, world, log); + return get<1>(artic::compile(file_names, file_data, false, false, arena, world, log)); } diff --git a/src/main.cpp b/src/main.cpp index 0919900d..02416a37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -322,7 +322,7 @@ int main(int argc, char** argv) { thorin.world().set(std::make_shared(std::cerr)); Arena arena; - auto program = compile( + auto [program, success] = compile( opts.files, file_data, opts.warns_as_errors, opts.enable_all_warns, @@ -341,7 +341,7 @@ int main(int argc, char** argv) { log::out.stream.flush(); } - if (!program) + if (!success) return EXIT_FAILURE; if (opts.opt_level == 1) From 4811ceb4b8a44e509c2b413b083f9d8389bf882f Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 15:47:24 +0100 Subject: [PATCH 6/8] fix crash when printing a SummonExpr due to TypeTable lifetime being too short --- include/artic/emit.h | 1 + src/emit.cpp | 5 +++-- src/main.cpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/artic/emit.h b/include/artic/emit.h index b96190ea..e1303aeb 100644 --- a/include/artic/emit.h +++ b/include/artic/emit.h @@ -154,6 +154,7 @@ std::tuple, bool> compile( bool warns_as_errors, bool enable_all_warns, Arena& arena, + TypeTable& table, thorin::World& world, Log& log); diff --git a/src/emit.cpp b/src/emit.cpp index 6a47dce7..27e041ea 100644 --- a/src/emit.cpp +++ b/src/emit.cpp @@ -2059,6 +2059,7 @@ std::tuple, bool> compile( bool warns_as_errors, bool enable_all_warns, Arena& arena, + TypeTable& type_table, thorin::World& world, Log& log) { @@ -2091,7 +2092,6 @@ std::tuple, bool> compile( if (enable_all_warns) name_binder.warn_on_shadowing = true; - TypeTable type_table; TypeChecker type_checker(log, type_table, arena); type_checker.warns_as_errors = warns_as_errors; @@ -2121,5 +2121,6 @@ bool compile( log::Output out(error_stream, false); Log log(out, &locator); Arena arena; - return get<1>(artic::compile(file_names, file_data, false, false, arena, world, log)); + TypeTable type_table; + return get<1>(artic::compile(file_names, file_data, false, false, arena, type_table, world, log)); } diff --git a/src/main.cpp b/src/main.cpp index 02416a37..0ef47cc9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -322,11 +322,12 @@ int main(int argc, char** argv) { thorin.world().set(std::make_shared(std::cerr)); Arena arena; + TypeTable type_table; auto [program, success] = compile( opts.files, file_data, opts.warns_as_errors, opts.enable_all_warns, - arena, thorin.world(), log); + arena, type_table, thorin.world(), log); log.print_summary(); From fac037020f890bcf7e391635f0b6457a0dfbfb75 Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Thu, 9 Jan 2025 15:59:44 +0100 Subject: [PATCH 7/8] added missing arena --- src/arena.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/arena.cpp diff --git a/src/arena.cpp b/src/arena.cpp new file mode 100644 index 00000000..3358bbdd --- /dev/null +++ b/src/arena.cpp @@ -0,0 +1,27 @@ +#include "artic/arena.h" + +#include + +Arena::Arena() : _block_size(4096) { + _data = { malloc(_block_size) }; + _available = _block_size; +} + +Arena::~Arena() { + for (auto& ptr : _data) + free(ptr); +} + +void Arena::grow() { + _block_size *= 2; + _data.push_back( malloc(_block_size) ); + _available = _block_size; +} + +void* Arena::alloc(size_t size) { + while (size > _available) + grow(); + size_t ptr = reinterpret_cast(_data.back()) + _block_size - _available; + _available -= size; + return reinterpret_cast(ptr); +} From da8013edd3ac50bdfabb767d064b23c4ce360220 Mon Sep 17 00:00:00 2001 From: Hugo Devillers Date: Fri, 1 Aug 2025 14:23:57 +0200 Subject: [PATCH 8/8] arena: track non-trivially destructible types and remember to call their dtor --- include/artic/arena.h | 17 ++++++++++++++++- src/arena.cpp | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/artic/arena.h b/include/artic/arena.h index 40e63cdc..274ae2e6 100644 --- a/include/artic/arena.h +++ b/include/artic/arena.h @@ -4,6 +4,7 @@ #include #include #include +#include template /** works like unique_ptr but doesn't actually own anything */ @@ -44,12 +45,25 @@ struct Arena { Arena(); ~Arena(); - template + template::value, bool>::type = true, typename ...Args> arena_ptr make_ptr(Args&& ...args) { void* ptr = alloc(sizeof(T)); new (ptr) T (std::forward(args)...); return arena_ptr(static_cast(ptr)); } + + template::value, bool>::type = true, typename ...Args> + arena_ptr make_ptr(Args&& ...args) { + void* ptr = alloc(sizeof(T)); + new (ptr) T (std::forward(args)...); + auto deleter = [] (T* t) -> void { + t->~T(); + }; + auto fn = static_cast(deleter); + auto generic_fn = reinterpret_cast(fn); + _cleanup.emplace_back(generic_fn, ptr); + return arena_ptr(static_cast(ptr)); + } private: void* alloc(size_t); void grow(); @@ -57,6 +71,7 @@ struct Arena { size_t _block_size; size_t _available; std::vector _data; + std::vector> _cleanup; }; #endif // ARTIC_ARENA_H diff --git a/src/arena.cpp b/src/arena.cpp index 3358bbdd..a05b7aca 100644 --- a/src/arena.cpp +++ b/src/arena.cpp @@ -8,6 +8,9 @@ Arena::Arena() : _block_size(4096) { } Arena::~Arena() { + for (auto [f, p] : _cleanup) { + f(p); + } for (auto& ptr : _data) free(ptr); }