Skip to content

Commit

Permalink
Extend bootstrap parser (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Feb 4, 2024
1 parent 46fdc70 commit edfe1f3
Show file tree
Hide file tree
Showing 46 changed files with 935 additions and 220 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci-cpp.yml
Expand Up @@ -104,6 +104,7 @@ jobs:
# if: github.event_name != 'pull_request'
env:
SPICE_STD_DIR: /home/runner/work/spice/spice/std
SPICE_BOOTSTRAP_DIR: /home/runner/work/spice/spice/src-bootstrap
run: |
cd ./bin/test
./spicetest --skip-github-tests
Expand All @@ -112,6 +113,7 @@ jobs:
# if: github.event_name == 'pull_request'
# env:
# SPICE_STD_DIR: /home/runner/work/spice/spice/std
# SPICE_BOOTSTRAP_DIR: /home/runner/work/spice/spice/src-bootstrap
# run: |
# cd ./bin/test
# valgrind -q --leak-check=full ./spicetest --skip-github-tests --leak-detection
Expand Down
58 changes: 4 additions & 54 deletions media/test-project/test.spice
@@ -1,62 +1,12 @@
import "std/data/map";

f<int> main() {
Map<int, string> map;
assert map.getSize() == 0l;
assert map.isEmpty();
map.insert(1, "Hello");
assert map.getSize() == 1l;
assert !map.isEmpty();
map.insert(2, "World");
assert map.getSize() == 2l;
map.insert(3, "Foo");
assert map.getSize() == 3l;
map.insert(4, "Bar");
assert map.getSize() == 4l;
assert map.contains(1);
assert map.contains(2);
assert map.contains(3);
assert map.contains(4);
assert map.get(1) == "Hello";
assert map.get(2) == "World";
assert map.get(3) == "Foo";
assert map.get(4) == "Bar";
map.remove(2);
assert map.getSize() == 3l;
assert !map.contains(2);
assert !map.isEmpty();
map.remove(1);
assert map.getSize() == 2l;
assert !map.contains(1);
assert !map.isEmpty();
string& foo = map.get(3);
assert foo == "Foo";
foo = "Baz";
assert map.get(3) == "Baz";
Result<string> bar = map.getSafe(4);
assert bar.isOk();
assert bar.unwrap() == "Bar";
Result<string> baz = map.getSafe(5);
assert baz.isErr();
map.remove(3);
assert map.getSize() == 1l;
assert !map.contains(3);
assert !map.isEmpty();
map.remove(4);
assert map.getSize() == 0l;
assert !map.contains(4);
assert map.isEmpty();
}

/*import "../../src-bootstrap/lexer/lexer";
import "../../src-bootstrap/parser/parser";
import "../../src-bootstrap/ast/ast-nodes";
import "bootstrap/lexer/lexer";
import "bootstrap/parser/parser";
import "bootstrap/ast/ast-nodes";

f<int> main() {
Lexer lexer = Lexer("./test-file.spice");
Parser parser = Parser(lexer);
ASTEntryNode* entryNode = parser.parse();
}*/
}

/*f<int> main() {
int i = 123; // Captured by ref
Expand Down
38 changes: 36 additions & 2 deletions src-bootstrap/ast/ast-nodes.spice
Expand Up @@ -205,6 +205,27 @@ public type ASTElseStmtNode struct /*: IVisitable*/ {

}

// ========================================================= SwitchStmtNode ======================================================

public type ASTSwitchStmtNode struct /*: IVisitable*/ {
compose public ASTNode node

}

// ========================================================= CaseBranchNode ======================================================

public type ASTCaseBranchNode struct /*: IVisitable*/ {
compose public ASTNode node

}

// ======================================================== DefaultBranchNode ====================================================

public type ASTDefaultBranchNode struct /*: IVisitable*/ {
compose public ASTNode node

}

// ===================================================== AnonymousBlockStmtNode ==================================================

public type ASTAnonymousBlockStmtNode struct /*: IVisitable*/ {
Expand Down Expand Up @@ -311,8 +332,7 @@ type SpecifierType enum {

public type ASTSpecifierNode struct /*: IVisitable*/ {
compose public ASTNode node

public SpecifierType specifierType = SpecifierType::TY_NONE
public SpecifierType specifierType = SpecifierType::NONE
}

// ========================================================== ModAttrNode ========================================================
Expand Down Expand Up @@ -350,6 +370,13 @@ public type ASTAttrNode struct /*: IVisitable*/ {

}

// ========================================================= ConstantLstNode =====================================================

public type ASTConstantLstNode struct /*: IVisitable*/ {
compose public ASTNode node

}

// ========================================================= ReturnStmtNode ======================================================

public type ASTReturnStmtNode struct /*: IVisitable*/ {
Expand All @@ -371,6 +398,13 @@ public type ASTContinueStmtNode struct /*: IVisitable*/ {

}

// ======================================================= FallthroughStmtNode ===================================================

public type ASTFallthroughStmtNode struct /*: IVisitable*/ {
compose public ASTNode node

}

// ========================================================= AssertStmtNode ======================================================

public type ASTAssertStmtNode struct /*: IVisitable*/ {
Expand Down
4 changes: 2 additions & 2 deletions src-bootstrap/compiler-pass.spice
Expand Up @@ -6,8 +6,8 @@ type ICompilerPass interface {
p changeToParentScope(ScopeType);
}

type CompilerPass struct : ICompilerPass {
GlobalResourceManager& globalResourceManager
type CompilerPass struct {
GlobalResourceManager& resourceManager
const CliOptions& cliOptions
SourceFile* sourceFile
Scope* rootScope
Expand Down
98 changes: 70 additions & 28 deletions src-bootstrap/global/global-resource-manager.spice
@@ -1,8 +1,17 @@
// Std imports
import "std/type/byte";
import "std/data/vector";
import "std/data/unordered-map";
import "std/time/timer";

// Own imports
import "../global/runtime-module-manager";
import "../linker/external-linker-interface";
import "../reader/code-loc";
import "../util/timer";
import "../util/memory";
import "../util/block-allocator";
import "../bindings/llvm/llvm";
import "../source-file";
import "../driver";

// Constants
Expand All @@ -11,47 +20,80 @@ public const string LTO_FILE_NAME = "lto-module";

/**
* The GlobalResourceManager is instantiated at startup of the compiler and serves as distribution point for globally used assets.
* This component owns all SourceFile instances and AST nodes and therefore is the resource root of the compiler.
* Other components of the compiler can request the required global resources from the GlobalResourceManager.
*/
public type GlobalResourceManager struct {
UnorderedMap<String, SourceFile*> sourceFiles
Vector<ASTNode> astNodes
const CliOptions& cliOptions
ExternalLinkerInterface linker
CacheManager cacheManager
RuntimeModuleManager runtimeModuleManager
llvm::Context context
llvm::IRBuilder builder
llvm::Module* ltoModule
llvm::TargetMachine* targetMachine
Timer totalTimer
ErrorManager errorManager
public llvm::Context context
public llvm::IRBuilder builder
public llvm::Module ltoModule
public llvm::TargetMachine targetMachine
public DefaultMemoryManager memoryManager
public Vector<String> compileTimeStringValues
public BlockAllocator<ASTNode> astNodeAlloc = BlockAllocator<ASTNode>(memoryManager) // Used to allocate all AST nodes
public UnorderedMap<String, heap SourceFile*> sourceFiles // The GlobalResourceManager owns all source files
public Vector<ASTNode*> astNodes
public const CliOptions& cliOptions
public ExternalLinkerInterface linker
public CacheManager cacheManager
public RuntimeModuleManager runtimeModuleManager
public Timer totalTimer
public ErrorManager errorManager
unsigned long nextCustomTypeId = BYTE_MAX_VALUE + 1 // Start at 256 because all primitive types come first
}

public p GlobalResourceManager.ctor(const CliOptions& cliOptions) {
this.cliOptions = cliOptions;
// ToDo: extend
}

public p GlobalResourceManager.dtor() {
// Delete all source files
foreach (const Pair<string, SourceFile *>& sourceFile : sourceFiles) {
//delete sourceFile.second;
// Initialize the required LLVM targets
if cliOptions.isNativeTarget {
llvm::initializeNativeTarget();
llvm::initializeNativeAsmPrinter();
} else {
llvm::initializeAllTargets();
llvm::initializeAllTargetMCs();
llvm::initializeAllAsmPrinters();
}

// Search after selected target
String error;
// ToDo: Lookup target

// Create target machine for LLVM
String cpuName = String("generic");
if cliOptions.isNativeTarget & cliOptions.usesCPUFeatures {
// Retrieve native CPU name and the supported CPU features
cpuName = llvm::sys::getHostCPUName();

}

// Delete target machine
//delete targetMachine;
// Create target machine
this.targetMachine = target.createTargetMachine(cpuName, cpuName.getRaw(), "", opt, llvm::Reloc::PIC_);

// Create lto module
if cliOptions.useLTO {
this.ltoModule = llvm::Module(LTO_FILE_NAME, context);
}
}

public p GlobalResourceManager.dtor() {
// Shutdown LLVM
llvm::llvm_shutdown();
}

public f<SourceFile*> GlobalResourceManager.createSourceFile(SourceFile* parent, const String& dependencyName, const FilePath& path, bool isStdFile) {
public f<heap SourceFile*> GlobalResourceManager.createSourceFile(SourceFile* parent, const String& depName, const FilePath& path, bool isStdFile) {
// Check if the source file was already added (e.g. by another source file that imports it)
const String filePathStr = path.toString();
if sourceFiles.contains(filePathStr) {
return sourceFiles.get[filePathStr];

// Create the new source file if it does not exist yet
if !sourceFiles.contains(filePathStr) {
//heap SourceFile* newSourceFile = new SourceFile(*this, parent, depName, path, isStdFile);
//this.sourceFiles.insert(filePathStr, newSourceFile);
}

// Create the new source file
SourceFile* newSourceFile = new SourceFile(parent, dependencyName, path, isStdFile);
newSourceFile.insert(filePathStr, newSourceFile);
return newSourceFile;
return this.sourceFiles.get(filePathStr);
}

public f<unsigned long> GlobalResourceManager.getNextCustomTypeId() {
return nextCustomTypeId++;
}
83 changes: 83 additions & 0 deletions src-bootstrap/global/runtime-module-manager.spice
@@ -0,0 +1,83 @@

const string STRING_RT_IMPORT_NAME = "__rt_string";
const string MEMORY_RT_IMPORT_NAME = "__rt_memory";
const string RTTI_RT_IMPORT_NAME = "__rt_rtti";

public type RuntimeModule enum {
STRING_RT = 1,
ARRAY_RT = 2,
OBJECT_RT = 4
}

type ModuleNamePair struct {
string importName
string fileName
}

public type RuntimeModuleManager struct {
GlobalResourceManager &resourceManager
UnorderedMap<RuntimeModule, SourceFile *> modules
}

public p RuntimeModuleManager.ctor(GlobalResourceManager &resourceManager) {
this.resourceManager = resourceManager;
}

public f<SourceFile *> RuntimeModuleManager.requestModule(SourceFile* parentSourceFile, RuntimeModule requestedModule) {
const string importName = resolveNamePair(requestedModule).importName;

// Check if the requested module is available already, if not load it
dyn rtFile = isModuleAvailable(requestedModule) ? getModule(requestedModule) : loadModule(parentSourceFile, requestedModule);

// Add the dependency to the parent source file
parentSourceFile.addDependency(rtFile, parentSourceFile.ast, importName, rtFile.filePath.str());
assert parentSourceFile.dependencies.contains(importName);
SourceFile* runtimeFile = parentSourceFile.dependencies.get(importName);
modules.insert(requestedModule, runtimeFile);

// Merge the module name registry with the one of the source file
parentSourceFile.mergeNameRegistries(*rtFile, importName);

// Tell the source file, that the requested runtime has been imported
parentSourceFile.importedRuntimeModules |= requestedModule;

return runtimeFile;
}

public f<SourceFile *> RuntimeModuleManager.getModule(RuntimeModule requestedModule) {
assert modules.contains(requestedModule);
return modules.get(requestedModule);
}

public f<bool> RuntimeModuleManager.isModuleAvailable(RuntimeModule requestedModule) {
return modules.contains(requestedModule);
}

public f<SourceFile *> RuntimeModuleManager.loadModule(SourceFile* parentSourceFile, RuntimeModule requestedModule) {
const ModuleNamePair namePair = resolveNamePair(requestedModule);
const string filePath = FileUtil::getStdDir() / "runtime" / fileName / ".spice";
assert filePath != parentSourceFile.filePath;

// Instruct the global resource manager to create a new source file
SourceFile* moduleSourceFile = resourceManager.createSourceFile(parentSourceFile, importName, filrPath, true);
moduleSourceFile.mainFile = false;

// Run frontend and first type checker run for the loaded source file
moduleSourceFile.runFrontEnd();
moduleSourceFile.runTypeCheckerPre();

return moduleSourceFile;
}

public f<ModuleNamePair> RuntimeModuleManager.resolveNamePair(RuntimeModule requestedModule) {
switch requestedModule {
case RuntimeModule::STRING_RT:
return ModuleNamePair{STRING_RT_IMPORT_NAME, "string_rt"};
case RuntimeModule::ARRAY_RT:
return ModuleNamePair{MEMORY_RT_IMPORT_NAME, "memory_rt"};
case RuntimeModule::OBJECT_RT:
return ModuleNamePair{RTTI_RT_IMPORT_NAME, "rtti_rt"};
default:
panic(Error("Requested unknown runtime module"));
}
}

0 comments on commit edfe1f3

Please sign in to comment.