Finish up the errors-backend and migrate serene's errs to llvm:
This commit is contained in:
parent
95e9edf61e
commit
64ee59fbc8
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<DiagnosticEngine> 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
|
||||
|
|
|
@ -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 <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
|
||||
|
|
|
@ -24,37 +24,62 @@
|
|||
#include <system_error>
|
||||
|
||||
#include <llvm/Support/Error.h>
|
||||
#include <llvm/Support/FormatVariadic.h>
|
||||
|
||||
namespace serene::errors {
|
||||
|
||||
template <typename T>
|
||||
class SereneError : public llvm::ErrorInfo<T> {
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -1,23 +1,76 @@
|
|||
|
||||
class Error<string _title = "", string _desc = ""> {
|
||||
string title = _title;
|
||||
string description = _desc;
|
||||
|
||||
class Error<string _desc = "", string _help = ""> {
|
||||
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,
|
||||
];
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 <llvm/ADT/StringRef.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 <llvm/Support/Error.h>
|
||||
#include <mlir/IR/BuiltinOps.h>
|
||||
|
||||
#include <memory>
|
||||
|
@ -40,12 +41,12 @@ namespace exprs {
|
|||
class Expression;
|
||||
|
||||
using Node = std::shared_ptr<Expression>;
|
||||
using MaybeNode = Result<Node, errors::ErrorTree>;
|
||||
using MaybeNode = llvm::Expected<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 expressions to implement.
|
||||
|
@ -111,34 +112,25 @@ std::shared_ptr<T> makeAndCast(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
|
||||
// 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 <typename T, typename... Args>
|
||||
Result<Node, errors::ErrorTree> makeSuccessfulNode(Args &&...args) {
|
||||
return Result<Node, errors::ErrorTree>::success(
|
||||
make<T>(std::forward<Args>(args)...));
|
||||
MaybeNode makeSuccessfulNode(Args &&...args) {
|
||||
return make<T>(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
/// The hlper function to create an Errorful `Result<T,...>` (`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 <typename T, typename... 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 creates an Error (`llvm::Error`) by passing all
|
||||
/// the given arguments to the constructor of the template param `E`.
|
||||
template <typename E, typename T = Node, typename... Args>
|
||||
llvm::Expected<T> makeErrorful(Args &&...args) {
|
||||
return llvm::make_error<E>(std::forward<Args>(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 <typename... Args>
|
||||
/// The hlper function to creates an Error (`llvm::Error`) by passing all
|
||||
/// the given arguments to the constructor of the template param `E`.
|
||||
template <typename E, typename... Args>
|
||||
MaybeNode makeErrorNode(Args &&...args) {
|
||||
std::vector<errors::ErrorPtr> v{
|
||||
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
|
||||
return MaybeNode::error(v);
|
||||
return makeErrorful<E, Node>(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
/// Convert the given AST to string by calling the `toString` method
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<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
|
||||
/// MLIR's SimpelObjectCache.
|
||||
class ObjectCache : public llvm::ObjectCache {
|
||||
|
@ -179,10 +178,9 @@ public:
|
|||
llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
|
||||
symbolMap);
|
||||
|
||||
llvm::Optional<errors::ErrorTree> addNS(Namespace &ns,
|
||||
reader::LocationRange &loc);
|
||||
llvm::Error addNS(Namespace &ns, reader::LocationRange &loc);
|
||||
|
||||
llvm::Optional<errors::ErrorTree> addAST(exprs::Ast &ast);
|
||||
llvm::Error addAST(exprs::Ast &ast);
|
||||
|
||||
Namespace &getActiveNS();
|
||||
};
|
||||
|
|
|
@ -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 <llvm/ExecutionEngine/Orc/Core.h>
|
||||
#include <llvm/ExecutionEngine/Orc/ThreadSafeModule.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Support/Error.h>
|
||||
#include <mlir/IR/Builders.h>
|
||||
#include <mlir/IR/BuiltinOps.h>
|
||||
#include <mlir/IR/OwningOpRef.h>
|
||||
|
@ -72,7 +73,7 @@ using Ast = std::vector<Node>;
|
|||
} // namespace exprs
|
||||
|
||||
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 MaybeModuleOp = llvm::Optional<mlir::OwningOpRef<mlir::ModuleOp>>;
|
||||
using SemanticEnv = Environment<std::string, exprs::Node>;
|
||||
|
@ -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<llvm::StringRef> &getSymList() { return symbolList; };
|
||||
|
|
|
@ -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 <llvm/ADT/StringRef.h>
|
||||
|
@ -39,7 +39,7 @@ class Namespace;
|
|||
using SemanticEnv = Environment<std::string, exprs::Node>;
|
||||
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.
|
||||
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`
|
||||
/// 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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "serene/utils.h"
|
||||
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
#include <llvm/Support/Error.h>
|
||||
#include <llvm/Support/FormatAdapters.h>
|
||||
#include <llvm/Support/FormatVariadic.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,
|
||||
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<DiagnosticEngine> makeDiagnosticEngine(SereneContext &ctx) {
|
|||
return std::make_unique<DiagnosticEngine>(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);
|
||||
};
|
||||
|
||||
|
|
|
@ -16,22 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <typename ConcreteType>
|
||||
class IError : public TraitBase<ConcreteType, IError> {
|
||||
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"
|
|
@ -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
|
|
@ -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<Node>(sym->location, errors::CantResolveSymbol, msg);
|
||||
return errors::makeError<errors::CantResolveSymbol>(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<Node>(first->location, errors::DontKnowHowToCallNode,
|
||||
msg);
|
||||
return errors::makeError<errors::DontKnowHowToCallNode>(first->location,
|
||||
msg);
|
||||
}
|
||||
};
|
||||
|
||||
auto analyzedParams = semantics::analyze(state, rawParams);
|
||||
|
||||
if (!analyzedParams) {
|
||||
return MaybeNode::error(analyzedParams.getError());
|
||||
return analyzedParams.takeError();
|
||||
}
|
||||
|
||||
return makeSuccessfulNode<Call>(list->location, targetNode,
|
||||
analyzedParams.getValue());
|
||||
return makeSuccessfulNode<Call>(list->location, targetNode, *analyzedParams);
|
||||
};
|
||||
} // namespace exprs
|
||||
} // namespace serene
|
||||
|
|
|
@ -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<Node>(list->elements[0]->location,
|
||||
errors::DefWrongNumberOfArgs, msg);
|
||||
return errors::makeError<errors::DefWrongNumberOfArgs>(
|
||||
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<Symbol>(list->elements[1].get());
|
||||
if (binding == nullptr) {
|
||||
return makeErrorful<Node>(list->elements[1]->location,
|
||||
errors::DefExpectSymbol, "");
|
||||
return errors::makeError<errors::DefExpectSymbol>(
|
||||
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
|
||||
|
|
|
@ -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<Node>(list->elements[0]->location, errors::FnNoArgsList,
|
||||
"The argument list is mandatory.");
|
||||
return errors::makeError<errors::FnNoArgsList>(
|
||||
list->elements[0]->location, "The argument list is mandatory.");
|
||||
}
|
||||
|
||||
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}'",
|
||||
stringifyExprType(list->elements[1]->getType()));
|
||||
|
||||
return makeErrorful<Node>(list->elements[1]->location,
|
||||
errors::FnArgsMustBeList, msg);
|
||||
return errors::makeError<errors::FnArgsMustBeList>(
|
||||
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<Fn>(ctx, list->location, *args, body);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<errors::CantResolveSymbol>(
|
||||
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<errors::CantResolveSymbol>(
|
||||
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<errors::CantResolveSymbol>(sym.location, os.str());
|
||||
}
|
||||
|
||||
auto rawFPtr = expectedSymbol->getAddress();
|
||||
|
@ -239,8 +235,8 @@ MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const {
|
|||
auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
|
||||
|
||||
if (fptr == nullptr) {
|
||||
return MaybeJITPtr::error(errors::makeErrorTree(
|
||||
sym.location, errors::CantResolveSymbol, "Lookup function is null!"));
|
||||
return errors::makeError<errors::CantResolveSymbol>(
|
||||
sym.location, "Lookup function is null!");
|
||||
}
|
||||
|
||||
return fptr;
|
||||
|
@ -281,8 +277,7 @@ void Halley::registerSymbols(
|
|||
mainJitDylib.getExecutionSession(), engine->getDataLayout())))));
|
||||
};
|
||||
|
||||
llvm::Optional<errors::ErrorTree> 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<errors::ErrorTree> 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<errors::CompilationError>(
|
||||
loc, "Filed to create dylib for " + ns.name);
|
||||
}
|
||||
|
||||
ctx.pushJITDylib(ns, &(*newDylib));
|
||||
|
@ -301,7 +296,7 @@ llvm::Optional<errors::ErrorTree> Halley::addNS(Namespace &ns,
|
|||
auto maybeModule = ns.compileToLLVM();
|
||||
|
||||
if (!maybeModule.hasValue()) {
|
||||
return errors::makeErrorTree(loc, errors::CompilationError);
|
||||
return errors::makeError<errors::CompilationError>(loc);
|
||||
}
|
||||
|
||||
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
|
||||
// engine
|
||||
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) {
|
||||
|
@ -462,12 +457,11 @@ MaybeJIT Halley::make(SereneContext &serene_ctx,
|
|||
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 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<errors::ErrorTree> 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; };
|
||||
|
|
|
@ -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::StringError>(
|
||||
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(
|
||||
|
|
|
@ -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++; };
|
||||
|
|
|
@ -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<errors::InvalidDigitForNumber>(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<errors::TwoFloatPoints>(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<errors::InvalidDigitForNumber>(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<errors::InvalidCharacterForSymbol>(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<errors::EOFWhileScaningAList>(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,
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "serene/exprs/expression.h"
|
||||
#include "serene/namespace.h"
|
||||
|
||||
#include <llvm/Support/Error.h>
|
||||
|
||||
namespace serene::semantics {
|
||||
|
||||
std::unique_ptr<AnalysisState> AnalysisState::moveToNewEnv() {
|
||||
|
@ -30,7 +32,7 @@ std::unique_ptr<AnalysisState> 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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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<errors::NSLoadError>(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<errors::NSAddToSMError>(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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
#include <llvm/TableGen/Error.h>
|
||||
#include <llvm/TableGen/Record.h>
|
||||
|
||||
#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<void(llvm::raw_ostream &)> 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<llvm::StringInit>(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<llvm::StringInit>(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<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) {
|
||||
|
@ -130,9 +165,9 @@ void ErrorsBackend::run(llvm::raw_ostream &os) {
|
|||
|
||||
os << "#include \"serene/errors/base.h\"\n\n#include "
|
||||
"<llvm/Support/Error.h>\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) {
|
||||
|
|
Loading…
Reference in New Issue