Replace the shared_ptr in the node with a unique ptr

This commit is contained in:
Sameer Rahmani 2021-04-17 00:18:13 +01:00
parent 1330bad6fb
commit 3b6d165baa
16 changed files with 162 additions and 49 deletions

View File

@ -24,6 +24,7 @@
#include "serene/serene.h"
#include "serene/reader/reader.h"
#include "serene/reader/semantics.h"
#include "serene/sir/sir.hpp"
#include <iostream>
#include <llvm/Support/CommandLine.h>
@ -34,7 +35,7 @@ using namespace serene;
namespace cl = llvm::cl;
namespace {
enum Action { None, DumpAST, DumpIR };
enum Action { None, DumpAST, DumpIR, DumpSemantic };
}
static cl::opt<std::string> inputFile(cl::Positional,
@ -42,10 +43,14 @@ static cl::opt<std::string> inputFile(cl::Positional,
cl::init("-"),
cl::value_desc("filename"));
static cl::opt<enum Action>
emitAction("emit", cl::desc("Select what to dump."),
cl::values(clEnumValN(DumpIR, "sir", "Output the SLIR only")),
cl::values(clEnumValN(DumpAST, "ast", "Output the AST only")));
static cl::opt<enum Action> emitAction(
"emit", cl::desc("Select what to dump."),
cl::values(clEnumValN(DumpSemantic, "ast1",
"Output the AST after one level of analysis only")),
cl::values(clEnumValN(DumpIR, "sir", "Output the SLIR only")),
cl::values(clEnumValN(DumpAST, "ast", "Output the AST only"))
);
int main(int argc, char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "Serene compiler \n");
@ -56,16 +61,39 @@ int main(int argc, char *argv[]) {
r->toString();
delete r;
return 0;
}
};
case Action::DumpSemantic: {
reader::FileReader *r = new reader::FileReader(inputFile);
reader::Semantics analyzer;
auto maybeAst = r->read();
if (!maybeAst) {
throw std::move(maybeAst.getError());
}
auto &ast = maybeAst.getValue();
auto afterAst = analyzer.analyze(ast);
if (afterAst) {
// dump(afterAst.getValue());
delete r;
return 0;
} else {
throw std::move(afterAst.getError());
}
delete r;
return 0;
};
case Action::DumpIR: {
reader::FileReader *r = new reader::FileReader(inputFile);
auto ast = r->read();
if (!ast) {
throw ast.takeError();
throw std::move(ast.getError());
}
serene::sir::dumpSIR(*ast);
serene::sir::dumpSIR(ast.getValue());
delete r;
return 0;
}

View File

@ -1,3 +1 @@
(def a true)
;; (defn hello! (name)
;; (println "Hello %s" name))

View File

@ -47,9 +47,11 @@ enum class ExprType {
};
class Expression;
using node = std::shared_ptr<Expression>;
using node = std::unique_ptr<Expression>;
using maybe_node = Result<node>;
using ast = llvm::SmallVector<node, 0>;
using maybe_ast = Result<ast>;
/// The base class of the expressions which provides the common interface for
/// the expressions to implement.
@ -84,7 +86,7 @@ public:
/// passed to the constructor of type T.
/// \return A shared pointer to an Expression
template <typename T, typename... Args> node make(Args &&...args) {
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
return std::make_unique<T>(std::forward<Args>(args)...);
};
/// Create a new `node` of type `T` and forwards any given parameter
@ -98,10 +100,12 @@ template <typename T, typename... Args> node make(Args &&...args) {
/// passed to the constructor of type T.
/// \return A shared pointer to a value of type T.
template <typename T, typename... Args>
std::shared_ptr<T> makeAndCast(Args &&...args) {
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
std::unique_ptr<T> makeAndCast(Args &&...args) {
return std::make_unique<T>(std::forward<Args>(args)...);
};
void dump(ast &);
} // namespace exprs
} // namespace serene

View File

@ -45,8 +45,8 @@ public:
List(List &&e) noexcept = default; // Move ctor
List(const reader::LocationRange &loc) : Expression(loc){};
List(const reader::LocationRange &loc, node e);
List(const reader::LocationRange &loc, llvm::ArrayRef<node> elems);
List(const reader::LocationRange &loc, node &e);
List(const reader::LocationRange &loc, llvm::MutableArrayRef<node> elems);
ExprType getType() const;
std::string toString() const;

View File

@ -1,3 +1,4 @@
/* -*- C++ -*-
* Serene programming language.
*

View File

@ -73,7 +73,7 @@ public:
void setInput(const llvm::StringRef string);
llvm::Expected<exprs::ast> read();
exprs::maybe_ast read();
// Dumps the AST data to stdout
void toString();
@ -92,7 +92,7 @@ public:
// Dumps the AST data to stdout
void toString();
llvm::Expected<exprs::ast> read();
exprs::maybe_ast read();
~FileReader();
};

View File

@ -37,7 +37,7 @@ class Semantics {
public:
Semantics(){};
exprs::maybe_node analyze(exprs::ast &);
exprs::maybe_ast analyze(exprs::ast &);
};
}; // namespace serene::reader

View File

@ -67,16 +67,22 @@ public:
return Result(std::in_place_index_t<1>(), std::move(e));
}
/// Return the value if it's successful otherwise throw an error
T &&getValue() && { return std::move(std::get<0>(contents)); };
/// Return the error value if it's errorful otherwise throw an error
E &&getError() && { return std::move(std::get<1>(contents)); };
// using std::get, it'll throw if contents doesn't contain what you ask for
/// Return the value if it's successful otherwise throw an error
T &getValue() { return std::get<0>(contents); };
T &getValue() & { return std::get<0>(contents); };
/// Return the error value if it's errorful otherwise throw an error
E &getError() { return std::get<1>(contents); };
E &getError() & { return std::get<1>(contents); };
const T &getValue() const { return std::get<0>(contents); }
const E &getError() const { return std::get<1>(contents); }
const T &getValue() const & { return std::get<0>(contents); }
const E &getError() const & { return std::get<1>(contents); }
/// Return the a boolean value indicating whether the value is succesful
/// or errorful.
@ -84,5 +90,60 @@ public:
operator bool() const { return ok(); }
};
/// A similar type to Rust's Result data structure. It either holds a value of
/// type `T` successfully or holds a value of type `E` errorfully. It is
/// designed to be used in situations which the return value of a function might
/// contains some errors. The official way to use this type is to use the
/// factory functions `Success` and `Error`. For example:
///
/// \code
/// auto successfulResult = Result<int>::Success(3);
/// auto notOkResult = Result<int>::Error(SomeLLVMError());
// \endcode
///
/// In order check for a value being errorful or successful checkout the `ok`
/// method or simply use the value as a conditiona.
// template <typename T, typename E = llvm::Error> class SharedResult {
// // The actual data container
// std::variant<std::shared_ptr<T>, E> contents;
// /// The main constructor which we made private to avoid ambiguousness in
// /// input type. `Success` and `Error` call this ctor.
// template <typename InPlace, typename Content>
// SharedResult(InPlace i, Content &&c) : contents(i,
// std::forward<Content>(c)){};
// public:
// /// Create a succesfull result with the given value of type `T`.
// static SharedResult Success(std::shared_ptr<T> v) {
// return Result(std::in_place_index_t<0>(), v);
// }
// /// Create an errorful result with the given value of type `E` (default
// /// `llvm::Error`).
// static SharedResult Error(E e) {
// return Result(std::in_place_index_t<1>(), std::move(e));
// }
// // using std::get, it'll throw if contents doesn't contain what you ask for
// /// Return the value if it's successful otherwise throw an error
// T &getValue() { return std::get<0>(contents); };
// /// Return the error value if it's errorful otherwise throw an error
// E &getError() { return std::get<1>(contents); };
// const T &getValue() const { return std::get<0>(contents); }
// const E &getError() const { return std::get<1>(contents); }
// /// Return the a boolean value indicating whether the value is succesful
// /// or errorful.
// bool ok() const { return std::holds_alternative<T>(contents); };
// operator bool() const { return ok(); }
// };
} // namespace serene
#endif

View File

@ -11,6 +11,7 @@ set(HEADER_LIST
"${INCLUDE_DIR}/serene/reader/reader.h"
"${INCLUDE_DIR}/serene/reader/location.h"
"${INCLUDE_DIR}/serene/reader/errors.h"
"${INCLUDE_DIR}/serene/reader/semantics.h"
"${INCLUDE_DIR}/serene/errors.h"
"${INCLUDE_DIR}/serene/errors/error.h"
@ -52,6 +53,7 @@ add_library(serene
reader/reader.cpp
reader/location.cpp
reader/errors.cpp
reader/semantics.cpp
# IR
sir/sir.cpp

View File

@ -23,10 +23,20 @@
*/
#include "serene/exprs/expression.h"
#include "llvm/Support/FormatVariadic.h"
namespace serene {
namespace exprs {
void dump(ast &tree) {
std::string result = "";
// for (auto &node : tree) {
// result = llvm::formatv("{0} {1}", result, node->toString());
// }
llvm::outs() << result << "#\n";
};
// template <typename T, typename... Args>
// T* make(Args &&...args) {
// return new T(std::forward<Args>(args)...);

View File

@ -24,17 +24,20 @@
#include "serene/exprs/list.h"
#include "llvm/Support/FormatVariadic.h"
#include <iterator>
namespace serene {
namespace exprs {
List::List(const List &l) : Expression(l.location){};
List::List(const reader::LocationRange &loc, node e) : Expression(loc) {
List::List(const reader::LocationRange &loc, node &e) : Expression(loc) {
elements.push_back(std::move(e));
};
List::List(const reader::LocationRange &loc, llvm::ArrayRef<node> elems)
: Expression(loc), elements(elems.begin(), elems.end()){};
List::List(const reader::LocationRange &loc, llvm::MutableArrayRef<node> elems)
: Expression(loc) {
std::move(elems.begin(), elems.end(), elements.begin());
};
ExprType List::getType() const { return ExprType::List; };
std::string List::toString() const {
@ -50,13 +53,13 @@ std::string List::toString() const {
};
maybe_node List::analyze(reader::SemanticContext &ctx) {
return Result<node>::Success(node(this));
return Result<node>::Success(node(std::move(this)));
};
bool List::classof(const Expression *e) {
return e->getType() == ExprType::List;
};
void List::append(node n) { elements.push_back(n); }
void List::append(node n) { elements.push_back(std::move(n)); }
} // namespace exprs
} // namespace serene

View File

@ -37,7 +37,7 @@ std::string Symbol::toString() const {
}
maybe_node Symbol::analyze(reader::SemanticContext &ctx) {
return Result<node>::Success(node(this));
return Result<node>::Success(node(std::move(this)));
};
bool Symbol::classof(const Expression *e) {

View File

@ -55,7 +55,7 @@ mlir::LogicalResult Namespace::setTree(exprs::ast &t) {
if (initialized) {
return mlir::failure();
}
this->tree = t;
this->tree = std::move(t);
this->initialized = true;
return mlir::success();
}

View File

@ -166,7 +166,7 @@ exprs::node Reader::readSymbol() {
// TODO: Replece this with a tranceback function or something to raise
// synatx error.
llvm::errs() << llvm::formatv(
"Invalid character at the start of a symbol: '{}'\n", c);
"Invalid character at the start of a symbol: '{0}'\n", c);
exit(1);
}
@ -257,7 +257,7 @@ exprs::node Reader::readExpr() {
/// Reads all the expressions in the reader's buffer as an AST.
/// Each expression type (from the reader perspective) has a
/// reader function.
llvm::Expected<exprs::ast> Reader::read() {
exprs::maybe_ast Reader::read() {
char c = getChar(true);
while (c != EOF) {
@ -271,7 +271,7 @@ llvm::Expected<exprs::ast> Reader::read() {
c = getChar(true);
}
return this->ast;
return Result<exprs::ast>::Success(std::move(this->ast));
};
/// Reads the input into an AST and prints it out as string again.
@ -280,10 +280,10 @@ void Reader::toString() {
std::string result = "";
if (!maybeAst) {
throw maybeAst.takeError();
throw std::move(maybeAst.getError());
}
exprs::ast ast = *maybeAst;
exprs::ast ast = std::move(maybeAst.getValue());
for (auto &node : ast) {
result = llvm::formatv("{0} {1}", result, node->toString());
@ -294,7 +294,7 @@ void Reader::toString() {
// in the reader as an AST.
/// Each expression type (from the reader perspective) has a
/// reader function.
llvm::Expected<exprs::ast> FileReader::read() {
exprs::maybe_ast FileReader::read() {
// TODO: Add support for relative path as well
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
@ -304,7 +304,7 @@ llvm::Expected<exprs::ast> FileReader::read() {
llvm::errs() << "Could not open input file: " << EC.message() << "\n";
llvm::errs() << fmt::format("File: '{}'\n", file);
llvm::errs() << "Use absolute path for now\n";
return llvm::make_error<MissingFileError>(file);
return Result<exprs::ast>::Error(llvm::make_error<MissingFileError>(file));
}
reader->setInput(fileOrErr.get()->getBuffer().str());
@ -317,10 +317,10 @@ void FileReader::toString() {
exprs::ast ast;
if (!maybeAst) {
throw maybeAst.takeError();
throw std::move(maybeAst.getError());
}
ast = *maybeAst;
ast = std::move(maybeAst.getValue());
std::string result = "";
for (auto &node : ast) {

View File

@ -26,21 +26,27 @@
#include "serene/exprs/expression.h"
namespace serene::reader {
exprs::ast Semantics::analyze(exprs::ast &inputAst) {
exprs::maybe_ast Semantics::analyze(exprs::ast &inputAst) {
// TODO: Fetch the current namespace from the JIT engine later and if it is
// `nil` then the given `ast` has to start with a namespace definition.
exprs::node tmp;
exprs::ast ast;
for (auto &element : inputAst) {
auto maybeNode = element->analyze(context);
if (!maybeNode) {
// TODO: Check the error type to see whether we can continue or not.
// If not, raise otherwise push it to the exception queue and move on.
auto err = maybeNode.takeError();
throw err;
return Result<exprs::ast>::Error(std::move(maybeNode.getError()));
}
tmp = std::move(maybeNode).getValue();
llvm::outs() << "HERE\n" << tmp->toString() << " n\n";
ast.push_back(std::move(tmp));
}
return Result<exprs::ast>::Success(std::move(ast));
};
}; // namespace serene::reader

View File

@ -37,7 +37,7 @@ TEST_CASE("Read numbers", "[reader]") {
FAIL();
}
auto ast = maybeAst.get();
auto ast = std::move(maybeAst).getValue();
REQUIRE_FALSE(ast.empty());
CHECK(ast.front()->toString() == "<Number [loc: 0:1:1 | 0:1:1]: 3>");
@ -48,7 +48,7 @@ TEST_CASE("Read numbers", "[reader]") {
FAIL();
}
ast = maybeAst.get();
ast = std::move(maybeAst.getValue());
REQUIRE_FALSE(ast.empty());
CHECK(ast.front()->toString() == "<Number [loc: 0:2:2 | 0:3:3]: -34>");
@ -59,7 +59,7 @@ TEST_CASE("Read numbers", "[reader]") {
FAIL();
}
ast = maybeAst.get();
ast = std::move(maybeAst.getValue());
REQUIRE_FALSE(ast.empty());
CHECK(ast.front()->toString() == "<Number [loc: 0:2:2 | 0:7:7]: -3.5434>");
@ -70,7 +70,7 @@ TEST_CASE("Read numbers", "[reader]") {
FAIL();
}
ast = maybeAst.get();
ast = std::move(maybeAst.getValue());
REQUIRE(ast.size() == 3);
CHECK(ast.front()->toString() == "<Number [loc: 0:1:1 | 0:6:6]: 444323>");
CHECK(ast[1]->toString() == "<Number [loc: 0:8:8 | 0:11:11]: 2123>");
@ -87,7 +87,7 @@ TEST_CASE("Read Lists and Symbols", "[reader]") {
FAIL();
}
auto ast = maybeAst.get();
auto ast = std::move(maybeAst.getValue());
REQUIRE_FALSE(ast.empty());
CHECK(ast.front()->toString() ==
"<List [loc: 0:0:0 | 0:5:5]: <Symbol [loc: 0:2:2 | 0:2:2]: x> <Number "
@ -100,7 +100,7 @@ TEST_CASE("Read Lists and Symbols", "[reader]") {
FAIL();
}
ast = maybeAst.get();
ast = std::move(maybeAst.getValue());
REQUIRE_FALSE(ast.empty());
CHECK(ast.front()->toString() ==
"<List [loc: 0:0:0 | 0:11:11]: <Symbol [loc: 0:2:2 | 0:2:2]: x> <List "
@ -114,7 +114,7 @@ TEST_CASE("Read Lists and Symbols", "[reader]") {
FAIL();
}
ast = maybeAst.get();
ast = std::move(maybeAst.getValue());
REQUIRE_FALSE(ast.empty());
CHECK(ast.front()->toString() ==
"<List [loc: 0:0:0 | 1:3:7]: <Symbol [loc: 0:2:2 | 0:2:2]: x> <Symbol "