From eb1ddec43332b9ce4b5655350f0a4079f125ec09 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sun, 3 Mar 2024 21:26:07 +0100 Subject: [PATCH] Extend bootstrap compiler --- .run/spice.run.xml | 2 +- media/test-project/test.spice | 71 +++------------- src-bootstrap/exception/cli-error.spice | 16 ++-- src-bootstrap/exception/lexer-error.spice | 8 +- src-bootstrap/exception/linker-error.spice | 10 ++- src-bootstrap/exception/parser-error.spice | 18 ++-- src-bootstrap/exception/semantic-error.spice | 58 ++++++++++--- src-bootstrap/irgenerator/ir-generator.spice | 70 +++++++++++++++- src-bootstrap/lexer/lexer.spice | 1 + .../linker/external-linker-interface.spice | 83 +++++++++++++++++++ src-bootstrap/parser/parser.spice | 2 +- src-bootstrap/util/block-allocator.spice | 22 ++--- src/typechecker/OpRuleManager.cpp | 3 + src/typechecker/TypeChecker.cpp | 7 +- std/io/filepath.spice | 6 +- 15 files changed, 269 insertions(+), 108 deletions(-) diff --git a/.run/spice.run.xml b/.run/spice.run.xml index 27a9da96e..f5034be42 100644 --- a/.run/spice.run.xml +++ b/.run/spice.run.xml @@ -1,5 +1,5 @@ - + diff --git a/media/test-project/test.spice b/media/test-project/test.spice index 5163ed34f..fdc13042e 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,62 +1,17 @@ -import "bootstrap/bindings/llvm/llvm" as llvm; -import "std/data/vector"; +import "std/os/env"; +import "bootstrap/lexer/lexer"; f main() { - llvm::initializeNativeTarget(); - llvm::initializeNativeAsmPrinter(); - - heap string targetTriple = llvm::getDefaultTargetTriple(); - string error; - llvm::Target target = llvm::getTargetFromTriple(targetTriple, &error); - llvm::TargetMachine targetMachine = target.createTargetMachine(targetTriple, "generic", "", llvm::LLVMCodeGenOptLevel::Default, llvm::LLVMRelocMode::Default, llvm::LLVMCodeModel::Default); - - llvm::LLVMContext context; - llvm::Module module = llvm::Module("test", context); - module.setDataLayout(targetMachine.createDataLayout()); - //module.setTargetTriple(targetTriple); // This emits target dependent information in the IR, which is not what we want here. - llvm::Builder builder = llvm::Builder(context); - - llvm::Type returnType = builder.getInt32Ty(); - Vector argTypes; - llvm::Type funcType = llvm::getFunctionType(returnType, argTypes); - llvm::Function func = llvm::Function(module, "main", funcType); - func.setLinkage(llvm::LLVMLinkage::ExternalLinkage); - - llvm::BasicBlock entry = llvm::BasicBlock(context, ""); - func.pushBack(entry); - builder.setInsertPoint(entry); - - llvm::Value calcResult = builder.createAdd(builder.getInt32(1), builder.getInt32(2), "calcResult"); - - llvm::Value helloWorldStr = builder.createGlobalStringPtr("Hello, world!\n", "helloWorldStr"); - Vector printfArgTypes; - printfArgTypes.pushBack(builder.getPtrTy()); - printfArgTypes.pushBack(builder.getInt32Ty()); - llvm::Type printfFuncType = llvm::getFunctionType(builder.getInt32Ty(), printfArgTypes, true); - llvm::Function printfFunc = module.getOrInsertFunction("printf", printfFuncType); - - Vector printfArgs; - printfArgs.pushBack(helloWorldStr); - printfArgs.pushBack(calcResult); - builder.createCall(printfFunc, printfArgs); - - builder.createRet(builder.getInt32(0)); - - assert !llvm::verifyFunction(func); - string output; - assert !llvm::verifyModule(module, &output); - - printf("Unoptimized IR:\n%s", module.print()); - - llvm::PassBuilderOptions pto; - llvm::PassBuilder passBuilder = llvm::PassBuilder(pto); - passBuilder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O2); - passBuilder.addPass(llvm::AlwaysInlinerPass()); - passBuilder.run(module, targetMachine); - - printf("Optimized IR:\n%s", module.print()); - - targetMachine.emitToFile(module, "this-is-a-test.o", llvm::LLVMCodeGenFileType::ObjectFile); + String filePath = getEnv("SPICE_STD_DIR") + "/../test/test-files/bootstrap-compiler/standalone-lexer-test/test-file.spice"; + Lexer lexer = Lexer(filePath.getRaw()); + unsigned long tokenCount = 0l; + while (!lexer.isEOF()) { + Token token = lexer.getToken(); + token.print(); + lexer.advance(); + tokenCount++; + } + printf("\nLexed tokens: %d\n", tokenCount); } /*import "bootstrap/util/block-allocator"; @@ -65,5 +20,5 @@ import "bootstrap/util/memory"; f main() { DefaultMemoryManager defaultMemoryManager; IMemoryManager* memoryManager = &defaultMemoryManager; - BlockAllocator allocator = BlockAllocator(memoryManager, 10); + BlockAllocator allocator = BlockAllocator(memoryManager, 10l); }*/ \ No newline at end of file diff --git a/src-bootstrap/exception/cli-error.spice b/src-bootstrap/exception/cli-error.spice index bcf174f76..d945b3191 100644 --- a/src-bootstrap/exception/cli-error.spice +++ b/src-bootstrap/exception/cli-error.spice @@ -32,11 +32,13 @@ public p CliError.ctor(const CliErrorType errorType, const string message) { * @return Prefix string for the error type */ f CliError.getMessagePrefix(const CliErrorType errorType) { - if errorType == CliErrorType.INCOMPLETE_TARGET_TRIPLE { return "Incomplete target triple"; } - if errorType == CliErrorType.INVALID_TARGET_TRIPLE { return "Invalid target triple"; } - if errorType == CliErrorType.SOURCE_FILE_MISSING { return "Source file missing"; } - if errorType == CliErrorType.OPT_DEBUG_INFO_INCOMPATIBILITY { return "Cannot emit debug info with optimization enabled"; } - if errorType == CliErrorType.NON_ZERO_EXIT_CODE { return "Non-zero exit code"; } - if errorType == CliErrorType.COMING_SOON_CLI { return "Coming soon"; } - return "Unknown error"; + switch errorType { + case CliErrorType::INCOMPLETE_TARGET_TRIPLE: { return "Incomplete target triple"; } + case CliErrorType::INVALID_TARGET_TRIPLE: { return "Invalid target triple"; } + case CliErrorType::SOURCE_FILE_MISSING: { return "Source file missing"; } + case CliErrorType::OPT_DEBUG_INFO_INCOMPATIBILITY: { return "Cannot emit debug info with optimization enabled"; } + case CliErrorType::NON_ZERO_EXIT_CODE: { return "Non-zero exit code"; } + case CliErrorType::COMING_SOON_CLI: { return "Coming soon"; } + default: { return "Unknown error"; } + } } \ No newline at end of file diff --git a/src-bootstrap/exception/lexer-error.spice b/src-bootstrap/exception/lexer-error.spice index 8e54970f3..44c7ab726 100644 --- a/src-bootstrap/exception/lexer-error.spice +++ b/src-bootstrap/exception/lexer-error.spice @@ -1,4 +1,4 @@ -// Imports +// Own imports import "../util/code-loc"; public type LexerErrorType enum { @@ -30,6 +30,8 @@ public p ParserError.ctor(const CodeLoc* codeLoc, const LexerErrorType errorType * @return Prefix string for the error type */ f ParserError.getMessagePrefix(const LexerErrorType errorType) { - if errorType == LexerErrorType.TOKENIZING_FAILED { return "Parsing failed"; } - return "Unknown error"; + switch errorType { + case LexerErrorType::TOKENIZING_FAILED: { return "Tokenizing failed"; } + default: { return "Unknown error"; } + } } \ No newline at end of file diff --git a/src-bootstrap/exception/linker-error.spice b/src-bootstrap/exception/linker-error.spice index bd8492c1e..286f287c5 100644 --- a/src-bootstrap/exception/linker-error.spice +++ b/src-bootstrap/exception/linker-error.spice @@ -1,4 +1,4 @@ -// Imports +// Own imports import "../util/code-loc"; public type LinkerErrorType enum { @@ -28,7 +28,9 @@ public p LinkerError.ctor(const LinkerErrorType errorType, const string message) * @return Prefix string for the error type */ f LinkerError.getMessagePrefix(const LinkerErrorType errorType) { - if errorType == LinkerErrorType.PARSING_FAILED { return "Parsing failed"; } - if errorType == LinkerErrorType.NUMBER_OUT_OF_RANGE { return "Number is out of range"; } - return "Unknown error"; + switch errorType { + case LinkerErrorType::LINKER_NOT_FOUND: { return "Linker not found"; } + case LinkerErrorType::LINKER_ERROR: { return "Linker error occurred"; } + default: { return "Unknown error"; } + } } \ No newline at end of file diff --git a/src-bootstrap/exception/parser-error.spice b/src-bootstrap/exception/parser-error.spice index cee5504c7..85bb4afbd 100644 --- a/src-bootstrap/exception/parser-error.spice +++ b/src-bootstrap/exception/parser-error.spice @@ -4,7 +4,10 @@ import "../util/code-loc"; public type ParserErrorType enum { PARSING_FAILED, NUMBER_OUT_OF_RANGE, - INVALID_CHAR_LITERAL + INVALID_SPECIFIER_COMBINATION, + INVALID_CHAR_LITERAL, + INVALID_ATTR_VALUE_TYPE, + RESERVED_KEYWORD } /** @@ -32,8 +35,13 @@ public p ParserError.ctor(const CodeLoc* codeLoc, const ParserErrorType errorTyp * @return Prefix string for the error type */ f ParserError.getMessagePrefix(const ParserErrorType errorType) { - if errorType == ParserErrorType.PARSING_FAILED { return "Parsing failed"; } - if errorType == ParserErrorType.NUMBER_OUT_OF_RANGE { return "Number is out of range"; } - if errorType == ParserErrorType.INVALID_CHAR_LITERAL { return "Invalid char literal"; } - return "Unknown error"; + switch errorType { + case ParserErrorType::PARSING_FAILED: { return "Parsing failed"; } + case ParserErrorType::NUMBER_OUT_OF_RANGE: { return "Number is out of range"; } + case ParserErrorType::INVALID_SPECIFIER_COMBINATION: { return "Invalid specifier combination"; } + case ParserErrorType::INVALID_CHAR_LITERAL: { return "Invalid char literal"; } + case ParserErrorType::INVALID_ATTR_VALUE_TYPE: { return "Invalid attribute value type"; } + case ParserErrorType::RESERVED_KEYWORD: { return "Usage of reserved keyword"; } + default: { return "Unknown error"; } + } } \ No newline at end of file diff --git a/src-bootstrap/exception/semantic-error.spice b/src-bootstrap/exception/semantic-error.spice index 1161f4571..637b77d3a 100644 --- a/src-bootstrap/exception/semantic-error.spice +++ b/src-bootstrap/exception/semantic-error.spice @@ -6,15 +6,24 @@ public type SemanticErrorType enum { REFERENCED_UNDEFINED_FUNCTION, REFERENCED_UNDEFINED_VARIABLE, REFERENCED_UNDEFINED_STRUCT, + REFERENCED_UNDEFINED_FIELD, + USED_BEFORE_DECLARED, FUNCTION_AMBIGUITY, STRUCT_AMBIGUITY, + INTERFACE_AMBIGUITY, + DUPLICATE_SYMBOL, VARIABLE_DECLARED_TWICE, + GLOBAL_DECLARED_TWICE, FUNCTION_DECLARED_TWICE, GENERIC_TYPE_DECLARED_TWICE, + STRUCT_WITH_ILLEGAL_NAME, + STRUCT_INFINITE_SIZE, STRUCT_DECLARED_TWICE, + MISSING_NO_ARGS_CTOR, INTERFACE_DECLARED_TWICE, INTERFACE_METHOD_NOT_IMPLEMENTED, ENUM_DECLARED_TWICE, + INVALID_SYMBOL_ACCESS, DUPLICATE_ENUM_ITEM_NAME, DUPLICATE_ENUM_ITEM_VALUE, GLOBAL_OF_TYPE_DYN, @@ -22,51 +31,73 @@ public type SemanticErrorType enum { GLOBAL_CONST_WITHOUT_VALUE, MISSING_RETURN_STMT, INVALID_PARAM_ORDER, + LAMBDA_WITH_OPTIONAL_PARAMS, + REFERENCED_OVERLOADED_FCT, DTOR_MUST_BE_PROCEDURE, DTOR_WITH_PARAMS, OPERATOR_WRONG_DATA_TYPE, + INVALID_ITERATOR, UNEXPECTED_DYN_TYPE, REASSIGN_CONST_VARIABLE, CONDITION_MUST_BE_BOOL, + SWITCH_EXPR_MUST_BE_PRIMITIVE, + SWITCH_CASE_TYPE_MISMATCH, MISSING_MAIN_FUNCTION, FCT_PARAM_IS_TYPE_DYN, INVALID_BREAK_NUMBER, INVALID_CONTINUE_NUMBER, + FALLTHROUGH_NOT_ALLOWED, + CASE_CONSTANT_NOT_ENUM, PRINTF_TYPE_ERROR, PRINTF_ARG_COUNT_ERROR, - STD_NOT_FOUND, DUPLICATE_IMPORT_NAME, IMPORTED_FILE_NOT_EXISTING, CIRCULAR_DEPENDENCY, + ACCESS_TO_NON_EXISTING_MEMBER, INVALID_MEMBER_ACCESS, SCOPE_ACCESS_ONLY_IMPORTS, UNKNOWN_DATATYPE, + UNKNOWN_ATTR, + INVALID_ATTR_TARGET, + MISSING_ATTR_VALUE, NUMBER_OF_FIELDS_NOT_MATCHING, FIELD_TYPE_NOT_MATCHING, ARRAY_SIZE_INVALID, FOREACH_IDX_NOT_LONG, + ARRAY_INDEX_NOT_INT_OR_LONG, ARRAY_ITEM_TYPE_NOT_MATCHING, EXPECTED_ARRAY_TYPE, - SIZEOF_DYNAMIC_SIZED_ARRAY, + EXPECTED_ERROR_TYPE, RETURN_WITHOUT_VALUE_RESULT, RETURN_WITH_VALUE_IN_PROCEDURE, + INVALID_STRUCT_INSTANTIATION, DYN_POINTERS_NOT_ALLOWED, + REF_POINTERS_ARE_NOT_ALLOWED, + DYN_REFERENCES_NOT_ALLOWED, + MULTI_REF_NOT_ALLOWED, DYN_ARRAYS_NOT_ALLOWED, + REFERENCE_WITHOUT_INITIALIZER, + TEMP_TO_NON_CONST_REF, GENERIC_TYPE_NOT_IN_TEMPLATE, SPECIFIER_AT_ILLEGAL_CONTEXT, INSUFFICIENT_VISIBILITY, - TID_INVALID, JOIN_ARG_MUST_BE_TID, EXPECTED_GENERIC_TYPE, + EXPECTED_NON_GENERIC_TYPE, EXPECTED_STRUCT_TYPE, EXPECTED_INTERFACE_TYPE, + ALIAS_WITH_TEMPLATE_LIST, INTERFACE_WITH_TEMPLATE_LIST, + INVALID_TEMPLATE_TYPES, EXPECTED_VALUE, EXPECTED_TYPE, UNSAFE_OPERATION_IN_SAFE_CONTEXT, ASSERTION_CONDITION_BOOL, ARRAY_INDEX_OUT_OF_BOUNDS, - RESERVED_KEYWORD, + EXPECTED_CONST_VARIABLE, + DIVISION_BY_ZERO, + TEST_FUNCTION_WITH_PARAMS, + TEST_FUNCTION_WRONG_RETURN_TYPE, COMING_SOON_SA } @@ -86,13 +117,14 @@ public p SemanticError.ctor(const AstNode* node, const SemanticErrorType errorTy * @return Prefix string for the error type */ f SemanticError.getMessagePrefix(const SemanticErrorType errorType) { - if errorType == SemanticErrorType.REFERENCED_UNDEFINED_FUNCTION { return "Referenced undefined function"; } - if errorType == SemanticErrorType.REFERENCED_UNDEFINED_VARIABLE { return "Referenced undefined variable"; } - if errorType == SemanticErrorType.REFERENCED_UNDEFINED_STRUCT { return "Referenced undefined struct"; } - if errorType == SemanticErrorType.FUNCTION_AMBIGUITY { return "Function ambiguity"; } - if errorType == SemanticErrorType.STRUCT_AMBIGUITY { return "Struct ambiguity"; } - if errorType == SemanticErrorType.VARIABLE_DECLARED_TWICE { return "Multiple declarations of the same variable"; } - if errorType == SemanticErrorType.FUNCTION_DECLARED_TWICE { return "Multiple declarations of a function/procedure"; } - // ToDo: Extend - return "Unknown error"; + switch errorType { + case SemanticErrorType::REFERENCED_UNDEFINED_FUNCTION: { return "Referenced undefined function"; } + case SemanticErrorType::REFERENCED_UNDEFINED_VARIABLE: { return "Referenced undefined variable"; } + case SemanticErrorType::REFERENCED_UNDEFINED_STRUCT: { return "Referenced undefined struct"; } + case SemanticErrorType::FUNCTION_AMBIGUITY: { return "Function ambiguity"; } + case SemanticErrorType::STRUCT_AMBIGUITY: { return "Struct ambiguity"; } + case SemanticErrorType::VARIABLE_DECLARED_TWICE: { return "Multiple declarations of the same variable"; } + case SemanticErrorType::FUNCTION_DECLARED_TWICE: { return "Multiple declarations of a function/procedure"; } + default: { return "Unknown error"; } + } } \ No newline at end of file diff --git a/src-bootstrap/irgenerator/ir-generator.spice b/src-bootstrap/irgenerator/ir-generator.spice index 3642ece81..7da846cbf 100644 --- a/src-bootstrap/irgenerator/ir-generator.spice +++ b/src-bootstrap/irgenerator/ir-generator.spice @@ -1,7 +1,75 @@ // Std imports +import "std/data/vector"; +import "std/data/stack"; // Own imports +import "bindings/llvm/llvm" as llvm; -public type Generator struct { +type CommonLLVMTypes struct { + llvm::StructType fatPtrType +} +public type IRGenerator struct/* : ICompilerPass*/ { + llvm::Context& context + llvm::Builder& builder + llvm::Module* module + //OpRuleConversionManager conversionManager + //StdFunctionManager stdFunctionManager + //DebugInfoGenerator diGenerator + CommonLLVMTypes llvmTypes + Vector breakBlocks + Vector continueBlocks + Stack fallthroughBlocks + llvm::BasicBlock* allocaInsertBlock = nil + llvm::Instruction* allocaInsertInst = nil + bool blockAlreadyTerminated = false + //Vector deferredVTableInitializations +} + +public p IRGenerator.ctor(GlobalResourceManager& resourceManager, SourceFile* sourceFile) { + this.context = resourceManager.context; + this.builder = resourceManager.builder; + this.module = sourceFile.module; + this.stdFunctionManager = StdFunctionManager(resourceManager, sourceFile.llvmModule); + + // Attach information to the module + this.module.setTargetTriple(this.cliOptions.targetTriple); + this.module.setDataLayout(resourceManager.targetMachine.createDataLayout()); + + // Initialiize debug info generator + if this.cliOptions.generateDebugInfo { + this.diGenerator.initialize(sourceFile.fileName, sourceFile.fileDir); + } +} + +public f IRGenerator.createAlloca(llvm::Type llvmType, String varName) { + if !this.cliOptions.namesForIRValues { varName.clear(); } + + if this.allocaInsertInst != nil { // If there is already an alloca inst, insert right after that + llvm::AllocaInst allocaInst = this.builder.createAlloca(llvmType, llvm::Value(), varName); + allocaInst.setDebugLoc(llvm::DebugLoc()); + allocaInstrInst = allocaInst; + } else { // This is the first alloca inst in the current function -> insert at the entry block + // Save current basic block and move insert cursor to entry block of the current function + llvm::BasicBlock currentBlock = this.builder.getInsertBlock(); + this.builder.setInsertPoint(this.allocaInsertBlock); + + // Allocate the size of the given LLVM type + this.allocaInsertInst = this.builder.createAlloca(llvmType, llvm::Value(), varName); + this.allocaInsertInst.setDebugLoc(llvm::DebugLoc()); + + // Resotre old basic block + this.builder.setInsertPoint(currentBlock); + } + return (llvm::Value) allocaInsertInst; +} + +public f IRGenerator.insertLoad(llvm::Type llvmType, llvm::Value ptr, bool isVolatile, const String& varName = "") { + assert ptr.getType().isPointerTy(); + return this.builder.createLoad(llvmType, ptr, isVolatile, this.cliOptions.namesForIRValues ? varName.getRaw() : ""); +} + +public p IRGenerator.insertStore(llvm::Value value, llvm::Value ptr, bool isVolatile) { + assert ptr.getType().isPointerTy(); + this.builder.createStore(value, ptr, isVolatile); } \ No newline at end of file diff --git a/src-bootstrap/lexer/lexer.spice b/src-bootstrap/lexer/lexer.spice index 2cb142861..38baa6e87 100644 --- a/src-bootstrap/lexer/lexer.spice +++ b/src-bootstrap/lexer/lexer.spice @@ -12,6 +12,7 @@ import "../reader/reader"; import "../reader/code-loc"; public type Lexer struct/* : ICompilerPass*/ { + //compose CompilerPass compilerPass Reader reader Token curTok } diff --git a/src-bootstrap/linker/external-linker-interface.spice b/src-bootstrap/linker/external-linker-interface.spice index e69de29bb..a10dd8c55 100644 --- a/src-bootstrap/linker/external-linker-interface.spice +++ b/src-bootstrap/linker/external-linker-interface.spice @@ -0,0 +1,83 @@ +// Std imports +import "std/data/vector"; +import "std/io/filepath"; +import "std/type/error"; + +// Own imports +import "../driver"; + +public type ExternalLinkerInterface struct { + CliOptions& cliOptions + public FilePath outputPath + Vector objectFilePaths + Vector linkerFlags +} + +public p ExternalLinkerInterface.ctor(const CliOptions& cliOptions) { + this.cliOptions = cliOptions; + this.outputPath = cliOptions.outputPath; +} + +public p ExternalLinkerInterface.prepare() { + // Set target to linker + this.addLinkerFlag("--target=" + this.cliOptions.targetTriple); + + // Static linking + if this.cliOptions.staticLinking { + this.addLinkerFlag("-static"); + } + + // Stripping symbols + if !this.cliOptions.generateDebugInfo { + this.addLinkerFlag("-Wl,-s"); + } + + // Web Assembly + if this.cliOptions.targetArch == TARGET_WASM32 || this.cliOptions.targetArch == TARGET_WASM64 { + this.addLinkerFlag("-nostdlib"); + this.addLinkerFlag("-Wl,--no-entry"); + this.addLinkerFlag("-Wl,--export-all"); + } +} + +/** + * Start the linking process + */ +public p ExternalLinkerInterface.link() { + assert !this.outputPath.isEmpty(); + + // ToDo +} + +/** + * Add another object file to be linked when calling 'link()' + * + * @param objectFilePath Path to the object file + */ +public p ExternalLinkerInterface.addObjectFilePath(string objectFilePath) { + this.objectFilePaths.pushBack(objectFilePath); +} + +/** + * Add another linker flag for the call to the linker executable + * + * @param linkerFlag Linker flag + */ +public p ExternalLinkerInterface.addLinkerFlag(string linkerFlag) { + this.linkerFlags.pushBack(linkerFlag); +} + +/** + * Add another source file to compile and link in (C or C++) + * + * @param additionalSource Additional source file + */ +public p ExternalLinkerInterface.addAdditionalSourcePath(FilePath additionalSource) { + // Check if the file exists + if !additionalSource.exists() { + panic(Error("The additional source file '" + additionalSource.toGenericString() + "' does not exist")); + } + + // Add the file to the linker + this.addObjectFilePath(additionalSource.toNativeString()); +} \ No newline at end of file diff --git a/src-bootstrap/parser/parser.spice b/src-bootstrap/parser/parser.spice index 20914aaef..55a351a3c 100644 --- a/src-bootstrap/parser/parser.spice +++ b/src-bootstrap/parser/parser.spice @@ -11,7 +11,7 @@ import "../ast/ast-nodes"; type T dyn; public type Parser struct : ICompilerPass { - //compose CompilerPass + //compose CompilerPass compilerPass Lexer& lexer Stack parentStack } diff --git a/src-bootstrap/util/block-allocator.spice b/src-bootstrap/util/block-allocator.spice index cfcfeb47f..4d813df7f 100644 --- a/src-bootstrap/util/block-allocator.spice +++ b/src-bootstrap/util/block-allocator.spice @@ -1,6 +1,7 @@ // Std imports import "std/data/vector"; import "std/type/error"; +import "std/type/long"; import "std/os/system"; // Own imports @@ -10,15 +11,15 @@ type Base dyn; public type BlockAllocator struct { IMemoryManager* memoryManager - Vector memoryBlocks + Vector memoryBlocks Vector allocatedObjects - unsigned int blockSize - unsigned int offsetInBlock = 0 + unsigned long blockSize + unsigned long offsetInBlock = 0l } -public p BlockAllocator.ctor(IMemoryManager* memoryManager, unsigned int blockSize = 0) { +public p BlockAllocator.ctor(IMemoryManager* memoryManager, unsigned long blockSize = 0l) { this.memoryManager = memoryManager; - this.blockSize = blockSize == 0 ? getPageSize() : blockSize; + this.blockSize = blockSize == 0l ? (unsigned long) getPageSize() : blockSize; // Allocate the first block this.allocateNewBlock(); } @@ -39,13 +40,12 @@ public p BlockAllocator.dtor() { public p BlockAllocator.allocateNewBlock() { // Allocate new block - byte* ptr = this.memoryManager.allocate(this.blockSize); - if ptr != nil { - String msg = "Could not allocate memory block for BlockAllocator. Already allocated " + this.memoryBlocks.size() + " blocks."; - panic(Error(msg)); + heap byte* ptr = this.memoryManager.allocate(this.blockSize); + if ptr != nil { + panic(Error("Could not allocate memory block for BlockAllocator.")); } // Store pointer and reset offset - this.memoryBlocks.push(ptr); - this.offsetInBlock = 0; + this.memoryBlocks.pushBack(ptr); + this.offsetInBlock = 0l; } \ No newline at end of file diff --git a/src/typechecker/OpRuleManager.cpp b/src/typechecker/OpRuleManager.cpp index 8e9fbd696..1ded20ba2 100644 --- a/src/typechecker/OpRuleManager.cpp +++ b/src/typechecker/OpRuleManager.cpp @@ -595,6 +595,9 @@ SymbolType OpRuleManager::getCastResultType(const ASTNode *node, SymbolType lhsT if (lhsType.specifiers.isHeap != rhsType.specifiers.isHeap) ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType); + // Allow identity casts + if (lhsType.matches(rhsType, false, true, true)) + return lhsType; // Allow casts string -> char* and string -> char[] if (lhsType.isOneOf({TY_PTR, TY_ARRAY}) && lhsType.getContainedTy().is(TY_CHAR) && rhsType.is(TY_STRING)) return lhsType; diff --git a/src/typechecker/TypeChecker.cpp b/src/typechecker/TypeChecker.cpp index 843d3fdeb..1de79595a 100644 --- a/src/typechecker/TypeChecker.cpp +++ b/src/typechecker/TypeChecker.cpp @@ -1808,9 +1808,10 @@ bool TypeChecker::visitOrdinaryFctCall(FctCallNode *node, const std::vectorgetNameRegistryEntry(fqFunctionName); - if (!functionRegistryEntry) - SOFT_ERROR_BOOL(node, REFERENCED_UNDEFINED_FUNCTION, - "Function/procedure/struct '" + node->functionNameFragments.back() + "' could not be found") + if (!functionRegistryEntry) { + const std::string msg = "Function/procedure/struct '" + node->functionNameFragments.back() + "' could not be found"; + SOFT_ERROR_BOOL(node, REFERENCED_UNDEFINED_FUNCTION, msg) + } SymbolTableEntry *functionEntry = functionRegistryEntry->targetEntry; // Check if the target symbol is a struct -> this must be a constructor call diff --git a/std/io/filepath.spice b/std/io/filepath.spice index 482bb9bb0..04f6bee00 100644 --- a/std/io/filepath.spice +++ b/std/io/filepath.spice @@ -40,6 +40,10 @@ public inline p FilePath.makeGeneric() { this.replaceSeparator(PATH_SEPARATOR_UNIX); } +public inline p FilePath.makeNative() { + this.replaceSeparator(PATH_SEPARATOR); +} + /** * Returns the content of the filepath without modifying. * @@ -65,7 +69,7 @@ public inline f FilePath.toGenericString() { * @return The content of the filepath using the native path separator */ public inline f FilePath.toNativeString() { - this.replaceSeparator(PATH_SEPARATOR); + this.makeNative(); return this.path.getRaw(); }