Add SLIR skeleton to start the generator

This commit is contained in:
Sameer Rahmani 2021-06-08 22:01:08 +01:00
parent bfac2eff3f
commit 616dca53fb
15 changed files with 80 additions and 63 deletions

View File

@ -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)

View File

@ -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());

View File

@ -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

View File

@ -1 +1 @@
add_subdirectory("serene/sir/")
add_subdirectory("serene/slir/")

View File

@ -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

View File

@ -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;
};

View File

@ -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();

View File

@ -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})

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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()) ==

View File

@ -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)");