diff --git a/CMakeLists.txt b/CMakeLists.txt index 483c1c7..a90c84c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,11 +185,11 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) add_definitions(${LLVM_DEFINITIONS}) # /LLVM setup ================================================================= - + #add_subdirectory(serene-tblgen) add_subdirectory(serene) # include(tablegen-serene) # Create the tools we use to compile Serene - #add_subdirectory(serene-tblgen) + # The compiled library code is here # add_subdirectory(libserene) # The static library containing builtin special forms and functions diff --git a/serene-tblgen/CMakeLists.txt b/serene-tblgen/CMakeLists.txt index 0f1f913..987e3b6 100644 --- a/serene-tblgen/CMakeLists.txt +++ b/serene-tblgen/CMakeLists.txt @@ -14,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -include_directories(${PROJECT_SOURCE_DIR}/serene-tblgen) add_executable(serene-tblgen serene/errors-backend.cpp @@ -28,8 +27,10 @@ set(SERENE_TABLEGEN $ CACHE set(SERENE_TABLEGEN_EXE SereneTablegen CACHE STRING "Where to find the tbl-srn binary") + set(SERENE_TABLEGEN_TARGET SereneTablegen CACHE STRING "Target name for the tbl-srn") target_link_libraries(serene-tblgen PRIVATE LLVMTableGenGlobalISel ${llvm_libs}) +target_include_directories(${PROJECT_SOURCE_DIR}/serene-tblgen) set_target_properties(serene-tblgen PROPERTIES FOLDER "serene-tblgen") diff --git a/serene/src/CMakeLists.txt b/serene/src/CMakeLists.txt index c544c98..f261139 100644 --- a/serene/src/CMakeLists.txt +++ b/serene/src/CMakeLists.txt @@ -20,6 +20,7 @@ target_sources(serene PRIVATE commands/commands.cpp jit/jit.cpp + errors.cpp ast.cpp namespace.cpp diff --git a/serene/src/_errors.h b/serene/src/_errors.h new file mode 100644 index 0000000..9f2ae74 --- /dev/null +++ b/serene/src/_errors.h @@ -0,0 +1,47 @@ +/* -*- C++ -*- + * Serene Programming Language + * + * Copyright (c) 2019-2023 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ERRORS_H +#define _ERRORS_H + +#include + +// TODO: Autogenerate this file + +namespace serene::errors { +enum class Type { + NSLoadError = 0, + NSAddToSMError, + InvalidDigitForNumber, + TwoFloatPoints, + InvalidCharacterForSymbol, + EOFWhileScaningAList, + // This error has to be the final error at all time. DO NOT CHANGE IT! + FINALERROR, +}; + +static std::string errorMessages[static_cast(Type::FINALERROR) + 1] = { + "Faild to load the namespace", // NSLoadError + "Faild to add the namespace to the source manager", // NSAddToSMError + "Invalid number format", // InvalidDigitForNumber + "Invalid float number format", // TwoFloatPoints, + "Invalid symbol format", // InvalidCharacterForSymbol + "Reached the end of the file while scanning for a list", // EOFWhileScaningAList +}; +} // namespace serene::errors +#endif diff --git a/serene/src/ast.cpp b/serene/src/ast.cpp index d445b26..6019f0d 100644 --- a/serene/src/ast.cpp +++ b/serene/src/ast.cpp @@ -104,6 +104,7 @@ bool List::classof(const Expression *e) { return e->getType() == TypeID::LIST; }; +void List::append(Node &n) { elements.push_back(std::move(n)); } // ============================================================================ // String // ============================================================================ diff --git a/serene/src/ast.h b/serene/src/ast.h index a39d62e..3a6f493 100644 --- a/serene/src/ast.h +++ b/serene/src/ast.h @@ -134,6 +134,7 @@ struct List : public Expression { std::string toString() const override; ~List() = default; + void append(Node &n); static bool classof(const Expression *e); }; @@ -221,7 +222,7 @@ Node make(Args &&...args) { /// passed to the constructor of type T. /// \return A unique pointer to a value of type T. template -std::shared_ptr makeAndCast(Args &&...args) { +std::unique_ptr makeAndCast(Args &&...args) { return std::make_unique(std::forward(args)...); }; diff --git a/serene/src/errors.cpp b/serene/src/errors.cpp new file mode 100644 index 0000000..3995ca6 --- /dev/null +++ b/serene/src/errors.cpp @@ -0,0 +1,35 @@ +/* -*- C++ -*- + * Serene Programming Language + * + * Copyright (c) 2019-2023 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "errors.h" + +#include +#include + +namespace serene::errors { + +// We need this to make Error class a llvm::Error friendy implementation +char Error::ID; + +std::string getMessage(const llvm::Error &e) { + std::string msg; + llvm::raw_string_ostream os(msg); + os << e; + return os.str(); +}; +} // namespace serene::errors diff --git a/serene/src/errors.h b/serene/src/errors.h new file mode 100644 index 0000000..0dea5b1 --- /dev/null +++ b/serene/src/errors.h @@ -0,0 +1,66 @@ +/* -*- C++ -*- + * Serene Programming Language + * + * Copyright (c) 2019-2023 Sameer Rahmani + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ERRORS_H +#define ERRORS_H + +#include "_errors.h" +#include "location.h" + +#include + +#include +#include + +namespace serene::errors { + +class Error : public llvm::ErrorInfo { +public: + // We need this to make Error class a llvm::Error friendy implementation + static char ID; + + Type type; + LocationRange location; + std::string msg; + + void log(llvm::raw_ostream &os) const override { os << msg; } + + std::error_code convertToErrorCode() const override { + // TODO: Fix this by creating a mapping from ErrorType to standard + // errc or return the ErrorType number instead + return std::make_error_code(std::errc::io_error); + } + + Error(Type errtype, LocationRange &loc) : type(errtype), location(loc){}; + + Error(Type errtype, LocationRange &loc, llvm::StringRef msg) + : type(errtype), location(loc), msg(msg.str()){}; + + LocationRange &where() { return location; }; +}; + +llvm::Error make(Type t, LocationRange &loc, llvm::StringRef msg) { + return llvm::make_error(t, loc, msg); +} + +llvm::Error make(Type t, LocationRange &loc) { + return llvm::make_error(t, loc); +} + +}; // namespace serene::errors +#endif diff --git a/serene/src/reader.cpp b/serene/src/reader.cpp index 8087b2b..f55c72d 100644 --- a/serene/src/reader.cpp +++ b/serene/src/reader.cpp @@ -18,7 +18,9 @@ #include "reader.h" -// #include "serene/errors.h" +#include "errors.h" +#include "jit/jit.h" +#include "utils.h" // #include "serene/exprs/expression.h" // #include "serene/exprs/list.h" // #include "serene/exprs/number.h" @@ -46,7 +48,6 @@ namespace serene { -namespace reader { // LocationRange::LocationRange(const LocationRange &loc) { // start = loc.start.clone(); // end = loc.end.clone(); @@ -98,11 +99,11 @@ void decLocation(Location &loc, const char *c) { } } -Reader::Reader(SereneContext &ctx, llvm::StringRef buffer, llvm::StringRef ns, +Reader::Reader(jit::JIT &engine, llvm::StringRef buffer, llvm::StringRef ns, std::optional filename) - : ctx(ctx), ns(ns), filename(filename), buf(buffer), + : engine(engine), ns(ns), filename(filename), buf(buffer), currentLocation(Location(ns, filename)) { - UNUSED(this->ctx); + UNUSED(this->engine); READER_LOG("Setting the first char of the buffer"); currentChar = buf.begin() - 1; currentPos = 1; @@ -110,9 +111,9 @@ Reader::Reader(SereneContext &ctx, llvm::StringRef buffer, llvm::StringRef ns, currentLocation.col = 1; }; -Reader::Reader(SereneContext &ctx, llvm::MemoryBufferRef buffer, +Reader::Reader(jit::JIT &engine, llvm::MemoryBufferRef buffer, llvm::StringRef ns, std::optional filename) - : Reader(ctx, buffer.getBuffer(), ns, filename){}; + : Reader(engine, buffer.getBuffer(), ns, filename){}; Reader::~Reader() { READER_LOG("Destroying the reader"); } @@ -173,7 +174,8 @@ const char *Reader::nextChar(bool skipWhitespace, unsigned count) { }; bool Reader::isEndOfBuffer(const char *c) { - return *c == '\0' || currentPos > buf.size() || ((const int)*c == EOF); + return *c == '\0' || currentPos > buf.size() || + (static_cast(*c) == EOF); }; Location Reader::getCurrentLocation() { return currentLocation.clone(); }; @@ -208,7 +210,7 @@ bool Reader::isValidForIdentifier(char c) { /// Reads a number, /// \param neg whether to read a negative number or not. -exprs::MaybeNode Reader::readNumber(bool neg) { +ast::MaybeNode Reader::readNumber(bool neg) { READER_LOG("Reading a number..."); std::string number(neg ? "-" : ""); bool floatNum = false; @@ -220,7 +222,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) { LocationRange loc(getCurrentLocation()); if (isdigit(*c) == 0) { - return errors::makeError(ctx, errors::InvalidDigitForNumber, loc); + return errors::make(errors::Type::InvalidDigitForNumber, loc); } for (;;) { @@ -231,7 +233,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) { if ((isdigit(*c) != 0) || *c == '.') { if (*c == '.' && floatNum) { loc = LocationRange(getCurrentLocation()); - return errors::makeError(ctx, errors::TwoFloatPoints, loc); + return errors::make(errors::Type::TwoFloatPoints, loc); } if (*c == '.') { @@ -247,16 +249,16 @@ exprs::MaybeNode Reader::readNumber(bool neg) { if (((std::isalpha(*c) != 0) && !empty) || empty) { advance(); loc.start = getCurrentLocation(); - return errors::makeError(ctx, errors::InvalidDigitForNumber, loc); + return errors::make(errors::Type::InvalidDigitForNumber, loc); } loc.end = getCurrentLocation(); - return exprs::make(loc, number, neg, floatNum); + return ast::make(loc, number, neg, floatNum); }; /// Reads a symbol. If the symbol looks like a number /// If reads it as number -exprs::MaybeNode Reader::readSymbol() { +ast::MaybeNode Reader::readSymbol() { READER_LOG("Reading a symbol..."); LocationRange loc; const auto *c = nextChar(); @@ -271,7 +273,7 @@ exprs::MaybeNode Reader::readSymbol() { msg = "An extra ')' is detected."; } - return errors::makeError(ctx, errors::InvalidCharacterForSymbol, loc, msg); + return errors::make(errors::Type::InvalidCharacterForSymbol, loc, msg); } if (*c == '-') { @@ -307,17 +309,17 @@ exprs::MaybeNode Reader::readSymbol() { // TODO: Make sure that `/` is not at the start or at the end of the symbol loc.end = getCurrentLocation(); - return exprs::makeSuccessfulNode(loc, sym, this->ns); + return ast::makeSuccessfulNode(loc, sym, this->ns); }; /// Reads a list recursively -exprs::MaybeNode Reader::readList() { +ast::MaybeNode Reader::readList() { READER_LOG("Reading a list..."); const auto *c = nextChar(); advance(); - auto list = exprs::makeAndCast(getCurrentLocation()); + auto list = ast::makeAndCast(getCurrentLocation()); // TODO: Replace the assert with an actual check. assert(*c == '('); @@ -331,8 +333,7 @@ exprs::MaybeNode Reader::readList() { advance(true); advance(); list->location.end = getCurrentLocation(); - return errors::makeError(ctx, errors::EOFWhileScaningAList, - list->location); + return errors::make(errors::Type::EOFWhileScaningAList, list->location); } switch (*c) { @@ -359,13 +360,13 @@ exprs::MaybeNode Reader::readList() { }; /// Reads an expression by dispatching to the proper reader function. -exprs::MaybeNode Reader::readExpr() { +ast::MaybeNode Reader::readExpr() { const auto *c = nextChar(true); READER_LOG("Read char at `readExpr`: " << *c); if (isEndOfBuffer(c)) { - return exprs::EmptyNode; + return ast::EmptyNode; } switch (*c) { @@ -383,7 +384,7 @@ exprs::MaybeNode 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. -exprs::MaybeAst Reader::read() { +ast::MaybeAst Reader::read() { for (size_t current_pos = 0; current_pos < buf.size();) { const auto *c = nextChar(true); @@ -411,21 +412,21 @@ exprs::MaybeAst Reader::read() { return std::move(this->ast); }; -exprs::MaybeAst read(SereneContext &ctx, const llvm::StringRef input, - llvm::StringRef ns, - std::optional filename) { - reader::Reader r(ctx, input, ns, filename); +ast::MaybeAst read(jit::JIT &engine, const llvm::StringRef input, + llvm::StringRef ns, + std::optional filename) { + Reader r(engine, input, ns, filename); auto ast = r.read(); return ast; } -exprs::MaybeAst read(SereneContext &ctx, const llvm::MemoryBufferRef input, - llvm::StringRef ns, - std::optional filename) { - reader::Reader r(ctx, input, ns, filename); +ast::MaybeAst read(jit::JIT &engine, const llvm::MemoryBufferRef input, + llvm::StringRef ns, + std::optional filename) { + Reader r(engine, input, ns, filename); auto ast = r.read(); return ast; } -} // namespace reader + } // namespace serene diff --git a/serene/src/reader.h b/serene/src/reader.h index 1d837f5..ce1e1c0 100644 --- a/serene/src/reader.h +++ b/serene/src/reader.h @@ -43,10 +43,19 @@ #include #include +#define READER_LOG(...) \ + DEBUG_WITH_TYPE("READER", llvm::dbgs() \ + << "[READER]: " << __VA_ARGS__ << "\n"); + namespace serene { +namespace jit { +class JIT; +} // namespace jit + /// Base reader class which reads from a string directly. class Reader { private: + jit::JIT &engine; llvm::StringRef ns; std::optional filename; @@ -77,36 +86,36 @@ private: static bool isValidForIdentifier(char c); // The property to store the ast tree - Ast ast; + ast::Ast ast; - MaybeNode readSymbol(); - MaybeNode readNumber(bool); - MaybeNode readList(); - MaybeNode readExpr(); + ast::MaybeNode readSymbol(); + ast::MaybeNode readNumber(bool); + ast::MaybeNode readList(); + ast::MaybeNode readExpr(); bool isEndOfBuffer(const char *); public: - Reader(llvm::StringRef buf, llvm::StringRef ns, + Reader(jit::JIT &engine, llvm::StringRef buf, llvm::StringRef ns, std::optional filename); - Reader(llvm::MemoryBufferRef buf, llvm::StringRef ns, + Reader(jit::JIT &engine, llvm::MemoryBufferRef buf, llvm::StringRef ns, std::optional filename); // void setInput(const llvm::StringRef string); /// Parses the the input and creates a possible AST out of it or errors /// otherwise. - MaybeAst read(); + ast::MaybeAst read(); ~Reader(); }; /// Parses the given `input` string and returns a `Result` /// which may contains an AST or an `llvm::Error` -MaybeAst read(llvm::StringRef input, llvm::StringRef ns, - std::optional filename); -MaybeAst read(llvm::MemoryBufferRef input, llvm::StringRef ns, - std::optional filename); +ast::MaybeAst read(llvm::StringRef input, llvm::StringRef ns, + std::optional filename); +ast::MaybeAst read(llvm::MemoryBufferRef input, llvm::StringRef ns, + std::optional filename); } // namespace serene #endif diff --git a/serene/src/source_mgr.cpp b/serene/src/source_mgr.cpp index 5f5ac93..89ede19 100644 --- a/serene/src/source_mgr.cpp +++ b/serene/src/source_mgr.cpp @@ -16,12 +16,13 @@ * along with this program. If not, see . */ -#include "serene/source_mgr.h" +#include "source_mgr.h" -#include "serene/namespace.h" -#include "serene/reader/location.h" -#include "serene/reader/reader.h" -#include "serene/utils.h" +#include "errors.h" +#include "jit/jit.h" +#include "location.h" +#include "reader.h" +#include "utils.h" #include @@ -75,8 +76,8 @@ SourceMgr::MemBufPtr SourceMgr::findFileInLoadPath(const std::string &name, return nullptr; }; -MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, - reader::LocationRange importLoc) { +MaybeNS SourceMgr::readNamespace(jit::JIT &engine, std::string name, + LocationRange importLoc) { std::string importedFile; SMGR_LOG("Attempt to load namespace: " + name); @@ -84,7 +85,7 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, if (newBufOrErr == nullptr) { auto msg = llvm::formatv("Couldn't find namespace '{0}'", name).str(); - return errors::makeError(ctx, errors::NSLoadError, importLoc, msg); + return errors::make(errors::Type::NSLoadError, importLoc, msg); } auto bufferId = AddNewSourceBuffer(std::move(newBufOrErr), importLoc); @@ -93,7 +94,7 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, if (bufferId == 0) { auto msg = llvm::formatv("Couldn't add namespace '{0}'", name).str(); - return errors::makeError(ctx, errors::NSAddToSMError, importLoc, msg); + return errors::make(errors::Type; : NSAddToSMError, importLoc, msg); } // Since we moved the buffer to be added as the source storage we @@ -101,8 +102,8 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, const auto *buf = getMemoryBuffer(bufferId); // Read the content of the buffer by passing it the reader - auto maybeAst = reader::read(ctx, buf->getBuffer(), name, - std::optional(llvm::StringRef(importedFile))); + auto maybeAst = read(jit, buf->getBuffer(), name, + std::optional(llvm::StringRef(importedFile))); if (!maybeAst) { SMGR_LOG("Couldn't Read namespace: " + name); @@ -111,7 +112,7 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, // Create the NS and set the AST auto ns = - ctx.makeNamespace(name, std::optional(llvm::StringRef(importedFile))); + engine.makeNamespace(name, std::optional(llvm::StringRef(importedFile))); if (auto errs = ns->addTree(*maybeAst)) { SMGR_LOG("Couldn't set the AST for namespace: " + name); @@ -122,7 +123,7 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, }; unsigned SourceMgr::AddNewSourceBuffer(std::unique_ptr f, - reader::LocationRange includeLoc) { + LocationRange includeLoc) { SrcBuffer nb; nb.buffer = std::move(f); nb.importLoc = includeLoc; diff --git a/serene/src/source_mgr.h b/serene/src/source_mgr.h index d5a681a..da901f9 100644 --- a/serene/src/source_mgr.h +++ b/serene/src/source_mgr.h @@ -20,6 +20,7 @@ #define SERENE_SOURCE_MGR_H #include "location.h" +#include "namespace.h" #include #include @@ -38,7 +39,9 @@ << "[SMGR]: " << __VA_ARGS__ << "\n"); namespace serene { -class SereneContext; +namespace jit { +class JIT; +} // namespace jit /// This class is quite similar to the `llvm::SourceMgr` in functionality. We /// even borrowed some of the code from the original implementation but removed @@ -181,7 +184,7 @@ public: /// /// \p importLoc is a location in the source code where the give namespace is /// imported. - MaybeNS readNamespace(SereneContext &ctx, std::string name, + MaybeNS readNamespace(jit::JIT &engine, std::string name, LocationRange importLoc); };