Finish up the errors-backend and migrate serene's errs to llvm:

This commit is contained in:
Sameer Rahmani 2022-02-04 22:47:01 +00:00
parent 95e9edf61e
commit 64ee59fbc8
32 changed files with 353 additions and 398 deletions

View File

@ -227,7 +227,7 @@ public:
// TODO: Fix this by calling to the diag engine // TODO: Fix this by calling to the diag engine
if (err) { if (err) {
llvm::errs() << err.getValue().back()->getMessage() << "\n"; llvm::errs() << err << "\n";
serene::terminate(*ctx, 1); serene::terminate(*ctx, 1);
return nullptr; return nullptr;
} }

View File

@ -19,8 +19,7 @@
#ifndef SERENE_DIAGNOSTICS_H #ifndef SERENE_DIAGNOSTICS_H
#define SERENE_DIAGNOSTICS_H #define SERENE_DIAGNOSTICS_H
#include "serene/errors/constants.h" #include "serene/errors.h"
#include "serene/errors/error.h"
#include "serene/reader/location.h" #include "serene/reader/location.h"
#include "serene/source_mgr.h" #include "serene/source_mgr.h"
@ -51,16 +50,15 @@ class Diagnostic {
SereneContext &ctx; SereneContext &ctx;
reader::LocationRange loc; reader::LocationRange loc;
std::string fn; std::string fn;
errors::ErrorVariant *err = nullptr; llvm::Error *err = nullptr;
Type type = Type::Error; Type type = Type::Error;
std::string message, lineContents; std::string message, lineContents;
std::string getPrefix(llvm::StringRef prefix = ""); std::string getPrefix(llvm::StringRef prefix = "");
public: public:
Diagnostic(SereneContext &ctx, reader::LocationRange loc, Diagnostic(SereneContext &ctx, reader::LocationRange loc, llvm::Error *e,
errors::ErrorVariant *e, llvm::StringRef msg, llvm::StringRef msg, llvm::StringRef fn = "")
llvm::StringRef fn = "")
: ctx(ctx), loc(loc), fn(fn), err(e), message(msg){}; : ctx(ctx), loc(loc), fn(fn), err(e), message(msg){};
protected: protected:
@ -73,7 +71,7 @@ class DiagnosticEngine {
mlir::DiagnosticEngine &diagEngine; mlir::DiagnosticEngine &diagEngine;
Diagnostic toDiagnostic(reader::LocationRange loc, errors::ErrorVariant &e, Diagnostic toDiagnostic(reader::LocationRange loc, llvm::Error &e,
llvm::StringRef msg, llvm::StringRef fn = ""); llvm::StringRef msg, llvm::StringRef fn = "");
void print(llvm::raw_ostream &os, Diagnostic &d); void print(llvm::raw_ostream &os, Diagnostic &d);
@ -82,11 +80,10 @@ public:
DiagnosticEngine(SereneContext &ctx); DiagnosticEngine(SereneContext &ctx);
void enqueueError(llvm::StringRef msg); void enqueueError(llvm::StringRef msg);
void emitSyntaxError(reader::LocationRange loc, errors::ErrorVariant &e, void emitSyntaxError(reader::LocationRange loc, llvm::Error &e,
llvm::StringRef msg = ""); llvm::StringRef msg = "");
void emit(const errors::ErrorPtr &err); void emit(const llvm::Error &err);
void emit(const errors::ErrorTree &errs);
/// Throw out an error with the given `msg` and terminate the execution /// Throw out an error with the given `msg` and terminate the execution
void panic(llvm::StringRef msg); void panic(llvm::StringRef msg);
@ -99,8 +96,8 @@ std::unique_ptr<DiagnosticEngine> makeDiagnosticEngine(SereneContext &ctx);
/// Throw out an error with the given `msg` and terminate the execution. /// Throw out an error with the given `msg` and terminate the execution.
SERENE_EXPORT void panic(SereneContext &ctx, llvm::StringRef msg); SERENE_EXPORT void panic(SereneContext &ctx, llvm::StringRef msg);
/// Throw the give `ErrorTree` \p errs and terminate the execution. /// Throw the give `llvm::Error` \p errs to the stderr.
SERENE_EXPORT void throwErrors(SereneContext &ctx, errors::ErrorTree &errs); SERENE_EXPORT void throwErrors(SereneContext &ctx, llvm::Error &errs);
} // namespace serene } // namespace serene
#endif #endif

View File

@ -19,7 +19,21 @@
#ifndef SERENE_ERRORS_H #ifndef SERENE_ERRORS_H
#define SERENE_ERRORS_H #define SERENE_ERRORS_H
#include "serene/errors/base.h"
#include "serene/errors/errc.h" #include "serene/errors/errc.h"
#include "serene/errors/error.h"
#define GET_CLASS_DEFS
#include "serene/errors/errs.h.inc"
#include <llvm/Support/Error.h>
namespace serene::errors {
template <typename E, typename... Args>
llvm::Error makeError(Args &&...args) {
return llvm::make_error<E>(std::forward<Args>(args)...);
};
} // namespace serene::errors
#endif #endif

View File

@ -24,37 +24,62 @@
#include <system_error> #include <system_error>
#include <llvm/Support/Error.h> #include <llvm/Support/Error.h>
#include <llvm/Support/FormatVariadic.h>
namespace serene::errors { namespace serene::errors {
template <typename T> struct ErrorVariant {
class SereneError : public llvm::ErrorInfo<T> { int id;
const std::string title;
const std::string desc;
const std::string help;
static ErrorVariant make(int id, const char *t, const char *d,
const char *h) {
return ErrorVariant(id, t, d, h);
};
private:
ErrorVariant(int id, const char *t, const char *d, const char *h)
: id(id), title(t), desc(d), help(h){};
};
class SereneError : public llvm::ErrorInfoBase {
reader::LocationRange location; reader::LocationRange location;
std::string msg; std::string msg;
public: public:
static const int ID = -1; static const int ID = -1;
void log(llvm::raw_ostream &os) const { os << msg; }; void log(llvm::raw_ostream &os) const override { os << msg; };
std::string message() const override { return msg; }; std::string message() const override { return msg; };
std::string &getTitle() const { return T::title; };
std::string &getDesc() const { return T::description; }; std::error_code convertToErrorCode() const override {
std::error_code convertToErrorCode() const { return std::error_code(); }; return std::error_code();
};
SereneError(reader::LocationRange &loc, std::string &msg) SereneError(reader::LocationRange &loc, std::string &msg)
: location(loc), msg(msg){}; : location(loc), msg(msg){};
SereneError(reader::LocationRange &loc, const char *msg)
: location(loc), msg(msg){};
SereneError(reader::LocationRange &loc, llvm::StringRef msg)
: location(loc), msg(msg.str()){};
SereneError(reader::LocationRange &loc) : location(loc){};
SereneError(SereneError &e) = delete;
reader::LocationRange &where() { return location; }; reader::LocationRange &where() { return location; };
static const void *classID() { return &T::ID; } static const void *classID() { return &ID; }
bool isA(const void *const id) const override { bool isA(const void *const id) const override {
// the check with -1 is a shortcut for us to figure return id == classID() || llvm::ErrorInfoBase::isA(id);
// out whether we're dealing with an Serene error or
// LLVM error
return *(const int *)id == -1 || id == classID() ||
llvm::ErrorInfoBase::isA(id);
} }
~SereneError() = default;
}; };
}; // namespace serene::errors }; // namespace serene::errors

View File

@ -1,81 +0,0 @@
/* -*- C++ -*-
* Serene Programming Language
*
* Copyright (c) 2019-2022 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef SERENE_ERRORS_ERROR_H
#define SERENE_ERRORS_ERROR_H
#include "serene/errors/constants.h"
#include "serene/errors/errs.h.inc"
#include "serene/errors/traits.h"
#include "serene/reader/traits.h"
#include "serene/traits.h"
#include <serene/export.h>
#include <llvm/ADT/Optional.h>
namespace serene::reader {
class LocationRange;
} // namespace serene::reader
namespace serene::errors {
class Error;
using ErrorPtr = std::shared_ptr<errors::Error>;
// tree? Yupe, Errors can be stackable which makes a vector of them a tree
using ErrorTree = std::vector<ErrorPtr>;
using OptionalErrors = llvm::Optional<ErrorTree>;
/// This data structure represent the Lisp error. This type of expression
/// doesn't show up in the AST but the compiler might rewrite the AST
/// to contains error expressions
class SERENE_EXPORT Error
: public WithTrait<Error, IError, reader::ILocatable, serene::IDebuggable> {
reader::LocationRange location;
ErrorVariant *variant;
std::string message;
public:
Error(reader::LocationRange &loc, ErrorVariant &err, llvm::StringRef msg)
: location(loc), variant(&err), message(msg){};
Error(reader::LocationRange &loc, ErrorVariant &err)
: location(loc), variant(&err){};
std::string toString() const;
reader::LocationRange &where();
ErrorVariant *getVariant();
std::string &getMessage();
~Error() = default;
};
/// Creates a new Error in the give location \p loc, with the given
/// variant \p and an optional message \p msg and retuns a shared ptr
/// to the error. This is the official API to make errors.
ErrorPtr makeError(reader::LocationRange &loc, ErrorVariant &err,
llvm::StringRef msg = "msg");
/// Creates a new ErrorTree out of a new Error that creats from the input
/// argument and pass them to `makeError` function.
ErrorTree makeErrorTree(reader::LocationRange &loc, ErrorVariant &err,
llvm::StringRef msg = "msg");
}; // namespace serene::errors
#endif

View File

@ -1,23 +1,76 @@
class Error<string _title = "", string _desc = ""> {
string title = _title; class Error<string _desc = "", string _help = ""> {
string description = _desc; string desc = _desc;
string help = _help;
} }
def Err : Error<"Err1 titel"> { // Examples of how to define a new error
let description = [{ // def Err : Error<"Err1 titel"> {
err1 // let description = [{
multiline // err1
desc}]; // multiline
} // desc}];
// }
def Err2 : Error { // def Err2 : Error {
let title = "err 2 titel"; // let title = "err 2 titel";
let description = "err2 desc"; // let description = "err2 desc";
} // }
def Err3 : Error<"err3", [{ // def Err3 : Error<"err3", [{
err3 // err3
multiline // multiline
desc // desc
}]>; // }]>;
def UnknownError: Error<"Can't find any description for this error.">;
def DefExpectSymbol: Error<"The first argument to 'def' has to be a Symbol.">;
def DefWrongNumberOfArgs: Error<"Wrong number of arguments is passed to the 'def' form.">;
def FnNoArgsList: Error<"'fn' form requires an argument list.">;
def FnArgsMustBeList: Error<"'fn' arguments should be a list.">;
def CantResolveSymbol: Error<"Can't resolve the given name.">;
def DontKnowHowToCallNode: Error<"Don't know how to call the given expression.">;
def PassFailureError: Error<"Pass Failure.">;
def NSLoadError: Error<"Faild to find a namespace.">;
def NSAddToSMError: Error<"Faild to add the namespace to the source manager.">;
def
EOFWhileScaningAList: Error<"EOF reached before closing of list">;
def InvalidDigitForNumber: Error<"Invalid digit for a number.">;
def
TwoFloatPoints: Error<"Two or more float point characters in a number">;
def
InvalidCharacterForSymbol: Error<"Invalid character for a symbol">;
def CompilationError: Error<"Compilation error!">;
defvar errorsIndex = [
UnknownError,
DefExpectSymbol,
DefWrongNumberOfArgs,
FnNoArgsList,
FnArgsMustBeList,
CantResolveSymbol,
DontKnowHowToCallNode,
PassFailureError,
NSLoadError,
NSAddToSMError,
EOFWhileScaningAList,
InvalidDigitForNumber,
TwoFloatPoints,
InvalidCharacterForSymbol,
CompilationError,
];

View File

@ -20,7 +20,7 @@
#define SERENE_EXPRS_CALL_H #define SERENE_EXPRS_CALL_H
#include "serene/context.h" #include "serene/context.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"

View File

@ -20,7 +20,7 @@
#define SERENE_EXPRS_DEF_H #define SERENE_EXPRS_DEF_H
#include "serene/context.h" #include "serene/context.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include <llvm/ADT/StringRef.h> #include <llvm/ADT/StringRef.h>

View File

@ -20,13 +20,14 @@
#define SERENE_EXPRS_EXPRESSION_H #define SERENE_EXPRS_EXPRESSION_H
#include "serene/context.h" #include "serene/context.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/traits.h" #include "serene/exprs/traits.h"
#include "serene/namespace.h" #include "serene/namespace.h"
#include "serene/reader/location.h" #include "serene/reader/location.h"
#include "serene/semantics.h" #include "serene/semantics.h"
#include "serene/utils.h" #include "serene/utils.h"
#include <llvm/Support/Error.h>
#include <mlir/IR/BuiltinOps.h> #include <mlir/IR/BuiltinOps.h>
#include <memory> #include <memory>
@ -40,12 +41,12 @@ namespace exprs {
class Expression; class Expression;
using Node = std::shared_ptr<Expression>; using Node = std::shared_ptr<Expression>;
using MaybeNode = Result<Node, errors::ErrorTree>; using MaybeNode = llvm::Expected<Node>;
using Ast = std::vector<Node>; using Ast = std::vector<Node>;
using MaybeAst = Result<Ast, errors::ErrorTree>; using MaybeAst = llvm::Expected<Ast>;
static auto EmptyNode = MaybeNode::success(nullptr); static auto EmptyNode = nullptr;
/// The base class of the expressions which provides the common interface for /// The base class of the expressions which provides the common interface for
/// the expressions to implement. /// the expressions to implement.
@ -111,34 +112,25 @@ std::shared_ptr<T> makeAndCast(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...); return std::make_shared<T>(std::forward<Args>(args)...);
}; };
/// The helper function to create a new `Node` and use that as the success case /// The helper function to create a new `Node` and returnsit. It should be useds
// of a `Result`. It should be useds where every we want to return a `MaybeNode` /// where every we want to return a `MaybeNode` successfully.
/// successfully
template <typename T, typename... Args> template <typename T, typename... Args>
Result<Node, errors::ErrorTree> makeSuccessfulNode(Args &&...args) { MaybeNode makeSuccessfulNode(Args &&...args) {
return Result<Node, errors::ErrorTree>::success( return make<T>(std::forward<Args>(args)...);
make<T>(std::forward<Args>(args)...));
}; };
/// The hlper function to create an Errorful `Result<T,...>` (`T` would be /// The hlper function to creates an Error (`llvm::Error`) by passing all
/// either `Node` or `Ast` most of the time) with just one error created from /// the given arguments to the constructor of the template param `E`.
/// passing any argument to this function to the `serene::errors::Error` template <typename E, typename T = Node, typename... Args>
/// constructor. llvm::Expected<T> makeErrorful(Args &&...args) {
template <typename T, typename... Args> return llvm::make_error<E>(std::forward<Args>(args)...);
Result<T, errors::ErrorTree> makeErrorful(Args &&...args) {
std::vector<errors::ErrorPtr> v{
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
return Result<T, errors::ErrorTree>::error(v);
}; };
/// The hlper function to create an Error node (The failure case of a MaybeNod) /// The hlper function to creates an Error (`llvm::Error`) by passing all
/// with just one error created from passing any argument to this function to /// the given arguments to the constructor of the template param `E`.
/// the `serene::errors::Error` constructor. template <typename E, typename... Args>
template <typename... Args>
MaybeNode makeErrorNode(Args &&...args) { MaybeNode makeErrorNode(Args &&...args) {
std::vector<errors::ErrorPtr> v{ return makeErrorful<E, Node>(std::forward<Args>(args)...);
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
return MaybeNode::error(v);
}; };
/// Convert the given AST to string by calling the `toString` method /// Convert the given AST to string by calling the `toString` method

View File

@ -20,7 +20,7 @@
#define SERENE_EXPRS_FN_H #define SERENE_EXPRS_FN_H
#include "serene/context.h" #include "serene/context.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/namespace.h" #include "serene/namespace.h"

View File

@ -25,7 +25,6 @@
#define SERENE_JIT_HALLEY_H #define SERENE_JIT_HALLEY_H
#include "serene/errors.h" #include "serene/errors.h"
#include "serene/errors/error.h"
#include "serene/export.h" #include "serene/export.h"
#include "serene/namespace.h" #include "serene/namespace.h"
#include "serene/utils.h" #include "serene/utils.h"
@ -58,7 +57,7 @@ namespace jit {
class Halley; class Halley;
using MaybeJIT = llvm::Expected<std::unique_ptr<Halley>>; using MaybeJIT = llvm::Expected<std::unique_ptr<Halley>>;
using MaybeJITPtr = serene::Result<void (*)(void **), errors::ErrorTree>; using MaybeJITPtr = llvm::Expected<void (*)(void **)>;
/// A simple object cache following Lang's LLJITWithObjectCache example and /// A simple object cache following Lang's LLJITWithObjectCache example and
/// MLIR's SimpelObjectCache. /// MLIR's SimpelObjectCache.
class ObjectCache : public llvm::ObjectCache { class ObjectCache : public llvm::ObjectCache {
@ -179,10 +178,9 @@ public:
llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)> llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
symbolMap); symbolMap);
llvm::Optional<errors::ErrorTree> addNS(Namespace &ns, llvm::Error addNS(Namespace &ns, reader::LocationRange &loc);
reader::LocationRange &loc);
llvm::Optional<errors::ErrorTree> addAST(exprs::Ast &ast); llvm::Error addAST(exprs::Ast &ast);
Namespace &getActiveNS(); Namespace &getActiveNS();
}; };

View File

@ -34,7 +34,7 @@
#define SERENE_NAMESPACE_H #define SERENE_NAMESPACE_H
#include "serene/environment.h" #include "serene/environment.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/export.h" #include "serene/export.h"
#include "serene/slir/generatable.h" #include "serene/slir/generatable.h"
#include "serene/traits.h" #include "serene/traits.h"
@ -47,6 +47,7 @@
#include <llvm/ExecutionEngine/Orc/Core.h> #include <llvm/ExecutionEngine/Orc/Core.h>
#include <llvm/ExecutionEngine/Orc/ThreadSafeModule.h> #include <llvm/ExecutionEngine/Orc/ThreadSafeModule.h>
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/Support/Error.h>
#include <mlir/IR/Builders.h> #include <mlir/IR/Builders.h>
#include <mlir/IR/BuiltinOps.h> #include <mlir/IR/BuiltinOps.h>
#include <mlir/IR/OwningOpRef.h> #include <mlir/IR/OwningOpRef.h>
@ -72,7 +73,7 @@ using Ast = std::vector<Node>;
} // namespace exprs } // namespace exprs
using NSPtr = std::shared_ptr<Namespace>; using NSPtr = std::shared_ptr<Namespace>;
using MaybeNS = Result<NSPtr, errors::ErrorTree>; using MaybeNS = llvm::Expected<NSPtr>;
using MaybeModule = llvm::Optional<llvm::orc::ThreadSafeModule>; using MaybeModule = llvm::Optional<llvm::orc::ThreadSafeModule>;
using MaybeModuleOp = llvm::Optional<mlir::OwningOpRef<mlir::ModuleOp>>; using MaybeModuleOp = llvm::Optional<mlir::OwningOpRef<mlir::ModuleOp>>;
using SemanticEnv = Environment<std::string, exprs::Node>; using SemanticEnv = Environment<std::string, exprs::Node>;
@ -137,7 +138,7 @@ public:
/// many elements. /// many elements.
/// ///
/// This function runs the semantic analyzer on the \p ast as well. /// This function runs the semantic analyzer on the \p ast as well.
errors::OptionalErrors addTree(exprs::Ast &ast); llvm::Error addTree(exprs::Ast &ast);
exprs::Ast &getTree(); exprs::Ast &getTree();
const std::vector<llvm::StringRef> &getSymList() { return symbolList; }; const std::vector<llvm::StringRef> &getSymList() { return symbolList; };

View File

@ -20,7 +20,7 @@
#define SERENE_SEMANTICS_H #define SERENE_SEMANTICS_H
#include "serene/environment.h" #include "serene/environment.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/utils.h" #include "serene/utils.h"
#include <llvm/ADT/StringRef.h> #include <llvm/ADT/StringRef.h>
@ -39,7 +39,7 @@ class Namespace;
using SemanticEnv = Environment<std::string, exprs::Node>; using SemanticEnv = Environment<std::string, exprs::Node>;
namespace semantics { namespace semantics {
using AnalyzeResult = Result<exprs::Ast, std::vector<errors::ErrorPtr>>; using AnalyzeResult = llvm::Expected<exprs::Ast>;
/// This struct represent the state necessary for each analysis job. /// This struct represent the state necessary for each analysis job.
struct AnalysisState { struct AnalysisState {
@ -62,10 +62,9 @@ std::unique_ptr<AnalysisState> makeAnalysisState(Args &&...args) {
/// The entry point to the Semantic analysis phase. It calls the `analyze` /// The entry point to the Semantic analysis phase. It calls the `analyze`
/// method of each node in the given \p form and creates a new AST that /// method of each node in the given \p form and creates a new AST that
/// contains a more comprehensive set of nodes in a semantically correct /// contains a more comprehensive set of nodes in a semantically correct
/// AST. If the `analyze` method of a node return a `nullptr` value as the /// AST. If the `analyze` method of a node return a `nullptr` value then the
/// `success` result (Checkout the `Result` type in `utils.h`) then the /// original node will be used instead. Any possible error will be returned.
/// original node will be used instead. Any possible error will return as ///
/// the `error` case of the `Result` type.
/// \param state The semantic analysis state that keep track of the envs. /// \param state The semantic analysis state that keep track of the envs.
/// \param form The actual AST in question. /// \param form The actual AST in question.
AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms); AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms);

View File

@ -50,13 +50,11 @@ add_library(serene
jit/layers.cpp jit/layers.cpp
jit/halley.cpp jit/halley.cpp
errors.cpp
# Reader # Reader
reader/reader.cpp reader/reader.cpp
# Errors
errors/error.cpp
# IR # IR
slir/slir.cpp slir/slir.cpp
slir/dialect.cpp slir/dialect.cpp

View File

@ -126,11 +126,11 @@ MaybeNS SereneContext::importNamespace(const std::string &name,
auto maybeNS = readNamespace(name, loc); auto maybeNS = readNamespace(name, loc);
if (maybeNS) { if (maybeNS) {
auto &ns = maybeNS.getValue(); auto &ns = *maybeNS;
auto err = jit->addNS(*ns, loc); if (auto err = jit->addNS(*ns, loc)) {
if (err) { return err;
return MaybeNS::error(err.getValue());
} }
insertNS(ns); insertNS(ns);
} }

View File

@ -24,6 +24,7 @@
#include "serene/utils.h" #include "serene/utils.h"
#include <llvm/ADT/StringRef.h> #include <llvm/ADT/StringRef.h>
#include <llvm/Support/Error.h>
#include <llvm/Support/FormatAdapters.h> #include <llvm/Support/FormatAdapters.h>
#include <llvm/Support/FormatVariadic.h> #include <llvm/Support/FormatVariadic.h>
#include <llvm/Support/WithColor.h> #include <llvm/Support/WithColor.h>
@ -158,8 +159,7 @@ void DiagnosticEngine::print(llvm::raw_ostream &os, Diagnostic &d) {
}; };
Diagnostic DiagnosticEngine::toDiagnostic(reader::LocationRange loc, Diagnostic DiagnosticEngine::toDiagnostic(reader::LocationRange loc,
errors::ErrorVariant &e, llvm::Error &e, llvm::StringRef msg,
llvm::StringRef msg,
llvm::StringRef fn) { llvm::StringRef fn) {
return Diagnostic(ctx, loc, &e, msg, fn); return Diagnostic(ctx, loc, &e, msg, fn);
@ -171,8 +171,7 @@ void DiagnosticEngine::enqueueError(llvm::StringRef msg) {
}; };
void DiagnosticEngine::emitSyntaxError(reader::LocationRange loc, void DiagnosticEngine::emitSyntaxError(reader::LocationRange loc,
errors::ErrorVariant &e, llvm::Error &e, llvm::StringRef msg) {
llvm::StringRef msg) {
Diagnostic diag(ctx, loc, &e, msg); Diagnostic diag(ctx, loc, &e, msg);
diag.print(llvm::errs(), "SyntaxError"); diag.print(llvm::errs(), "SyntaxError");
@ -203,23 +202,27 @@ std::unique_ptr<DiagnosticEngine> makeDiagnosticEngine(SereneContext &ctx) {
return std::make_unique<DiagnosticEngine>(ctx); return std::make_unique<DiagnosticEngine>(ctx);
} }
void DiagnosticEngine::emit(const errors::ErrorPtr &err) { void DiagnosticEngine::emit(const llvm::Error &err) {
UNUSED(ctx); UNUSED(ctx);
// TODO: create a diag and print it // TODO: create a diag and print it
llvm::errs() << err->toString() << "\n"; llvm::errs() << err << "\n";
}; };
void DiagnosticEngine::emit(const errors::ErrorTree &errs) { // void DiagnosticEngine::emit(const llvm::Error &errs) {
for (const auto &e : errs) { //
emit(e); // // for (const auto &e : errs) {
} // // emit(e);
}; // // }
//
// };
void panic(SereneContext &ctx, llvm::StringRef msg) { void panic(SereneContext &ctx, llvm::StringRef msg) {
ctx.diagEngine->panic(msg); ctx.diagEngine->panic(msg);
}; };
void throwErrors(SereneContext &ctx, errors::ErrorTree &errs) { void throwErrors(SereneContext &ctx, llvm::Error &errs) {
// llvm::handleErrors(errs,
// [](const errors::SereneError &e){});
ctx.diagEngine->emit(errs); ctx.diagEngine->emit(errs);
}; };

View File

@ -16,22 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef SERENE_ERRORS_TRAITS_H #include "serene/errors.h"
#define SERENE_ERRORS_TRAITS_H
#include "serene/errors/constants.h" #define GET_ERRS_ARRAY
#include "serene/traits.h" #include "serene/errors/errs.h.inc"
namespace serene::errors {
template <typename ConcreteType>
class IError : public TraitBase<ConcreteType, IError> {
public:
IError(){};
IError(const IError &) = delete;
ErrorVariant *getVariant();
std::string getMessage();
};
} // namespace serene::errors
#endif

View File

@ -1,50 +0,0 @@
/*
* Serene Programming Language
*
* Copyright (c) 2019-2022 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "serene/errors/error.h"
#include <llvm/Support/FormatVariadic.h>
#include <memory>
namespace serene {
namespace errors {
std::string Error::toString() const {
return llvm::formatv("<Error E{0}: {1}>", this->variant->id, this->message);
}
reader::LocationRange &Error::where() { return this->location; };
ErrorVariant *Error::getVariant() { return this->variant; }
std::string &Error::getMessage() { return this->message; }
ErrorPtr makeError(reader::LocationRange &loc, ErrorVariant &err,
llvm::StringRef msg) {
return std::make_shared<Error>(loc, err, msg);
};
ErrorTree makeErrorTree(reader::LocationRange &loc, ErrorVariant &err,
llvm::StringRef msg) {
std::vector errs{makeError(loc, err, msg)};
return errs;
};
} // namespace errors
} // namespace serene

View File

@ -18,7 +18,7 @@
#include "serene/exprs/call.h" #include "serene/exprs/call.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/def.h" #include "serene/exprs/def.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
@ -63,7 +63,7 @@ MaybeNode Call::make(semantics::AnalysisState &state, List *list) {
return maybeFirst; return maybeFirst;
} }
Node first = maybeFirst.getValue(); Node &first = *maybeFirst;
// No rewrite is needed for the first element // No rewrite is needed for the first element
if (!first) { if (!first) {
@ -97,7 +97,7 @@ MaybeNode Call::make(semantics::AnalysisState &state, List *list) {
if (!maybeResult.hasValue()) { if (!maybeResult.hasValue()) {
std::string msg = std::string msg =
llvm::formatv("Can't resolve the symbol '{0}'", sym->name); llvm::formatv("Can't resolve the symbol '{0}'", sym->name);
return makeErrorful<Node>(sym->location, errors::CantResolveSymbol, msg); return errors::makeError<errors::CantResolveSymbol>(sym->location, msg);
} }
targetNode = std::move(maybeResult.getValue()); targetNode = std::move(maybeResult.getValue());
@ -122,19 +122,18 @@ MaybeNode Call::make(semantics::AnalysisState &state, List *list) {
default: { default: {
std::string msg = llvm::formatv("Don't know how to call a '{0}'", std::string msg = llvm::formatv("Don't know how to call a '{0}'",
stringifyExprType(first->getType())); stringifyExprType(first->getType()));
return makeErrorful<Node>(first->location, errors::DontKnowHowToCallNode, return errors::makeError<errors::DontKnowHowToCallNode>(first->location,
msg); msg);
} }
}; };
auto analyzedParams = semantics::analyze(state, rawParams); auto analyzedParams = semantics::analyze(state, rawParams);
if (!analyzedParams) { if (!analyzedParams) {
return MaybeNode::error(analyzedParams.getError()); return analyzedParams.takeError();
} }
return makeSuccessfulNode<Call>(list->location, targetNode, return makeSuccessfulNode<Call>(list->location, targetNode, *analyzedParams);
analyzedParams.getValue());
}; };
} // namespace exprs } // namespace exprs
} // namespace serene } // namespace serene

View File

@ -18,7 +18,7 @@
#include "serene/exprs/def.h" #include "serene/exprs/def.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/exprs/fn.h" #include "serene/exprs/fn.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
@ -55,8 +55,8 @@ MaybeNode Def::make(semantics::AnalysisState &state, List *list) {
// TODO: Add support for docstring as the 3rd argument (4th element) // TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() != 3) { if (list->count() != 3) {
std::string msg = llvm::formatv("Expected 3 got {0}", list->count()); std::string msg = llvm::formatv("Expected 3 got {0}", list->count());
return makeErrorful<Node>(list->elements[0]->location, return errors::makeError<errors::DefWrongNumberOfArgs>(
errors::DefWrongNumberOfArgs, msg); list->elements[0]->location, msg);
} }
// Make sure that the list starts with a `def` // Make sure that the list starts with a `def`
@ -68,8 +68,8 @@ MaybeNode Def::make(semantics::AnalysisState &state, List *list) {
// Make sure that the first argument is a Symbol // Make sure that the first argument is a Symbol
Symbol *binding = llvm::dyn_cast<Symbol>(list->elements[1].get()); Symbol *binding = llvm::dyn_cast<Symbol>(list->elements[1].get());
if (binding == nullptr) { if (binding == nullptr) {
return makeErrorful<Node>(list->elements[1]->location, return errors::makeError<errors::DefExpectSymbol>(
errors::DefExpectSymbol, ""); list->elements[1]->location);
} }
// Analyze the value // Analyze the value
@ -79,7 +79,7 @@ MaybeNode Def::make(semantics::AnalysisState &state, List *list) {
// TODO: To refactor this logic into a generic function // TODO: To refactor this logic into a generic function
if (value) { if (value) {
// Success value // Success value
auto &valueNode = value.getValue(); auto &valueNode = *value;
if (valueNode) { if (valueNode) {
// A rewrite is necessary // A rewrite is necessary

View File

@ -18,7 +18,7 @@
#include "serene/exprs/fn.h" #include "serene/exprs/fn.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/exprs/symbol.h" #include "serene/exprs/symbol.h"
@ -66,8 +66,8 @@ MaybeNode Fn::make(semantics::AnalysisState &state, List *list) {
// TODO: Add support for docstring as the 3rd argument (4th element) // TODO: Add support for docstring as the 3rd argument (4th element)
if (list->count() < 2) { if (list->count() < 2) {
return makeErrorful<Node>(list->elements[0]->location, errors::FnNoArgsList, return errors::makeError<errors::FnNoArgsList>(
"The argument list is mandatory."); list->elements[0]->location, "The argument list is mandatory.");
} }
Symbol *fnSym = llvm::dyn_cast<Symbol>(list->elements[0].get()); Symbol *fnSym = llvm::dyn_cast<Symbol>(list->elements[0].get());
@ -83,8 +83,8 @@ MaybeNode Fn::make(semantics::AnalysisState &state, List *list) {
llvm::formatv("Arguments of a function has to be a list, got '{0}'", llvm::formatv("Arguments of a function has to be a list, got '{0}'",
stringifyExprType(list->elements[1]->getType())); stringifyExprType(list->elements[1]->getType()));
return makeErrorful<Node>(list->elements[1]->location, return errors::makeError<errors::FnArgsMustBeList>(
errors::FnArgsMustBeList, msg); list->elements[1]->location, msg);
} }
Ast body; Ast body;
@ -100,10 +100,10 @@ MaybeNode Fn::make(semantics::AnalysisState &state, List *list) {
auto maybeAst = semantics::analyze(state, body); auto maybeAst = semantics::analyze(state, body);
if (!maybeAst) { if (!maybeAst) {
return MaybeNode::error(std::move(maybeAst.getError())); return maybeAst.takeError();
} }
body = maybeAst.getValue(); body = *maybeAst;
} }
return makeSuccessfulNode<Fn>(ctx, list->location, *args, body); return makeSuccessfulNode<Fn>(ctx, list->location, *args, body);

View File

@ -18,7 +18,7 @@
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/errors/error.h" #include "serene/errors.h"
#include "serene/exprs/call.h" #include "serene/exprs/call.h"
#include "serene/exprs/def.h" #include "serene/exprs/def.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"

View File

@ -29,8 +29,7 @@
#include "serene/context.h" #include "serene/context.h"
#include "serene/diagnostics.h" #include "serene/diagnostics.h"
#include "serene/errors/constants.h" #include "serene/errors.h"
#include "serene/errors/error.h"
#include "serene/exprs/symbol.h" #include "serene/exprs/symbol.h"
#include "serene/namespace.h" #include "serene/namespace.h"
#include "serene/utils.h" #include "serene/utils.h"
@ -202,18 +201,16 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const {
auto *ns = ctx.getNS(sym.nsName); auto *ns = ctx.getNS(sym.nsName);
if (ns == nullptr) { if (ns == nullptr) {
return MaybeJITPtr::error(errors::makeErrorTree( return errors::makeError<errors::CantResolveSymbol>(
sym.location, errors::CantResolveSymbol, sym.location, "Can't find the namespace in the context: " + sym.nsName);
"Can't find the namespace in the context: " + sym.nsName));
} }
auto *dylib = ctx.getLatestJITDylib(*ns); auto *dylib = ctx.getLatestJITDylib(*ns);
// //
if (dylib == nullptr) { if (dylib == nullptr) {
return MaybeJITPtr::error( return errors::makeError<errors::CantResolveSymbol>(
errors::makeErrorTree(sym.location, errors::CantResolveSymbol, sym.location, "Don't know about namespace: " + sym.nsName);
"Don't know about namespace: " + sym.nsName));
} }
auto expectedSymbol = auto expectedSymbol =
@ -230,8 +227,7 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const {
llvm::raw_string_ostream os(errorMessage); llvm::raw_string_ostream os(errorMessage);
llvm::handleAllErrors(expectedSymbol.takeError(), llvm::handleAllErrors(expectedSymbol.takeError(),
[&os](llvm::ErrorInfoBase &ei) { ei.log(os); }); [&os](llvm::ErrorInfoBase &ei) { ei.log(os); });
return MaybeJITPtr::error(errors::makeErrorTree( return errors::makeError<errors::CantResolveSymbol>(sym.location, os.str());
sym.location, errors::CantResolveSymbol, os.str()));
} }
auto rawFPtr = expectedSymbol->getAddress(); auto rawFPtr = expectedSymbol->getAddress();
@ -239,8 +235,8 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const {
auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr); auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
if (fptr == nullptr) { if (fptr == nullptr) {
return MaybeJITPtr::error(errors::makeErrorTree( return errors::makeError<errors::CantResolveSymbol>(
sym.location, errors::CantResolveSymbol, "Lookup function is null!")); sym.location, "Lookup function is null!");
} }
return fptr; return fptr;
@ -281,8 +277,7 @@ void Halley::registerSymbols(
mainJitDylib.getExecutionSession(), engine->getDataLayout()))))); mainJitDylib.getExecutionSession(), engine->getDataLayout())))));
}; };
llvm::Optional<errors::ErrorTree> Halley::addNS(Namespace &ns, llvm::Error Halley::addNS(Namespace &ns, reader::LocationRange &loc) {
reader::LocationRange &loc) {
HALLEY_LOG(llvm::formatv("Creating Dylib {0}#{1}", ns.name, HALLEY_LOG(llvm::formatv("Creating Dylib {0}#{1}", ns.name,
ctx.getNumberOfJITDylibs(ns) + 1)); ctx.getNumberOfJITDylibs(ns) + 1));
@ -291,8 +286,8 @@ llvm::Optional<errors::ErrorTree> Halley::addNS(Namespace &ns,
llvm::formatv("{0}#{1}", ns.name, ctx.getNumberOfJITDylibs(ns) + 1)); llvm::formatv("{0}#{1}", ns.name, ctx.getNumberOfJITDylibs(ns) + 1));
if (!newDylib) { if (!newDylib) {
return errors::makeErrorTree(loc, errors::CompilationError, return errors::makeError<errors::CompilationError>(
"Filed to create dylib for " + ns.name); loc, "Filed to create dylib for " + ns.name);
} }
ctx.pushJITDylib(ns, &(*newDylib)); ctx.pushJITDylib(ns, &(*newDylib));
@ -301,7 +296,7 @@ llvm::Optional<errors::ErrorTree> Halley::addNS(Namespace &ns,
auto maybeModule = ns.compileToLLVM(); auto maybeModule = ns.compileToLLVM();
if (!maybeModule.hasValue()) { if (!maybeModule.hasValue()) {
return errors::makeErrorTree(loc, errors::CompilationError); return errors::makeError<errors::CompilationError>(loc);
} }
auto tsm = std::move(maybeModule.getValue()); auto tsm = std::move(maybeModule.getValue());
@ -310,7 +305,7 @@ llvm::Optional<errors::ErrorTree> Halley::addNS(Namespace &ns,
// TODO: Make sure that the data layout of the module is the same as the // TODO: Make sure that the data layout of the module is the same as the
// engine // engine
cantFail(engine->addIRModule(*newDylib, std::move(tsm))); cantFail(engine->addIRModule(*newDylib, std::move(tsm)));
return llvm::None; return llvm::Error::success();
}; };
void Halley::setEngine(std::unique_ptr<llvm::orc::LLJIT> e, bool isLazy) { void Halley::setEngine(std::unique_ptr<llvm::orc::LLJIT> e, bool isLazy) {
@ -462,12 +457,11 @@ MaybeJIT Halley::make(SereneContext &serene_ctx,
return MaybeJIT(std::move(jitEngine)); return MaybeJIT(std::move(jitEngine));
}; };
llvm::Optional<errors::ErrorTree> Halley::addAST(exprs::Ast &ast) { llvm::Error Halley::addAST(exprs::Ast &ast) {
auto offset = activeNS->getTree().size(); auto offset = activeNS->getTree().size();
auto errs = activeNS->addTree(ast);
if (errs) { if (auto errs = activeNS->addTree(ast)) {
return errs.getValue(); return errs;
} }
auto maybeModule = activeNS->compileToLLVMFromOffset(offset); auto maybeModule = activeNS->compileToLLVMFromOffset(offset);
@ -479,7 +473,7 @@ llvm::Optional<errors::ErrorTree> Halley::addAST(exprs::Ast &ast) {
// TODO: Make sure that the data layout of the module is the same as the // TODO: Make sure that the data layout of the module is the same as the
// engine // engine
cantFail(engine->addIRModule(*dylib, std::move(tsm))); cantFail(engine->addIRModule(*dylib, std::move(tsm)));
return llvm::None; return llvm::Error::success();
}; };
Namespace &Halley::getActiveNS() { return *activeNS; }; Namespace &Halley::getActiveNS() { return *activeNS; };

View File

@ -127,13 +127,11 @@ llvm::Error NSLayer::add(orc::ResourceTrackerSP &rt, llvm::StringRef nsname,
if (!maybeNS) { if (!maybeNS) {
// TODO: Fix this by making Serene errors compatible with llvm::Error // TODO: Fix this by making Serene errors compatible with llvm::Error
auto err = maybeNS.getError(); auto err = maybeNS.takeError();
return llvm::make_error<llvm::StringError>( return err;
llvm::Twine(err.front()->getMessage()),
std::make_error_code(std::errc::io_error));
} }
auto ns = maybeNS.getValue(); auto ns = *maybeNS;
LAYER_LOG("Add the materialize unit for: " + nsname); LAYER_LOG("Add the materialize unit for: " + nsname);
return rt->getJITDylib().define( return rt->getJITDylib().define(

View File

@ -25,7 +25,6 @@
#include "serene/namespace.h" #include "serene/namespace.h"
#include "serene/context.h" #include "serene/context.h"
#include "serene/errors/constants.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/llvm/IR/Value.h" #include "serene/llvm/IR/Value.h"
#include "serene/semantics.h" #include "serene/semantics.h"
@ -90,13 +89,13 @@ mlir::LogicalResult Namespace::define(std::string &name, exprs::Node &node) {
} }
exprs::Ast &Namespace::getTree() { return this->tree; } exprs::Ast &Namespace::getTree() { return this->tree; }
errors::OptionalErrors Namespace::addTree(exprs::Ast &ast) { llvm::Error Namespace::addTree(exprs::Ast &ast) {
// TODO: Remove the parse phase // TODO: Remove the parse phase
if (ctx.getTargetPhase() == CompilationPhase::Parse) { if (ctx.getTargetPhase() == CompilationPhase::Parse) {
// we just want the raw AST // we just want the raw AST
this->tree.insert(this->tree.end(), ast.begin(), ast.end()); this->tree.insert(this->tree.end(), ast.begin(), ast.end());
return llvm::None; return llvm::Error::success();
} }
auto &rootEnv = getRootEnv(); auto &rootEnv = getRootEnv();
@ -106,13 +105,13 @@ errors::OptionalErrors Namespace::addTree(exprs::Ast &ast) {
auto maybeForm = semantics::analyze(*state, ast); auto maybeForm = semantics::analyze(*state, ast);
if (!maybeForm) { if (!maybeForm) {
return maybeForm.getError(); return maybeForm.takeError();
} }
auto semanticAst = std::move(maybeForm.getValue()); auto semanticAst = std::move(*maybeForm);
this->tree.insert(this->tree.end(), semanticAst.begin(), semanticAst.end()); this->tree.insert(this->tree.end(), semanticAst.begin(), semanticAst.end());
return llvm::None; return llvm::Error::success();
} }
uint Namespace::nextFnCounter() { return fn_counter++; }; uint Namespace::nextFnCounter() { return fn_counter++; };

View File

@ -18,7 +18,7 @@
#include "serene/reader/reader.h" #include "serene/reader/reader.h"
#include "serene/errors/constants.h" #include "serene/errors.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/exprs/list.h" #include "serene/exprs/list.h"
#include "serene/exprs/number.h" #include "serene/exprs/number.h"
@ -225,7 +225,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) {
LocationRange loc(getCurrentLocation()); LocationRange loc(getCurrentLocation());
if (isdigit(*c) == 0) { if (isdigit(*c) == 0) {
return exprs::makeErrorNode(loc, errors::InvalidDigitForNumber); return errors::makeError<errors::InvalidDigitForNumber>(loc);
} }
for (;;) { for (;;) {
@ -236,8 +236,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) {
if ((isdigit(*c) != 0) || *c == '.') { if ((isdigit(*c) != 0) || *c == '.') {
if (*c == '.' && floatNum) { if (*c == '.' && floatNum) {
loc = LocationRange(getCurrentLocation()); loc = LocationRange(getCurrentLocation());
ctx.diagEngine->emitSyntaxError(loc, errors::TwoFloatPoints); return errors::makeError<errors::TwoFloatPoints>(loc);
terminate(ctx, 1);
} }
if (*c == '.') { if (*c == '.') {
@ -253,8 +252,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) {
if (((std::isalpha(*c) != 0) && !empty) || empty) { if (((std::isalpha(*c) != 0) && !empty) || empty) {
advance(); advance();
loc.start = getCurrentLocation(); loc.start = getCurrentLocation();
ctx.diagEngine->emitSyntaxError(loc, errors::InvalidDigitForNumber); return errors::makeError<errors::InvalidDigitForNumber>(loc);
terminate(ctx, 1);
} }
loc.end = getCurrentLocation(); loc.end = getCurrentLocation();
@ -278,7 +276,7 @@ exprs::MaybeNode Reader::readSymbol() {
msg = "An extra ')' is detected."; msg = "An extra ')' is detected.";
} }
return exprs::makeErrorNode(loc, errors::InvalidCharacterForSymbol, msg); return errors::makeError<errors::InvalidCharacterForSymbol>(loc, msg);
} }
if (*c == '-') { if (*c == '-') {
@ -338,7 +336,7 @@ exprs::MaybeNode Reader::readList() {
advance(true); advance(true);
advance(); advance();
list->location.end = getCurrentLocation(); list->location.end = getCurrentLocation();
return exprs::makeErrorNode(list->location, errors::EOFWhileScaningAList); return errors::makeError<errors::EOFWhileScaningAList>(list->location);
} }
switch (*c) { switch (*c) {
@ -356,12 +354,12 @@ exprs::MaybeNode Reader::readList() {
return expr; return expr;
} }
list->append(expr.getValue()); list->append(*expr);
} }
} while (!list_terminated); } while (!list_terminated);
return exprs::MaybeNode::success(list); return list;
}; };
/// Reads an expression by dispatching to the proper reader function. /// Reads an expression by dispatching to the proper reader function.
@ -403,18 +401,18 @@ exprs::MaybeAst Reader::read() {
auto tmp = readExpr(); auto tmp = readExpr();
if (tmp) { if (tmp) {
if (tmp.getValue() == nullptr) { if (*tmp == nullptr) {
break; break;
} }
this->ast.push_back(move(tmp.getValue())); this->ast.push_back(move(*tmp));
} else { } else {
return exprs::MaybeAst::error(tmp.getError()); return tmp.takeError();
} }
} }
return exprs::MaybeAst::success(std::move(this->ast)); return std::move(this->ast);
}; };
exprs::MaybeAst read(SereneContext &ctx, const llvm::StringRef input, exprs::MaybeAst read(SereneContext &ctx, const llvm::StringRef input,

View File

@ -22,6 +22,8 @@
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
#include "serene/namespace.h" #include "serene/namespace.h"
#include <llvm/Support/Error.h>
namespace serene::semantics { namespace serene::semantics {
std::unique_ptr<AnalysisState> AnalysisState::moveToNewEnv() { std::unique_ptr<AnalysisState> AnalysisState::moveToNewEnv() {
@ -30,7 +32,7 @@ std::unique_ptr<AnalysisState> AnalysisState::moveToNewEnv() {
}; };
AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) { AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) {
errors::ErrorTree errors; llvm::Error errors = llvm::Error::success();
exprs::Ast ast; exprs::Ast ast;
for (auto &element : forms) { for (auto &element : forms) {
@ -38,7 +40,7 @@ AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) {
// Is it a `success` result // Is it a `success` result
if (maybeNode) { if (maybeNode) {
auto &node = maybeNode.getValue(); auto &node = *maybeNode;
if (node) { if (node) {
// is there a new node to replace the current node ? // is there a new node to replace the current node ?
@ -53,15 +55,17 @@ AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) {
// `analyze` returned an errorful result. This type of error // `analyze` returned an errorful result. This type of error
// is llvm related and has to be raised later // is llvm related and has to be raised later
// (std::move()); // (std::move());
auto errVector = maybeNode.getError(); auto err = maybeNode.takeError();
errors.insert(errors.end(), errVector.begin(), errVector.end()); errors = llvm::joinErrors(std::move(errors), std::move(err));
} }
} }
if (errors.empty()) { // If the errors (which is an ErrorList) contains error and is
return AnalyzeResult::success(std::move(ast)); // not succssful
if (!errors) {
return std::move(ast);
} }
return AnalyzeResult::error(std::move(errors)); return std::move(errors);
}; };
}; // namespace serene::semantics }; // namespace serene::semantics

View File

@ -25,7 +25,6 @@
#include "serene/serene.h" #include "serene/serene.h"
#include "serene/diagnostics.h" #include "serene/diagnostics.h"
#include "serene/errors/constants.h"
#include "serene/exprs/expression.h" #include "serene/exprs/expression.h"
// TODO: Remove it // TODO: Remove it
@ -122,7 +121,7 @@ SERENE_EXPORT exprs::MaybeNode eval(SereneContext &ctx, exprs::Ast &input) {
auto errs = ctx.jit->addAST(input); auto errs = ctx.jit->addAST(input);
if (errs) { if (errs) {
return exprs::MaybeNode::error(errs.getValue()); return errs;
} }
// auto e = input[0]; // auto e = input[0];

View File

@ -24,7 +24,6 @@
#include "serene/source_mgr.h" #include "serene/source_mgr.h"
#include "serene/errors/constants.h"
#include "serene/namespace.h" #include "serene/namespace.h"
#include "serene/reader/location.h" #include "serene/reader/location.h"
#include "serene/reader/reader.h" #include "serene/reader/reader.h"
@ -90,10 +89,8 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name,
MemBufPtr newBufOrErr(findFileInLoadPath(name, importedFile)); MemBufPtr newBufOrErr(findFileInLoadPath(name, importedFile));
if (newBufOrErr == nullptr) { if (newBufOrErr == nullptr) {
auto msg = llvm::formatv("Couldn't find namespace '{0}'", name); auto msg = llvm::formatv("Couldn't find namespace '{0}'", name).str();
auto err = errors::makeErrorTree(importLoc, errors::NSLoadError, return errors::makeError<errors::NSLoadError>(importLoc, msg);
llvm::StringRef(msg));
return MaybeNS::error(err);
} }
auto bufferId = AddNewSourceBuffer(std::move(newBufOrErr), importLoc); auto bufferId = AddNewSourceBuffer(std::move(newBufOrErr), importLoc);
@ -101,10 +98,8 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name,
UNUSED(nsTable.insert_or_assign(name, bufferId)); UNUSED(nsTable.insert_or_assign(name, bufferId));
if (bufferId == 0) { if (bufferId == 0) {
auto msg = llvm::formatv("Couldn't add namespace '{0}'", name); auto msg = llvm::formatv("Couldn't add namespace '{0}'", name).str();
auto err = errors::makeErrorTree(importLoc, errors::NSAddToSMError, return errors::makeError<errors::NSAddToSMError>(importLoc, msg);
llvm::StringRef(msg));
return MaybeNS::error(err);
} }
// Since we moved the buffer to be added as the source storage we // Since we moved the buffer to be added as the source storage we
@ -117,17 +112,16 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name,
if (!maybeAst) { if (!maybeAst) {
SMGR_LOG("Couldn't Read namespace: " + name); SMGR_LOG("Couldn't Read namespace: " + name);
return MaybeNS::error(maybeAst.getError()); return maybeAst.takeError();
} }
// Create the NS and set the AST // Create the NS and set the AST
auto ns = auto ns =
ctx.makeNamespace(name, llvm::Optional(llvm::StringRef(importedFile))); ctx.makeNamespace(name, llvm::Optional(llvm::StringRef(importedFile)));
auto errs = ns->addTree(maybeAst.getValue()); if (auto errs = ns->addTree(*maybeAst)) {
if (errs) {
SMGR_LOG("Couldn't set the AST for namespace: " + name); SMGR_LOG("Couldn't set the AST for namespace: " + name);
return MaybeNS::error(errs.getValue()); return errs;
} }
return ns; return ns;

View File

@ -84,20 +84,20 @@ int main(int argc, char *argv[]) {
auto maybeAst = serene::read(*ctx, line); auto maybeAst = serene::read(*ctx, line);
if (!maybeAst) { if (!maybeAst) {
serene::throwErrors(*ctx, maybeAst.getError()); auto err = maybeAst.takeError();
serene::throwErrors(*ctx, err);
continue; continue;
} }
auto x = serene::eval(*ctx, maybeAst.getValue()); auto x = serene::eval(*ctx, *maybeAst);
if (!x.ok()) { if (!x) {
auto errs = x.getError(); auto err = x.takeError();
for (auto &err : errs) { serene::throwErrors(*ctx, err);
llvm::errs() << err->getMessage() << "\n";
}
continue; continue;
} }
serene::print(*ctx, maybeAst.getValue(), result);
serene::print(*ctx, *maybeAst, result);
llvm::outs() << result << "\n"; llvm::outs() << result << "\n";
// Add text to history // Add text to history

View File

@ -332,11 +332,12 @@ int main(int argc, char *argv[]) {
auto maybeNS = ctx->importNamespace(inputNS, runLoc); auto maybeNS = ctx->importNamespace(inputNS, runLoc);
if (!maybeNS) { if (!maybeNS) {
throwErrors(*ctx, maybeNS.getError()); auto err = maybeNS.takeError();
throwErrors(*ctx, err);
return (int)std::errc::no_such_file_or_directory; return (int)std::errc::no_such_file_or_directory;
} }
auto ns = maybeNS.getValue(); auto ns = *maybeNS;
switch (emitAction) { switch (emitAction) {
case Action::DumpAST: case Action::DumpAST:
@ -360,7 +361,7 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
auto tsm = std::move(maybeModule.getValue()); auto tsm = std::move(*maybeModule);
tsm.withModuleDo([](auto &m) { m.dump(); }); tsm.withModuleDo([](auto &m) { m.dump(); });
break; break;

View File

@ -26,7 +26,8 @@
#include <llvm/TableGen/Error.h> #include <llvm/TableGen/Error.h>
#include <llvm/TableGen/Record.h> #include <llvm/TableGen/Record.h>
#define DEBUG_TYPE "errors-backend" #define DEBUG_TYPE "errors-backend"
#define INSTANCE_SUFFIX "Instance"
namespace serene { namespace serene {
@ -47,9 +48,10 @@ public:
static void inNamespace(llvm::StringRef name, llvm::raw_ostream &os, static void inNamespace(llvm::StringRef name, llvm::raw_ostream &os,
std::function<void(llvm::raw_ostream &)> f) { std::function<void(llvm::raw_ostream &)> f) {
os << "namespace " << name << " {\n\n"; os << "namespace " << name << " {\n\n";
f(os); f(os);
os << "} // namespace " << name << "\n"; os << "}; // namespace " << name << "\n";
}; };
void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec, void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec,
@ -58,36 +60,31 @@ void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec,
const auto recName = defRec.getName(); const auto recName = defRec.getName();
os << "class " << recName << " : public SereneError<" << recName << "> {\n" os << "class " << recName << " : public llvm::ErrorInfo<" << recName << ", "
<< "SereneError> {\n"
<< "public:\n" << "public:\n"
<< " static const int ID = " << id << ";\n"; << " using llvm::ErrorInfo<" << recName << ", "
<< "SereneError>::ErrorInfo;\n"
<< " constexpr static const int ID = " << id << ";\n};\n\n"
<< "static const ErrorVariant " << recName << INSTANCE_SUFFIX
<< " = ErrorVariant::make(\n"
<< " " << id << ",\n"
<< " \"" << recName << "\",\n";
for (const auto &val : defRec.getValues()) { auto desc = defRec.getValueAsString("desc");
auto valName = val.getName();
if (!(valName == "title" || valName == "description")) { if (desc.empty()) {
llvm::PrintWarning("Only 'title' and 'description' are allowed."); llvm::PrintError("'desc' field is empty for " + recName);
llvm::PrintWarning("Record: " + recName); }
continue;
}
auto *stringVal = llvm::dyn_cast<llvm::StringInit>(val.getValue()); os << " \"" << desc << "\",\n";
if (stringVal == nullptr) { auto help = defRec.getValueAsString("help");
llvm::PrintError("The value of " + valName + " is not string.");
llvm::PrintError("Record: " + recName);
continue;
}
if (stringVal->getValue().empty()) { if (!help.empty()) {
llvm::PrintError("The value of " + valName + " is an empty string.");
llvm::PrintError("Record: " + recName);
continue;
}
os << " inline static const std::string " << valName << " = "; const llvm::MemoryBufferRef value(help, "help");
const llvm::MemoryBufferRef value(stringVal->getValue(), valName);
llvm::line_iterator lines(value, false); llvm::line_iterator lines(value, false);
while (!lines.is_at_end()) { while (!lines.is_at_end()) {
if (lines.line_number() != 1) { if (lines.line_number() != 1) {
@ -103,25 +100,63 @@ void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec,
os << '\n'; os << '\n';
} }
} }
} else {
os << " \"\"";
} }
os << "};\n\n";
os << ");\n";
// os << " " << help << ");\n";
// auto *stringVal = llvm::dyn_cast<llvm::StringInit>(val.getValue());
}; };
void ErrorsBackend::createNSBody(llvm::raw_ostream &os) { void ErrorsBackend::createNSBody(llvm::raw_ostream &os) {
int counter = 1; auto *index = records.getGlobal("errorsIndex");
for (const auto &defPair : records.getDefs()) {
llvm::Record &defRec = *defPair.second;
if (!defRec.isSubClassOf("Error")) { if (index == nullptr) {
continue; llvm::PrintError("'errorsIndex' var is missing!");
} return;
createErrorClass(counter, defRec, os);
counter++;
} }
(void)records; auto *indexList = llvm::dyn_cast<llvm::ListInit>(index);
if (indexList == nullptr) {
llvm::PrintError("'errorsIndex' has to be a list!");
return;
}
os << "#ifdef GET_CLASS_DEFS\n";
inNamespace("serene::errors", os, [&](llvm::raw_ostream &os) {
for (size_t i = 0; i < indexList->size(); i++) {
// llvm::Record &defRec = *defPair.second;
llvm::Record *defRec = indexList->getElementAsRecord(i);
if (!defRec->isSubClassOf("Error")) {
continue;
}
createErrorClass(i, *defRec, os);
}
});
os << "#undef GET_CLASS_DEFS\n#endif\n\n";
os << "#ifdef GET_ERRS_ARRAY\n\n";
inNamespace("serene::errors", os, [&](llvm::raw_ostream &os) {
os << "static const std::array<int, ErrorVariant *> "
"variants{\n";
for (size_t i = 0; i < indexList->size(); i++) {
// llvm::Record &defRec = *defPair.second;
llvm::Record *defRec = indexList->getElementAsRecord(i);
if (!defRec->isSubClassOf("Error")) {
continue;
}
os << " &" << defRec->getName() << INSTANCE_SUFFIX << ",\n";
}
});
os << "\n};\n#undef GET_ERRS_ARRAY\n#endif\n";
} }
void ErrorsBackend::run(llvm::raw_ostream &os) { void ErrorsBackend::run(llvm::raw_ostream &os) {
@ -130,9 +165,9 @@ void ErrorsBackend::run(llvm::raw_ostream &os) {
os << "#include \"serene/errors/base.h\"\n\n#include " os << "#include \"serene/errors/base.h\"\n\n#include "
"<llvm/Support/Error.h>\n\n"; "<llvm/Support/Error.h>\n\n";
os << "#ifndef SERENE_ERRORS_ERRORS_H\n#define SERENE_ERRORS_ERRORS_H\n\n";
inNamespace("serene::errors", os, createNSBody(os);
[&](llvm::raw_ostream &os) { createNSBody(os); }); os << "#endif\n";
} }
void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) { void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) {