Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic import of runtime modules #204

Merged
merged 5 commits into from
Sep 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ jobs:
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
version: v1.11.2
version: v1.11.3
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
9 changes: 8 additions & 1 deletion Options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,11 @@ if (SPICE_IS_GH_ACTIONS)
ADD_DEFINITIONS(-DSPICE_IS_GH_ACTIONS)
else()
message(STATUS "Spice: Running all the tests.")
endif()
endif()

# Add additional definitions
IF (WIN32)
ADD_DEFINITIONS(-DOS_WINDOWS)
ELSE()
ADD_DEFINITIONS(-DOS_UNIX)
ENDIF()
29 changes: 11 additions & 18 deletions media/test-project/os-test.spice
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*import "std/data/vector" as vec;
import "std/data/vector" as vec;
import "std/data/pair" as pair;

f<int> main() {
Expand All @@ -8,7 +8,7 @@ f<int> main() {

pair::Pair<int, string> p1 = pairVector.get(1);
printf("Hello %s!", p1.getSecond());
}*/
}

/*import "std/net/http" as http;

Expand All @@ -17,21 +17,14 @@ f<int> main() {
server.serve("/test", "Hello World!");
}*/

import "std/runtime/string_rt" as _rt_str;
/*public f<bool> src(bool x, bool y) {
return ((x ? 1 : 4) & (y ? 1 : 4)) == 0;
}

public f<int> tgt(int x, int y) {
return x ^ y;
}

f<int> main() {
//_rt_str::String s = _rt_str::String("Test");
//printf("%s", s.getRaw());
// Plus
printf("Result: %s\n", "Hello " + "World!");
string s1 = "Hello " + "World!";
printf("Result: %s\n", s1);
// Mul
printf("Result: %s\n", 4s * "Hi");
string s2 = "Hello " * 5;
printf("Result: %s\n", s2);
printf("Result: %s\n", 20 * 'a');
string s3 = 2 * 'c' * 7;
printf("Result: %s\n", s3);
//printf("%s", s1 + s2);
}
printf("Result: %d, %d", src(false, true), tgt(0, 1));
}*/
14 changes: 9 additions & 5 deletions src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
#include <util/CommonUtil.h>
#include <util/CompilerWarning.h>

AnalyzerVisitor::AnalyzerVisitor(const llvm::LLVMContext *context, const llvm::IRBuilder<> *builder,
const ThreadFactory &threadFactory, const SourceFile &sourceFile, CliOptions &options,
bool requiresMainFct, bool isStdFile)
: context(context), builder(builder), threadFactory(threadFactory), requiresMainFct(requiresMainFct), isStdFile(isStdFile) {
AnalyzerVisitor::AnalyzerVisitor(const llvm::LLVMContext *context, const llvm::IRBuilder<> *builder, const SourceFile &sourceFile,
CliOptions &options, RuntimeModules &runtimeModules, bool requiresMainFct, bool isStdFile)
: context(context), builder(builder), runtimeModules(runtimeModules), requiresMainFct(requiresMainFct), isStdFile(isStdFile) {
// Retrieve symbol table
this->currentScope = this->rootScope = sourceFile.symbolTable.get();

Expand Down Expand Up @@ -67,7 +66,7 @@ std::any AnalyzerVisitor::visitEntry(EntryNode *node) {
}

std::any AnalyzerVisitor::visitMainFctDef(MainFctDefNode *node) {
std::string mainSignature = MAIN_FUNCTION_NAME + "()";
std::string mainSignature = std::string(MAIN_FUNCTION_NAME) + "()";

if (runNumber == 1) { // First run
// Check if the function is already defined
Expand Down Expand Up @@ -2305,8 +2304,13 @@ std::any AnalyzerVisitor::visitCustomDataType(CustomDataTypeNode *node) {
}

SymbolType AnalyzerVisitor::insertAnonStringStructSymbol(const AstNode *declNode) {
// Insert anonymous string symbol
SymbolType stringStructType(TY_STRING, "", {.isStringStruct = true}, {});
currentScope->insertAnonymous(stringStructType, declNode);

// Enable string runtime
runtimeModules.stringRuntime = true;

return stringStructType;
}

Expand Down
26 changes: 14 additions & 12 deletions src/analyzer/AnalyzerVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
#include <llvm/IR/IRBuilder.h>
#include <llvm/Support/Host.h>

const std::string MAIN_FUNCTION_NAME = "main";
const std::string RETURN_VARIABLE_NAME = "result";
const std::string THIS_VARIABLE_NAME = "this";
const std::string FOREACH_DEFAULT_IDX_VARIABLE_NAME = "idx";
const std::string CTOR_VARIABLE_NAME = "ctor";
const std::string DTOR_VARIABLE_NAME = "dtor";
const std::string STRUCT_SCOPE_PREFIX = "struct:";
const std::string ENUM_SCOPE_PREFIX = "enum:";
const std::string UNUSED_VARIABLE_NAME = "_";
const char *const MAIN_FUNCTION_NAME = "main";
const char *const RETURN_VARIABLE_NAME = "result";
const char *const THIS_VARIABLE_NAME = "this";
const char *const FOREACH_DEFAULT_IDX_VARIABLE_NAME = "idx";
const char *const CTOR_VARIABLE_NAME = "ctor";
const char *const DTOR_VARIABLE_NAME = "dtor";
const char *const STRUCT_SCOPE_PREFIX = "struct:";
const char *const ENUM_SCOPE_PREFIX = "enum:";
const char *const UNUSED_VARIABLE_NAME = "_";
const std::vector<std::string> RESERVED_KEYWORDS = {"new", "switch", "case", "yield", "stash", "pick", "sync", "class"};

// Forward declarations
Expand All @@ -32,6 +32,7 @@ class LinkerInterface;
class SymbolTable;
class SymbolTableEntry;
class SourceFile;
struct RuntimeModules;

/**
* Visitor for analyzing a source file.
Expand All @@ -42,12 +43,13 @@ class SourceFile;
* - Type inference
* - Type checking
* - Resolve generic functions/procedure/structs
* - Detect usages of runtime modules
*/
class AnalyzerVisitor : public AstVisitor {
public:
// Constructors
explicit AnalyzerVisitor(const llvm::LLVMContext *context, const llvm::IRBuilder<> *builder, const ThreadFactory &threadFactory,
const SourceFile &sourceFile, CliOptions &options, bool requiresMainFct, bool stdFile);
explicit AnalyzerVisitor(const llvm::LLVMContext *context, const llvm::IRBuilder<> *builder, const SourceFile &sourceFile,
CliOptions &options, RuntimeModules &runtimeModules, bool requiresMainFct, bool stdFile);

// Friend classes
friend class OpRuleManager;
Expand Down Expand Up @@ -111,7 +113,7 @@ class AnalyzerVisitor : public AstVisitor {
const llvm::LLVMContext *context;
const llvm::IRBuilder<> *builder;
std::unique_ptr<OpRuleManager> opRuleManager;
const ThreadFactory &threadFactory;
RuntimeModules &runtimeModules;
bool requiresMainFct = true;
bool hasMainFunction = false;
bool isStdFile = false;
Expand Down
11 changes: 2 additions & 9 deletions src/analyzer/PreAnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,10 @@ std::any PreAnalyzerVisitor::visitImportStmt(ImportStmtNode *node) {
if (node->importPath.rfind("std/", 0) == 0) { // Include source file from standard library
std::string sourceFileIden = node->importPath.substr(node->importPath.find("std/") + 4);
// Find std library
std::string stdPath;
if (FileUtil::fileExists("/usr/lib/spice/std")) {
stdPath = "/usr/lib/spice/std/";
} else if (std::getenv("SPICE_STD_DIR") && FileUtil::dirExists(std::string(std::getenv("SPICE_STD_DIR")))) {
stdPath = std::string(std::getenv("SPICE_STD_DIR"));
if (stdPath.rfind(FileUtil::DIR_SEPARATOR) != stdPath.size() - 1)
stdPath += FileUtil::DIR_SEPARATOR;
} else {
std::string stdPath = FileUtil::getStdDir();
if (stdPath.empty())
throw SemanticError(node->codeLoc, STD_NOT_FOUND,
"Standard library could not be found. Check if the env var SPICE_STD_DIR exists");
}
// Check if source file exists
std::string defaultPath = stdPath + sourceFileIden + ".spice";
std::string osPath = stdPath + sourceFileIden + "_" + cliOptions.targetOs + ".spice";
Expand Down
4 changes: 1 addition & 3 deletions src/ast/AstNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ class AstNode {

SymbolType setEvaluatedSymbolType(const SymbolType &symbolType) {
size_t index = getSymbolTypeIndex();
// if (symbolTypes.capacity() <= index)
// symbolTypes.reserve(index + 1);
symbolTypes.insert(symbolTypes.begin() + index, symbolType);
return symbolType;
}
Expand Down Expand Up @@ -126,7 +124,7 @@ class AstNode {
const CodeLoc codeLoc;
size_t symbolTypeIndex = SIZE_MAX;
std::vector<SymbolType> symbolTypes;
CompileTimeValue compileTimeValue;
CompileTimeValue compileTimeValue = {};
std::string compileTimeStringValue;
bool hasDirectCompileTimeValue = false;
};
Expand Down
6 changes: 3 additions & 3 deletions src/cli/CliInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ void CliInterface::createInterface() {
std::string installPath = FileUtil::getSpiceBinDir();
FileUtil::createDirs(installPath);
installPath += FileUtil::getFileName(cliOptions.mainSourceFile.substr(0, cliOptions.mainSourceFile.length() - 6));
#ifdef OS_WINDOWS
#if OS_WINDOWS
installPath += ".exe";
#endif
cliOptions.outputPath = installPath;
Expand All @@ -48,7 +48,7 @@ void CliInterface::createInterface() {
cliOptions.outputPath = ".";
if (cliOptions.outputPath == "." || cliOptions.outputPath == "..") {
cliOptions.outputPath = FileUtil::getFileName(cliOptions.mainSourceFile.substr(0, cliOptions.mainSourceFile.length() - 6));
#ifdef OS_WINDOWS
#if OS_WINDOWS
cliOptions.outputPath += ".exe";
#endif
}
Expand Down Expand Up @@ -307,7 +307,7 @@ void CliInterface::addUninstallSubcommand() {
subCmd->callback([&]() {
std::string installPath = FileUtil::getSpiceBinDir();
installPath += FileUtil::getFileName(cliOptions.mainSourceFile.substr(0, cliOptions.mainSourceFile.length() - 6));
#ifdef OS_WINDOWS
#if OS_WINDOWS
installPath += ".exe";
#endif
if (!FileUtil::fileExists(installPath)) {
Expand Down
7 changes: 0 additions & 7 deletions src/cli/CliInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@

#include "../../lib/cli11/CLI11.hpp"

#ifdef __unix__
#define OS_UNIX
#elif defined(_WIN32) || defined(WIN32)
#define OS_WINDOWS
#endif

/**
* Representation of the various cli options
*/
Expand Down Expand Up @@ -42,7 +36,6 @@ class CliInterface {
public:
// Constructors
explicit CliInterface() = default;
explicit CliInterface(CliOptions options) : cliOptions(std::move(options)) {}

// Public methods
void createInterface();
Expand Down
70 changes: 44 additions & 26 deletions src/dependency/SourceFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
#include <visualizer/CSTVisualizerVisitor.h>

SourceFile::SourceFile(llvm::LLVMContext *context, llvm::IRBuilder<> *builder, ThreadFactory &threadFactory,
LinkerInterface &linker, CliOptions &options, SourceFile *parent, std::string name,
const std::string &filePath, bool stdFile)
: context(context), builder(builder), threadFactory(threadFactory), linker(linker), name(std::move(name)), filePath(filePath),
stdFile(stdFile), parent(parent), options(options) {
RuntimeModules &runtimeModules, LinkerInterface &linker, CliOptions &options, SourceFile *parent,
std::string name, const std::string &filePath, bool stdFile)
: context(context), builder(builder), threadFactory(threadFactory), runtimeModules(runtimeModules), linker(linker),
name(std::move(name)), filePath(filePath), stdFile(stdFile), parent(parent), options(options) {
this->objectFilePath = options.outputDir + FileUtil::DIR_SEPARATOR + FileUtil::getFileName(filePath) + ".o";

// Deduce fileName and fileDir
Expand Down Expand Up @@ -71,8 +71,8 @@ void SourceFile::visualizeCST() {
dotCode += " label=\"" + replacedFilePath + "\";\n ";

// Visualize the imported source files
for (const auto &[_, sourceFile] : dependencies)
sourceFile.first->visualizeCST();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->visualizeCST();

// Generate dot code for this source file
CSTVisualizerVisitor visualizerVisitor(antlrCtx.lexer, antlrCtx.parser);
Expand Down Expand Up @@ -106,8 +106,8 @@ void SourceFile::visualizeCST() {

void SourceFile::buildAST() {
// Transform the imported source files
for (const auto &[_, sourceFile] : dependencies)
sourceFile.first->buildAST();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->buildAST();

// Transform this source file
AstBuilderVisitor astBuilder(ast.get(), filePath);
Expand All @@ -126,8 +126,8 @@ void SourceFile::visualizeAST() {
dotCode += " label=\"" + replacedFilePath + "\";\n ";

// Visualize the imported source files
for (const auto &[_, sourceFile] : dependencies)
sourceFile.first->visualizeAST();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->visualizeAST();

// Generate dot code for this source file
ASTVisualizerVisitor visualizerVisitor(ast.get());
Expand Down Expand Up @@ -165,9 +165,9 @@ void SourceFile::preAnalyze() {
antlrCtx.parser->reset();

// Pre-analyze the imported source files
for (const auto &[_, sourceFile] : dependencies) {
sourceFile.first->buildAST();
sourceFile.first->preAnalyze();
for (const auto &sourceFile : dependencies) {
sourceFile.second.first->buildAST();
sourceFile.second.first->preAnalyze();
}
}

Expand All @@ -188,7 +188,7 @@ void SourceFile::analyze() {
}

// Analyze this source file
analyzer = std::make_shared<AnalyzerVisitor>(context, builder, threadFactory, *this, options, parent == nullptr, stdFile);
analyzer = std::make_shared<AnalyzerVisitor>(context, builder, *this, options, runtimeModules, parent == nullptr, stdFile);
analyzer->visit(ast.get());
antlrCtx.parser->reset();
}
Expand All @@ -207,8 +207,27 @@ void SourceFile::reAnalyze() {
} while (repetitionRequired);

// Re-analyze the imported source files
for (const auto &[importName, sourceFile] : dependencies)
sourceFile.first->reAnalyze();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->reAnalyze();

// If this is the main source file, import the required runtime modules
if (parent == nullptr) {
std::vector<std::pair<std::string, std::string>> runtimeFiles;
if (runtimeModules.stringRuntime)
runtimeFiles.emplace_back("__rt_string", "string_rt");
if (runtimeModules.threadRuntime)
runtimeFiles.emplace_back("__rt_thread", "thread_rt");

std::string runtimePath = FileUtil::getStdDir() + "runtime" + FileUtil::DIR_SEPARATOR;
for (const auto &[importName, fileName] : runtimeFiles) {
addDependency(ast.get(), importName, runtimePath + fileName + ".spice", true);
auto &[stringRuntimeFile, _] = dependencies.at(importName);
stringRuntimeFile->buildAST();
stringRuntimeFile->preAnalyze();
stringRuntimeFile->analyze();
stringRuntimeFile->reAnalyze();
}
}

// Save the JSON version in the compiler output
compilerOutput.symbolTableString = symbolTable->toJSON().dump(2);
Expand All @@ -222,8 +241,8 @@ void SourceFile::reAnalyze() {

void SourceFile::generate() {
// Generate the imported source files
for (const auto &[_, sourceFile] : dependencies)
sourceFile.first->generate();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->generate();

// Generate this source file
generator = std::make_shared<GeneratorVisitor>(context, builder, threadFactory, linker, options, *this, objectFilePath);
Expand Down Expand Up @@ -257,8 +276,8 @@ void SourceFile::optimize() {
return;

// Optimize the imported source files
for (const auto &[_, sourceFile] : dependencies)
sourceFile.first->optimize();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->optimize();

generator->optimize();

Expand All @@ -275,8 +294,8 @@ void SourceFile::optimize() {

void SourceFile::emitObjectFile() {
// Optimize the imported source files
for (const auto &[_, sourceFile] : dependencies)
sourceFile.first->emitObjectFile();
for (const auto &sourceFile : dependencies)
sourceFile.second.first->emitObjectFile();

// Dump assembly code
if (options.dumpAssembly) { // GCOV_EXCL_START
Expand All @@ -302,10 +321,9 @@ void SourceFile::addDependency(const AstNode *declAstNode, const std::string &na
throw SemanticError(declAstNode->codeLoc, CIRCULAR_DEPENDENCY, "Circular import detected while importing '" + filePath + "'");

// Add the dependency
dependencies.insert(
{name,
{std::make_shared<SourceFile>(context, builder, threadFactory, linker, options, this, name, filePath, stdFile),
declAstNode}});
auto sourceFile = std::make_shared<SourceFile>(context, builder, threadFactory, runtimeModules, linker, options, this, name,
filePath, stdFile);
dependencies.insert({name, {sourceFile, declAstNode}});
}

bool SourceFile::isAlreadyImported(const std::string &filePathSearch) const {
Expand Down
Loading