Add the read and print functionality to the repl
This commit is contained in:
parent
3fb6fb3740
commit
fc11896c28
1
dev.org
1
dev.org
|
@ -108,6 +108,7 @@ on ADF
|
||||||
|
|
||||||
* TODOs
|
* TODOs
|
||||||
** Bootstrap*
|
** Bootstrap*
|
||||||
|
*** TODO Use =const= where ever it makes sense
|
||||||
*** TODO Create different pass pipeline for different compilation phases
|
*** TODO Create different pass pipeline for different compilation phases
|
||||||
So we can use them directly via command line, like -O1 for example
|
So we can use them directly via command line, like -O1 for example
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ public:
|
||||||
/// Insert the given `ns` into the context. The Context object is
|
/// Insert the given `ns` into the context. The Context object is
|
||||||
/// the owner of all the namespaces. The `ns` will overwrite any
|
/// the owner of all the namespaces. The `ns` will overwrite any
|
||||||
/// namespace with the same name.
|
/// namespace with the same name.
|
||||||
void insertNS(const std::shared_ptr<Namespace> &ns);
|
void insertNS(NSPtr &ns);
|
||||||
|
|
||||||
/// Sets the n ame of the current namespace in the context and return
|
/// Sets the n ame of the current namespace in the context and return
|
||||||
/// a boolean indicating the status of this operation. The operation
|
/// a boolean indicating the status of this operation. The operation
|
||||||
|
@ -107,8 +107,8 @@ public:
|
||||||
Namespace &getCurrentNS();
|
Namespace &getCurrentNS();
|
||||||
|
|
||||||
/// Lookup the namespace with the give name in the current context and
|
/// Lookup the namespace with the give name in the current context and
|
||||||
/// return a shared pointer to it or a `nullptr` in it doesn't exist.
|
/// return a pointer to it or a `nullptr` in it doesn't exist.
|
||||||
std::shared_ptr<Namespace> getNS(llvm::StringRef ns_name);
|
Namespace *getNS(llvm::StringRef ns_name);
|
||||||
|
|
||||||
SereneContext()
|
SereneContext()
|
||||||
: pm(&mlirContext), diagEngine(makeDiagnosticEngine(*this)),
|
: pm(&mlirContext), diagEngine(makeDiagnosticEngine(*this)),
|
||||||
|
@ -134,8 +134,8 @@ public:
|
||||||
CompilationPhase getTargetPhase() { return targetPhase; };
|
CompilationPhase getTargetPhase() { return targetPhase; };
|
||||||
int getOptimizatioLevel();
|
int getOptimizatioLevel();
|
||||||
|
|
||||||
NSPtr readNamespace(const std::string &name);
|
MaybeNS readNamespace(const std::string &name);
|
||||||
NSPtr readNamespace(std::string name, reader::LocationRange loc);
|
MaybeNS readNamespace(const std::string &name, reader::LocationRange loc);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CompilationPhase targetPhase;
|
CompilationPhase targetPhase;
|
||||||
|
@ -143,7 +143,7 @@ private:
|
||||||
// The namespace table. Every namespace that needs to be compiled has
|
// The namespace table. Every namespace that needs to be compiled has
|
||||||
// to register itself with the context and appear on this table.
|
// to register itself with the context and appear on this table.
|
||||||
// This table acts as a cache as well.
|
// This table acts as a cache as well.
|
||||||
std::map<std::string, std::shared_ptr<Namespace>> namespaces;
|
std::map<std::string, NSPtr> namespaces;
|
||||||
|
|
||||||
// Why string vs pointer? We might rewrite the namespace and
|
// Why string vs pointer? We might rewrite the namespace and
|
||||||
// holding a pointer means that it might point to the old version
|
// holding a pointer means that it might point to the old version
|
||||||
|
|
|
@ -20,14 +20,18 @@
|
||||||
#define SERENE_DIAGNOSTICS_H
|
#define SERENE_DIAGNOSTICS_H
|
||||||
|
|
||||||
#include "serene/errors/constants.h"
|
#include "serene/errors/constants.h"
|
||||||
|
#include "serene/errors/error.h"
|
||||||
#include "serene/reader/location.h"
|
#include "serene/reader/location.h"
|
||||||
#include "serene/source_mgr.h"
|
#include "serene/source_mgr.h"
|
||||||
|
|
||||||
|
#include <serene/export.h>
|
||||||
|
|
||||||
#include <llvm/ADT/StringRef.h>
|
#include <llvm/ADT/StringRef.h>
|
||||||
#include <llvm/Support/raw_ostream.h>
|
#include <llvm/Support/raw_ostream.h>
|
||||||
#include <memory>
|
|
||||||
#include <mlir/IR/Diagnostics.h>
|
#include <mlir/IR/Diagnostics.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
class SereneContext;
|
class SereneContext;
|
||||||
class DiagnosticEngine;
|
class DiagnosticEngine;
|
||||||
|
@ -81,6 +85,9 @@ public:
|
||||||
void emitSyntaxError(reader::LocationRange loc, errors::ErrorVariant &e,
|
void emitSyntaxError(reader::LocationRange loc, errors::ErrorVariant &e,
|
||||||
llvm::StringRef msg = "");
|
llvm::StringRef msg = "");
|
||||||
|
|
||||||
|
void emit(const errors::ErrorPtr &err);
|
||||||
|
void emit(const errors::ErrorTree &errs);
|
||||||
|
|
||||||
/// Throw out an error with the given `msg` and terminate the execution
|
/// Throw out an error with the given `msg` and terminate the execution
|
||||||
void panic(llvm::StringRef msg);
|
void panic(llvm::StringRef msg);
|
||||||
};
|
};
|
||||||
|
@ -89,9 +96,11 @@ public:
|
||||||
/// `SereneContext`
|
/// `SereneContext`
|
||||||
std::unique_ptr<DiagnosticEngine> makeDiagnosticEngine(SereneContext &ctx);
|
std::unique_ptr<DiagnosticEngine> makeDiagnosticEngine(SereneContext &ctx);
|
||||||
|
|
||||||
/// Throw out an error with the given `msg` and terminate the execution
|
/// Throw out an error with the given `msg` and terminate the execution.
|
||||||
void panic(SereneContext &ctx, llvm::StringRef msg);
|
SERENE_EXPORT void panic(SereneContext &ctx, llvm::StringRef msg);
|
||||||
|
|
||||||
|
/// Throw the give `ErrorTree` \p errs and terminate the execution.
|
||||||
|
SERENE_EXPORT void throwErrors(SereneContext &ctx, errors::ErrorTree &errs);
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,6 +28,13 @@
|
||||||
namespace serene {
|
namespace serene {
|
||||||
namespace errors {
|
namespace errors {
|
||||||
|
|
||||||
|
/// This enum represent the expression type and **not** the value type.
|
||||||
|
enum class ErrType {
|
||||||
|
Syntax,
|
||||||
|
Semantic,
|
||||||
|
Compile,
|
||||||
|
};
|
||||||
|
|
||||||
enum ErrID {
|
enum ErrID {
|
||||||
E0000 = 0,
|
E0000 = 0,
|
||||||
E0001,
|
E0001,
|
||||||
|
|
|
@ -19,23 +19,25 @@
|
||||||
#ifndef SERENE_ERRORS_ERROR_H
|
#ifndef SERENE_ERRORS_ERROR_H
|
||||||
#define SERENE_ERRORS_ERROR_H
|
#define SERENE_ERRORS_ERROR_H
|
||||||
|
|
||||||
#include "serene/context.h"
|
|
||||||
#include "serene/errors/constants.h"
|
#include "serene/errors/constants.h"
|
||||||
#include "serene/errors/traits.h"
|
#include "serene/errors/traits.h"
|
||||||
#include "serene/reader/location.h"
|
|
||||||
#include "serene/reader/traits.h"
|
#include "serene/reader/traits.h"
|
||||||
#include "serene/traits.h"
|
#include "serene/traits.h"
|
||||||
//#include "serene/exprs/expression.h"
|
|
||||||
#include <llvm/Support/Error.h>
|
#include <llvm/ADT/Optional.h>
|
||||||
|
|
||||||
|
namespace serene::reader {
|
||||||
|
class LoccationRange;
|
||||||
|
} // namespace serene::reader
|
||||||
|
|
||||||
namespace serene::errors {
|
namespace serene::errors {
|
||||||
|
class Error;
|
||||||
|
|
||||||
/// This enum represent the expression type and **not** the value type.
|
using ErrorPtr = std::shared_ptr<errors::Error>;
|
||||||
enum class ErrType {
|
|
||||||
Syntax,
|
// tree? Yupe, Errors can be stackable which makes a vector of them a tree
|
||||||
Semantic,
|
using ErrorTree = std::vector<ErrorPtr>;
|
||||||
Compile,
|
using OptionalErrors = llvm::Optional<ErrorTree>;
|
||||||
};
|
|
||||||
|
|
||||||
/// This data structure represent the Lisp error. This type of expression
|
/// 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
|
/// doesn't show up in the AST but the compiler might rewrite the AST
|
||||||
|
@ -56,10 +58,21 @@ public:
|
||||||
std::string toString() const;
|
std::string toString() const;
|
||||||
reader::LocationRange &where();
|
reader::LocationRange &where();
|
||||||
ErrorVariant *getVariant();
|
ErrorVariant *getVariant();
|
||||||
std::string getMessage();
|
std::string &getMessage();
|
||||||
~Error() = default;
|
~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
|
}; // namespace serene::errors
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#ifndef SERENE_ERRORS_TRAITS_H
|
#ifndef SERENE_ERRORS_TRAITS_H
|
||||||
#define SERENE_ERRORS_TRAITS_H
|
#define SERENE_ERRORS_TRAITS_H
|
||||||
|
|
||||||
#include "serene/context.h"
|
|
||||||
#include "serene/errors/constants.h"
|
#include "serene/errors/constants.h"
|
||||||
#include "serene/traits.h"
|
#include "serene/traits.h"
|
||||||
|
|
||||||
|
|
|
@ -37,16 +37,11 @@ namespace exprs {
|
||||||
|
|
||||||
class Expression;
|
class Expression;
|
||||||
|
|
||||||
using Node = std::shared_ptr<Expression>;
|
using Node = std::shared_ptr<Expression>;
|
||||||
using ErrorPtr = std::shared_ptr<errors::Error>;
|
using MaybeNode = Result<Node, errors::ErrorTree>;
|
||||||
|
|
||||||
// tree? Yupe, Errors can be stackable which makes a vector of them a tree
|
|
||||||
using ErrorTree = std::vector<ErrorPtr>;
|
|
||||||
|
|
||||||
using MaybeNode = Result<Node, ErrorTree>;
|
|
||||||
|
|
||||||
using Ast = std::vector<Node>;
|
using Ast = std::vector<Node>;
|
||||||
using MaybeAst = Result<Ast, ErrorTree>;
|
using MaybeAst = Result<Ast, errors::ErrorTree>;
|
||||||
|
|
||||||
static auto EmptyNode = MaybeNode::success(nullptr);
|
static auto EmptyNode = MaybeNode::success(nullptr);
|
||||||
|
|
||||||
|
@ -118,8 +113,9 @@ std::shared_ptr<T> makeAndCast(Args &&...args) {
|
||||||
// of a `Result`. It should be useds where every we want to return a `MaybeNode`
|
// of a `Result`. It should be useds where every we want to return a `MaybeNode`
|
||||||
/// successfully
|
/// successfully
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
Result<Node, ErrorTree> makeSuccessfulNode(Args &&...args) {
|
Result<Node, errors::ErrorTree> makeSuccessfulNode(Args &&...args) {
|
||||||
return Result<Node, ErrorTree>::success(make<T>(std::forward<Args>(args)...));
|
return Result<Node, errors::ErrorTree>::success(
|
||||||
|
make<T>(std::forward<Args>(args)...));
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The hlper function to create an Errorful `Result<T,...>` (`T` would be
|
/// The hlper function to create an Errorful `Result<T,...>` (`T` would be
|
||||||
|
@ -127,10 +123,10 @@ Result<Node, ErrorTree> makeSuccessfulNode(Args &&...args) {
|
||||||
/// passing any argument to this function to the `serene::errors::Error`
|
/// passing any argument to this function to the `serene::errors::Error`
|
||||||
/// constructor.
|
/// constructor.
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
Result<T, ErrorTree> makeErrorful(Args &&...args) {
|
Result<T, errors::ErrorTree> makeErrorful(Args &&...args) {
|
||||||
std::vector<ErrorPtr> v{
|
std::vector<errors::ErrorPtr> v{
|
||||||
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
|
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
|
||||||
return Result<T, ErrorTree>::error(v);
|
return Result<T, errors::ErrorTree>::error(v);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The hlper function to create an Error node (The failure case of a MaybeNod)
|
/// The hlper function to create an Error node (The failure case of a MaybeNod)
|
||||||
|
@ -138,7 +134,7 @@ Result<T, ErrorTree> makeErrorful(Args &&...args) {
|
||||||
/// the `serene::errors::Error` constructor.
|
/// the `serene::errors::Error` constructor.
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
MaybeNode makeErrorNode(Args &&...args) {
|
MaybeNode makeErrorNode(Args &&...args) {
|
||||||
std::vector<ErrorPtr> v{
|
std::vector<errors::ErrorPtr> v{
|
||||||
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
|
std::move(makeAndCast<errors::Error>(std::forward<Args>(args)...))};
|
||||||
return MaybeNode::error(v);
|
return MaybeNode::error(v);
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "serene/errors.h"
|
#include "serene/errors.h"
|
||||||
#include "serene/export.h"
|
#include "serene/export.h"
|
||||||
|
#include "serene/exprs/expression.h"
|
||||||
|
#include "serene/namespace.h"
|
||||||
#include "serene/slir/generatable.h"
|
#include "serene/slir/generatable.h"
|
||||||
#include "serene/utils.h"
|
#include "serene/utils.h"
|
||||||
|
|
||||||
|
@ -162,6 +164,9 @@ public:
|
||||||
void registerSymbols(
|
void registerSymbols(
|
||||||
llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
|
llvm::function_ref<llvm::orc::SymbolMap(llvm::orc::MangleAndInterner)>
|
||||||
symbolMap);
|
symbolMap);
|
||||||
|
|
||||||
|
std::unique_ptr<exprs::Expression> eval(SereneContext &ctx,
|
||||||
|
std::string input);
|
||||||
};
|
};
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define SERENE_NAMESPACE_H
|
#define SERENE_NAMESPACE_H
|
||||||
|
|
||||||
#include "serene/environment.h"
|
#include "serene/environment.h"
|
||||||
|
#include "serene/errors/error.h"
|
||||||
#include "serene/export.h"
|
#include "serene/export.h"
|
||||||
#include "serene/slir/generatable.h"
|
#include "serene/slir/generatable.h"
|
||||||
#include "serene/traits.h"
|
#include "serene/traits.h"
|
||||||
|
@ -98,8 +99,8 @@ public:
|
||||||
|
|
||||||
/// Expand the current tree of the namespace with the given \p ast by
|
/// Expand the current tree of the namespace with the given \p ast by
|
||||||
/// semantically analazing it first. If the give \p ast in not valid
|
/// semantically analazing it first. If the give \p ast in not valid
|
||||||
/// it will emit an error.
|
/// it will return analysis errors.
|
||||||
mlir::LogicalResult expandTree(exprs::Ast &ast);
|
errors::OptionalErrors expandTree(exprs::Ast &ast);
|
||||||
|
|
||||||
/// Increase the function counter by one
|
/// Increase the function counter by one
|
||||||
uint nextFnCounter();
|
uint nextFnCounter();
|
||||||
|
@ -127,10 +128,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
using NSPtr = std::shared_ptr<Namespace>;
|
using NSPtr = std::shared_ptr<Namespace>;
|
||||||
|
|
||||||
|
using MaybeNS = Result<NSPtr, errors::ErrorTree>;
|
||||||
/// Create a naw namespace with the given `name` and optional `filename` and
|
/// Create a naw namespace with the given `name` and optional `filename` and
|
||||||
/// return a shared pointer to it in the given Serene context. If the
|
/// return a shared pointer to it in the given Serene context. If the
|
||||||
/// `setCurrent` argument is set to true, the created NS will become the curret
|
/// `setCurrent` argument is set to true, the created NS will become the
|
||||||
/// namespace in the context
|
/// curret namespace in the context
|
||||||
SERENE_EXPORT NSPtr makeNamespace(SereneContext &ctx, llvm::StringRef name,
|
SERENE_EXPORT NSPtr makeNamespace(SereneContext &ctx, llvm::StringRef name,
|
||||||
llvm::Optional<llvm::StringRef> filename,
|
llvm::Optional<llvm::StringRef> filename,
|
||||||
bool setCurrent = true);
|
bool setCurrent = true);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include "serene/exprs/expression.h"
|
#include "serene/exprs/expression.h"
|
||||||
|
|
||||||
namespace serene::reader {
|
namespace serene::reader {
|
||||||
using AnalyzeResult = Result<exprs::Ast, std::vector<exprs::ErrorPtr>>;
|
using AnalyzeResult = Result<exprs::Ast, std::vector<errors::ErrorPtr>>;
|
||||||
/// The entry point to the Semantic analysis phase. It calls the `analyze`
|
/// The entry point to the Semantic analysis phase. It calls the `analyze`
|
||||||
/// method of each node in the given AST and creates a new AST that contains a
|
/// method of each node in the given AST and creates a new AST that contains a
|
||||||
/// more comprehensive set of nodes in a semantically correct AST. If the
|
/// more comprehensive set of nodes in a semantically correct AST. If the
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "serene/config.h"
|
#include "serene/config.h"
|
||||||
#include "serene/context.h"
|
#include "serene/context.h"
|
||||||
#include "serene/export.h"
|
#include "serene/export.h"
|
||||||
|
#include "serene/exprs/expression.h"
|
||||||
#include "serene/source_mgr.h"
|
#include "serene/source_mgr.h"
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
|
@ -38,5 +39,42 @@ SERENE_EXPORT void registerSereneCLOptions();
|
||||||
/// Applies the global compiler options on the give \p SereneContext. This
|
/// Applies the global compiler options on the give \p SereneContext. This
|
||||||
/// function has to be called after `llvm::cl::ParseCommandLineOptions`.
|
/// function has to be called after `llvm::cl::ParseCommandLineOptions`.
|
||||||
SERENE_EXPORT void applySereneCLOptions(SereneContext &ctx);
|
SERENE_EXPORT void applySereneCLOptions(SereneContext &ctx);
|
||||||
|
|
||||||
|
/// Reads the the given \p input as a Serene source code in the given
|
||||||
|
/// \c SereneContext \p ctx and returns the possible AST tree of the input or an
|
||||||
|
/// error otherwise.
|
||||||
|
///
|
||||||
|
/// In case of an error Serene will throw the error messages vis the diagnostic
|
||||||
|
/// engine as well and the error that this function returns will be the generic
|
||||||
|
/// error message.
|
||||||
|
///
|
||||||
|
/// Be aware than this function reads the input in the context of the current
|
||||||
|
/// namespace. So for example if the input is somthing like:
|
||||||
|
///
|
||||||
|
/// (ns example.code) ....
|
||||||
|
///
|
||||||
|
/// and the current ns is `user` then if there is a syntax error in the input
|
||||||
|
/// the error will be reported under the `user` ns. This is logical because
|
||||||
|
/// this function reads the code and not evaluate it. the `ns` form has to be
|
||||||
|
/// evaluated in order to change the ns.
|
||||||
|
SERENE_EXPORT exprs::MaybeAst read(SereneContext &ctx, std::string &input);
|
||||||
|
|
||||||
|
/// Evaluates the given AST form \p input in the given \c SereneContext \p ctx
|
||||||
|
/// and retuns a new expression as the result or a possible error.
|
||||||
|
///
|
||||||
|
/// In case of an error Serene will throw the error messages vis the diagnostic
|
||||||
|
/// engine as well and the error that this function returns will be the
|
||||||
|
/// generic error message.
|
||||||
|
// SERENE_EXPORT exprs::MaybeNode eval(SereneContext &ctx, exprs::Ast input);
|
||||||
|
|
||||||
|
// TODO: Return a Serene String type instead of the std::string
|
||||||
|
// TODO: Create an overload to get a stream instead of the result string
|
||||||
|
/// Prints the given AST form \p input in the given \c SereneContext \p ctx
|
||||||
|
/// into the given \p result.
|
||||||
|
/// Note: print is a lisp action. Don't confuse it with a print function such
|
||||||
|
/// as `println`.
|
||||||
|
SERENE_EXPORT void print(SereneContext &ctx, const exprs::Ast &input,
|
||||||
|
std::string &result);
|
||||||
|
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,10 +28,11 @@
|
||||||
#include <llvm/Support/ErrorOr.h>
|
#include <llvm/Support/ErrorOr.h>
|
||||||
#include <llvm/Support/MemoryBuffer.h>
|
#include <llvm/Support/MemoryBuffer.h>
|
||||||
#include <llvm/Support/SourceMgr.h>
|
#include <llvm/Support/SourceMgr.h>
|
||||||
#include <memory>
|
|
||||||
#include <mlir/IR/Diagnostics.h>
|
#include <mlir/IR/Diagnostics.h>
|
||||||
#include <mlir/Support/Timing.h>
|
#include <mlir/Support/Timing.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#define SMGR_LOG(...) \
|
#define SMGR_LOG(...) \
|
||||||
DEBUG_WITH_TYPE("sourcemgr", llvm::dbgs() \
|
DEBUG_WITH_TYPE("sourcemgr", llvm::dbgs() \
|
||||||
<< "[SMGR]: " << __VA_ARGS__ << "\n");
|
<< "[SMGR]: " << __VA_ARGS__ << "\n");
|
||||||
|
@ -173,15 +174,15 @@ public:
|
||||||
reader::LocationRange includeLoc);
|
reader::LocationRange includeLoc);
|
||||||
|
|
||||||
/// Lookup for a file containing the namespace definition of with given
|
/// Lookup for a file containing the namespace definition of with given
|
||||||
/// namespace name \p name and throw an error. In case that the file exists,
|
/// namespace name \p name. In case that the file exists, it returns an
|
||||||
/// use the parser to read the file and create an AST from it. Then create a
|
/// `ErrorTree`. It will use the parser to read the file and create an AST
|
||||||
/// namespace, set the its AST to the AST that we just read from the file and
|
/// from it. Then create a namespace, set the its AST to the AST that we just
|
||||||
/// return a shared pointer to the namespace.
|
/// read from the file and return a shared pointer to the namespace.
|
||||||
///
|
///
|
||||||
/// \p importLoc is a location in the source code where the give namespace is
|
/// \p importLoc is a location in the source code where the give namespace is
|
||||||
/// imported.
|
/// imported.
|
||||||
NSPtr readNamespace(SereneContext &ctx, std::string name,
|
MaybeNS readNamespace(SereneContext &ctx, std::string name,
|
||||||
reader::LocationRange importLoc);
|
reader::LocationRange importLoc);
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace serene
|
}; // namespace serene
|
||||||
|
|
|
@ -29,13 +29,14 @@
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
|
|
||||||
void SereneContext::insertNS(const std::shared_ptr<Namespace> &ns) {
|
void SereneContext::insertNS(NSPtr &ns) {
|
||||||
namespaces[ns->name] = ns;
|
auto nsName = ns->name;
|
||||||
|
namespaces[nsName] = ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<Namespace> SereneContext::getNS(llvm::StringRef ns_name) {
|
Namespace *SereneContext::getNS(llvm::StringRef ns_name) {
|
||||||
if (namespaces.count(ns_name.str()) != 0) {
|
if (namespaces.count(ns_name.str()) != 0) {
|
||||||
return namespaces[ns_name.str()];
|
return namespaces[ns_name.str()].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -90,14 +91,14 @@ int SereneContext::getOptimizatioLevel() {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSPtr SereneContext::readNamespace(const std::string &name) {
|
MaybeNS SereneContext::readNamespace(const std::string &name) {
|
||||||
auto loc = reader::LocationRange::UnknownLocation(name);
|
auto loc = reader::LocationRange::UnknownLocation(name);
|
||||||
|
|
||||||
return readNamespace(name, loc);
|
return readNamespace(name, loc);
|
||||||
};
|
};
|
||||||
|
|
||||||
NSPtr SereneContext::readNamespace(std::string name,
|
MaybeNS SereneContext::readNamespace(const std::string &name,
|
||||||
reader::LocationRange loc) {
|
reader::LocationRange loc) {
|
||||||
return sourceManager.readNamespace(*this, std::move(name), loc);
|
return sourceManager.readNamespace(*this, std::move(name), loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,8 +203,24 @@ std::unique_ptr<DiagnosticEngine> makeDiagnosticEngine(SereneContext &ctx) {
|
||||||
return std::make_unique<DiagnosticEngine>(ctx);
|
return std::make_unique<DiagnosticEngine>(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiagnosticEngine::emit(const errors::ErrorPtr &err) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
// TODO: create a diag and print it
|
||||||
|
llvm::errs() << err->toString() << "\n";
|
||||||
|
};
|
||||||
|
|
||||||
|
void DiagnosticEngine::emit(const errors::ErrorTree &errs) {
|
||||||
|
for (const auto &e : errs) {
|
||||||
|
emit(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void panic(SereneContext &ctx, llvm::StringRef msg) {
|
void panic(SereneContext &ctx, llvm::StringRef msg) {
|
||||||
ctx.diagEngine->panic(msg);
|
ctx.diagEngine->panic(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void throwErrors(SereneContext &ctx, errors::ErrorTree &errs) {
|
||||||
|
ctx.diagEngine->emit(errs);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include <llvm/Support/FormatVariadic.h>
|
#include <llvm/Support/FormatVariadic.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
namespace errors {
|
namespace errors {
|
||||||
|
|
||||||
|
@ -31,7 +33,18 @@ reader::LocationRange &Error::where() { return this->location; };
|
||||||
|
|
||||||
ErrorVariant *Error::getVariant() { return this->variant; }
|
ErrorVariant *Error::getVariant() { return this->variant; }
|
||||||
|
|
||||||
std::string Error::getMessage() { return this->message; }
|
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 errors
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
|
@ -34,11 +34,12 @@
|
||||||
#include <llvm/ADT/StringRef.h>
|
#include <llvm/ADT/StringRef.h>
|
||||||
#include <llvm/Support/FormatVariadic.h>
|
#include <llvm/Support/FormatVariadic.h>
|
||||||
#include <llvm/Support/raw_ostream.h>
|
#include <llvm/Support/raw_ostream.h>
|
||||||
#include <memory>
|
|
||||||
#include <mlir/IR/Builders.h>
|
#include <mlir/IR/Builders.h>
|
||||||
#include <mlir/IR/BuiltinOps.h>
|
#include <mlir/IR/BuiltinOps.h>
|
||||||
#include <mlir/IR/Verifier.h>
|
#include <mlir/IR/Verifier.h>
|
||||||
#include <mlir/Support/LogicalResult.h>
|
#include <mlir/Support/LogicalResult.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -61,12 +62,12 @@ void Namespace::enqueueError(llvm::StringRef e) const {
|
||||||
|
|
||||||
exprs::Ast &Namespace::getTree() { return this->tree; }
|
exprs::Ast &Namespace::getTree() { return this->tree; }
|
||||||
|
|
||||||
mlir::LogicalResult Namespace::expandTree(exprs::Ast &ast) {
|
errors::OptionalErrors Namespace::expandTree(exprs::Ast &ast) {
|
||||||
|
|
||||||
if (ctx.getTargetPhase() == CompilationPhase::Parse) {
|
if (ctx.getTargetPhase() == CompilationPhase::Parse) {
|
||||||
// we just want the raw AST
|
// we just want the raw AST
|
||||||
this->tree.insert(this->tree.end(), ast.begin(), ast.end());
|
this->tree.insert(this->tree.end(), ast.begin(), ast.end());
|
||||||
return mlir::success();
|
return llvm::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the semantic analyer on the ast and then if everything
|
// Run the semantic analyer on the ast and then if everything
|
||||||
|
@ -74,13 +75,12 @@ mlir::LogicalResult Namespace::expandTree(exprs::Ast &ast) {
|
||||||
auto maybeAst = reader::analyze(ctx, ast);
|
auto maybeAst = reader::analyze(ctx, ast);
|
||||||
|
|
||||||
if (!maybeAst) {
|
if (!maybeAst) {
|
||||||
enqueueError("Semantic analysis failed!");
|
return maybeAst.getError();
|
||||||
return mlir::failure();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto semanticAst = std::move(maybeAst.getValue());
|
auto semanticAst = std::move(maybeAst.getValue());
|
||||||
this->tree.insert(this->tree.end(), semanticAst.begin(), semanticAst.end());
|
this->tree.insert(this->tree.end(), semanticAst.begin(), semanticAst.end());
|
||||||
return mlir::success();
|
return llvm::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint Namespace::nextFnCounter() { return fn_counter++; };
|
uint Namespace::nextFnCounter() { return fn_counter++; };
|
||||||
|
@ -154,11 +154,12 @@ MaybeModule Namespace::compileToLLVM() {
|
||||||
|
|
||||||
Namespace::~Namespace(){};
|
Namespace::~Namespace(){};
|
||||||
|
|
||||||
std::shared_ptr<Namespace>
|
NSPtr makeNamespace(SereneContext &ctx, llvm::StringRef name,
|
||||||
makeNamespace(SereneContext &ctx, llvm::StringRef name,
|
llvm::Optional<llvm::StringRef> filename, bool setCurrent) {
|
||||||
llvm::Optional<llvm::StringRef> filename, bool setCurrent) {
|
|
||||||
auto nsPtr = std::make_shared<Namespace>(ctx, name, filename);
|
auto nsPtr = std::make_shared<Namespace>(ctx, name, filename);
|
||||||
|
|
||||||
ctx.insertNS(nsPtr);
|
ctx.insertNS(nsPtr);
|
||||||
|
|
||||||
if (setCurrent) {
|
if (setCurrent) {
|
||||||
if (!ctx.setCurrentNS(nsPtr->name)) {
|
if (!ctx.setCurrentNS(nsPtr->name)) {
|
||||||
throw std::runtime_error("Couldn't set the current NS");
|
throw std::runtime_error("Couldn't set the current NS");
|
||||||
|
|
|
@ -27,7 +27,7 @@ AnalyzeResult analyze(serene::SereneContext &ctx, exprs::Ast &inputAst) {
|
||||||
// TODO: Fetch the current namespace from the JIT engine later and if it is
|
// TODO: Fetch the current namespace from the JIT engine later and if it is
|
||||||
// `nil` then the given `ast` has to start with a namespace definition.
|
// `nil` then the given `ast` has to start with a namespace definition.
|
||||||
|
|
||||||
std::vector<exprs::ErrorPtr> errors;
|
errors::ErrorTree errors;
|
||||||
exprs::Ast ast;
|
exprs::Ast ast;
|
||||||
|
|
||||||
for (auto &element : inputAst) {
|
for (auto &element : inputAst) {
|
||||||
|
|
|
@ -24,6 +24,11 @@
|
||||||
|
|
||||||
#include "serene/serene.h"
|
#include "serene/serene.h"
|
||||||
|
|
||||||
|
#include "serene/diagnostics.h"
|
||||||
|
#include "serene/exprs/expression.h"
|
||||||
|
#include "serene/reader/reader.h"
|
||||||
|
|
||||||
|
#include <llvm/ADT/None.h>
|
||||||
#include <llvm/Support/TargetSelect.h>
|
#include <llvm/Support/TargetSelect.h>
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
|
@ -81,4 +86,24 @@ void applySereneCLOptions(SereneContext &ctx) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SERENE_EXPORT exprs::MaybeAst read(SereneContext &ctx, std::string &input) {
|
||||||
|
auto ¤tNS = ctx.getCurrentNS();
|
||||||
|
auto filename =
|
||||||
|
!currentNS.filename.hasValue()
|
||||||
|
? llvm::None
|
||||||
|
: llvm::Optional<llvm::StringRef>(currentNS.filename.getValue());
|
||||||
|
|
||||||
|
return reader::read(ctx, input, currentNS.name, filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
// SERENE_EXPORT exprs::MaybeNode eval(SereneContext &ctx, exprs::Ast input){
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
|
SERENE_EXPORT void print(SereneContext &ctx, const exprs::Ast &input,
|
||||||
|
std::string &result) {
|
||||||
|
UNUSED(ctx);
|
||||||
|
result = exprs::astToString(&input);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace serene
|
} // namespace serene
|
||||||
|
|
|
@ -31,12 +31,13 @@
|
||||||
#include "serene/reader/semantics.h"
|
#include "serene/reader/semantics.h"
|
||||||
#include "serene/utils.h"
|
#include "serene/utils.h"
|
||||||
|
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#include <llvm/Support/FormatVariadic.h>
|
#include <llvm/Support/FormatVariadic.h>
|
||||||
#include <llvm/Support/Locale.h>
|
#include <llvm/Support/Locale.h>
|
||||||
#include <llvm/Support/MemoryBufferRef.h>
|
#include <llvm/Support/MemoryBufferRef.h>
|
||||||
#include <llvm/Support/Path.h>
|
#include <llvm/Support/Path.h>
|
||||||
#include <mlir/Support/LogicalResult.h>
|
#include <mlir/Support/LogicalResult.h>
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
namespace serene {
|
namespace serene {
|
||||||
|
|
||||||
|
@ -77,8 +78,8 @@ SourceMgr::findFileInLoadPath(const std::string &name,
|
||||||
return newBufOrErr;
|
return newBufOrErr;
|
||||||
};
|
};
|
||||||
|
|
||||||
NSPtr SourceMgr::readNamespace(SereneContext &ctx, std::string name,
|
MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name,
|
||||||
reader::LocationRange importLoc) {
|
reader::LocationRange importLoc) {
|
||||||
std::string importedFile;
|
std::string importedFile;
|
||||||
|
|
||||||
SMGR_LOG("Attempt to load namespace: " + name);
|
SMGR_LOG("Attempt to load namespace: " + name);
|
||||||
|
@ -86,9 +87,9 @@ NSPtr SourceMgr::readNamespace(SereneContext &ctx, std::string name,
|
||||||
|
|
||||||
if (!newBufOrErr) {
|
if (!newBufOrErr) {
|
||||||
auto msg = llvm::formatv("Couldn't find namespace '{0}'", name);
|
auto msg = llvm::formatv("Couldn't find namespace '{0}'", name);
|
||||||
ctx.diagEngine->emitSyntaxError(importLoc, errors::NSLoadError,
|
auto err = errors::makeErrorTree(importLoc, errors::NSLoadError,
|
||||||
llvm::StringRef(msg));
|
llvm::StringRef(msg));
|
||||||
return nullptr;
|
return MaybeNS::error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bufferId = AddNewSourceBuffer(std::move(*newBufOrErr), importLoc);
|
auto bufferId = AddNewSourceBuffer(std::move(*newBufOrErr), importLoc);
|
||||||
|
@ -97,11 +98,9 @@ NSPtr SourceMgr::readNamespace(SereneContext &ctx, std::string name,
|
||||||
|
|
||||||
if (bufferId == 0) {
|
if (bufferId == 0) {
|
||||||
auto msg = llvm::formatv("Couldn't add namespace '{0}'", name);
|
auto msg = llvm::formatv("Couldn't add namespace '{0}'", name);
|
||||||
// TODO: enqueue the error here
|
auto err = errors::makeErrorTree(importLoc, errors::NSAddToSMError,
|
||||||
ctx.diagEngine->emitSyntaxError(importLoc, errors::NSAddToSMError,
|
llvm::StringRef(msg));
|
||||||
llvm::StringRef(msg));
|
return MaybeNS::error(err);
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we moved the buffer to be added as the source storage we
|
// Since we moved the buffer to be added as the source storage we
|
||||||
|
@ -114,21 +113,17 @@ NSPtr SourceMgr::readNamespace(SereneContext &ctx, std::string name,
|
||||||
|
|
||||||
if (!maybeAst) {
|
if (!maybeAst) {
|
||||||
SMGR_LOG("Couldn't Read namespace: " + name);
|
SMGR_LOG("Couldn't Read namespace: " + name);
|
||||||
// The code that is calling this function has to flush the dia engine, so we
|
return MaybeNS::error(maybeAst.getError());
|
||||||
// don't have to emit an error
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the NS and set the AST
|
// Create the NS and set the AST
|
||||||
auto ns =
|
auto ns =
|
||||||
makeNamespace(ctx, name, llvm::Optional(llvm::StringRef(importedFile)));
|
makeNamespace(ctx, name, llvm::Optional(llvm::StringRef(importedFile)));
|
||||||
|
|
||||||
if (mlir::failed(ns->expandTree(maybeAst.getValue()))) {
|
auto errs = ns->expandTree(maybeAst.getValue());
|
||||||
|
if (errs) {
|
||||||
SMGR_LOG("Couldn't set the AST for namespace: " + name);
|
SMGR_LOG("Couldn't set the AST for namespace: " + name);
|
||||||
// The code that is calling this function has to flush the dia engine, so we
|
return MaybeNS::error(errs.getValue());
|
||||||
// don't have to emit an error
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ns;
|
return ns;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "serene/diagnostics.h"
|
||||||
#include "serene/linenoise.h"
|
#include "serene/linenoise.h"
|
||||||
#include "serene/serene.h"
|
#include "serene/serene.h"
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ static std::string banner =
|
||||||
|
|
||||||
static std::string art = "\n";
|
static std::string art = "\n";
|
||||||
|
|
||||||
|
// TODO: Change the default value to be OS agnostic
|
||||||
static cl::opt<std::string>
|
static cl::opt<std::string>
|
||||||
historyFile("h", cl::desc("The absolute path to the history file to use."),
|
historyFile("h", cl::desc("The absolute path to the history file to use."),
|
||||||
cl::value_desc("filename"), cl::init("~/.serene-repl.history"));
|
cl::value_desc("filename"), cl::init("~/.serene-repl.history"));
|
||||||
|
@ -67,6 +69,7 @@ int main(int argc, char *argv[]) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Read line
|
// Read line
|
||||||
std::string line;
|
std::string line;
|
||||||
|
std::string result;
|
||||||
std::string prompt = ctx->getCurrentNS().name + "> ";
|
std::string prompt = ctx->getCurrentNS().name + "> ";
|
||||||
|
|
||||||
auto quit = linenoise::Readline(prompt.c_str(), line);
|
auto quit = linenoise::Readline(prompt.c_str(), line);
|
||||||
|
@ -75,8 +78,15 @@ int main(int argc, char *argv[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::outs() << "echo: '" << line << "'"
|
auto maybeAst = serene::read(*ctx, line);
|
||||||
<< "\n";
|
|
||||||
|
if (!maybeAst) {
|
||||||
|
serene::throwErrors(*ctx, maybeAst.getError());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
serene::print(*ctx, maybeAst.getValue(), result);
|
||||||
|
llvm::outs() << result << "\n";
|
||||||
|
|
||||||
// Add text to history
|
// Add text to history
|
||||||
linenoise::AddHistory(line.c_str());
|
linenoise::AddHistory(line.c_str());
|
||||||
|
|
|
@ -287,13 +287,16 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto runLoc = reader::LocationRange::UnknownLocation(inputNS);
|
auto runLoc = reader::LocationRange::UnknownLocation(inputNS);
|
||||||
auto ns = ctx->sourceManager.readNamespace(*ctx, inputNS, runLoc);
|
auto maybeNS = ctx->sourceManager.readNamespace(*ctx, inputNS, runLoc);
|
||||||
|
|
||||||
if (!ns) {
|
if (!maybeNS) {
|
||||||
|
throwErrors(*ctx, maybeNS.getError());
|
||||||
return (int)std::errc::no_such_file_or_directory;
|
return (int)std::errc::no_such_file_or_directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ns = maybeNS.getValue();
|
||||||
|
|
||||||
ctx->insertNS(ns);
|
ctx->insertNS(ns);
|
||||||
|
|
||||||
switch (emitAction) {
|
switch (emitAction) {
|
||||||
|
@ -303,6 +306,7 @@ int main(int argc, char *argv[]) {
|
||||||
llvm::outs() << exprs::astToString(&ast) << "\n";
|
llvm::outs() << exprs::astToString(&ast) << "\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Action::DumpSLIR:
|
case Action::DumpSLIR:
|
||||||
case Action::DumpMLIR:
|
case Action::DumpMLIR:
|
||||||
case Action::DumpLIR: {
|
case Action::DumpLIR: {
|
||||||
|
|
Loading…
Reference in New Issue