Skip to content

Commit

Permalink
Merge branch 'refactor/arena' into feature/default-parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kurtenacker committed Jan 29, 2025
2 parents b4497bf + ad24820 commit d213910
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 160 deletions.
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
12 changes: 6 additions & 6 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 Expand Up @@ -1188,7 +1188,7 @@ const artic::Type* CallExpr::infer(TypeChecker& checker) {
auto default_param = fn_params->args[i]->isa<DefaultParamPtrn>();
if (default_param) {
auto default_expr = default_param->default_expr.get();
args_tuple->args.push_back(std::unique_ptr<Expr>(default_expr));
args_tuple->args.push_back(arena_ptr(default_expr));
}
}
}
Expand Down
Loading

0 comments on commit d213910

Please sign in to comment.