Skip to content

Allow defaults in function signatures with syntax (..., p = e, ...). #30

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

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
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
35 changes: 25 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 All @@ -1640,6 +1637,24 @@ struct ImplicitParamPtrn : public Ptrn {
void print(Printer&) const override;
};

struct DefaultParamPtrn : public Ptrn {
Ptr<Ptrn> underlying;
Ptr<Expr> default_expr;

DefaultParamPtrn(const Loc& loc, Ptr<Ptrn>&& underlying, Ptr<Expr>&& default_expr)
: Ptrn(loc), underlying(std::move(underlying)), default_expr(std::move(default_expr))
{}

bool is_trivial() const override;

void emit(Emitter&, const thorin::Def*) const override;
const artic::Type* infer(TypeChecker&) override;
const artic::Type* check(TypeChecker&, const artic::Type*) override;
void bind(NameBinder&) override;
void resolve_summons(Summoner&) override;
void print(Printer&) const override;
};

/// A pattern that matches against a structure field.
struct FieldPtrn : public Ptrn {
Identifier id;
Expand Down
7 changes: 5 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,9 @@ class TypeChecker : public Logger {

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

friend class artic::ast::CallExpr; //Needs access to _arena. Please fix.
};

} // 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);
}
16 changes: 10 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,25 +644,29 @@ 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();
}

bool ImplicitParamPtrn::is_trivial() const {
return underlying->is_trivial();
}

bool DefaultParamPtrn::is_trivial() const {
return underlying->is_trivial();
}

void FieldPtrn::collect_bound_ptrns(std::vector<const IdPtrn*>& bound_ptrns) const {
if (ptrn)
ptrn->collect_bound_ptrns(bound_ptrns);
Expand Down
5 changes: 5 additions & 0 deletions src/bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,11 @@ void ImplicitParamPtrn::bind(artic::NameBinder& binder) {
underlying->bind(binder);
}

void DefaultParamPtrn::bind(artic::NameBinder& binder) {
underlying->bind(binder);
default_expr->bind(binder);
}

void FieldPtrn::bind(NameBinder& binder) {
if (ptrn) binder.bind(*ptrn);
}
Expand Down
Loading
Loading