Compare commits
2 Commits
9d894b662b
...
97c1b3e7c1
Author | SHA1 | Date |
---|---|---|
Sameer Rahmani | 97c1b3e7c1 | |
Sameer Rahmani | 6cfe47b6d6 |
|
@ -33,6 +33,7 @@ typedef enum {
|
|||
SYMBOL,
|
||||
TYPE,
|
||||
FN,
|
||||
NS,
|
||||
NUMBER,
|
||||
INT,
|
||||
CSTRING,
|
||||
|
|
|
@ -19,9 +19,9 @@ target_sources(serene PRIVATE
|
|||
|
||||
commands/commands.cpp
|
||||
jit/jit.cpp
|
||||
ast/ast.cpp
|
||||
reader.cpp
|
||||
|
||||
source_mgr.cpp
|
||||
errors.cpp
|
||||
ast.cpp
|
||||
namespace.cpp
|
||||
|
||||
)
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ERRORS_H
|
||||
#define _ERRORS_H
|
||||
#ifndef SERENE__ERRORS_H
|
||||
#define SERENE__ERRORS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ast.h"
|
||||
#include "ast/ast.h"
|
||||
|
||||
#include <llvm/Support/FormatVariadic.h>
|
||||
|
||||
|
@ -59,21 +59,16 @@ bool Symbol::classof(const Expression *e) {
|
|||
// ============================================================================
|
||||
// Number
|
||||
// ============================================================================
|
||||
Number::Number(const LocationRange &loc, const long &num)
|
||||
: Expression(loc), value(num), isNeg(num < 0), isFloat(false){};
|
||||
|
||||
Number::Number(const LocationRange &loc, const double &num)
|
||||
: Expression(loc), value(num), isNeg(num < 0), isFloat(true){};
|
||||
Number::Number(const LocationRange &loc, const llvm::StringRef &n, bool neg,
|
||||
bool fl)
|
||||
: Expression(loc), value(n), isNeg(neg), isFloat(fl){};
|
||||
|
||||
Number::Number(Number &n) : Expression(n.location) { this->value = n.value; };
|
||||
|
||||
TypeID Number::getType() const { return TypeID::NUMBER; };
|
||||
|
||||
std::string Number::toString() const {
|
||||
if (isFloat) {
|
||||
return llvm::formatv("<Number {0}{1}>", std::get<double>(value));
|
||||
}
|
||||
return llvm::formatv("<Number {0}{1}>", std::get<long>(value));
|
||||
return llvm::formatv("<Number {0}{1}>", isNeg ? "-" : "", value);
|
||||
}
|
||||
|
||||
bool Number::classof(const Expression *e) {
|
||||
|
@ -83,11 +78,18 @@ bool Number::classof(const Expression *e) {
|
|||
// ============================================================================
|
||||
// List
|
||||
// ============================================================================
|
||||
List::List(const LocationRange &loc) : Expression(loc){};
|
||||
|
||||
List::List(const LocationRange &loc, Ast &v) : Expression(loc) {
|
||||
this->elements.swap(v);
|
||||
v.clear();
|
||||
};
|
||||
|
||||
List::List(List &&l) noexcept : Expression(l.location) {
|
||||
this->elements.swap(l.elements);
|
||||
l.elements.clear();
|
||||
};
|
||||
|
||||
TypeID List::getType() const { return TypeID::LIST; };
|
||||
|
||||
std::string List::toString() const {
|
||||
|
@ -165,4 +167,32 @@ bool Error::classof(const Expression *e) {
|
|||
return e->getType() == TypeID::KEYWORD;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Namespace
|
||||
// ============================================================================
|
||||
Namespace::Namespace(const LocationRange &loc, llvm::StringRef name)
|
||||
: Namespace(loc, name, std::nullopt){};
|
||||
Namespace::Namespace(const LocationRange &loc, llvm::StringRef name,
|
||||
std::optional<llvm::StringRef> filename)
|
||||
: Expression(loc), name(name), filename(filename) {
|
||||
createEnv(nullptr);
|
||||
};
|
||||
|
||||
Namespace::SemanticEnv &Namespace::createEnv(SemanticEnv *parent) {
|
||||
auto env = std::make_unique<SemanticEnv>(parent);
|
||||
environments.push_back(std::move(env));
|
||||
|
||||
return *environments.back();
|
||||
};
|
||||
|
||||
TypeID Namespace::getType() const { return TypeID::NS; };
|
||||
|
||||
std::string Namespace::toString() const {
|
||||
return llvm::formatv("<NS {0}>", name);
|
||||
}
|
||||
|
||||
bool Namespace::classof(const Expression *e) {
|
||||
return e->getType() == TypeID::NS;
|
||||
};
|
||||
|
||||
} // namespace serene::ast
|
|
@ -16,9 +16,10 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AST_H
|
||||
#define AST_H
|
||||
#ifndef AST_AST_H
|
||||
#define AST_AST_H
|
||||
|
||||
#include "environment.h"
|
||||
#include "location.h"
|
||||
#include "serene/config.h"
|
||||
|
||||
|
@ -44,7 +45,6 @@ constexpr static auto EmptyNode = nullptr;
|
|||
// common interface for the expressions to implement.
|
||||
// ============================================================================
|
||||
struct Expression {
|
||||
|
||||
/// The location range provide information regarding to where in the input
|
||||
/// string the current expression is used.
|
||||
LocationRange location;
|
||||
|
@ -101,15 +101,13 @@ struct Symbol : public Expression {
|
|||
// ============================================================================
|
||||
struct Number : public Expression {
|
||||
// TODO: [ast] Split the number type into their own types
|
||||
std::variant<long, double> value;
|
||||
std::string value;
|
||||
// /TODO
|
||||
|
||||
bool isNeg;
|
||||
bool isFloat;
|
||||
|
||||
Number(const LocationRange &loc, const long &num);
|
||||
Number(const LocationRange &loc, const unsigned long &num);
|
||||
Number(const LocationRange &loc, const double &num);
|
||||
Number(const LocationRange &loc, const llvm::StringRef &n, bool neg, bool fl);
|
||||
Number(Number &n);
|
||||
|
||||
TypeID getType() const override;
|
||||
|
@ -126,9 +124,10 @@ struct Number : public Expression {
|
|||
struct List : public Expression {
|
||||
Ast elements;
|
||||
|
||||
explicit List(const LocationRange &loc);
|
||||
List(const LocationRange &loc, Ast &v);
|
||||
List(const List &l) = delete;
|
||||
List(List &&l) noexcept = default;
|
||||
List(const List &l) = delete;
|
||||
List(List &&l) noexcept;
|
||||
|
||||
TypeID getType() const override;
|
||||
std::string toString() const override;
|
||||
|
@ -197,6 +196,60 @@ struct Error : public Expression {
|
|||
static bool classof(const Expression *e);
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Namespace
|
||||
// ============================================================================
|
||||
struct Namespace : public Expression {
|
||||
using SemanticEnv = Environment<Node>;
|
||||
using SemanticEnvPtr = std::unique_ptr<SemanticEnv>;
|
||||
using SemanticEnvironments = std::vector<SemanticEnvPtr>;
|
||||
|
||||
std::string name;
|
||||
std::optional<std::string> filename;
|
||||
|
||||
Ast tree;
|
||||
|
||||
SemanticEnvironments environments;
|
||||
|
||||
Namespace(const LocationRange &loc, llvm::StringRef name);
|
||||
Namespace(const LocationRange &loc, llvm::StringRef name,
|
||||
std::optional<llvm::StringRef> filename);
|
||||
Namespace(Namespace &s) = delete;
|
||||
|
||||
/// Create a new environment with the give \p parent as the parent,
|
||||
/// push the environment to the internal environment storage and
|
||||
/// return a reference to it. The namespace itself is the owner of
|
||||
/// environments.
|
||||
SemanticEnv &createEnv(SemanticEnv *parent);
|
||||
|
||||
/// Return a referenece to the top level (root) environment of ns.
|
||||
SemanticEnv &getRootEnv();
|
||||
|
||||
/// Define a new binding in the root environment with the given \p name
|
||||
/// and the given \p node. Defining a new binding with a name that
|
||||
/// already exists in legal and will overwrite the previous binding and
|
||||
/// the given name will point to a new value from now on.
|
||||
mlir::LogicalResult define(std::string &name, Node &node);
|
||||
|
||||
/// Add the given \p ast to the namespace and return any possible error.
|
||||
/// The given \p ast will be added to a vector of ASTs by expanding
|
||||
/// the tree vector to contain \p ast.
|
||||
///
|
||||
/// This function runs the semantic analyzer on the \p ast as well.
|
||||
llvm::Error ExpandTree(Ast &ast);
|
||||
|
||||
Ast &getTree();
|
||||
|
||||
TypeID getType() const override;
|
||||
std::string toString() const override;
|
||||
|
||||
~Namespace() = default;
|
||||
|
||||
static bool classof(const Expression *e);
|
||||
};
|
||||
|
||||
using MaybeNS = llvm::Expected<std::unique_ptr<Namespace>>;
|
||||
|
||||
/// Create a new `node` of type `T` and forwards any given parameter
|
||||
/// to the constructor of type `T`. This is the **official way** to create
|
||||
/// a new `Expression`. Here is an example:
|
|
@ -32,4 +32,13 @@ std::string getMessage(const llvm::Error &e) {
|
|||
os << e;
|
||||
return os.str();
|
||||
};
|
||||
|
||||
llvm::Error make(Type t, const LocationRange &loc, llvm::StringRef msg) {
|
||||
return llvm::make_error<Error>(t, loc, msg);
|
||||
}
|
||||
|
||||
llvm::Error make(Type t, const LocationRange &loc) {
|
||||
return llvm::make_error<Error>(t, loc);
|
||||
}
|
||||
|
||||
} // namespace serene::errors
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ERRORS_H
|
||||
#define ERRORS_H
|
||||
#ifndef SERENE_ERRORS_H
|
||||
#define SERENE_ERRORS_H
|
||||
|
||||
#include "_errors.h"
|
||||
#include "location.h"
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
static char ID;
|
||||
|
||||
Type type;
|
||||
LocationRange location;
|
||||
const LocationRange location;
|
||||
std::string msg;
|
||||
|
||||
void log(llvm::raw_ostream &os) const override { os << msg; }
|
||||
|
@ -46,21 +46,18 @@ public:
|
|||
return std::make_error_code(std::errc::io_error);
|
||||
}
|
||||
|
||||
Error(Type errtype, LocationRange &loc) : type(errtype), location(loc){};
|
||||
Error(Type errtype, const LocationRange &loc)
|
||||
: type(errtype), location(loc){};
|
||||
|
||||
Error(Type errtype, LocationRange &loc, llvm::StringRef msg)
|
||||
Error(Type errtype, const LocationRange &loc, llvm::StringRef msg)
|
||||
: type(errtype), location(loc), msg(msg.str()){};
|
||||
|
||||
LocationRange &where() { return location; };
|
||||
const LocationRange &where() { return location; };
|
||||
};
|
||||
|
||||
llvm::Error make(Type t, LocationRange &loc, llvm::StringRef msg) {
|
||||
return llvm::make_error<Error>(t, loc, msg);
|
||||
}
|
||||
llvm::Error make(Type t, const LocationRange &loc, llvm::StringRef msg);
|
||||
|
||||
llvm::Error make(Type t, LocationRange &loc) {
|
||||
return llvm::make_error<Error>(t, loc);
|
||||
}
|
||||
llvm::Error make(Type t, const LocationRange &loc);
|
||||
|
||||
}; // namespace serene::errors
|
||||
#endif
|
||||
|
|
|
@ -59,6 +59,10 @@ class LLJIT;
|
|||
class LLLazyJIT;
|
||||
} // namespace llvm::orc
|
||||
|
||||
namespace serene {
|
||||
class Namespace;
|
||||
} // namespace serene
|
||||
|
||||
#define MAIN_PROCESS_JD_NAME "*main*"
|
||||
#define JIT_LOG(...) \
|
||||
DEBUG_WITH_TYPE("JIT", llvm::dbgs() << "[JIT]: " << __VA_ARGS__ << "\n");
|
||||
|
|
|
@ -62,6 +62,8 @@ struct Location {
|
|||
static Location UnknownLocation(llvm::StringRef ns) {
|
||||
return Location(ns, std::nullopt, nullptr, 0, 0, false);
|
||||
}
|
||||
|
||||
~Location() = default;
|
||||
};
|
||||
|
||||
class LocationRange {
|
||||
|
@ -74,11 +76,17 @@ public:
|
|||
LocationRange(Location _start, Location _end) : start(_start), end(_end){};
|
||||
// LocationRange(const LocationRange &);
|
||||
|
||||
LocationRange(LocationRange &lr) : start(lr.start), end(lr.end){};
|
||||
|
||||
LocationRange(const LocationRange &lr) : start(lr.start), end(lr.end){};
|
||||
|
||||
bool isKnownLocation() const { return start.knownLocation; };
|
||||
|
||||
static LocationRange UnknownLocation(llvm::StringRef ns) {
|
||||
return LocationRange(Location::UnknownLocation(ns));
|
||||
}
|
||||
|
||||
~LocationRange() = default;
|
||||
};
|
||||
|
||||
void incLocation(Location &, const char *);
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#ifndef NAMESPACE_H
|
||||
#define NAMESPACE_H
|
||||
|
||||
#include "ast.h"
|
||||
#include "ast/ast.h"
|
||||
#include "environment.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
|
@ -99,11 +99,11 @@ void decLocation(Location &loc, const char *c) {
|
|||
}
|
||||
}
|
||||
|
||||
Reader::Reader(jit::JIT &engine, llvm::StringRef buffer, llvm::StringRef ns,
|
||||
Reader::Reader(llvm::StringRef buffer, llvm::StringRef ns,
|
||||
std::optional<llvm::StringRef> filename)
|
||||
: engine(engine), ns(ns), filename(filename), buf(buffer),
|
||||
: ns(ns), filename(filename), buf(buffer),
|
||||
currentLocation(Location(ns, filename)) {
|
||||
UNUSED(this->engine);
|
||||
|
||||
READER_LOG("Setting the first char of the buffer");
|
||||
currentChar = buf.begin() - 1;
|
||||
currentPos = 1;
|
||||
|
@ -111,9 +111,9 @@ Reader::Reader(jit::JIT &engine, llvm::StringRef buffer, llvm::StringRef ns,
|
|||
currentLocation.col = 1;
|
||||
};
|
||||
|
||||
Reader::Reader(jit::JIT &engine, llvm::MemoryBufferRef buffer,
|
||||
llvm::StringRef ns, std::optional<llvm::StringRef> filename)
|
||||
: Reader(engine, buffer.getBuffer(), ns, filename){};
|
||||
Reader::Reader(llvm::MemoryBufferRef buffer, llvm::StringRef ns,
|
||||
std::optional<llvm::StringRef> filename)
|
||||
: Reader(buffer.getBuffer(), ns, filename){};
|
||||
|
||||
Reader::~Reader() { READER_LOG("Destroying the reader"); }
|
||||
|
||||
|
@ -317,9 +317,10 @@ ast::MaybeNode Reader::readList() {
|
|||
READER_LOG("Reading a list...");
|
||||
|
||||
const auto *c = nextChar();
|
||||
LocationRange loc(getCurrentLocation());
|
||||
advance();
|
||||
|
||||
auto list = ast::makeAndCast<ast::List>(getCurrentLocation());
|
||||
auto list = ast::makeAndCast<ast::List>(loc);
|
||||
|
||||
// TODO: Replace the assert with an actual check.
|
||||
assert(*c == '(');
|
||||
|
@ -327,16 +328,16 @@ ast::MaybeNode Reader::readList() {
|
|||
bool list_terminated = false;
|
||||
|
||||
do {
|
||||
const auto *c = nextChar(true);
|
||||
const auto *ch = nextChar(true);
|
||||
|
||||
if (isEndOfBuffer(c)) {
|
||||
if (isEndOfBuffer(ch)) {
|
||||
advance(true);
|
||||
advance();
|
||||
list->location.end = getCurrentLocation();
|
||||
return errors::make(errors::Type::EOFWhileScaningAList, list->location);
|
||||
}
|
||||
|
||||
switch (*c) {
|
||||
switch (*ch) {
|
||||
case ')':
|
||||
advance(true);
|
||||
advance();
|
||||
|
@ -412,18 +413,16 @@ ast::MaybeAst Reader::read() {
|
|||
return std::move(this->ast);
|
||||
};
|
||||
|
||||
ast::MaybeAst read(jit::JIT &engine, const llvm::StringRef input,
|
||||
llvm::StringRef ns,
|
||||
ast::MaybeAst read(const llvm::StringRef input, llvm::StringRef ns,
|
||||
std::optional<llvm::StringRef> filename) {
|
||||
Reader r(engine, input, ns, filename);
|
||||
Reader r(input, ns, filename);
|
||||
auto ast = r.read();
|
||||
return ast;
|
||||
}
|
||||
|
||||
ast::MaybeAst read(jit::JIT &engine, const llvm::MemoryBufferRef input,
|
||||
llvm::StringRef ns,
|
||||
ast::MaybeAst read(const llvm::MemoryBufferRef input, llvm::StringRef ns,
|
||||
std::optional<llvm::StringRef> filename) {
|
||||
Reader r(engine, input, ns, filename);
|
||||
Reader r(input, ns, filename);
|
||||
|
||||
auto ast = r.read();
|
||||
return ast;
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#ifndef READER_H
|
||||
#define READER_H
|
||||
|
||||
#include "ast.h"
|
||||
#include "ast/ast.h"
|
||||
#include "location.h"
|
||||
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
|
@ -55,7 +55,6 @@ class JIT;
|
|||
/// Base reader class which reads from a string directly.
|
||||
class Reader {
|
||||
private:
|
||||
jit::JIT &engine;
|
||||
llvm::StringRef ns;
|
||||
std::optional<llvm::StringRef> filename;
|
||||
|
||||
|
@ -96,9 +95,9 @@ private:
|
|||
bool isEndOfBuffer(const char *);
|
||||
|
||||
public:
|
||||
Reader(jit::JIT &engine, llvm::StringRef buf, llvm::StringRef ns,
|
||||
Reader(llvm::StringRef buf, llvm::StringRef ns,
|
||||
std::optional<llvm::StringRef> filename);
|
||||
Reader(jit::JIT &engine, llvm::MemoryBufferRef buf, llvm::StringRef ns,
|
||||
Reader(llvm::MemoryBufferRef buf, llvm::StringRef ns,
|
||||
std::optional<llvm::StringRef> filename);
|
||||
|
||||
// void setInput(const llvm::StringRef string);
|
||||
|
|
|
@ -76,8 +76,8 @@ SourceMgr::MemBufPtr SourceMgr::findFileInLoadPath(const std::string &name,
|
|||
return nullptr;
|
||||
};
|
||||
|
||||
MaybeNS SourceMgr::readNamespace(jit::JIT &engine, std::string name,
|
||||
LocationRange importLoc) {
|
||||
ast::MaybeNS SourceMgr::readNamespace(std::string name,
|
||||
const LocationRange &importLoc) {
|
||||
std::string importedFile;
|
||||
|
||||
SMGR_LOG("Attempt to load namespace: " + name);
|
||||
|
@ -94,7 +94,7 @@ MaybeNS SourceMgr::readNamespace(jit::JIT &engine, std::string name,
|
|||
|
||||
if (bufferId == 0) {
|
||||
auto msg = llvm::formatv("Couldn't add namespace '{0}'", name).str();
|
||||
return errors::make(errors::Type; : NSAddToSMError, importLoc, msg);
|
||||
return errors::make(errors::Type::NSAddToSMError, importLoc, msg);
|
||||
}
|
||||
|
||||
// Since we moved the buffer to be added as the source storage we
|
||||
|
@ -102,7 +102,7 @@ MaybeNS SourceMgr::readNamespace(jit::JIT &engine, std::string name,
|
|||
const auto *buf = getMemoryBuffer(bufferId);
|
||||
|
||||
// Read the content of the buffer by passing it the reader
|
||||
auto maybeAst = read(jit, buf->getBuffer(), name,
|
||||
auto maybeAst = read(buf->getBuffer(), name,
|
||||
std::optional(llvm::StringRef(importedFile)));
|
||||
|
||||
if (!maybeAst) {
|
||||
|
@ -111,11 +111,11 @@ MaybeNS SourceMgr::readNamespace(jit::JIT &engine, std::string name,
|
|||
}
|
||||
|
||||
// Create the NS and set the AST
|
||||
auto ns =
|
||||
engine.makeNamespace(name, std::optional(llvm::StringRef(importedFile)));
|
||||
auto ns = ast::makeAndCast<ast::Namespace>(
|
||||
importLoc, name, std::optional(llvm::StringRef(importedFile)));
|
||||
|
||||
if (auto errs = ns->addTree(*maybeAst)) {
|
||||
SMGR_LOG("Couldn't set the AST for namespace: " + name);
|
||||
if (auto errs = ns->ExpandTree(*maybeAst)) {
|
||||
SMGR_LOG("Couldn't set thre AST for namespace: " + name);
|
||||
return errs;
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ MaybeNS SourceMgr::readNamespace(jit::JIT &engine, std::string name,
|
|||
};
|
||||
|
||||
unsigned SourceMgr::AddNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> f,
|
||||
LocationRange includeLoc) {
|
||||
const LocationRange &includeLoc) {
|
||||
SrcBuffer nb;
|
||||
nb.buffer = std::move(f);
|
||||
nb.importLoc = includeLoc;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#ifndef SERENE_SOURCE_MGR_H
|
||||
#define SERENE_SOURCE_MGR_H
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "location.h"
|
||||
#include "namespace.h"
|
||||
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/ADT/StringMap.h>
|
||||
|
@ -174,7 +174,7 @@ public:
|
|||
/// Add a new source buffer to this source manager. This takes ownership of
|
||||
/// the memory buffer.
|
||||
unsigned AddNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> f,
|
||||
LocationRange includeLoc);
|
||||
const LocationRange &includeLoc);
|
||||
|
||||
/// Lookup for a file containing the namespace definition of with given
|
||||
/// namespace name \p name. In case that the file exists, it returns an
|
||||
|
@ -184,8 +184,7 @@ public:
|
|||
///
|
||||
/// \p importLoc is a location in the source code where the give namespace is
|
||||
/// imported.
|
||||
MaybeNS readNamespace(jit::JIT &engine, std::string name,
|
||||
LocationRange importLoc);
|
||||
ast::MaybeNS readNamespace(std::string name, const LocationRange &importLoc);
|
||||
};
|
||||
|
||||
}; // namespace serene
|
||||
|
|
Loading…
Reference in New Issue