diff --git a/include/serene/context.h b/include/serene/context.h index 81f1e05..0957966 100644 --- a/include/serene/context.h +++ b/include/serene/context.h @@ -227,7 +227,7 @@ public: // TODO: Fix this by calling to the diag engine if (err) { - llvm::errs() << err.getValue().back()->getMessage() << "\n"; + llvm::errs() << err << "\n"; serene::terminate(*ctx, 1); return nullptr; } diff --git a/include/serene/diagnostics.h b/include/serene/diagnostics.h index 1e4afcb..a28c616 100644 --- a/include/serene/diagnostics.h +++ b/include/serene/diagnostics.h @@ -19,8 +19,7 @@ #ifndef SERENE_DIAGNOSTICS_H #define SERENE_DIAGNOSTICS_H -#include "serene/errors/constants.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/reader/location.h" #include "serene/source_mgr.h" @@ -51,16 +50,15 @@ class Diagnostic { SereneContext &ctx; reader::LocationRange loc; std::string fn; - errors::ErrorVariant *err = nullptr; - Type type = Type::Error; + llvm::Error *err = nullptr; + Type type = Type::Error; std::string message, lineContents; std::string getPrefix(llvm::StringRef prefix = ""); public: - Diagnostic(SereneContext &ctx, reader::LocationRange loc, - errors::ErrorVariant *e, llvm::StringRef msg, - llvm::StringRef fn = "") + Diagnostic(SereneContext &ctx, reader::LocationRange loc, llvm::Error *e, + llvm::StringRef msg, llvm::StringRef fn = "") : ctx(ctx), loc(loc), fn(fn), err(e), message(msg){}; protected: @@ -73,7 +71,7 @@ class DiagnosticEngine { 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 = ""); void print(llvm::raw_ostream &os, Diagnostic &d); @@ -82,11 +80,10 @@ public: DiagnosticEngine(SereneContext &ctx); void enqueueError(llvm::StringRef msg); - void emitSyntaxError(reader::LocationRange loc, errors::ErrorVariant &e, + void emitSyntaxError(reader::LocationRange loc, llvm::Error &e, llvm::StringRef msg = ""); - void emit(const errors::ErrorPtr &err); - void emit(const errors::ErrorTree &errs); + void emit(const llvm::Error &err); /// Throw out an error with the given `msg` and terminate the execution void panic(llvm::StringRef msg); @@ -99,8 +96,8 @@ std::unique_ptr makeDiagnosticEngine(SereneContext &ctx); /// Throw out an error with the given `msg` and terminate the execution. SERENE_EXPORT void panic(SereneContext &ctx, llvm::StringRef msg); -/// Throw the give `ErrorTree` \p errs and terminate the execution. -SERENE_EXPORT void throwErrors(SereneContext &ctx, errors::ErrorTree &errs); +/// Throw the give `llvm::Error` \p errs to the stderr. +SERENE_EXPORT void throwErrors(SereneContext &ctx, llvm::Error &errs); } // namespace serene #endif diff --git a/include/serene/errors.h b/include/serene/errors.h index 5ed9777..ce93741 100644 --- a/include/serene/errors.h +++ b/include/serene/errors.h @@ -19,7 +19,21 @@ #ifndef SERENE_ERRORS_H #define SERENE_ERRORS_H +#include "serene/errors/base.h" #include "serene/errors/errc.h" -#include "serene/errors/error.h" + +#define GET_CLASS_DEFS +#include "serene/errors/errs.h.inc" + +#include + +namespace serene::errors { + +template +llvm::Error makeError(Args &&...args) { + return llvm::make_error(std::forward(args)...); +}; + +} // namespace serene::errors #endif diff --git a/include/serene/errors/base.h b/include/serene/errors/base.h index f7540dc..bf554da 100644 --- a/include/serene/errors/base.h +++ b/include/serene/errors/base.h @@ -24,37 +24,62 @@ #include #include +#include namespace serene::errors { -template -class SereneError : public llvm::ErrorInfo { +struct ErrorVariant { + 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; std::string msg; public: 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 &getTitle() const { return T::title; }; - std::string &getDesc() const { return T::description; }; - std::error_code convertToErrorCode() const { return std::error_code(); }; + + std::error_code convertToErrorCode() const override { + return std::error_code(); + }; SereneError(reader::LocationRange &loc, std::string &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; }; - static const void *classID() { return &T::ID; } + static const void *classID() { return &ID; } bool isA(const void *const id) const override { - // the check with -1 is a shortcut for us to figure - // out whether we're dealing with an Serene error or - // LLVM error - return *(const int *)id == -1 || id == classID() || - llvm::ErrorInfoBase::isA(id); + return id == classID() || llvm::ErrorInfoBase::isA(id); } + + ~SereneError() = default; }; }; // namespace serene::errors diff --git a/include/serene/errors/error.h b/include/serene/errors/error.h deleted file mode 100644 index e17ec75..0000000 --- a/include/serene/errors/error.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2022 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 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 - -#include - -namespace serene::reader { -class LocationRange; -} // namespace serene::reader - -namespace serene::errors { -class Error; - -using ErrorPtr = std::shared_ptr; - -// tree? Yupe, Errors can be stackable which makes a vector of them a tree -using ErrorTree = std::vector; -using OptionalErrors = llvm::Optional; - -/// 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 { - 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 diff --git a/include/serene/errors/errors.td b/include/serene/errors/errors.td index 979d762..71b64d7 100644 --- a/include/serene/errors/errors.td +++ b/include/serene/errors/errors.td @@ -1,23 +1,76 @@ -class Error { - string title = _title; - string description = _desc; + +class Error { + string desc = _desc; + string help = _help; } -def Err : Error<"Err1 titel"> { - let description = [{ -err1 -multiline -desc}]; -} +// Examples of how to define a new error +// def Err : Error<"Err1 titel"> { +// let description = [{ +// err1 +// multiline +// desc}]; +// } -def Err2 : Error { - let title = "err 2 titel"; - let description = "err2 desc"; -} +// def Err2 : Error { +// let title = "err 2 titel"; +// let description = "err2 desc"; +// } -def Err3 : Error<"err3", [{ -err3 -multiline -desc -}]>; +// def Err3 : Error<"err3", [{ +// err3 +// multiline +// 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, +]; diff --git a/include/serene/exprs/call.h b/include/serene/exprs/call.h index 8ae2206..b8d0a86 100644 --- a/include/serene/exprs/call.h +++ b/include/serene/exprs/call.h @@ -20,7 +20,7 @@ #define SERENE_EXPRS_CALL_H #include "serene/context.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/expression.h" #include "serene/exprs/list.h" diff --git a/include/serene/exprs/def.h b/include/serene/exprs/def.h index e4c0f27..834badb 100644 --- a/include/serene/exprs/def.h +++ b/include/serene/exprs/def.h @@ -20,7 +20,7 @@ #define SERENE_EXPRS_DEF_H #include "serene/context.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/expression.h" #include diff --git a/include/serene/exprs/expression.h b/include/serene/exprs/expression.h index 0f1c228..3a1ee0e 100644 --- a/include/serene/exprs/expression.h +++ b/include/serene/exprs/expression.h @@ -20,13 +20,14 @@ #define SERENE_EXPRS_EXPRESSION_H #include "serene/context.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/traits.h" #include "serene/namespace.h" #include "serene/reader/location.h" #include "serene/semantics.h" #include "serene/utils.h" +#include #include #include @@ -40,12 +41,12 @@ namespace exprs { class Expression; using Node = std::shared_ptr; -using MaybeNode = Result; +using MaybeNode = llvm::Expected; using Ast = std::vector; -using MaybeAst = Result; +using MaybeAst = llvm::Expected; -static auto EmptyNode = MaybeNode::success(nullptr); +static auto EmptyNode = nullptr; /// The base class of the expressions which provides the common interface for /// the expressions to implement. @@ -111,34 +112,25 @@ std::shared_ptr makeAndCast(Args &&...args) { return std::make_shared(std::forward(args)...); }; -/// The helper function to create a new `Node` and use that as the success case -// of a `Result`. It should be useds where every we want to return a `MaybeNode` -/// successfully +/// The helper function to create a new `Node` and returnsit. It should be useds +/// where every we want to return a `MaybeNode` successfully. template -Result makeSuccessfulNode(Args &&...args) { - return Result::success( - make(std::forward(args)...)); +MaybeNode makeSuccessfulNode(Args &&...args) { + return make(std::forward(args)...); }; -/// The hlper function to create an Errorful `Result` (`T` would be -/// either `Node` or `Ast` most of the time) with just one error created from -/// passing any argument to this function to the `serene::errors::Error` -/// constructor. -template -Result makeErrorful(Args &&...args) { - std::vector v{ - std::move(makeAndCast(std::forward(args)...))}; - return Result::error(v); +/// The hlper function to creates an Error (`llvm::Error`) by passing all +/// the given arguments to the constructor of the template param `E`. +template +llvm::Expected makeErrorful(Args &&...args) { + return llvm::make_error(std::forward(args)...); }; -/// The hlper function to create an Error node (The failure case of a MaybeNod) -/// with just one error created from passing any argument to this function to -/// the `serene::errors::Error` constructor. -template +/// The hlper function to creates an Error (`llvm::Error`) by passing all +/// the given arguments to the constructor of the template param `E`. +template MaybeNode makeErrorNode(Args &&...args) { - std::vector v{ - std::move(makeAndCast(std::forward(args)...))}; - return MaybeNode::error(v); + return makeErrorful(std::forward(args)...); }; /// Convert the given AST to string by calling the `toString` method diff --git a/include/serene/exprs/fn.h b/include/serene/exprs/fn.h index b37b48b..79c7c2a 100644 --- a/include/serene/exprs/fn.h +++ b/include/serene/exprs/fn.h @@ -20,7 +20,7 @@ #define SERENE_EXPRS_FN_H #include "serene/context.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/expression.h" #include "serene/exprs/list.h" #include "serene/namespace.h" diff --git a/include/serene/jit/halley.h b/include/serene/jit/halley.h index e7f0237..f218c17 100644 --- a/include/serene/jit/halley.h +++ b/include/serene/jit/halley.h @@ -25,7 +25,6 @@ #define SERENE_JIT_HALLEY_H #include "serene/errors.h" -#include "serene/errors/error.h" #include "serene/export.h" #include "serene/namespace.h" #include "serene/utils.h" @@ -58,7 +57,7 @@ namespace jit { class Halley; using MaybeJIT = llvm::Expected>; -using MaybeJITPtr = serene::Result; +using MaybeJITPtr = llvm::Expected; /// A simple object cache following Lang's LLJITWithObjectCache example and /// MLIR's SimpelObjectCache. class ObjectCache : public llvm::ObjectCache { @@ -179,10 +178,9 @@ public: llvm::function_ref symbolMap); - llvm::Optional addNS(Namespace &ns, - reader::LocationRange &loc); + llvm::Error addNS(Namespace &ns, reader::LocationRange &loc); - llvm::Optional addAST(exprs::Ast &ast); + llvm::Error addAST(exprs::Ast &ast); Namespace &getActiveNS(); }; diff --git a/include/serene/namespace.h b/include/serene/namespace.h index 59a727d..19be767 100644 --- a/include/serene/namespace.h +++ b/include/serene/namespace.h @@ -34,7 +34,7 @@ #define SERENE_NAMESPACE_H #include "serene/environment.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/export.h" #include "serene/slir/generatable.h" #include "serene/traits.h" @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -72,7 +73,7 @@ using Ast = std::vector; } // namespace exprs using NSPtr = std::shared_ptr; -using MaybeNS = Result; +using MaybeNS = llvm::Expected; using MaybeModule = llvm::Optional; using MaybeModuleOp = llvm::Optional>; using SemanticEnv = Environment; @@ -137,7 +138,7 @@ public: /// many elements. /// /// 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(); const std::vector &getSymList() { return symbolList; }; diff --git a/include/serene/semantics.h b/include/serene/semantics.h index b4b0570..70c47c2 100644 --- a/include/serene/semantics.h +++ b/include/serene/semantics.h @@ -20,7 +20,7 @@ #define SERENE_SEMANTICS_H #include "serene/environment.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/utils.h" #include @@ -39,7 +39,7 @@ class Namespace; using SemanticEnv = Environment; namespace semantics { -using AnalyzeResult = Result>; +using AnalyzeResult = llvm::Expected; /// This struct represent the state necessary for each analysis job. struct AnalysisState { @@ -62,10 +62,9 @@ std::unique_ptr makeAnalysisState(Args &&...args) { /// 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 /// 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 -/// `success` result (Checkout the `Result` type in `utils.h`) then the -/// original node will be used instead. Any possible error will return as -/// the `error` case of the `Result` type. +/// AST. If the `analyze` method of a node return a `nullptr` value then the +/// original node will be used instead. Any possible error will be returned. +/// /// \param state The semantic analysis state that keep track of the envs. /// \param form The actual AST in question. AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms); diff --git a/src/libserene/CMakeLists.txt b/src/libserene/CMakeLists.txt index 8dc20cf..b818103 100644 --- a/src/libserene/CMakeLists.txt +++ b/src/libserene/CMakeLists.txt @@ -50,13 +50,11 @@ add_library(serene jit/layers.cpp jit/halley.cpp + errors.cpp # Reader reader/reader.cpp - # Errors - errors/error.cpp - # IR slir/slir.cpp slir/dialect.cpp diff --git a/src/libserene/context.cpp b/src/libserene/context.cpp index 26aa667..7df64b9 100644 --- a/src/libserene/context.cpp +++ b/src/libserene/context.cpp @@ -126,11 +126,11 @@ MaybeNS SereneContext::importNamespace(const std::string &name, auto maybeNS = readNamespace(name, loc); if (maybeNS) { - auto &ns = maybeNS.getValue(); - auto err = jit->addNS(*ns, loc); - if (err) { - return MaybeNS::error(err.getValue()); + auto &ns = *maybeNS; + if (auto err = jit->addNS(*ns, loc)) { + return err; } + insertNS(ns); } diff --git a/src/libserene/diagnostics.cpp b/src/libserene/diagnostics.cpp index d3fc629..fd13cbb 100644 --- a/src/libserene/diagnostics.cpp +++ b/src/libserene/diagnostics.cpp @@ -24,6 +24,7 @@ #include "serene/utils.h" #include +#include #include #include #include @@ -158,8 +159,7 @@ void DiagnosticEngine::print(llvm::raw_ostream &os, Diagnostic &d) { }; Diagnostic DiagnosticEngine::toDiagnostic(reader::LocationRange loc, - errors::ErrorVariant &e, - llvm::StringRef msg, + llvm::Error &e, llvm::StringRef msg, llvm::StringRef fn) { return Diagnostic(ctx, loc, &e, msg, fn); @@ -171,8 +171,7 @@ void DiagnosticEngine::enqueueError(llvm::StringRef msg) { }; void DiagnosticEngine::emitSyntaxError(reader::LocationRange loc, - errors::ErrorVariant &e, - llvm::StringRef msg) { + llvm::Error &e, llvm::StringRef msg) { Diagnostic diag(ctx, loc, &e, msg); diag.print(llvm::errs(), "SyntaxError"); @@ -203,23 +202,27 @@ std::unique_ptr makeDiagnosticEngine(SereneContext &ctx) { return std::make_unique(ctx); } -void DiagnosticEngine::emit(const errors::ErrorPtr &err) { +void DiagnosticEngine::emit(const llvm::Error &err) { UNUSED(ctx); // TODO: create a diag and print it - llvm::errs() << err->toString() << "\n"; + llvm::errs() << err << "\n"; }; -void DiagnosticEngine::emit(const errors::ErrorTree &errs) { - for (const auto &e : errs) { - emit(e); - } -}; +// void DiagnosticEngine::emit(const llvm::Error &errs) { +// +// // for (const auto &e : errs) { +// // emit(e); +// // } +// +// }; void panic(SereneContext &ctx, llvm::StringRef 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); }; diff --git a/include/serene/errors/traits.h b/src/libserene/errors.cpp similarity index 63% rename from include/serene/errors/traits.h rename to src/libserene/errors.cpp index db033a7..7bfb922 100644 --- a/include/serene/errors/traits.h +++ b/src/libserene/errors.cpp @@ -16,22 +16,7 @@ * along with this program. If not, see . */ -#ifndef SERENE_ERRORS_TRAITS_H -#define SERENE_ERRORS_TRAITS_H +#include "serene/errors.h" -#include "serene/errors/constants.h" -#include "serene/traits.h" - -namespace serene::errors { -template -class IError : public TraitBase { -public: - IError(){}; - IError(const IError &) = delete; - - ErrorVariant *getVariant(); - std::string getMessage(); -}; - -} // namespace serene::errors -#endif +#define GET_ERRS_ARRAY +#include "serene/errors/errs.h.inc" diff --git a/src/libserene/errors/error.cpp b/src/libserene/errors/error.cpp deleted file mode 100644 index be72387..0000000 --- a/src/libserene/errors/error.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2022 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 "serene/errors/error.h" - -#include - -#include - -namespace serene { -namespace errors { - -std::string Error::toString() const { - return llvm::formatv("", 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(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 diff --git a/src/libserene/exprs/call.cpp b/src/libserene/exprs/call.cpp index 7ff181b..1d25b1f 100644 --- a/src/libserene/exprs/call.cpp +++ b/src/libserene/exprs/call.cpp @@ -18,7 +18,7 @@ #include "serene/exprs/call.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/def.h" #include "serene/exprs/expression.h" #include "serene/exprs/list.h" @@ -63,7 +63,7 @@ MaybeNode Call::make(semantics::AnalysisState &state, List *list) { return maybeFirst; } - Node first = maybeFirst.getValue(); + Node &first = *maybeFirst; // No rewrite is needed for the first element if (!first) { @@ -97,7 +97,7 @@ MaybeNode Call::make(semantics::AnalysisState &state, List *list) { if (!maybeResult.hasValue()) { std::string msg = llvm::formatv("Can't resolve the symbol '{0}'", sym->name); - return makeErrorful(sym->location, errors::CantResolveSymbol, msg); + return errors::makeError(sym->location, msg); } targetNode = std::move(maybeResult.getValue()); @@ -122,19 +122,18 @@ MaybeNode Call::make(semantics::AnalysisState &state, List *list) { default: { std::string msg = llvm::formatv("Don't know how to call a '{0}'", stringifyExprType(first->getType())); - return makeErrorful(first->location, errors::DontKnowHowToCallNode, - msg); + return errors::makeError(first->location, + msg); } }; auto analyzedParams = semantics::analyze(state, rawParams); if (!analyzedParams) { - return MaybeNode::error(analyzedParams.getError()); + return analyzedParams.takeError(); } - return makeSuccessfulNode(list->location, targetNode, - analyzedParams.getValue()); + return makeSuccessfulNode(list->location, targetNode, *analyzedParams); }; } // namespace exprs } // namespace serene diff --git a/src/libserene/exprs/def.cpp b/src/libserene/exprs/def.cpp index 4c3d3be..2cdb46e 100644 --- a/src/libserene/exprs/def.cpp +++ b/src/libserene/exprs/def.cpp @@ -18,7 +18,7 @@ #include "serene/exprs/def.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/expression.h" #include "serene/exprs/fn.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) if (list->count() != 3) { std::string msg = llvm::formatv("Expected 3 got {0}", list->count()); - return makeErrorful(list->elements[0]->location, - errors::DefWrongNumberOfArgs, msg); + return errors::makeError( + list->elements[0]->location, msg); } // 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 Symbol *binding = llvm::dyn_cast(list->elements[1].get()); if (binding == nullptr) { - return makeErrorful(list->elements[1]->location, - errors::DefExpectSymbol, ""); + return errors::makeError( + list->elements[1]->location); } // Analyze the value @@ -79,7 +79,7 @@ MaybeNode Def::make(semantics::AnalysisState &state, List *list) { // TODO: To refactor this logic into a generic function if (value) { // Success value - auto &valueNode = value.getValue(); + auto &valueNode = *value; if (valueNode) { // A rewrite is necessary diff --git a/src/libserene/exprs/fn.cpp b/src/libserene/exprs/fn.cpp index 4d6327f..755e3be 100644 --- a/src/libserene/exprs/fn.cpp +++ b/src/libserene/exprs/fn.cpp @@ -18,7 +18,7 @@ #include "serene/exprs/fn.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/expression.h" #include "serene/exprs/list.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) if (list->count() < 2) { - return makeErrorful(list->elements[0]->location, errors::FnNoArgsList, - "The argument list is mandatory."); + return errors::makeError( + list->elements[0]->location, "The argument list is mandatory."); } Symbol *fnSym = llvm::dyn_cast(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}'", stringifyExprType(list->elements[1]->getType())); - return makeErrorful(list->elements[1]->location, - errors::FnArgsMustBeList, msg); + return errors::makeError( + list->elements[1]->location, msg); } Ast body; @@ -100,10 +100,10 @@ MaybeNode Fn::make(semantics::AnalysisState &state, List *list) { auto maybeAst = semantics::analyze(state, body); if (!maybeAst) { - return MaybeNode::error(std::move(maybeAst.getError())); + return maybeAst.takeError(); } - body = maybeAst.getValue(); + body = *maybeAst; } return makeSuccessfulNode(ctx, list->location, *args, body); diff --git a/src/libserene/exprs/list.cpp b/src/libserene/exprs/list.cpp index 7e2d930..4da09c6 100644 --- a/src/libserene/exprs/list.cpp +++ b/src/libserene/exprs/list.cpp @@ -18,7 +18,7 @@ #include "serene/exprs/list.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/call.h" #include "serene/exprs/def.h" #include "serene/exprs/expression.h" diff --git a/src/libserene/jit/halley.cpp b/src/libserene/jit/halley.cpp index b2c3bc6..00d8bee 100644 --- a/src/libserene/jit/halley.cpp +++ b/src/libserene/jit/halley.cpp @@ -29,8 +29,7 @@ #include "serene/context.h" #include "serene/diagnostics.h" -#include "serene/errors/constants.h" -#include "serene/errors/error.h" +#include "serene/errors.h" #include "serene/exprs/symbol.h" #include "serene/namespace.h" #include "serene/utils.h" @@ -202,18 +201,16 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { auto *ns = ctx.getNS(sym.nsName); if (ns == nullptr) { - return MaybeJITPtr::error(errors::makeErrorTree( - sym.location, errors::CantResolveSymbol, - "Can't find the namespace in the context: " + sym.nsName)); + return errors::makeError( + sym.location, "Can't find the namespace in the context: " + sym.nsName); } auto *dylib = ctx.getLatestJITDylib(*ns); // if (dylib == nullptr) { - return MaybeJITPtr::error( - errors::makeErrorTree(sym.location, errors::CantResolveSymbol, - "Don't know about namespace: " + sym.nsName)); + return errors::makeError( + sym.location, "Don't know about namespace: " + sym.nsName); } auto expectedSymbol = @@ -230,8 +227,7 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { llvm::raw_string_ostream os(errorMessage); llvm::handleAllErrors(expectedSymbol.takeError(), [&os](llvm::ErrorInfoBase &ei) { ei.log(os); }); - return MaybeJITPtr::error(errors::makeErrorTree( - sym.location, errors::CantResolveSymbol, os.str())); + return errors::makeError(sym.location, os.str()); } auto rawFPtr = expectedSymbol->getAddress(); @@ -239,8 +235,8 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { auto fptr = reinterpret_cast(rawFPtr); if (fptr == nullptr) { - return MaybeJITPtr::error(errors::makeErrorTree( - sym.location, errors::CantResolveSymbol, "Lookup function is null!")); + return errors::makeError( + sym.location, "Lookup function is null!"); } return fptr; @@ -281,8 +277,7 @@ void Halley::registerSymbols( mainJitDylib.getExecutionSession(), engine->getDataLayout()))))); }; -llvm::Optional Halley::addNS(Namespace &ns, - reader::LocationRange &loc) { +llvm::Error Halley::addNS(Namespace &ns, reader::LocationRange &loc) { HALLEY_LOG(llvm::formatv("Creating Dylib {0}#{1}", ns.name, ctx.getNumberOfJITDylibs(ns) + 1)); @@ -291,8 +286,8 @@ llvm::Optional Halley::addNS(Namespace &ns, llvm::formatv("{0}#{1}", ns.name, ctx.getNumberOfJITDylibs(ns) + 1)); if (!newDylib) { - return errors::makeErrorTree(loc, errors::CompilationError, - "Filed to create dylib for " + ns.name); + return errors::makeError( + loc, "Filed to create dylib for " + ns.name); } ctx.pushJITDylib(ns, &(*newDylib)); @@ -301,7 +296,7 @@ llvm::Optional Halley::addNS(Namespace &ns, auto maybeModule = ns.compileToLLVM(); if (!maybeModule.hasValue()) { - return errors::makeErrorTree(loc, errors::CompilationError); + return errors::makeError(loc); } auto tsm = std::move(maybeModule.getValue()); @@ -310,7 +305,7 @@ llvm::Optional Halley::addNS(Namespace &ns, // TODO: Make sure that the data layout of the module is the same as the // engine cantFail(engine->addIRModule(*newDylib, std::move(tsm))); - return llvm::None; + return llvm::Error::success(); }; void Halley::setEngine(std::unique_ptr e, bool isLazy) { @@ -462,12 +457,11 @@ MaybeJIT Halley::make(SereneContext &serene_ctx, return MaybeJIT(std::move(jitEngine)); }; -llvm::Optional Halley::addAST(exprs::Ast &ast) { +llvm::Error Halley::addAST(exprs::Ast &ast) { auto offset = activeNS->getTree().size(); - auto errs = activeNS->addTree(ast); - if (errs) { - return errs.getValue(); + if (auto errs = activeNS->addTree(ast)) { + return errs; } auto maybeModule = activeNS->compileToLLVMFromOffset(offset); @@ -479,7 +473,7 @@ llvm::Optional Halley::addAST(exprs::Ast &ast) { // TODO: Make sure that the data layout of the module is the same as the // engine cantFail(engine->addIRModule(*dylib, std::move(tsm))); - return llvm::None; + return llvm::Error::success(); }; Namespace &Halley::getActiveNS() { return *activeNS; }; diff --git a/src/libserene/jit/layers.cpp b/src/libserene/jit/layers.cpp index dbbbff6..55fc2ae 100644 --- a/src/libserene/jit/layers.cpp +++ b/src/libserene/jit/layers.cpp @@ -127,13 +127,11 @@ llvm::Error NSLayer::add(orc::ResourceTrackerSP &rt, llvm::StringRef nsname, if (!maybeNS) { // TODO: Fix this by making Serene errors compatible with llvm::Error - auto err = maybeNS.getError(); - return llvm::make_error( - llvm::Twine(err.front()->getMessage()), - std::make_error_code(std::errc::io_error)); + auto err = maybeNS.takeError(); + return err; } - auto ns = maybeNS.getValue(); + auto ns = *maybeNS; LAYER_LOG("Add the materialize unit for: " + nsname); return rt->getJITDylib().define( diff --git a/src/libserene/namespace.cpp b/src/libserene/namespace.cpp index 658d6c4..03aa744 100644 --- a/src/libserene/namespace.cpp +++ b/src/libserene/namespace.cpp @@ -25,7 +25,6 @@ #include "serene/namespace.h" #include "serene/context.h" -#include "serene/errors/constants.h" #include "serene/exprs/expression.h" #include "serene/llvm/IR/Value.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; } -errors::OptionalErrors Namespace::addTree(exprs::Ast &ast) { +llvm::Error Namespace::addTree(exprs::Ast &ast) { // TODO: Remove the parse phase if (ctx.getTargetPhase() == CompilationPhase::Parse) { // we just want the raw AST this->tree.insert(this->tree.end(), ast.begin(), ast.end()); - return llvm::None; + return llvm::Error::success(); } auto &rootEnv = getRootEnv(); @@ -106,13 +105,13 @@ errors::OptionalErrors Namespace::addTree(exprs::Ast &ast) { auto maybeForm = semantics::analyze(*state, ast); 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()); - return llvm::None; + return llvm::Error::success(); } uint Namespace::nextFnCounter() { return fn_counter++; }; diff --git a/src/libserene/reader/reader.cpp b/src/libserene/reader/reader.cpp index 1745ad1..56333a6 100644 --- a/src/libserene/reader/reader.cpp +++ b/src/libserene/reader/reader.cpp @@ -18,7 +18,7 @@ #include "serene/reader/reader.h" -#include "serene/errors/constants.h" +#include "serene/errors.h" #include "serene/exprs/expression.h" #include "serene/exprs/list.h" #include "serene/exprs/number.h" @@ -225,7 +225,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) { LocationRange loc(getCurrentLocation()); if (isdigit(*c) == 0) { - return exprs::makeErrorNode(loc, errors::InvalidDigitForNumber); + return errors::makeError(loc); } for (;;) { @@ -236,8 +236,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) { if ((isdigit(*c) != 0) || *c == '.') { if (*c == '.' && floatNum) { loc = LocationRange(getCurrentLocation()); - ctx.diagEngine->emitSyntaxError(loc, errors::TwoFloatPoints); - terminate(ctx, 1); + return errors::makeError(loc); } if (*c == '.') { @@ -253,8 +252,7 @@ exprs::MaybeNode Reader::readNumber(bool neg) { if (((std::isalpha(*c) != 0) && !empty) || empty) { advance(); loc.start = getCurrentLocation(); - ctx.diagEngine->emitSyntaxError(loc, errors::InvalidDigitForNumber); - terminate(ctx, 1); + return errors::makeError(loc); } loc.end = getCurrentLocation(); @@ -278,7 +276,7 @@ exprs::MaybeNode Reader::readSymbol() { msg = "An extra ')' is detected."; } - return exprs::makeErrorNode(loc, errors::InvalidCharacterForSymbol, msg); + return errors::makeError(loc, msg); } if (*c == '-') { @@ -338,7 +336,7 @@ exprs::MaybeNode Reader::readList() { advance(true); advance(); list->location.end = getCurrentLocation(); - return exprs::makeErrorNode(list->location, errors::EOFWhileScaningAList); + return errors::makeError(list->location); } switch (*c) { @@ -356,12 +354,12 @@ exprs::MaybeNode Reader::readList() { return expr; } - list->append(expr.getValue()); + list->append(*expr); } } while (!list_terminated); - return exprs::MaybeNode::success(list); + return list; }; /// Reads an expression by dispatching to the proper reader function. @@ -403,18 +401,18 @@ exprs::MaybeAst Reader::read() { auto tmp = readExpr(); if (tmp) { - if (tmp.getValue() == nullptr) { + if (*tmp == nullptr) { break; } - this->ast.push_back(move(tmp.getValue())); + this->ast.push_back(move(*tmp)); } 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, diff --git a/src/libserene/semantics.cpp b/src/libserene/semantics.cpp index 3838810..b39a455 100644 --- a/src/libserene/semantics.cpp +++ b/src/libserene/semantics.cpp @@ -22,6 +22,8 @@ #include "serene/exprs/expression.h" #include "serene/namespace.h" +#include + namespace serene::semantics { std::unique_ptr AnalysisState::moveToNewEnv() { @@ -30,7 +32,7 @@ std::unique_ptr AnalysisState::moveToNewEnv() { }; AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) { - errors::ErrorTree errors; + llvm::Error errors = llvm::Error::success(); exprs::Ast ast; for (auto &element : forms) { @@ -38,7 +40,7 @@ AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) { // Is it a `success` result if (maybeNode) { - auto &node = maybeNode.getValue(); + auto &node = *maybeNode; if (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 // is llvm related and has to be raised later // (std::move()); - auto errVector = maybeNode.getError(); - errors.insert(errors.end(), errVector.begin(), errVector.end()); + auto err = maybeNode.takeError(); + errors = llvm::joinErrors(std::move(errors), std::move(err)); } } - if (errors.empty()) { - return AnalyzeResult::success(std::move(ast)); + // If the errors (which is an ErrorList) contains error and is + // not succssful + if (!errors) { + return std::move(ast); } - return AnalyzeResult::error(std::move(errors)); + return std::move(errors); }; }; // namespace serene::semantics diff --git a/src/libserene/serene.cpp b/src/libserene/serene.cpp index be977c2..935ebb3 100644 --- a/src/libserene/serene.cpp +++ b/src/libserene/serene.cpp @@ -25,7 +25,6 @@ #include "serene/serene.h" #include "serene/diagnostics.h" -#include "serene/errors/constants.h" #include "serene/exprs/expression.h" // TODO: Remove it @@ -122,7 +121,7 @@ SERENE_EXPORT exprs::MaybeNode eval(SereneContext &ctx, exprs::Ast &input) { auto errs = ctx.jit->addAST(input); if (errs) { - return exprs::MaybeNode::error(errs.getValue()); + return errs; } // auto e = input[0]; diff --git a/src/libserene/source_mgr.cpp b/src/libserene/source_mgr.cpp index d76042e..30af058 100644 --- a/src/libserene/source_mgr.cpp +++ b/src/libserene/source_mgr.cpp @@ -24,7 +24,6 @@ #include "serene/source_mgr.h" -#include "serene/errors/constants.h" #include "serene/namespace.h" #include "serene/reader/location.h" #include "serene/reader/reader.h" @@ -90,10 +89,8 @@ MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, MemBufPtr newBufOrErr(findFileInLoadPath(name, importedFile)); if (newBufOrErr == nullptr) { - auto msg = llvm::formatv("Couldn't find namespace '{0}'", name); - auto err = errors::makeErrorTree(importLoc, errors::NSLoadError, - llvm::StringRef(msg)); - return MaybeNS::error(err); + auto msg = llvm::formatv("Couldn't find namespace '{0}'", name).str(); + return errors::makeError(importLoc, msg); } 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)); if (bufferId == 0) { - auto msg = llvm::formatv("Couldn't add namespace '{0}'", name); - auto err = errors::makeErrorTree(importLoc, errors::NSAddToSMError, - llvm::StringRef(msg)); - return MaybeNS::error(err); + auto msg = llvm::formatv("Couldn't add namespace '{0}'", name).str(); + return errors::makeError(importLoc, msg); } // 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) { SMGR_LOG("Couldn't Read namespace: " + name); - return MaybeNS::error(maybeAst.getError()); + return maybeAst.takeError(); } // Create the NS and set the AST auto ns = ctx.makeNamespace(name, llvm::Optional(llvm::StringRef(importedFile))); - auto errs = ns->addTree(maybeAst.getValue()); - if (errs) { + if (auto errs = ns->addTree(*maybeAst)) { SMGR_LOG("Couldn't set the AST for namespace: " + name); - return MaybeNS::error(errs.getValue()); + return errs; } return ns; diff --git a/src/serene-repl/serene-repl.cpp b/src/serene-repl/serene-repl.cpp index 4f144f8..7eab758 100644 --- a/src/serene-repl/serene-repl.cpp +++ b/src/serene-repl/serene-repl.cpp @@ -84,20 +84,20 @@ int main(int argc, char *argv[]) { auto maybeAst = serene::read(*ctx, line); if (!maybeAst) { - serene::throwErrors(*ctx, maybeAst.getError()); + auto err = maybeAst.takeError(); + serene::throwErrors(*ctx, err); continue; } - auto x = serene::eval(*ctx, maybeAst.getValue()); + auto x = serene::eval(*ctx, *maybeAst); - if (!x.ok()) { - auto errs = x.getError(); - for (auto &err : errs) { - llvm::errs() << err->getMessage() << "\n"; - } + if (!x) { + auto err = x.takeError(); + serene::throwErrors(*ctx, err); continue; } - serene::print(*ctx, maybeAst.getValue(), result); + + serene::print(*ctx, *maybeAst, result); llvm::outs() << result << "\n"; // Add text to history diff --git a/src/serenec/serenec.cpp b/src/serenec/serenec.cpp index 930e24b..f86a39f 100644 --- a/src/serenec/serenec.cpp +++ b/src/serenec/serenec.cpp @@ -332,11 +332,12 @@ int main(int argc, char *argv[]) { auto maybeNS = ctx->importNamespace(inputNS, runLoc); if (!maybeNS) { - throwErrors(*ctx, maybeNS.getError()); + auto err = maybeNS.takeError(); + throwErrors(*ctx, err); return (int)std::errc::no_such_file_or_directory; } - auto ns = maybeNS.getValue(); + auto ns = *maybeNS; switch (emitAction) { case Action::DumpAST: @@ -360,7 +361,7 @@ int main(int argc, char *argv[]) { return 1; } - auto tsm = std::move(maybeModule.getValue()); + auto tsm = std::move(*maybeModule); tsm.withModuleDo([](auto &m) { m.dump(); }); break; diff --git a/tools/tbl-srn/serene/errors-backend.cpp b/tools/tbl-srn/serene/errors-backend.cpp index b88de7f..e67485d 100644 --- a/tools/tbl-srn/serene/errors-backend.cpp +++ b/tools/tbl-srn/serene/errors-backend.cpp @@ -26,7 +26,8 @@ #include #include -#define DEBUG_TYPE "errors-backend" +#define DEBUG_TYPE "errors-backend" +#define INSTANCE_SUFFIX "Instance" namespace serene { @@ -47,9 +48,10 @@ public: static void inNamespace(llvm::StringRef name, llvm::raw_ostream &os, std::function f) { + os << "namespace " << name << " {\n\n"; f(os); - os << "} // namespace " << name << "\n"; + os << "}; // namespace " << name << "\n"; }; 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(); - os << "class " << recName << " : public SereneError<" << recName << "> {\n" + os << "class " << recName << " : public llvm::ErrorInfo<" << recName << ", " + << "SereneError> {\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 valName = val.getName(); + auto desc = defRec.getValueAsString("desc"); - if (!(valName == "title" || valName == "description")) { - llvm::PrintWarning("Only 'title' and 'description' are allowed."); - llvm::PrintWarning("Record: " + recName); - continue; - } + if (desc.empty()) { + llvm::PrintError("'desc' field is empty for " + recName); + } - auto *stringVal = llvm::dyn_cast(val.getValue()); + os << " \"" << desc << "\",\n"; - if (stringVal == nullptr) { - llvm::PrintError("The value of " + valName + " is not string."); - llvm::PrintError("Record: " + recName); - continue; - } + auto help = defRec.getValueAsString("help"); - if (stringVal->getValue().empty()) { - llvm::PrintError("The value of " + valName + " is an empty string."); - llvm::PrintError("Record: " + recName); - continue; - } + if (!help.empty()) { - 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); while (!lines.is_at_end()) { if (lines.line_number() != 1) { @@ -103,25 +100,63 @@ void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec, os << '\n'; } } + } else { + os << " \"\""; } - os << "};\n\n"; + + os << ");\n"; + // os << " " << help << ");\n"; + // auto *stringVal = llvm::dyn_cast(val.getValue()); }; void ErrorsBackend::createNSBody(llvm::raw_ostream &os) { - int counter = 1; - for (const auto &defPair : records.getDefs()) { - llvm::Record &defRec = *defPair.second; + auto *index = records.getGlobal("errorsIndex"); - if (!defRec.isSubClassOf("Error")) { - continue; - } - - createErrorClass(counter, defRec, os); - - counter++; + if (index == nullptr) { + llvm::PrintError("'errorsIndex' var is missing!"); + return; } - (void)records; + auto *indexList = llvm::dyn_cast(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 " + "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) { @@ -130,9 +165,9 @@ void ErrorsBackend::run(llvm::raw_ostream &os) { os << "#include \"serene/errors/base.h\"\n\n#include " "\n\n"; - - inNamespace("serene::errors", os, - [&](llvm::raw_ostream &os) { createNSBody(os); }); + os << "#ifndef SERENE_ERRORS_ERRORS_H\n#define SERENE_ERRORS_ERRORS_H\n\n"; + createNSBody(os); + os << "#endif\n"; } void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) {