Add SLIR skeleton to start the generator
This commit is contained in:
parent
bfac2eff3f
commit
616dca53fb
|
@ -27,6 +27,10 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
|||
set(BIN_DIR ${CMAKE_SOURCE_DIR}/bin)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
|
||||
#set(CMAKE_CXX_LINK_EXECUTABLE "ld.lld")
|
||||
#set(CMAKE_C_LINK_EXECUTABLE "ld.lld")
|
||||
#set(LLVM_USE_LINKER "ld.lld")
|
||||
#set(LLVM_ENABLE_LLD ON)
|
||||
set(CMAKE_CXX_CLANG_TIDY clang-tidy)
|
||||
# Let's ensure -std=c++xx instead of -std=g++xx
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
@ -61,7 +65,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
|||
find_package(LLVM REQUIRED CONFIG)
|
||||
find_package(MLIR REQUIRED CONFIG)
|
||||
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
message(STATUS "Found LLVM ${LLVM_PAsCKAGE_VERSION}")
|
||||
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
|
||||
message(STATUS "Using MLIRConfig.cmake in: ${MLIR_DIR}")
|
||||
|
||||
|
@ -89,16 +93,6 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
|||
|
||||
llvm_map_components_to_libnames(llvm_libs support core irreader)
|
||||
|
||||
|
||||
# Formatting library
|
||||
FetchContent_Declare(
|
||||
fmtlib
|
||||
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
|
||||
GIT_TAG 7.0.1
|
||||
)
|
||||
FetchContent_MakeAvailable(fmtlib)
|
||||
|
||||
|
||||
# The compiled library code is here
|
||||
add_subdirectory(src/serene)
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/**
|
||||
* Serene programming language.
|
||||
*
|
||||
|
@ -77,8 +76,8 @@ int main(int argc, char *argv[]) {
|
|||
auto &ast = maybeAst.getValue();
|
||||
|
||||
auto ctx = makeSereneContext();
|
||||
auto ns = makeNamespace(ctx, "user", llvm::None);
|
||||
auto afterAst = reader::analyze(ctx, ast);
|
||||
auto ns = makeNamespace(*ctx, "user", llvm::None);
|
||||
auto afterAst = reader::analyze(*ctx, ast);
|
||||
|
||||
if (afterAst) {
|
||||
dump(afterAst.getValue());
|
||||
|
|
8
builder
8
builder
|
@ -3,11 +3,9 @@
|
|||
command=$1
|
||||
|
||||
|
||||
export CCC_CC=clang
|
||||
export CCC_CXX=clang++
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
|
||||
export CC=$(which clang)
|
||||
export CXX=$(which clang++)
|
||||
export LDFLAGS="-fuse-ld=lld"
|
||||
ROOT_DIR=`pwd`
|
||||
BUILD_DIR=$ROOT_DIR/build
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
add_subdirectory("serene/sir/")
|
||||
add_subdirectory("serene/slir/")
|
||||
|
|
|
@ -25,9 +25,12 @@
|
|||
#ifndef SERENE_CONTEXT_H
|
||||
#define SERENE_CONTEXT_H
|
||||
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "serene/environment.h"
|
||||
#include "serene/namespace.h"
|
||||
#include "serene/slir/dialect.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <memory>
|
||||
|
||||
namespace serene {
|
||||
|
||||
|
@ -44,12 +47,14 @@ class SereneContext {
|
|||
std::string current_ns;
|
||||
|
||||
public:
|
||||
mlir::MLIRContext mlirContext;
|
||||
|
||||
/// Insert the given `ns` into the context. The Context object is
|
||||
/// the owner of all the namespaces. The `ns` will overwrite any
|
||||
/// namespace with the same name.
|
||||
void insertNS(std::shared_ptr<Namespace> ns);
|
||||
|
||||
/// Sets the name 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
|
||||
/// will fail if the namespace does not exist in the namespace table.
|
||||
bool setCurrentNS(llvm::StringRef ns_name);
|
||||
|
@ -57,12 +62,15 @@ public:
|
|||
std::shared_ptr<Namespace> getCurrentNS();
|
||||
|
||||
std::shared_ptr<Namespace> getNS(llvm::StringRef ns_name);
|
||||
SereneContext(){};
|
||||
|
||||
SereneContext() {
|
||||
mlirContext.getOrLoadDialect<serene::slir::SereneDialect>();
|
||||
};
|
||||
};
|
||||
|
||||
/// Creates a new context object. Contexts are used through out the compilation
|
||||
/// process to store the state
|
||||
SereneContext makeSereneContext();
|
||||
std::unique_ptr<SereneContext> makeSereneContext();
|
||||
|
||||
}; // namespace serene
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace exprs {
|
|||
/// So it won't cast to actual numeric types and it has a string container
|
||||
/// to hold the parsed value.
|
||||
struct Number : public Expression {
|
||||
// TODO: Use a variant here instead
|
||||
std::string value;
|
||||
|
||||
bool isNeg;
|
||||
|
@ -53,6 +54,9 @@ struct Number : public Expression {
|
|||
|
||||
static bool classof(const Expression *e);
|
||||
|
||||
// TODO: This is horrible, we need to fix it after the mvp
|
||||
int toI64();
|
||||
|
||||
~Number() = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <llvm/ADT/StringRef.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <memory>
|
||||
#include <mlir/IR/Value.h>
|
||||
#include <mlir/Support/LogicalResult.h>
|
||||
#include <string>
|
||||
|
||||
|
@ -64,6 +65,7 @@ public:
|
|||
/// Which is a mapping from names to AST nodes ( no evaluation ).
|
||||
Environment<std::string, exprs::Node> semanticEnv;
|
||||
|
||||
Environment<llvm::StringRef, mlir::Value> symbolTable;
|
||||
Namespace(llvm::StringRef ns_name, llvm::Optional<llvm::StringRef> filename);
|
||||
|
||||
exprs::Ast &getTree();
|
||||
|
|
|
@ -28,9 +28,9 @@ set(HEADER_LIST
|
|||
"${INCLUDE_DIR}/serene/errors/traits.h"
|
||||
|
||||
|
||||
# "${INCLUDE_DIR}/serene/sir/sir.hpp"
|
||||
# "${INCLUDE_DIR}/serene/sir/dialect.hpp"
|
||||
# "${INCLUDE_DIR}/serene/sir/generator.hpp"
|
||||
"${INCLUDE_DIR}/serene/slir/slir.h"
|
||||
"${INCLUDE_DIR}/serene/slir/dialect.h"
|
||||
"${INCLUDE_DIR}/serene/slir/generator.h"
|
||||
"${INCLUDE_DIR}/serene/namespace.h")
|
||||
|
||||
# Make an automatic library - will be static or dynamic based on user setting
|
||||
|
@ -58,10 +58,10 @@ add_library(serene
|
|||
errors/error.cpp
|
||||
|
||||
# IR
|
||||
# sir/sir.cpp
|
||||
# sir/dialect.cpp
|
||||
# sir/value_op.cpp
|
||||
# sir/generator.cpp
|
||||
slir/slir.cpp
|
||||
slir/dialect.cpp
|
||||
slir/value_op.cpp
|
||||
slir/generator.cpp
|
||||
${HEADER_LIST})
|
||||
|
||||
|
||||
|
@ -81,6 +81,6 @@ target_include_directories(serene PRIVATE ${INCLUDE_DIR})
|
|||
target_include_directories(serene PUBLIC ${PROJECT_BINARY_DIR})
|
||||
|
||||
# This depends on (header only) boost
|
||||
target_link_libraries(serene ${llvm_libs} fmt::fmt)
|
||||
target_link_libraries(serene ${llvm_libs})
|
||||
source_group(TREE "${INCLUDE_DIR}" PREFIX "Header Files" FILES ${HEADER_LIST})
|
||||
#target_precompile_headers(serene PRIVATE ${HEADER_LIST})
|
||||
|
|
|
@ -58,5 +58,7 @@ std::shared_ptr<Namespace> SereneContext::getCurrentNS() {
|
|||
return nullptr;
|
||||
};
|
||||
|
||||
SereneContext makeSereneContext() { return SereneContext(); };
|
||||
std::unique_ptr<SereneContext> makeSereneContext() {
|
||||
return std::make_unique<SereneContext>();
|
||||
};
|
||||
}; // namespace serene
|
||||
|
|
|
@ -42,5 +42,7 @@ bool Number::classof(const Expression *e) {
|
|||
return e->getType() == ExprType::Number;
|
||||
};
|
||||
|
||||
int Number::toI64() { return std::stoi(this->value); };
|
||||
|
||||
} // namespace exprs
|
||||
} // namespace serene
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "serene/llvm/IR/Value.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include <fmt/core.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
|
|
@ -5,6 +5,15 @@ find_package(Catch2 REQUIRED)
|
|||
add_executable(tests serenetests.cpp)
|
||||
add_dependencies(tests SereneDialectGen)
|
||||
add_dependencies(tests serene)
|
||||
target_link_libraries(tests PRIVATE
|
||||
serene
|
||||
${llvm_libs}
|
||||
MLIRAnalysis
|
||||
MLIRIR
|
||||
MLIRParser
|
||||
MLIRSideEffectInterfaces
|
||||
MLIRTransforms
|
||||
)
|
||||
|
||||
target_compile_features(tests PRIVATE cxx_std_17)
|
||||
|
||||
|
|
|
@ -31,26 +31,26 @@ namespace serene {
|
|||
|
||||
TEST_CASE("Context tests", "[context]") {
|
||||
auto ctx = makeSereneContext();
|
||||
auto ns = ctx.getNS("blah");
|
||||
auto ns = ctx->getNS("blah");
|
||||
|
||||
REQUIRE_FALSE(ns);
|
||||
|
||||
auto userNs = makeNamespace(ctx, "user", llvm::Optional<llvm::StringRef>("/some/file"));
|
||||
auto userNs = makeNamespace(*ctx, "user", llvm::Optional<llvm::StringRef>("/some/file"));
|
||||
|
||||
CHECK(userNs->name == "user");
|
||||
REQUIRE(userNs->filename);
|
||||
CHECK(userNs->filename.getValue() == "/some/file");
|
||||
|
||||
ns = ctx.getNS("user");
|
||||
ns = ctx->getNS("user");
|
||||
|
||||
REQUIRE(ns);
|
||||
CHECK(ns->name == userNs->name);
|
||||
|
||||
|
||||
/// Creating new ns with the same name overrides the old one
|
||||
auto userNs1 = makeNamespace(ctx, "user", llvm::Optional<llvm::StringRef>("/some/other/file"));
|
||||
auto userNs1 = makeNamespace(*ctx, "user", llvm::Optional<llvm::StringRef>("/some/other/file"));
|
||||
|
||||
ns = ctx.getNS("user");
|
||||
ns = ctx->getNS("user");
|
||||
|
||||
REQUIRE(ns);
|
||||
CHECK(ns->name == userNs1->name);
|
||||
|
@ -61,15 +61,15 @@ TEST_CASE("Context tests", "[context]") {
|
|||
|
||||
TEST_CASE("Get and Set current namespace", "[context]") {
|
||||
auto ctx = makeSereneContext();
|
||||
auto userNs = makeNamespace(ctx, "user", llvm::Optional<llvm::StringRef>("/some/file"));
|
||||
auto userNs = makeNamespace(*ctx, "user", llvm::Optional<llvm::StringRef>("/some/file"));
|
||||
|
||||
auto isSet = ctx.setCurrentNS("user");
|
||||
auto isSet = ctx->setCurrentNS("user");
|
||||
|
||||
REQUIRE(isSet);
|
||||
CHECK(ctx.getCurrentNS() == userNs);
|
||||
CHECK(ctx->getCurrentNS() == userNs);
|
||||
|
||||
isSet = ctx.setCurrentNS("user1");
|
||||
isSet = ctx->setCurrentNS("user1");
|
||||
REQUIRE_FALSE(isSet);
|
||||
CHECK(ctx.getCurrentNS() == userNs);
|
||||
CHECK(ctx->getCurrentNS() == userNs);
|
||||
};
|
||||
} // namespace serene
|
||||
|
|
|
@ -82,30 +82,30 @@ TEST_CASE("List Expression", "[expression]") {
|
|||
|
||||
TEST_CASE("List semantic analysis of 'def'", "[semantic]") {
|
||||
auto ctx = makeSereneContext();
|
||||
auto ns = makeNamespace(ctx, "user", llvm::None);
|
||||
auto ns = makeNamespace(*ctx, "user", llvm::None);
|
||||
auto ast = reader::read("(def (a) b)");
|
||||
auto afterAst = reader::analyze(ctx, ast.getValue());
|
||||
auto afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE_FALSE(afterAst);
|
||||
// Fetch the first error
|
||||
CHECK(afterAst.getError()[0]->toString() == "<Error E1: >");
|
||||
|
||||
ast = reader::read("(def a)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE_FALSE(afterAst);
|
||||
CHECK(afterAst.getError()[0]->toString() == "<Error E2: Expected 3 got 2>");
|
||||
|
||||
ast = reader::read("(def a b c)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE_FALSE(afterAst);
|
||||
CHECK(afterAst.getError()[0]->toString() == "<Error E2: Expected 3 got 4>");
|
||||
|
||||
ast = reader::read("(def a b)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) == "<Def a -> <Symbol b>>");
|
||||
|
||||
ast = reader::read("(def a (fn () a))");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
"<Def a -> <Fn a <List -> to <Symbol a>>>");
|
||||
|
@ -113,41 +113,41 @@ TEST_CASE("List semantic analysis of 'def'", "[semantic]") {
|
|||
|
||||
TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
|
||||
auto ctx = makeSereneContext();
|
||||
auto ns = makeNamespace(ctx, "user", llvm::None);
|
||||
auto ns = makeNamespace(*ctx, "user", llvm::None);
|
||||
auto ast = reader::read("(fn)");
|
||||
auto afterAst = reader::analyze(ctx, ast.getValue());
|
||||
auto afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE_FALSE(afterAst);
|
||||
REQUIRE(afterAst.getError().size() == 1);
|
||||
CHECK(afterAst.getError()[0]->toString() ==
|
||||
"<Error E3: The argument list is mandatory.>");
|
||||
|
||||
ast = reader::read("(fn ())");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) == "<Fn ___fn___0 <List -> to <>>");
|
||||
|
||||
ast = reader::read("(fn (a b c) a a a)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
"<Fn ___fn___1 <List <Symbol a> <Symbol b> <Symbol c>> to <Symbol a> <Symbol a> <Symbol a>>"
|
||||
);
|
||||
|
||||
ast = reader::read("(fn () a b)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
"<Fn ___fn___2 <List -> to <Symbol a> <Symbol b>>");
|
||||
|
||||
ast = reader::read("(fn (x) (fn (y) x) z)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
"<Fn ___fn___4 <List <Symbol x>> to <Fn ___fn___3 <List <Symbol y>> to <Symbol x>> <Symbol z>>"
|
||||
);
|
||||
|
||||
ast = reader::read("(fn (x) (def a b) (def b c))");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
"<Fn ___fn___5 <List <Symbol x>> to <Def a -> <Symbol b>> <Def b -> <Symbol c>>>");
|
||||
|
@ -155,26 +155,26 @@ TEST_CASE("List semantic analysis for 'fn'", "[semantic]") {
|
|||
|
||||
TEST_CASE("Complex semantic analysis", "[semantic]") {
|
||||
auto ctx = makeSereneContext();
|
||||
auto ns = makeNamespace(ctx, "user", llvm::None);
|
||||
auto ns = makeNamespace(*ctx, "user", llvm::None);
|
||||
auto ast =
|
||||
reader::read("(def a (fn (x) x))\n((def b (fn (x) (fn (y) y))))\n\n");
|
||||
auto afterAst = reader::analyze(ctx, ast.getValue());
|
||||
auto afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
"<Def a -> <Fn a <List <Symbol x>> to <Symbol x>>> <Call <Def b -> <Fn b <List <Symbol x>> to <Fn ___fn___1 <List <Symbol y>> to <Symbol y>>>> >");
|
||||
|
||||
ctx = makeSereneContext();
|
||||
ns = makeNamespace(ctx, "user", llvm::None);
|
||||
ns = makeNamespace(*ctx, "user", llvm::None);
|
||||
ast = reader::read("((a b))");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE_FALSE(afterAst);
|
||||
auto errs = afterAst.getError();
|
||||
CHECK(errs[0]->toString() == "<Error E5: Can't resolve the symbol 'a'>");
|
||||
|
||||
ctx = makeSereneContext();
|
||||
ns = makeNamespace(ctx, "user", llvm::None);
|
||||
ns = makeNamespace(*ctx, "user", llvm::None);
|
||||
ast = reader::read("(def a (fn (x) x)) (a b)");
|
||||
afterAst = reader::analyze(ctx, ast.getValue());
|
||||
afterAst = reader::analyze(*ctx, ast.getValue());
|
||||
REQUIRE(afterAst);
|
||||
|
||||
CHECK(astToString(&afterAst.getValue()) ==
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace serene {
|
|||
TEST_CASE("Namespace tests", "[namespace]") {
|
||||
auto ctx = makeSereneContext();
|
||||
auto userNs =
|
||||
makeNamespace(ctx, "user", llvm::Optional<llvm::StringRef>("/some/file"));
|
||||
makeNamespace(*ctx, "user", llvm::Optional<llvm::StringRef>("/some/file"));
|
||||
|
||||
auto r = new reader::Reader("(x 1) (def b a)");
|
||||
|
||||
|
|
Loading…
Reference in New Issue