Skip to content

Commit

Permalink
Implement let-values (#33)
Browse files Browse the repository at this point in the history
This is a rather large change because to implement let-values, we fixed a
couple of things along the way.

* `define-values` should not create a new environment. Just adds to the
current one.
* as a consequence of the previous point, we need to add an empty env
at interpreter construction time.
* implement a downcast function from expr to value as that is needed around a
few places.
* add more implementations for dumper.

Fixes #7
  • Loading branch information
pmatos committed Apr 8, 2023
1 parent 1a4bd2d commit d99153f
Show file tree
Hide file tree
Showing 22 changed files with 487 additions and 17 deletions.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ add_llvm_executable(norac
environment.cpp
utils/idpool.cpp
utils/upcast.cpp
utils/downcast.cpp
parser/parse.cpp
interpreter/interpreter.cpp
ast/arithplus.cpp
Expand All @@ -61,5 +62,6 @@ add_llvm_executable(norac
ast/application.cpp
ast/setbang.cpp
ast/ifcond.cpp
ast/letvalues.cpp
)
target_link_libraries(norac PRIVATE ${LIBS})
38 changes: 38 additions & 0 deletions src/ast/letvalues.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "ast/letvalues.h"

#include <utility>

#include "exprnode_inc.h"

using namespace nir;

LetValues::LetValues(const LetValues &DV) {
for (auto const &Id : DV.Ids) {
Ids.emplace_back(Id);
}
for (auto const &Expr : DV.Exprs) {
Exprs.emplace_back(std::make_unique<nir::ExprNode>(*Expr));
}
for (auto const &Expr : DV.Body) {
Body.emplace_back(std::make_unique<nir::ExprNode>(*Expr));
}
}

void LetValues::appendBinding(std::vector<Identifier> &&Ids,
std::unique_ptr<ExprNode> Expr) {
this->Ids.emplace_back(std::move(Ids));
this->Exprs.emplace_back(std::move(Expr));
}

void LetValues::appendBody(std::unique_ptr<ExprNode> Expr) {
Body.emplace_back(std::move(Expr));
}
nir::LetValues::IdRange LetValues::getBindingIds(size_t Idx) const {
assert(Idx < Ids.size());
return IdRange{Ids[Idx]};
}
ExprNode const &LetValues::getBindingExpr(size_t Idx) const {
return *Exprs[Idx];
}
ExprNode const &LetValues::getBodyExpr(size_t Idx) const { return *Body[Idx]; }
size_t nir::LetValues::exprsCount() const { return Exprs.size(); }
60 changes: 58 additions & 2 deletions src/dumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,29 @@ void Dumper::operator()(nir::Values const &V) {
}
}

void Dumper::operator()(nir::DefineValues const &DV) {}
void Dumper::operator()(nir::DefineValues const &DV) {
Dumper Dump;
std::cout << "(define-values (";

void Dumper::operator()(nir::ArithPlus const &AP) {}
for (const auto &Id : DV.getIds()) {
Dump(Id);
std::cout << " ";
}

std::cout << ") ";
std::visit(Dump, DV.getBody());
std::cout << ")";
}

void Dumper::operator()(nir::ArithPlus const &AP) {
Dumper Dump;
std::cout << "(+ ";
for (const auto &Arg : AP.getArgs()) {
std::visit(Dump, *Arg);
std::cout << " ";
}
std::cout << ")";
}

void Dumper::operator()(nir::Void const &Vd) {
// do nothing
Expand Down Expand Up @@ -162,4 +182,40 @@ void Dumper::operator()(nir::IfCond const &If) {

void Dumper::operator()(nir::BooleanLiteral const &Bool) {
std::cout << (Bool.value() ? "#t" : "#f");
}

void Dumper::operator()(nir::LetValues const &Let) {
Dumper Dump;
std::cout << "(let-values (";

for (size_t I = 0; I < Let.bindingCount(); ++I) {
// Starts binding
std::cout << "[";

// Starts binding Id List
std::cout << "(";

for (const auto &Id : Let.getBindingIds(I)) {
Dump(Id);
std::cout << " ";
}

// Closes binding Id List
std::cout << ")";

std::cout << " ";
std::visit(Dump, Let.getBindingExpr(I));

// Closes binding
std::cout << "]";
}

// Close bindings
std::cout << ") ";

for (size_t I = 0; I < Let.bodyCount(); ++I) {
std::visit(Dump, Let.getBodyExpr(I));
std::cout << "\n";
}
std::cout << ")";
}
4 changes: 4 additions & 0 deletions src/exprnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ std::unique_ptr<nir::TLNode> nir::ToTopLevelNode::operator()(nir::IfCond &&If) {
std::unique_ptr<nir::TLNode>
nir::ToTopLevelNode::operator()(nir::BooleanLiteral &&Bool) {
return std::make_unique<nir::TLNode>(std::move(Bool));
}
std::unique_ptr<nir::TLNode>
nir::ToTopLevelNode::operator()(nir::LetValues &&LV) {
return std::make_unique<nir::TLNode>(std::move(LV));
}
1 change: 1 addition & 0 deletions src/include/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ASTNodes
|- +Application
|- +SetBang
|- +IfCond
|- +LetValues
|- Value
|- +Integer
|- +Values
Expand Down
1 change: 1 addition & 0 deletions src/include/ast/definevalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class DefineValues {
: BeginIt(Ids.cbegin()), EndIt(Ids.cend()) {}
[[nodiscard]] auto begin() const { return BeginIt; }
[[nodiscard]] auto end() const { return EndIt; }
const Identifier &operator[](size_t Idx) const { return *(BeginIt + Idx); }

private:
std::vector<Identifier>::const_iterator BeginIt, EndIt;
Expand Down
61 changes: 61 additions & 0 deletions src/include/ast/letvalues.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#pragma once

#include <cassert>
#include <memory>
#include <vector>

#include "../exprnode.h"
#include "identifier.h"

namespace nir {

class LetValues {
public:
LetValues() = default;
LetValues(const LetValues &DV);
LetValues(LetValues &&DV) = default;
LetValues &operator=(const LetValues &DV) = delete;
LetValues &operator=(LetValues &&DV) = default;
~LetValues() = default;

// View over the Ids
// FIXME: we should be able to use C++20 view_interface here
// although my initial attempt failed.
class IdRange {
public:
IdRange() = delete;
IdRange(const std::vector<Identifier> &Ids)
: BeginIt(Ids.cbegin()), EndIt(Ids.cend()) {}
[[nodiscard]] auto begin() const { return BeginIt; }
[[nodiscard]] auto end() const { return EndIt; }
[[nodiscard]] Identifier const &operator[](size_t Idx) const {
return *(BeginIt + Idx);
}

private:
std::vector<Identifier>::const_iterator BeginIt, EndIt;
};

IdRange getBindingIds(size_t Idx) const;
ExprNode const &getBindingExpr(size_t Idx) const;
ExprNode const &getBodyExpr(size_t Idx) const;

void appendBinding(std::vector<Identifier> &&Ids,
std::unique_ptr<ExprNode> Expr);
void appendBody(std::unique_ptr<ExprNode> Expr);

size_t bindingCount() const {
assert(Ids.size() == Exprs.size());
return Ids.size();
}
size_t idsCount() const { return Ids.size(); }
size_t exprsCount() const;
size_t bodyCount() const { return Body.size(); }

private:
std::vector<std::vector<Identifier>> Ids;
std::vector<std::unique_ptr<ExprNode>> Exprs;
std::vector<std::unique_ptr<ExprNode>> Body;
};

}; // namespace nir
8 changes: 5 additions & 3 deletions src/include/astnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ class Application;
class SetBang;
class IfCond;
class BooleanLiteral;
class LetValues;

using ASTNode = std::variant<Linklet, Identifier, Integer, ArithPlus,
DefineValues, Values, Void, Lambda, Begin, List,
Application, SetBang, IfCond, BooleanLiteral>;
using ASTNode =
std::variant<Linklet, Identifier, Integer, ArithPlus, DefineValues, Values,
Void, Lambda, Begin, List, Application, SetBang, IfCond,
BooleanLiteral, LetValues>;

}; // namespace nir
1 change: 1 addition & 0 deletions src/include/dumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ struct Dumper {
void operator()(nir::SetBang const &SB);
void operator()(nir::IfCond const &If);
void operator()(nir::BooleanLiteral const &Bool);
void operator()(nir::LetValues const &LV);
};
4 changes: 3 additions & 1 deletion src/include/exprnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ class Application;
class SetBang;
class IfCond;
class BooleanLiteral;
class LetValues;

using ExprNode =
std::variant<Integer, Identifier, Values, ArithPlus, Void, Lambda, Begin,
List, Application, SetBang, IfCond, BooleanLiteral>;
List, Application, SetBang, IfCond, BooleanLiteral, LetValues>;

struct ToTopLevelNode {
std::unique_ptr<TLNode> operator()(nir::Identifier &&Id);
Expand All @@ -37,6 +38,7 @@ struct ToTopLevelNode {
std::unique_ptr<TLNode> operator()(nir::SetBang &&SB);
std::unique_ptr<TLNode> operator()(nir::IfCond &&If);
std::unique_ptr<TLNode> operator()(nir::BooleanLiteral &&Bool);
std::unique_ptr<TLNode> operator()(nir::LetValues &&LV);
};

}; // namespace nir
1 change: 1 addition & 0 deletions src/include/exprnode_inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
#include "ast/begin.h"
#include "ast/identifier.h"
#include "ast/ifcond.h"
#include "ast/letvalues.h"
#include "ast/setbang.h"
#include "valuenode_inc.h"
3 changes: 3 additions & 0 deletions src/include/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

class Interpreter {
public:
Interpreter();

std::unique_ptr<nir::ValueNode> operator()(nir::Identifier const &Id);
std::unique_ptr<nir::ValueNode> operator()(nir::Integer const &Int);
std::unique_ptr<nir::ValueNode> operator()(nir::Linklet const &Linklet);
Expand All @@ -31,6 +33,7 @@ class Interpreter {
std::unique_ptr<nir::ValueNode> operator()(nir::SetBang const &SB);
std::unique_ptr<nir::ValueNode> operator()(nir::IfCond const &If);
std::unique_ptr<nir::ValueNode> operator()(nir::BooleanLiteral const &Bool);
std::unique_ptr<nir::ValueNode> operator()(nir::LetValues const &LV);

private:
// Environment map for identifiers.
Expand Down
3 changes: 2 additions & 1 deletion src/include/toplevelnode.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ class Application;
class SetBang;
class IfCond;
class BooleanLiteral;
class LetValues;

using TLNode = std::variant<Identifier, Integer, ArithPlus, DefineValues,
Values, Void, Lambda, Begin, List, Application,
SetBang, IfCond, BooleanLiteral>;
SetBang, IfCond, BooleanLiteral, LetValues>;

}; // namespace nir
9 changes: 9 additions & 0 deletions src/include/utils/downcast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include <memory>

#include "exprnode.h"
#include "valuenode.h"

std::unique_ptr<nir::ValueNode>
downcastExprToValueNode(std::unique_ptr<nir::ExprNode> &&E);
Loading

0 comments on commit d99153f

Please sign in to comment.