Skip to content

Use an Arena for AST nodes #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions include/artic/arena.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#ifndef ARTIC_ARENA_H
#define ARTIC_ARENA_H

#include <type_traits>
#include <memory>
#include <vector>

template<typename T>
/** 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<typename S, std::enable_if_t<std::is_convertible_v<S*, T*>, bool> = true>
// arena_ptr(arena_ptr<S>& other) : _ptr(other._ptr) {}

template<typename S, std::enable_if_t<std::is_convertible_v<S*, T*>, bool> = true>
arena_ptr(arena_ptr<S>&& other) : _ptr(other._ptr) {
other._ptr = nullptr;
}
~arena_ptr() {
_ptr = nullptr;
}

// arena_ptr<T>& operator=(const arena_ptr<T>& other) { _ptr = other._ptr; return *this; }
arena_ptr<T>& operator=(arena_ptr<T>&& 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<T>& other) {
T* tmp = other._ptr;
other._ptr = _ptr;
_ptr = tmp;
}
};

struct Arena {
Arena();
~Arena();

template<typename T, typename ...Args>
arena_ptr<T> make_ptr(Args&& ...args) {
void* ptr = alloc(sizeof(T));
new (ptr) T (std::forward<Args>(args)...);
return arena_ptr<T>(static_cast<T*>(ptr));
}
private:
void* alloc(size_t);
void grow();

size_t _block_size;
size_t _available;
std::vector<void*> _data;
};

#endif // ARTIC_ARENA_H
17 changes: 7 additions & 10 deletions include/artic/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>
#include <variant>

#include "artic/arena.h"
#include "artic/loc.h"
#include "artic/log.h"
#include "artic/cast.h"
Expand All @@ -25,12 +26,8 @@ class TypeChecker;
class Emitter;
class Summoner;

template <typename T> using Ptr = std::unique_ptr<T>;
template <typename T> using PtrVector = std::vector<std::unique_ptr<T>>;
template <typename T, typename... Args>
std::unique_ptr<T> make_ptr(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
template <typename T> using Ptr = arena_ptr<T>;
template <typename T> using PtrVector = std::vector<Ptr<T>>;

namespace ast {

Expand Down Expand Up @@ -155,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 IdPtrn*>&) 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.
Expand Down Expand Up @@ -1579,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;
};
Expand All @@ -1600,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;
};
Expand All @@ -1618,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;
};
Expand Down
5 changes: 3 additions & 2 deletions include/artic/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -82,6 +82,7 @@ class TypeChecker : public Logger {

private:
std::unordered_set<const ast::Decl*> decls_;
Arena& _arena;
};

} // namespace artic
Expand Down
10 changes: 6 additions & 4 deletions include/artic/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -147,12 +148,13 @@ 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(
std::tuple<Ptr<ast::ModDecl>, bool> compile(
const std::vector<std::string>& file_names,
const std::vector<std::string>& file_data,
bool warns_as_errors,
bool enable_all_warns,
ast::ModDecl& program,
Arena& arena,
TypeTable& table,
thorin::World& world,
Log& log);

Expand Down
3 changes: 2 additions & 1 deletion include/artic/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -208,6 +208,7 @@ class Parser : public Logger {
Token ahead_[max_ahead];
Lexer& lexer_;
Loc prev_;
Arena& _arena;
};

} // namespace artic
Expand Down
6 changes: 4 additions & 2 deletions include/artic/summoner.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,6 +28,8 @@ class Summoner : public Logger {
bool error = false;
std::vector<TypeMap<const ast::Expr*>> scopes;

Arena& _arena;

friend ast::SummonExpr;
friend ast::ImplicitDecl;
friend ast::ModDecl;
Expand Down
5 changes: 3 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,7 +26,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)
Expand All @@ -35,7 +36,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)
Expand Down
27 changes: 27 additions & 0 deletions src/arena.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "artic/arena.h"

#include <cstdlib>

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<size_t>(_data.back()) + _block_size - _available;
_available -= size;
return reinterpret_cast<void*>(ptr);
}
12 changes: 6 additions & 6 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const IdPtrn*>& bound_ptrns) const {
Expand All @@ -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;
Expand All @@ -644,18 +644,18 @@ 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<PathExpr>(std::move(path));
as_expr = arena.make_ptr<PathExpr>(std::move(path));
return as_expr.get();
}

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<LiteralExpr>(loc, lit);
as_expr = arena.make_ptr<LiteralExpr>(loc, lit);
return as_expr.get();
}

Expand Down
10 changes: 5 additions & 5 deletions src/check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ inline std::pair<const Type*, const Type*> remove_ptr(const Type* type) {
const Type* TypeChecker::deref(Ptr<ast::Expr>& expr) {
auto [ref_type, type] = remove_ref(infer(*expr));
if (ref_type)
expr = make_ptr<ast::ImplicitCastExpr>(expr->loc, std::move(expr), type);
expr = _arena.make_ptr<ast::ImplicitCastExpr>(expr->loc, std::move(expr), type);
return type;
}

Expand All @@ -169,7 +169,7 @@ const Type* TypeChecker::coerce(Ptr<ast::Expr>& expr, const Type* expected) {
if (auto implicit = expected->isa<ImplicitParamType>()) {
// Only the empty tuple () can be coerced into a Summon[T]
if (is_unit(expr)) {
Ptr<ast::Expr> summoned = make_ptr<ast::SummonExpr>(expr->loc, Ptr<ast::Type>());
Ptr<ast::Expr> summoned = _arena.make_ptr<ast::SummonExpr>(expr->loc, Ptr<ast::Type>());
summoned->type = implicit->underlying;
expr.swap(summoned);
return implicit->underlying;
Expand All @@ -193,21 +193,21 @@ const Type* TypeChecker::coerce(Ptr<ast::Expr>& expr, const Type* expected) {
}

if (auto implicit = tuple_t->args[i]->isa<ImplicitParamType>()) {
Ptr<ast::Expr> summoned = make_ptr<ast::SummonExpr>(loc, Ptr<ast::Type>());
Ptr<ast::Expr> summoned = _arena.make_ptr<ast::SummonExpr>(loc, Ptr<ast::Type>());
summoned->type = implicit->underlying;
args.push_back(std::move(summoned));
continue;
}

bad_arguments(loc, "non-implicit arguments", i, tuple_t->args.size());
}
expr = make_ptr<ast::TupleExpr>(loc, std::move(args));
expr = _arena.make_ptr<ast::TupleExpr>(loc, std::move(args));
}

auto type = expr->type ? expr->type : check(*expr, expected);
if (type != expected) {
if (type->subtype(expected)) {
expr = make_ptr<ast::ImplicitCastExpr>(expr->loc, std::move(expr), expected);
expr = _arena.make_ptr<ast::ImplicitCastExpr>(expr->loc, std::move(expr), expected);
return expected;
} else
return incompatible_types(expr->loc, type, expected);
Expand Down
Loading
Loading