diff --git a/.run/spice.run.xml b/.run/spice.run.xml index d59378dae..c69468147 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 890dfe14c..50c34f9b7 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,57 +1,5 @@ -import "std/data/vector"; -import "../../src-bootstrap/bindings/llvm/llvm" as llvm; +import "../../src-bootstrap/reader/reader"; f main() { - //llvm::initializeAllTargets(); - //llvm::initializeAllTargetInfos(); - //llvm::initializeAllTargetMCs(); - //llvm::initializeAllAsmPrinters(); - 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::CodeGenLevelDefault, llvm::LLVMRelocMode::RelocDefault, llvm::LLVMCodeModel::CodeModelDefault); - - llvm::LLVMContext context; - llvm::Module module = llvm::Module("test", context); - module.setDataLayout(targetMachine.createDataLayout()); - module.setTargetTriple(targetTriple); - 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("%s", module.print()); - - llvm::PassBuilderOptions passBuilderOptions; - //llvm::PassBuilder passBuilder = llvm::PassBuilder(module, passBuilderOptions); + Reader reader = Reader("./test.spice"); } \ No newline at end of file diff --git a/media/test-project/test2.spice b/media/test-project/test2.spice index 7d1cd3a0d..253aa716e 100644 --- a/media/test-project/test2.spice +++ b/media/test-project/test2.spice @@ -1,9 +1,16 @@ -public type Driveable interface { - public p drive(int); - public f isDriving(); +import "std/type/result"; +import "std/type/error"; + +type FilePtr alias byte*; +public type File struct { + FilePtr* filePtr } -#[test] -f testDriveable() { - return true; +// Link external functions +ext f fopen(string, string); + +public f> openFile(string path, string mode) { + FilePtr* fp = fopen(path, mode); + File file = File{fp}; + return fp != nil ? ok(file) : err(file, Error("Failed to open file")); } \ No newline at end of file diff --git a/src-bootstrap/ast/AbstractASTVisitor.spice b/src-bootstrap/ast/abstract-ast-visitor.spice similarity index 93% rename from src-bootstrap/ast/AbstractASTVisitor.spice rename to src-bootstrap/ast/abstract-ast-visitor.spice index 46adbb37d..9541f7901 100644 --- a/src-bootstrap/ast/AbstractASTVisitor.spice +++ b/src-bootstrap/ast/abstract-ast-visitor.spice @@ -1,3 +1,4 @@ +// Std imports import "std/type/any"; public type IAbstractAstVisitor interface { diff --git a/src-bootstrap/ast/ASTBuilder.spice b/src-bootstrap/ast/ast-builder.spice similarity index 81% rename from src-bootstrap/ast/ASTBuilder.spice rename to src-bootstrap/ast/ast-builder.spice index e72e03060..7134a2339 100644 --- a/src-bootstrap/ast/ASTBuilder.spice +++ b/src-bootstrap/ast/ast-builder.spice @@ -1,6 +1,6 @@ -import "../CompilerPass"; -import "../SourceFile"; -import "SpiceVisitor"; +import "../compiler-pass"; +import "../source-file"; +import "../ast/spice-visitor"; type ASTBuilder struct : ICompilerPass, SpiceVisitor { CompilerPass compilerPass diff --git a/src-bootstrap/ast/ASTNodes.spice b/src-bootstrap/ast/ast-nodes.spice similarity index 99% rename from src-bootstrap/ast/ASTNodes.spice rename to src-bootstrap/ast/ast-nodes.spice index e3ff36f55..6d4b5c36d 100644 --- a/src-bootstrap/ast/ASTNodes.spice +++ b/src-bootstrap/ast/ast-nodes.spice @@ -3,9 +3,9 @@ import "std/type/Any"; import "std/data/Vector"; // Own imports -import "AbstractASTVisitor"; -import "../util/CodeLoc"; -import "../symbol/SymbolType"; +import "../ast/abstract-ast-visitor"; +import "../reader/code-loc"; +import "../symbol/symbol-type"; /** * Saves a constant value for an AST node to realize features like array-out-of-bounds checks diff --git a/src-bootstrap/bindings/llvm/llvm.spice b/src-bootstrap/bindings/llvm/llvm.spice index 45bc5da42..0e4ade0b3 100644 --- a/src-bootstrap/bindings/llvm/llvm.spice +++ b/src-bootstrap/bindings/llvm/llvm.spice @@ -1,7 +1,10 @@ +#![core.compiler.warnings.ignore] + +// Std imports import "std/data/vector"; -import "linker-flags"; -#![core.compiler.warnings.ignore] +// Own imports +import "linker-flags"; // ===== External type definitions ===== type VoidPtr alias byte*; diff --git a/src-bootstrap/CompilerPass.spice b/src-bootstrap/compiler-pass.spice similarity index 91% rename from src-bootstrap/CompilerPass.spice rename to src-bootstrap/compiler-pass.spice index 3cbc82aa6..305cb6c11 100644 --- a/src-bootstrap/CompilerPass.spice +++ b/src-bootstrap/compiler-pass.spice @@ -1,4 +1,4 @@ -import "global/GlobalResourceManager"; +import "./global/global-resource-manager"; type ICompilerPass interface { p changeToScope(Scope*, const ScopeType&); diff --git a/src-bootstrap/CliInterface.spice b/src-bootstrap/driver.spice similarity index 94% rename from src-bootstrap/CliInterface.spice rename to src-bootstrap/driver.spice index 997305b38..88cb3675b 100644 --- a/src-bootstrap/CliInterface.spice +++ b/src-bootstrap/driver.spice @@ -1,4 +1,4 @@ -// Imports +// Std imports import "std/text/print"; import "std/os/cmd"; import "std/io/cli-parser"; @@ -37,7 +37,7 @@ public type CliOptions struct { /** * Helper class to setup the cli interface and command line parser */ -public type CliInterface struct { +public type Driver struct { CliParser cliParser public CliOptions cliOptions public bool shouldCompile = false @@ -45,12 +45,12 @@ public type CliInterface struct { public bool shouldExecute = false } -public p CliInterface.create() { +public p Driver.create() { this.cliParser = CliParser("Spice", "Spice programming language"); this.cliParser.setFooter("(c) Marc Auberer 2021-2023"); // Add version flag - this.cliParser.setVersion("Spice version 0.14.3\nbuilt by: GitHub Actions\n\n(c) Marc Auberer 2021-2023"); + this.cliParser.setVersion("Spice version 0.18.3\nbuilt by: GitHub Actions\n\n(c) Marc Auberer 2021-2023"); // Create sub-commands this.addBuildSubcommand(); @@ -64,7 +64,7 @@ public p CliInterface.create() { /** * Initialize the cli options based on the input of the user */ -public p CliInterface.enrich() { +public p Driver.enrich() { // Propagate target information if this.cliOptions.targetTriple.isEmpty() && this.cliOptions.targetArch.isEmpty() { // ToDo: Extend @@ -81,7 +81,7 @@ public p CliInterface.enrich() { /** * Add build subcommand to cli interface */ -p CliInterface.addBuildSubcommand() { +p Driver.addBuildSubcommand() { // Create sub-command itself CliSubcommand& subCmd = this.cliParser.createSubcommand("build", "Builds your Spice program and emits an executable"); subCmd.addAlias("b"); @@ -112,7 +112,7 @@ p CliInterface.addBuildSubcommand() { /** * Add run subcommand to cli interface */ -p CliInterface.addRunSubcommand() { +p Driver.addRunSubcommand() { // Create sub-command itself CliSubcommand& subCmd = this.cliParser.createSubcommand("run", "Builds your Spice program and runs it immediately"); subCmd.addAlias("r"); @@ -132,7 +132,7 @@ p CliInterface.addRunSubcommand() { /** * Add install subcommand to cli interface */ -p CliInterface.addInstallSubcommand() { +p Driver.addInstallSubcommand() { // Create sub-command itself CliSubcommand& subCmd = this.cliParser.createSubcommand("install", "Builds your Spice program and installs it to a directory in the PATH variable"); subCmd.addAlias("i"); @@ -143,7 +143,7 @@ p CliInterface.addInstallSubcommand() { /** * Add uninstall subcommand to cli interface */ -p CliInterface.addUninstallSubcommand() { +p Driver.addUninstallSubcommand() { // Create sub-command itself CliSubcommand& subCmd = this.cliParser.createSubcommand("uninstall", "Builds your Spice program and runs it immediately"); subCmd.addAlias("u"); @@ -151,7 +151,7 @@ p CliInterface.addUninstallSubcommand() { addCompileSubcommandOptions(subCmd); } -p CliInterface.addCompileSubcommandOptions(CliSubcommand& subCmd) { +p Driver.addCompileSubcommandOptions(CliSubcommand& subCmd) { // --debug-output CliOption& debugOutputFlag = subCmd.addFlag("--debug-output", this.cliOptions.printDebugOutput, "Enable debug output"); debugOutputFlag.addAlias("-d"); @@ -200,6 +200,6 @@ p CliInterface.addCompileSubcommandOptions(CliSubcommand& subCmd) { * @param argv Argument vector * @return Return code */ -public f CliInterface.parse(int argc, string[] argv) { +public f Driver.parse(int argc, string[] argv) { return this.cliParser.parse(argc, argv); } \ No newline at end of file diff --git a/src-bootstrap/exception/IRError.spice b/src-bootstrap/exception/IRError.spice deleted file mode 100644 index cb1e9b3b4..000000000 --- a/src-bootstrap/exception/IRError.spice +++ /dev/null @@ -1,56 +0,0 @@ -// Imports -import "../util/CodeLoc" as cl; - -public type IRErrorType enum { - TARGET_NOT_AVAILABLE, - CANT_OPEN_OUTPUT_FILE, - WRONG_OUTPUT_TYPE, - BRANCH_NOT_FOUND, - REFERENCED_UNDEFINED_FUNCTION_IR, - PRINTF_NULL_TYPE, - INVALID_FUNCTION, - INVALID_MODULE, - COMING_SOON_IR -} - -/** - * Custom exception for errors, occurring in the code generation phase - */ -public type IRError struct { - string errorMessage -} - -/** - * @param errorType Type of the error - * @param message Error message suffix - */ -public p IRError.ctor(const CodeLoc* codeLoc, const IRErrorType errorType, const string message) { - this.errorMessage = "[Error|Linker] " + this.getMessagePrefix(errorType) + ": " + message; -} - -/** - * @param errorType Type of the error - * @param message Error message suffix - */ -public p IRError.ctor(const IRErrorType errorType, const string message) { - this.errorMessage = "[Error|Linker] " + this.getMessagePrefix(errorType) + ": " + message; -} - -/** - * Get the prefix of the error message for a particular error - * - * @param errorType Type of the error - * @return Prefix string for the error type - */ -f IRError.getMessagePrefix(const IRErrorType errorType) { - if errorType == LinkerErrorType.TARGET_NOT_AVAILABLE { return "Selected target not available"; } - if errorType == LinkerErrorType.CANT_OPEN_OUTPUT_FILE { return "Could not open output file"; } - if errorType == LinkerErrorType.WRONG_OUTPUT_TYPE { return "Wrong type of output file"; } - if errorType == LinkerErrorType.BRANCH_NOT_FOUND { return "Branch not found"; } - if errorType == LinkerErrorType.REFERENCED_UNDEFINED_FUNCTION_IR { return "Referenced undefined function"; } - if errorType == LinkerErrorType.PRINTF_NULL_TYPE { return "Printf has null type"; } - if errorType == LinkerErrorType.INVALID_FUNCTION { return "Invalid function"; } - if errorType == LinkerErrorType.INVALID_MODULE { return "Invalid module"; } - if errorType == LinkerErrorType.COMING_SOON_IR { return "Coming soon"; } - return "Unknown error"; -} \ No newline at end of file diff --git a/src-bootstrap/exception/CliError.spice b/src-bootstrap/exception/cli-error.spice similarity index 96% rename from src-bootstrap/exception/CliError.spice rename to src-bootstrap/exception/cli-error.spice index b76b37d93..bcf174f76 100644 --- a/src-bootstrap/exception/CliError.spice +++ b/src-bootstrap/exception/cli-error.spice @@ -1,5 +1,5 @@ -// Imports -import "../util/CodeLoc" as cl; +// Own imports +import "../reader/code-loc"; public type CliErrorType enum { INCOMPLETE_TARGET_TRIPLE, diff --git a/src-bootstrap/exception/LexerError.spice b/src-bootstrap/exception/lexer-error.spice similarity index 86% rename from src-bootstrap/exception/LexerError.spice rename to src-bootstrap/exception/lexer-error.spice index c725135c8..8e54970f3 100644 --- a/src-bootstrap/exception/LexerError.spice +++ b/src-bootstrap/exception/lexer-error.spice @@ -1,5 +1,5 @@ // Imports -import "../util/CodeLoc" as cl; +import "../util/code-loc"; public type LexerErrorType enum { TOKENIZING_FAILED @@ -19,7 +19,7 @@ public type ParserError struct { * @param errorType Type of the error * @param message Error message suffix */ -public p ParserError.ctor(const cl::CodeLoc* codeLoc, const LexerErrorType errorType, const string message) { +public p ParserError.ctor(const CodeLoc* codeLoc, const LexerErrorType errorType, const string message) { this.errorMessage = "[Error|Lexer] " + codeLoc.toPrettyString() + ": " + this.getMessagePrefix(errorType) + ": " + message; } diff --git a/src-bootstrap/exception/LinkerError.spice b/src-bootstrap/exception/linker-error.spice similarity index 96% rename from src-bootstrap/exception/LinkerError.spice rename to src-bootstrap/exception/linker-error.spice index bd3adcc27..bd8492c1e 100644 --- a/src-bootstrap/exception/LinkerError.spice +++ b/src-bootstrap/exception/linker-error.spice @@ -1,5 +1,5 @@ // Imports -import "../util/CodeLoc" as cl; +import "../util/code-loc"; public type LinkerErrorType enum { LINKER_NOT_FOUND, diff --git a/src-bootstrap/exception/ParserError.spice b/src-bootstrap/exception/parser-error.spice similarity index 88% rename from src-bootstrap/exception/ParserError.spice rename to src-bootstrap/exception/parser-error.spice index 0e699943a..cee5504c7 100644 --- a/src-bootstrap/exception/ParserError.spice +++ b/src-bootstrap/exception/parser-error.spice @@ -1,5 +1,5 @@ // Imports -import "../util/CodeLoc" as cl; +import "../util/code-loc"; public type ParserErrorType enum { PARSING_FAILED, @@ -21,7 +21,7 @@ public type ParserError struct { * @param errorType Type of the error * @param message Error message suffix */ -public p ParserError.ctor(const cl::CodeLoc* codeLoc, const ParserErrorType errorType, const string message) { +public p ParserError.ctor(const CodeLoc* codeLoc, const ParserErrorType errorType, const string message) { this.errorMessage = "[Error|Parser] " + codeLoc.toPrettyString() + ": " + this.getMessagePrefix(errorType) + ": " + message; } diff --git a/src-bootstrap/exception/SemanticError.spice b/src-bootstrap/exception/semantic-error.spice similarity index 94% rename from src-bootstrap/exception/SemanticError.spice rename to src-bootstrap/exception/semantic-error.spice index 864729381..1161f4571 100644 --- a/src-bootstrap/exception/SemanticError.spice +++ b/src-bootstrap/exception/semantic-error.spice @@ -1,6 +1,6 @@ -// Imports -import "../ast/AstNodes" as ast; -import "../util/CodeLoc" as cl; +// Own imports +import "../ast/ast-nodes"; +import "../reader/code-loc"; public type SemanticErrorType enum { REFERENCED_UNDEFINED_FUNCTION, @@ -74,7 +74,7 @@ public type SemanticError struct { string message } -public p SemanticError.ctor(const ast::AstNode* node, const SemanticErrorType errorType, const string message) { +public p SemanticError.ctor(const AstNode* node, const SemanticErrorType errorType, const string message) { this.errorMessage = "[Error|Semantic] " + node.codeLoc.toPrettyString() + ":\n" + this.getMessagePrefix(errorType) + ": " + message + "\n\n" + node.errorMessage; } diff --git a/src-bootstrap/global/GlobalResourceManager.spice b/src-bootstrap/global/global-resource-manager.spice similarity index 89% rename from src-bootstrap/global/GlobalResourceManager.spice rename to src-bootstrap/global/global-resource-manager.spice index e7deaa6f4..8db172a9d 100644 --- a/src-bootstrap/global/GlobalResourceManager.spice +++ b/src-bootstrap/global/global-resource-manager.spice @@ -1,9 +1,9 @@ -import "../exception/ErrorManager"; -import "../global/RuntimeModuleManager"; -import "../linker/ExternalLinkerInterface"; -import "../util/CodeLoc"; -import "../util/Timer"; -import "../CliInterface"; +// Own imports +import "../global/runtime-module-manager"; +import "../linker/external-linker-interface"; +import "../reader/code-loc"; +import "../util/timer"; +import "../driver"; // Constants public const string MAIN_FILE_NAME = "root"; diff --git a/src-bootstrap/generator/generator.spice b/src-bootstrap/irgenerator/ir-generator.spice similarity index 52% rename from src-bootstrap/generator/generator.spice rename to src-bootstrap/irgenerator/ir-generator.spice index bbe2c37b5..3642ece81 100644 --- a/src-bootstrap/generator/generator.spice +++ b/src-bootstrap/irgenerator/ir-generator.spice @@ -1,4 +1,6 @@ -// Imports +// Std imports + +// Own imports public type Generator struct { diff --git a/src-bootstrap/lexer/Lexer.spice b/src-bootstrap/lexer/Lexer.spice deleted file mode 100644 index 6f47bcf28..000000000 --- a/src-bootstrap/lexer/Lexer.spice +++ /dev/null @@ -1,2 +0,0 @@ -// Imports -import "Token" as tk; \ No newline at end of file diff --git a/src-bootstrap/lexer/Reader.spice b/src-bootstrap/lexer/Reader.spice deleted file mode 100644 index 38280a8e6..000000000 --- a/src-bootstrap/lexer/Reader.spice +++ /dev/null @@ -1,40 +0,0 @@ -// Imports -import "std/io/file" as file; - -public type Reader struct { - File inputFile - char curChar - char nextChar - bool metEof - unsigned long line - unsigned long col -} - -public p Reader.ctor(const string inputFileName) { - this.inputFile = file.openFile(inputFileName, file::MODE_READ); - this.cursorPos = 0; - this.metEof = false; - this.line = 1; - this.col = 0; - // Fill -} - -public f Reader.getCurChar() { - return this.curChar; -} - -public f Reader.expectChar(char expected) { - bool gotExpected = expected == this.nextChar; - this.advance(); - return gotExpected; -} - -public p Reader.advance() { - int readChar = this.inputFile.readChar(); - if readChar == -1 { - metEof = true; - return; - } - this.curChar = this.nextChar; - this.nextChar = (char) readChar; -} \ No newline at end of file diff --git a/src-bootstrap/lexer/lexer.spice b/src-bootstrap/lexer/lexer.spice new file mode 100644 index 000000000..cb3b2eb20 --- /dev/null +++ b/src-bootstrap/lexer/lexer.spice @@ -0,0 +1,2 @@ +// Imports +import "../lexer/token"; \ No newline at end of file diff --git a/src-bootstrap/lexer/Token.spice b/src-bootstrap/lexer/token.spice similarity index 98% rename from src-bootstrap/lexer/Token.spice rename to src-bootstrap/lexer/token.spice index 97f6e6188..09512db55 100644 --- a/src-bootstrap/lexer/Token.spice +++ b/src-bootstrap/lexer/token.spice @@ -1,5 +1,5 @@ // Imports -import "../util/CodeLoc"; +import "../reader/code-loc"; // Enums public type TokenType enum { diff --git a/src-bootstrap/main.spice b/src-bootstrap/main.spice index c2cfc3126..de06b4de8 100644 --- a/src-bootstrap/main.spice +++ b/src-bootstrap/main.spice @@ -1,8 +1,10 @@ +// Std imports import "std/os/os"; -import "SourceFile"; -import "CliInterface"; -import "global/GlobalResourceManager"; +// Own imports +import "./source-file"; +import "./driver"; +import "./global/global-resource-manager"; /** * Compile main source file. All files, that are included by the main source file will be resolved recursively. @@ -44,28 +46,28 @@ f compileProject(const CliOptions& cliOptions) { */ f main(int argc, string[] argv) { // Initialize command line parser - CliInterface cli; - cli.create(); - const int exitCode = cli.parse(argc, argv); + Driver driver; + driver.create(); + const int exitCode = driver.parse(argc, argv); if exitCode != EXIT_SUCCESS { return exitCode; } // Cancel here if we do not have to compile - if !cli.shouldCompile { + if !driver.shouldCompile { return EXIT_SUCCESS; } - cli.enrich(); // Prepare the cli options + driver.enrich(); // Prepare the cli options // Kick off the compiling process - if !compileProject(cli.cliOptions) { + if !compileProject(driver.cliOptions) { return EXIT_FAILURE; } // Execute - if cli.cliOptions.execute { - cli.runBinary(); + if driver.cliOptions.execute { + driver.runBinary(); } return EXIT_SUCCESS; diff --git a/src-bootstrap/model/Function.spice b/src-bootstrap/model/function.spice similarity index 97% rename from src-bootstrap/model/Function.spice rename to src-bootstrap/model/function.spice index af37683ac..d93b6da14 100644 --- a/src-bootstrap/model/Function.spice +++ b/src-bootstrap/model/function.spice @@ -1,3 +1,4 @@ +// Std imports import "std/data/vector"; import "std/data/map"; diff --git a/src-bootstrap/parser/Parser.spice b/src-bootstrap/parser/parser.spice similarity index 76% rename from src-bootstrap/parser/Parser.spice rename to src-bootstrap/parser/parser.spice index cf6a92ac4..edb9bb0fe 100644 --- a/src-bootstrap/parser/Parser.spice +++ b/src-bootstrap/parser/parser.spice @@ -1,5 +1,5 @@ -// Imports -import "../lexer/Token" as tk; +// Own imports +import "../lexer/token"; public type Parser struct { diff --git a/src-bootstrap/util/CodeLoc.spice b/src-bootstrap/reader/code-loc.spice similarity index 81% rename from src-bootstrap/util/CodeLoc.spice rename to src-bootstrap/reader/code-loc.spice index ff772767f..0645e470f 100644 --- a/src-bootstrap/util/CodeLoc.spice +++ b/src-bootstrap/reader/code-loc.spice @@ -28,9 +28,9 @@ public f CodeLoc.toString() { * @return Pretty code location */ public f CodeLoc.toPrettyString() { - String codeLocStr = String(intTy.toString(this.line)); - if this.sourceFilePath.empty() { - return toString(line) + ":" + toString(this.col); + String codeLocStr = String(toString(this.line)); + if len(this.sourceFilePath) == 0 { + return toString(this.line) + ":" + toString(this.col); } return this.sourceFilePath + ":" + toString(this.line) + ":" + toString(this.col); } @@ -52,5 +52,5 @@ public f CodeLoc.toPrettyLineAndColumn() { } public f operator==(const CodeLoc &lhs, const CodeLoc &rhs) { - return /*lhs.sourceFilePath == rhs.sourceFilePath && */lhs.line == rhs.line && lhs.col == rhs.col; + return lhs.sourceFilePath == rhs.sourceFilePath && lhs.line == rhs.line && lhs.col == rhs.col; } \ No newline at end of file diff --git a/src-bootstrap/reader/reader.spice b/src-bootstrap/reader/reader.spice new file mode 100644 index 000000000..db7c40a67 --- /dev/null +++ b/src-bootstrap/reader/reader.spice @@ -0,0 +1,80 @@ +// Std imports +import "std/io/filepath"; +import "std/io/file"; +import "std/type/result"; +import "std/type/error"; + +// Own import +import "../reader/code-loc"; + +public type Reader struct { + File file + string filename + char curChar = '\0' + unsigned long line = 1l + unsigned long col = 0l +} + +public p Reader.ctor(const string inputFileName) { + this.filename = inputFileName; + Result result = openFile(inputFileName, MODE_READ); + if !result.isOk() { + panic(Error("Source file cannot be opened")); + } + this.file = result.unwrap(); +} + +public p Reader.dtor() { + this.file.close(); +} + +/** + * @brief Get the previously read character + * + * @return char Last character + */ +public f Reader.getChar() { + return this.curChar; +} + +/** + * @brief Get the code location of the previously read character + * + * @return CodeLoc Code location + */ +public f Reader.getCodeLoc() { + return CodeLoc(this.line, this.col, this.filename); +} + +/** + * @brief Advance the reader by one character + */ +public p Reader.advance() { + assert !this.isEOF(); + this.curChar = (char) this.file.readChar(); + if this.curChar == '\n' { + this.line++; + this.col = 0l; + } + this.col++; +} + +/** + * @brief Advance the reader by one character and check if this char equals the + * expected + * + * @param c Expected char + */ +public p Reader.expect(char c) { + assert this.curChar == c; + this.advance(); +} + +/** + * @brief Check if we are at the end of the input file + * + * @return At the end or not + */ +public f Reader.isEOF() { + return this.file.isEOF(); +} \ No newline at end of file diff --git a/src-bootstrap/SourceFile.spice b/src-bootstrap/source-file.spice similarity index 97% rename from src-bootstrap/SourceFile.spice rename to src-bootstrap/source-file.spice index 974027ac2..790b9fece 100644 --- a/src-bootstrap/SourceFile.spice +++ b/src-bootstrap/source-file.spice @@ -1,9 +1,9 @@ // Imports import "std/text/print"; import "std/data/pair"; -import "CliInterface"; -import "global/GlobalResourceManager"; -import "ast/AstNodes"; +import "./driver"; +import "./global/global-resource-manager"; +import "./ast/ast-nodes"; type CompileStageType enum { NONE, diff --git a/src-bootstrap/symbol/Scope.spice b/src-bootstrap/symboltablebuilder/scope.spice similarity index 99% rename from src-bootstrap/symbol/Scope.spice rename to src-bootstrap/symboltablebuilder/scope.spice index 08581027f..9903ab3eb 100644 --- a/src-bootstrap/symbol/Scope.spice +++ b/src-bootstrap/symboltablebuilder/scope.spice @@ -1,5 +1,7 @@ +// Std imports import "std/data/map"; +// Own imports type ScopeType enum { GLOBAL, diff --git a/src-bootstrap/symbol/SymbolTableEntry.spice b/src-bootstrap/symboltablebuilder/symbol-table-entry.spice similarity index 100% rename from src-bootstrap/symbol/SymbolTableEntry.spice rename to src-bootstrap/symboltablebuilder/symbol-table-entry.spice diff --git a/src-bootstrap/symbol/SymbolTable.spice b/src-bootstrap/symboltablebuilder/symbol-table.spice similarity index 98% rename from src-bootstrap/symbol/SymbolTable.spice rename to src-bootstrap/symboltablebuilder/symbol-table.spice index e35f2343f..ee39839ed 100644 --- a/src-bootstrap/symbol/SymbolTable.spice +++ b/src-bootstrap/symboltablebuilder/symbol-table.spice @@ -3,14 +3,14 @@ import "std/data/map"; import "std/data/vector"; // Own imports -import "../ast/AstNodes"; -import "SymbolType"; -import "SymbolTableEntry"; -import "TypeSpecifiers"; -import "Capture"; -import "GenericType"; -import "Function"; -import "Interface"; +import "../ast/ast-nodes"; +import "../symboltablebuilder/symbol-type"; +import "../symboltablebuilder/symbol-table-entry"; +import "../symboltablebuilder/type-specifiers"; +import "../model/capture"; +import "../model/generic-type"; +import "../model/function"; +import "../model/interface"; public type ScopeType enum { GLOBAL, diff --git a/src-bootstrap/symbol/SymbolType.spice b/src-bootstrap/symboltablebuilder/symbol-type.spice similarity index 97% rename from src-bootstrap/symbol/SymbolType.spice rename to src-bootstrap/symboltablebuilder/symbol-type.spice index a61ad3f9e..7ead7e287 100644 --- a/src-bootstrap/symbol/SymbolType.spice +++ b/src-bootstrap/symboltablebuilder/symbol-type.spice @@ -1,7 +1,9 @@ // Std imports import "std/data/vector"; -import "../util/CommonUtil"; -import "../symbol/Scope"; + +// Own imports +import "../util/common-util"; +import "../symbol/scope"; public type SymbolSuperType enum { TY_INVALID, diff --git a/src-bootstrap/util/CommonUtil.spice b/src-bootstrap/util/common-util.spice similarity index 100% rename from src-bootstrap/util/CommonUtil.spice rename to src-bootstrap/util/common-util.spice diff --git a/src-bootstrap/util/CompilerWarning.spice b/src-bootstrap/util/compiler-warning.spice similarity index 93% rename from src-bootstrap/util/CompilerWarning.spice rename to src-bootstrap/util/compiler-warning.spice index 156174b67..e0845d538 100644 --- a/src-bootstrap/util/CompilerWarning.spice +++ b/src-bootstrap/util/compiler-warning.spice @@ -1,5 +1,5 @@ // Own imports -import "CodeLoc" as cl; +import "../reader/code-loc"; public type CompilerWarningType enum { UNUSED_FUNCTION, @@ -31,7 +31,7 @@ public type CompilerWarning struct { * @param warningType Type of the warning * @param message Warning message suffix */ -public p CompilerWarning.ctor(const cl::CodeLoc* codeLoc, const CompilerWarningType warningType, const string message) { +public p CompilerWarning.ctor(const CodeLoc* codeLoc, const CompilerWarningType warningType, const string message) { this.warningMessage = "[Warning] " + codeLoc.toPrettyString() + ": " + this.getMessagePrefix(warningType) + ": " + message; } @@ -77,7 +77,7 @@ f CompilerWarning.getMessagePrefix(const CompilerWarningType warningType } f main() { - const cl::CodeLoc codeLoc = cl::CodeLoc(2l, 3l); + const CodeLoc codeLoc = CodeLoc(2l, 3l); CompilerWarning warning = CompilerWarning(&codeLoc, CompilerWarningType.UNUSED_STRUCT, "Dies ist ein Test"); warning.print(); } \ No newline at end of file diff --git a/src-bootstrap/util/FileUtil.spice b/src-bootstrap/util/file-util.spice similarity index 100% rename from src-bootstrap/util/FileUtil.spice rename to src-bootstrap/util/file-util.spice diff --git a/src/SourceFile.cpp b/src/SourceFile.cpp index f21e19f9b..8eabf56b2 100644 --- a/src/SourceFile.cpp +++ b/src/SourceFile.cpp @@ -54,6 +54,7 @@ void SourceFile::runLexer() { // Create error handlers for lexer and parser antlrCtx.lexerErrorHandler = std::make_unique(ThrowingErrorListenerMode::LEXER, filePath); antlrCtx.parserErrorHandler = std::make_unique(ThrowingErrorListenerMode::PARSER, filePath); + std::ifstream test; // Tokenize input antlrCtx.inputStream = std::make_unique(fileInputStream); diff --git a/src/Spice.g4 b/src/Spice.g4 index ccf090577..f3d8e5696 100644 --- a/src/Spice.g4 +++ b/src/Spice.g4 @@ -12,7 +12,7 @@ structDef: topLevelDefAttr? specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GRE interfaceDef: specifierLst? TYPE TYPE_IDENTIFIER (LESS typeLst GREATER)? INTERFACE LBRACE signature+ RBRACE; enumDef: specifierLst? TYPE TYPE_IDENTIFIER ENUM LBRACE enumItemLst RBRACE; genericTypeDef: TYPE TYPE_IDENTIFIER typeAltsLst SEMICOLON; -aliasDef: TYPE TYPE_IDENTIFIER ALIAS dataType SEMICOLON; +aliasDef: specifierLst? TYPE TYPE_IDENTIFIER ALIAS dataType SEMICOLON; globalVarDef: dataType TYPE_IDENTIFIER (ASSIGN constant)? SEMICOLON; extDecl: topLevelDefAttr? EXT (F LESS dataType GREATER | P) (IDENTIFIER | TYPE_IDENTIFIER) LPAREN (typeLst ELLIPSIS?)? RPAREN SEMICOLON; diff --git a/src/ast/ASTNodes.h b/src/ast/ASTNodes.h index b9172eefe..bffe0da51 100644 --- a/src/ast/ASTNodes.h +++ b/src/ast/ASTNodes.h @@ -161,6 +161,7 @@ class ASTNode { [[nodiscard]] virtual bool isFctOrProcDef() const { return false; } [[nodiscard]] virtual bool isStructDef() const { return false; } [[nodiscard]] virtual bool isStmtNode() const { return false; } + [[nodiscard]] virtual bool isParamNode() const { return false; } [[nodiscard]] virtual bool isAssignExpr() const { return false; } // Public members @@ -446,12 +447,14 @@ class AliasDefNode : public ASTNode { std::any accept(ParallelizableASTVisitor *visitor) const override { return visitor->visitAliasDef(this); } // Public get methods + [[nodiscard]] SpecifierLstNode *specifierLst() const { return getChild(); } [[nodiscard]] DataTypeNode *dataType() const { return getChild(); } // Public members std::string aliasName; std::string dataTypeString; SymbolTableEntry *entry = nullptr; + TypeSpecifiers aliasSpecifiers = TypeSpecifiers::of(TY_ALIAS); SymbolTableEntry *aliasedTypeContainerEntry = nullptr; }; @@ -916,6 +919,7 @@ class DeclStmtNode : public ASTNode { // Util methods void customItemsInitialization(size_t manifestationCount) override { entries.resize(manifestationCount, nullptr); } + [[nodiscard]] bool isParamNode() const override { return isParam; } // Public members std::string varName; diff --git a/src/global/GlobalResourceManager.cpp b/src/global/GlobalResourceManager.cpp index 3a9a29c65..1e3561247 100644 --- a/src/global/GlobalResourceManager.cpp +++ b/src/global/GlobalResourceManager.cpp @@ -57,6 +57,11 @@ GlobalResourceManager::GlobalResourceManager(const CliOptions &cliOptions) ltoModule = std::make_unique(LTO_FILE_NAME, context); } +GlobalResourceManager::~GlobalResourceManager() { + // Cleanup all global LLVM resources + llvm::llvm_shutdown(); +} + SourceFile *GlobalResourceManager::createSourceFile(SourceFile *parent, const std::string &dependencyName, const std::filesystem::path &path, bool isStdFile) { // Check if the source file was already added (e.g. by another source file that imports it) diff --git a/src/global/GlobalResourceManager.h b/src/global/GlobalResourceManager.h index c4ba33c12..375c2f1f8 100644 --- a/src/global/GlobalResourceManager.h +++ b/src/global/GlobalResourceManager.h @@ -36,6 +36,7 @@ class GlobalResourceManager { // Constructors explicit GlobalResourceManager(const CliOptions &cliOptions); GlobalResourceManager(const GlobalResourceManager &) = delete; + ~GlobalResourceManager(); // Public methods SourceFile *createSourceFile(SourceFile *parent, const std::string &dependencyName, const std::filesystem::path &path, diff --git a/src/irgenerator/DebugInfoGenerator.cpp b/src/irgenerator/DebugInfoGenerator.cpp index 4b65edc99..3f7a09a0b 100644 --- a/src/irgenerator/DebugInfoGenerator.cpp +++ b/src/irgenerator/DebugInfoGenerator.cpp @@ -325,7 +325,7 @@ llvm::DIType *DebugInfoGenerator::getDITypeForSymbolType(const ASTNode *node, co llvm::Type *structType = spiceStruct->entry->getType().toLLVMType(irGenerator->context, irGenerator->currentScope); assert(structType != nullptr); const llvm::StructLayout *structLayout = - irGenerator->module->getDataLayout().getStructLayout(static_cast(structType)); + irGenerator->module->getDataLayout().getStructLayout(reinterpret_cast(structType)); const uint32_t alignInBits = irGenerator->module->getDataLayout().getABITypeAlign(structType).value(); // Create struct type diff --git a/src/irgenerator/GenImplicit.cpp b/src/irgenerator/GenImplicit.cpp index 97f13e7b5..0354844ea 100644 --- a/src/irgenerator/GenImplicit.cpp +++ b/src/irgenerator/GenImplicit.cpp @@ -103,9 +103,14 @@ void IRGenerator::generateCtorOrDtorCall(SymbolTableEntry *entry, const Function } void IRGenerator::generateDeallocCall(llvm::Value *variableAddress) const { - // Issue call - llvm::Function *deallocFct = stdFunctionManager.getDeallocBytePtrRefFct(); - builder.CreateCall(deallocFct, variableAddress); + // In case of string runtime, call free manually. Otherwise, use the memory_rt implementation of sDealloc() + if (sourceFile->isStringRT()) { + llvm::Function *freeFct = stdFunctionManager.getFreeFctPtr(); + builder.CreateCall(freeFct, variableAddress); + } else { + llvm::Function *deallocFct = stdFunctionManager.getDeallocBytePtrRefFct(); + builder.CreateCall(deallocFct, variableAddress); + } } llvm::Function *IRGenerator::generateImplicitFunction(const std::function &generateBody, const Function *spiceFunc) { diff --git a/src/irgenerator/GenTopLevelDefinitions.cpp b/src/irgenerator/GenTopLevelDefinitions.cpp index 6596de247..712cea12f 100644 --- a/src/irgenerator/GenTopLevelDefinitions.cpp +++ b/src/irgenerator/GenTopLevelDefinitions.cpp @@ -479,45 +479,9 @@ std::any IRGenerator::visitStructDef(const StructDefNode *node) { currentScope = spiceStruct->scope; assert(currentScope); - // Create struct definition - const std::string mangledName = NameMangling::mangleStruct(*spiceStruct); - llvm::StructType *structType = llvm::StructType::create(context, mangledName); - // Set LLVM type to the struct entry SymbolTableEntry *structEntry = spiceStruct->entry; assert(structEntry != nullptr); - structEntry->setStructLLVMType(structType); - std::vector fieldTypes; - fieldTypes.reserve(node->fields().size()); - - // Collect interface types - if (const TypeLstNode *typeLst = node->interfaceTypeLst()) { - for (const DataTypeNode *interfaceTypeNode : typeLst->dataTypes()) { - const SymbolType symbolType = interfaceTypeNode->getEvaluatedSymbolType(manIdx); - assert(symbolType.is(TY_INTERFACE)); - const Interface *interface = symbolType.getInterface(interfaceTypeNode); - assert(interface != nullptr); - llvm::StructType *interfaceType = interface->entry->getStructLLVMType(); - assert(interfaceType != nullptr); - fieldTypes.push_back(interfaceType); - } - } else if (node->emitVTable) { - // If no interface was specified, we still need to add a pointer to the VTable - fieldTypes.push_back(builder.getPtrTy()); - } - - // Collect concrete field types - for (const FieldNode *field : node->fields()) { - SymbolTableEntry *fieldEntry = currentScope->lookupStrict(field->fieldName); - assert(fieldEntry && !fieldEntry->getType().hasAnyGenericParts()); - fieldTypes.push_back(fieldEntry->getType().toLLVMType(context, currentScope)); - } - - // Set field types to struct type - bool isPacked = false; - if (node->attrs() && node->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_PACKED)) - isPacked = node->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_PACKED)->boolValue; - structType->setBody(fieldTypes, isPacked); // Generate VTable if required if (node->emitVTable) { @@ -567,15 +531,6 @@ std::any IRGenerator::visitInterfaceDef(const InterfaceDefNode *node) { if (!spiceInterface->used && !spiceInterface->entry->getType().isPublic()) continue; - // Generate empty struct - const std::string mangledName = NameMangling::mangleInterface(*spiceInterface); - llvm::StructType *structType = llvm::StructType::create(context, mangledName); - structType->setBody(builder.getPtrTy()); - - // Set LLVM type to the interface entry - node->entry->setStructLLVMType(structType); - spiceInterface->entry->setStructLLVMType(structType); - // Generate VTable information generateVTable(spiceInterface); deferredVTableInitializations.emplace_back([=, this]() { generateVTableInitializer(spiceInterface); }, false); diff --git a/src/irgenerator/GenVTable.cpp b/src/irgenerator/GenVTable.cpp index 68997081e..b47c8530e 100644 --- a/src/irgenerator/GenVTable.cpp +++ b/src/irgenerator/GenVTable.cpp @@ -35,7 +35,7 @@ llvm::Constant *IRGenerator::generateTypeInfo(StructBase *spiceStruct) { std::vector interfaceTypes; if (spiceStruct->entry->getType().is(TY_STRUCT)) { - auto spiceStructEnsured = static_cast(spiceStruct); + auto spiceStructEnsured = reinterpret_cast(spiceStruct); interfaceTypes = spiceStructEnsured->interfaceTypes; } @@ -121,7 +121,7 @@ void IRGenerator::generateVTableInitializer(StructBase *spiceStruct) { // Generate VTable type llvm::PointerType *ptrTy = llvm::PointerType::get(context, 0); llvm::ArrayType *vtableArrayTy = llvm::ArrayType::get(ptrTy, arrayElementCount); - llvm::StructType *vtableTy = llvm::StructType::get(context, vtableArrayTy, false); + assert(spiceStruct->vtableType); // Generate VTable values std::vector arrayValues; @@ -135,7 +135,7 @@ void IRGenerator::generateVTableInitializer(StructBase *spiceStruct) { // Generate VTable struct std::vector fieldValues; fieldValues.push_back(llvm::ConstantArray::get(vtableArrayTy, arrayValues)); - llvm::Constant *initializer = llvm::ConstantStruct::get(vtableTy, fieldValues); + llvm::Constant *initializer = llvm::ConstantStruct::get(spiceStruct->vtableType, fieldValues); const std::string mangledName = NameMangling::mangleVTable(spiceStruct); llvm::GlobalVariable *global = module->getNamedGlobal(mangledName); diff --git a/src/irgenerator/GenValues.cpp b/src/irgenerator/GenValues.cpp index f7a34f9be..94e8d6262 100644 --- a/src/irgenerator/GenValues.cpp +++ b/src/irgenerator/GenValues.cpp @@ -339,7 +339,7 @@ std::any IRGenerator::visitStructInstantiation(const StructInstantiationNode *no // Get struct type assert(spiceStruct->entry != nullptr); - llvm::StructType *structType = spiceStruct->entry->getStructLLVMType(); + auto structType = reinterpret_cast(spiceStruct->entry->getType().toLLVMType(context, currentScope)); assert(structType != nullptr); if (!node->fieldLst()) { @@ -431,7 +431,7 @@ std::any IRGenerator::visitLambdaFunc(const LambdaFuncNode *node) { captureType = capture.second.capturedEntry->getType().toLLVMType(context, currentScope); captureTypes.push_back(captureType); } - capturesStructType = llvm::StructType::create(context, captureTypes, getUnusedGlobalName(ANON_GLOBAL_CAPTURES_ARRAY_NAME)); + capturesStructType = llvm::StructType::get(context, captureTypes); // Add the captures struct as first parameter paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr); paramTypes.push_back(builder.getPtrTy()); // The capture struct is always passed as pointer @@ -602,7 +602,7 @@ std::any IRGenerator::visitLambdaProc(const LambdaProcNode *node) { captureType = capture.second.capturedEntry->getType().toLLVMType(context, currentScope); captureTypes.push_back(captureType); } - capturesStructType = llvm::StructType::create(context, captureTypes, getUnusedGlobalName(ANON_GLOBAL_CAPTURES_ARRAY_NAME)); + capturesStructType = llvm::StructType::get(context, captureTypes); // Add the captures struct as first parameter paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr); paramTypes.push_back(builder.getPtrTy()); // The captures struct is always passed as pointer @@ -760,7 +760,7 @@ std::any IRGenerator::visitLambdaExpr(const LambdaExprNode *node) { captureType = capture.second.capturedEntry->getType().toLLVMType(context, currentScope); captureTypes.push_back(captureType); } - capturesStructType = llvm::StructType::create(context, captureTypes, getUnusedGlobalName(ANON_GLOBAL_CAPTURES_ARRAY_NAME)); + capturesStructType = llvm::StructType::get(context, captureTypes); // Add the captures struct as first parameter paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr); paramTypes.push_back(builder.getPtrTy()); // The capture struct is always passed as pointer diff --git a/src/irgenerator/IRGenerator.h b/src/irgenerator/IRGenerator.h index 80d02baf1..7519518b4 100644 --- a/src/irgenerator/IRGenerator.h +++ b/src/irgenerator/IRGenerator.h @@ -14,8 +14,6 @@ namespace spice::compiler { const char *const ANON_GLOBAL_STRING_NAME = "anon.string."; const char *const ANON_GLOBAL_ARRAY_NAME = "anon.array."; -const char *const ANON_GLOBAL_STRUCT_NAME = "anon.struct."; -const char *const ANON_GLOBAL_CAPTURES_ARRAY_NAME = "anon.captures."; const char *const CAPTURES_PARAM_NAME = "captures"; enum Likeliness { UNSPECIFIED, LIKELY, UNLIKELY }; diff --git a/src/irgenerator/OpRuleConversionManager.cpp b/src/irgenerator/OpRuleConversionManager.cpp index 5c611b9f2..8ae49ab52 100644 --- a/src/irgenerator/OpRuleConversionManager.cpp +++ b/src/irgenerator/OpRuleConversionManager.cpp @@ -495,12 +495,20 @@ LLVMExprResult OpRuleConversionManager::getEqualInst(const ASTNode *node, LLVMEx if (lhsSTy.isPtr() && rhsSTy.isPtr()) return {.value = builder.CreateICmpEQ(lhsV(), rhsV())}; - // Check if one value is of type pointer and one is of type int + // Check if lhs is of type pointer and rhs is of type int if (lhsT->isPointerTy() && rhsT->isIntegerTy(32)) { llvm::Value *lhsInt = builder.CreatePtrToInt(lhsV(), rhsT); return {.value = builder.CreateICmpEQ(lhsInt, rhsV())}; } + // Check if one value is a string and the other one is a char* + if ((lhsSTy.is(TY_STRING) && rhsSTy.isPtrOf(TY_CHAR)) || (lhsSTy.isPtrOf(TY_CHAR) && rhsSTy.is(TY_STRING))) { + // Generate call to the function isRawEqual(string, string) of the string std + llvm::Function *opFct = stdFunctionManager.getStringIsRawEqualStringStringFct(); + llvm::Value *result = builder.CreateCall(opFct, {lhsV(), rhsV()}); + return {.value = result}; + } + // Check for primitive type combinations switch (getTypeCombination(lhsSTy, rhsSTy)) { case COMB(TY_DOUBLE, TY_DOUBLE): @@ -620,12 +628,21 @@ LLVMExprResult OpRuleConversionManager::getNotEqualInst(const ASTNode *node, LLV if (lhsSTy.isPtr() && rhsSTy.isPtr()) return {.value = builder.CreateICmpNE(lhsV(), rhsV())}; - // Check if one value is of type pointer and one is of type int + // Check if lhs is of type pointer and rhs is of type int if (lhsT->isPointerTy() && rhsT->isIntegerTy(32)) { llvm::Value *lhsInt = builder.CreatePtrToInt(lhsV(), rhsT); return {.value = builder.CreateICmpNE(lhsInt, rhsV())}; } + // Check if one value is a string and the other one is a char* + if ((lhsSTy.is(TY_STRING) && rhsSTy.isPtrOf(TY_CHAR)) || (lhsSTy.isPtrOf(TY_CHAR) && rhsSTy.is(TY_STRING))) { + // Generate call to the function isRawEqual(string, string) of the string std + llvm::Function *opFct = stdFunctionManager.getStringIsRawEqualStringStringFct(); + llvm::Value *result = builder.CreateCall(opFct, {lhsV(), rhsV()}); + // Negate the result + return {.value = builder.CreateNot(result)}; + } + switch (getTypeCombination(lhsSTy, rhsSTy)) { case COMB(TY_DOUBLE, TY_DOUBLE): return {.value = builder.CreateFCmpONE(lhsV(), rhsV())}; @@ -1592,10 +1609,9 @@ LLVMExprResult OpRuleConversionManager::getCastInst(const ASTNode *node, SymbolT case COMB(TY_STRING, TY_STRING): // fallthrough case COMB(TY_STRING, TY_PTR): // fallthrough case COMB(TY_BOOL, TY_BOOL): // fallthrough - case COMB(TY_PTR, TY_STRING): - return {.value = rhsV()}; + case COMB(TY_PTR, TY_STRING): // fallthrough case COMB(TY_PTR, TY_PTR): - return {.value = lhsSTy.getContainedTy() == rhsSTy.getContainedTy() ? rhsV() : builder.CreatePointerCast(rhsV(), lhsT)}; + return {.value = rhsV()}; } throw CompilerError(UNHANDLED_BRANCH, "Operator fallthrough: (cast)"); // GCOV_EXCL_LINE } diff --git a/src/irgenerator/StdFunctionManager.cpp b/src/irgenerator/StdFunctionManager.cpp index 407bedb15..84f50fb97 100644 --- a/src/irgenerator/StdFunctionManager.cpp +++ b/src/irgenerator/StdFunctionManager.cpp @@ -19,6 +19,16 @@ llvm::Function *StdFunctionManager::getPrintfFct() const { return printfFct; } +llvm::Function *StdFunctionManager::getFreeFctPtr() const { + llvm::Function *freeFct = getProcedure("free", builder.getPtrTy()); + // Set attributes + freeFct->addFnAttr(llvm::Attribute::NoUnwind); + freeFct->addParamAttr(0, llvm::Attribute::NoCapture); + freeFct->addParamAttr(0, llvm::Attribute::NoUndef); + freeFct->addParamAttr(0, llvm::Attribute::ReadOnly); + return freeFct; +} + llvm::Function *StdFunctionManager::getExitFct() const { llvm::Function *exitFct = getProcedure("exit", builder.getInt32Ty()); // Set attributes diff --git a/src/irgenerator/StdFunctionManager.h b/src/irgenerator/StdFunctionManager.h index b9e7e3c7b..60013e31c 100644 --- a/src/irgenerator/StdFunctionManager.h +++ b/src/irgenerator/StdFunctionManager.h @@ -21,6 +21,7 @@ class StdFunctionManager { // Public methods for function retrieval [[nodiscard]] llvm::Function *getPrintfFct() const; + [[nodiscard]] llvm::Function *getFreeFctPtr() const; [[nodiscard]] llvm::Function *getExitFct() const; [[nodiscard]] llvm::Function *getMemcpyIntrinsic() const; [[nodiscard]] llvm::Function *getMemcmpIntrinsic() const; diff --git a/src/model/StructBase.cpp b/src/model/StructBase.cpp index 777c1a57a..ed454947a 100644 --- a/src/model/StructBase.cpp +++ b/src/model/StructBase.cpp @@ -36,7 +36,7 @@ std::string StructBase::getSignature(const std::string &name, const std::vector< for (size_t i = 0; i < concreteTemplateTypes.size(); i++) { if (i > 0) templateTyStr << ","; - templateTyStr << concreteTemplateTypes.at(i).getName(); + templateTyStr << concreteTemplateTypes.at(i).getName(false, true); } templateTyStr << ">"; } @@ -81,4 +81,4 @@ std::vector StructBase::getTemplateTypes() const { */ const CodeLoc &StructBase::getDeclCodeLoc() const { return declNode->codeLoc; } -} // namespace spice::compiler +} // namespace spice::compiler \ No newline at end of file diff --git a/src/symboltablebuilder/SymbolTable.cpp b/src/symboltablebuilder/SymbolTable.cpp index 4616c7b5c..890932fa5 100644 --- a/src/symboltablebuilder/SymbolTable.cpp +++ b/src/symboltablebuilder/SymbolTable.cpp @@ -28,7 +28,7 @@ SymbolTableEntry *SymbolTable::insert(const std::string &name, ASTNode *declNode entry->updateState(DECLARED, declNode); // Check if shadowed - if (parent != nullptr && parent->lookup(name) != nullptr) { + if (parent != nullptr && parent->lookup(name) != nullptr && !declNode->isParamNode()) { CompilerWarning warning(declNode->codeLoc, SHADOWED_VARIABLE, "Variable '" + name + "' shadows a variable in a parent scope"); scope->sourceFile->compilerOutput.warnings.push_back(warning); } diff --git a/src/symboltablebuilder/SymbolTableBuilder.cpp b/src/symboltablebuilder/SymbolTableBuilder.cpp index cec2d61bf..fd8c13e3d 100644 --- a/src/symboltablebuilder/SymbolTableBuilder.cpp +++ b/src/symboltablebuilder/SymbolTableBuilder.cpp @@ -320,6 +320,16 @@ std::any SymbolTableBuilder::visitAliasDef(AliasDefNode *node) { if (rootScope->lookupStrict(node->aliasName)) throw SemanticError(node, DUPLICATE_SYMBOL, "Duplicate symbol '" + node->aliasName + "'"); + // Build alias specifiers + if (SpecifierLstNode *specifierLst = node->specifierLst(); specifierLst) { + for (const SpecifierNode *specifier : specifierLst->specifiers()) { + if (specifier->type == SpecifierNode::TY_PUBLIC) + node->aliasSpecifiers.isPublic = true; + else + throw SemanticError(specifier, SPECIFIER_AT_ILLEGAL_CONTEXT, "Cannot use this specifier on an alias definition"); + } + } + // Add the alias to the symbol table node->entry = rootScope->insert(node->aliasName, node); diff --git a/src/symboltablebuilder/SymbolType.cpp b/src/symboltablebuilder/SymbolType.cpp index a984e7a19..e201782d3 100644 --- a/src/symboltablebuilder/SymbolType.cpp +++ b/src/symboltablebuilder/SymbolType.cpp @@ -3,6 +3,7 @@ #include "SymbolType.h" #include +#include #include #include #include @@ -173,28 +174,47 @@ llvm::Type *SymbolType::toLLVMType(llvm::LLVMContext &context, Scope *accessScop // If the type is not known yet, build the LLVM type if (!structType) { - Struct *spiceStruct = structSymbol->getType().getStruct(structSymbol->declNode); - assert(spiceStruct != nullptr); - const std::string mangledName = NameMangling::mangleStruct(*spiceStruct); - structType = llvm::StructType::create(context, mangledName); - structSymbol->setStructLLVMType(structType); - // Collect concrete field types std::vector fieldTypes; + bool isPacked = false; if (is(TY_STRUCT)) { // Struct + Struct *spiceStruct = structSymbol->getType().getStruct(structSymbol->declNode); + assert(spiceStruct != nullptr); + const std::string mangledName = NameMangling::mangleStruct(*spiceStruct); + structType = llvm::StructType::create(context, mangledName); + structSymbol->setStructLLVMType(structType); + const size_t totalFieldCount = spiceStruct->scope->getFieldCount(); fieldTypes.reserve(totalFieldCount); + + // If the struct has no interface types, but a vtable was requested, add another ptr field type + assert(structSymbol->declNode->isStructDef()); + auto structDeclNode = spice_pointer_cast(structSymbol->declNode); + if (!structDeclNode->hasInterfaces && structDeclNode->emitVTable) + fieldTypes.push_back(llvm::PointerType::get(context, 0)); + + // Collect all field types for (size_t i = 0; i < totalFieldCount; i++) { const SymbolTableEntry *fieldSymbol = spiceStruct->scope->symbolTable.lookupStrictByIndex(i); assert(fieldSymbol != nullptr); fieldTypes.push_back(fieldSymbol->getType().toLLVMType(context, accessScope)); } + + // Check if the struct is declared as packed + if (structDeclNode->attrs() && structDeclNode->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_PACKED)) + isPacked = structDeclNode->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_PACKED)->boolValue; } else { // Interface + Interface *spiceInterface = structSymbol->getType().getInterface(structSymbol->declNode); + assert(spiceInterface != nullptr); + const std::string mangledName = NameMangling::mangleInterface(*spiceInterface); + structType = llvm::StructType::create(context, mangledName); + structSymbol->setStructLLVMType(structType); + fieldTypes.push_back(llvm::PointerType::get(context, 0)); } // Set field types to struct type - structType->setBody(fieldTypes); + structType->setBody(fieldTypes, isPacked); } return structType; @@ -381,14 +401,15 @@ bool SymbolType::isCoveredByGenericTypeList(std::vector &genericTyp * Get the name of the symbol type as a string * * @param withSize Include the array size for sized types + * @param ignorePublic Ignore any potential public specifier * @return Symbol type name */ -std::string SymbolType::getName(bool withSize) const { // NOLINT(misc-no-recursion) +std::string SymbolType::getName(bool withSize, bool ignorePublic) const { // NOLINT(misc-no-recursion) std::stringstream name; // Append the specifiers const TypeSpecifiers defaultForSuperType = TypeSpecifiers::of(getBaseType().getSuperType()); - if (specifiers.isPublic && !defaultForSuperType.isPublic) + if (!ignorePublic && specifiers.isPublic && !defaultForSuperType.isPublic) name << "public "; if (specifiers.isInline && !defaultForSuperType.isInline) name << "inline "; @@ -565,11 +586,8 @@ bool SymbolType::matches(const SymbolType &otherType, bool ignoreArraySize, bool return false; } - // Ignore difference of specifiers - if (ignoreSpecifiers && !isPtr() && !isRef()) - return true; - - return specifiers.match(otherType.specifiers, allowConstify); + // Ignore or compare specifiers + return ignoreSpecifiers || specifiers.match(otherType.specifiers, allowConstify); } /** diff --git a/src/symboltablebuilder/SymbolType.h b/src/symboltablebuilder/SymbolType.h index d111dd975..7ab7360fe 100644 --- a/src/symboltablebuilder/SymbolType.h +++ b/src/symboltablebuilder/SymbolType.h @@ -84,6 +84,7 @@ class SymbolType { friend bool operator==(const TypeChainElement &lhs, const TypeChainElement &rhs); friend bool operator!=(const TypeChainElement &lhs, const TypeChainElement &rhs); [[nodiscard]] std::string getName(bool withSize) const; + [[nodiscard]] std::string getOriginalSubType() const; // Public members SymbolSuperType superType = TY_DYN; @@ -158,7 +159,7 @@ class SymbolType { } [[nodiscard]] ALWAYS_INLINE std::string getOriginalSubType() const { assert(isOneOf({TY_STRUCT, TY_INTERFACE, TY_ENUM, TY_GENERIC})); - return CommonUtil::getLastFragment(typeChain.back().subType, SCOPE_ACCESS_TOKEN); + return typeChain.back().getOriginalSubType(); } [[nodiscard]] ALWAYS_INLINE SymbolType removeReferenceWrapper() const { return isRef() ? getContainedTy() : *this; } [[nodiscard]] SymbolType getBaseType() const { @@ -170,7 +171,7 @@ class SymbolType { void setBaseTemplateTypes(const std::vector &templateTypes); [[nodiscard]] const std::vector &getTemplateTypes() const; [[nodiscard]] bool isCoveredByGenericTypeList(std::vector &genericTypeList) const; - [[nodiscard]] std::string getName(bool withSize = false) const; + [[nodiscard]] std::string getName(bool withSize = false, bool ignorePublic = false) const; [[nodiscard]] ALWAYS_INLINE size_t getArraySize() const { assert(getSuperType() == TY_ARRAY); return typeChain.back().data.arraySize; diff --git a/src/symboltablebuilder/TypeChain.cpp b/src/symboltablebuilder/TypeChain.cpp index 4736c28bb..2d62d94aa 100644 --- a/src/symboltablebuilder/TypeChain.cpp +++ b/src/symboltablebuilder/TypeChain.cpp @@ -78,16 +78,18 @@ std::string SymbolType::TypeChainElement::getName(bool withSize) const { return "bool"; case TY_STRUCT: // fall-through case TY_INTERFACE: { - std::string templateStr; + std::stringstream name; + name << subType; if (!templateTypes.empty()) { - for (const auto &templateType : templateTypes) { - if (!templateStr.empty()) - templateStr += ","; - templateStr += templateType.getName(); + name << "<"; + for (size_t i = 0; i < templateTypes.size(); i++) { + if (i > 0) + name << ","; + name << templateTypes.at(i).getName(); } - templateStr = "<" + templateStr + ">"; + name << ">"; } - return subType + templateStr; + return name.str(); } case TY_ENUM: return "enum"; @@ -133,4 +135,13 @@ std::string SymbolType::TypeChainElement::getName(bool withSize) const { } } +/** + * Get the original sub type, without any namespace information + * + * @return last fragment of sub type + */ +std::string SymbolType::TypeChainElement::getOriginalSubType() const { + return CommonUtil::getLastFragment(subType, SCOPE_ACCESS_TOKEN); +} + } // namespace spice::compiler \ No newline at end of file diff --git a/src/typechecker/OpRuleManager.cpp b/src/typechecker/OpRuleManager.cpp index 08e9a0fe2..2c96af664 100644 --- a/src/typechecker/OpRuleManager.cpp +++ b/src/typechecker/OpRuleManager.cpp @@ -294,6 +294,10 @@ ExprResult OpRuleManager::getEqualResultType(ASTNode *node, SymbolType lhs, Symb if (lhs.isPtr() && rhs.is(TY_INT)) return ExprResult(SymbolType(TY_BOOL)); + // Allow 'string == char*' and vice versa straight away + if ((lhs.is(TY_STRING) && rhs.isPtrOf(TY_CHAR)) || (lhs.isPtrOf(TY_CHAR) && rhs.is(TY_STRING))) + return ExprResult(SymbolType(TY_BOOL)); + // Check primitive type combinations return ExprResult(validateBinaryOperation(node, EQUAL_OP_RULES, ARRAY_LENGTH(EQUAL_OP_RULES), "==", lhs, rhs)); } @@ -316,6 +320,10 @@ ExprResult OpRuleManager::getNotEqualResultType(ASTNode *node, SymbolType lhs, S if (lhs.isPtr() && rhs.is(TY_INT)) return ExprResult(SymbolType(TY_BOOL)); + // Allow 'string != char*' and vice versa straight away + if ((lhs.is(TY_STRING) && rhs.isPtrOf(TY_CHAR)) || (lhs.isPtrOf(TY_CHAR) && rhs.is(TY_STRING))) + return ExprResult(SymbolType(TY_BOOL)); + // Check primitive type combinations return ExprResult(validateBinaryOperation(node, NOT_EQUAL_OP_RULES, ARRAY_LENGTH(NOT_EQUAL_OP_RULES), "!=", lhs, rhs)); } diff --git a/src/typechecker/StructManager.cpp b/src/typechecker/StructManager.cpp index 1e32c9285..73b6363f9 100644 --- a/src/typechecker/StructManager.cpp +++ b/src/typechecker/StructManager.cpp @@ -224,7 +224,18 @@ bool StructManager::matchTemplateTypes(Struct &candidate, const std::vectorgetFieldCount() - candidate.fieldTypes.size(); + for (size_t i = 0; i < fieldCount; i++) { + SymbolTableEntry *fieldEntry = candidate.scope->symbolTable.lookupStrictByIndex(i); + SymbolType fieldType = fieldEntry->getType(); + if (fieldType.hasAnyGenericParts()) { + TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping); + fieldEntry->updateType(fieldType, true); + } + } + + // Loop over all explicit field types and substantiate the generic ones for (SymbolType &fieldType : candidate.fieldTypes) if (fieldType.hasAnyGenericParts()) TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping); diff --git a/src/typechecker/TypeChecker.cpp b/src/typechecker/TypeChecker.cpp index 918276d58..035a1a931 100644 --- a/src/typechecker/TypeChecker.cpp +++ b/src/typechecker/TypeChecker.cpp @@ -1502,8 +1502,14 @@ std::any TypeChecker::visitFctCall(FctCallNode *node) { } // Retrieve entry of the first fragment - SymbolTableEntry *firstFragEntry = currentScope->lookup(node->functionNameFragments.front()); + const std::string &firstFrag = node->functionNameFragments.front(); + SymbolTableEntry *firstFragEntry = currentScope->lookup(firstFrag); if (firstFragEntry) { + // Check if we have seen a 'this.' prefix, because the generator needs that + if (firstFragEntry->scope->type == ScopeType::STRUCT && firstFrag != THIS_VARIABLE_NAME) + SOFT_ERROR_ER(node, REFERENCED_UNDEFINED_VARIABLE, + "The symbol '" + firstFrag + "' could not be found. Missing 'this.' prefix?") + firstFragEntry->used = true; // Decide of which type the function call is const SymbolType &baseType = firstFragEntry->getType().getBaseType(); @@ -2232,6 +2238,11 @@ std::any TypeChecker::visitCustomDataType(CustomDataTypeNode *node) { SymbolType symbolType = *genericType; if (typeMapping.contains(firstFragment)) symbolType = typeMapping.at(firstFragment); + + // Check if the replacement is a String type + if (!isImported && symbolType.isStringObj() && !sourceFile->isStringRT()) + sourceFile->requestRuntimeModule(STRING_RT); + return node->setEvaluatedSymbolType(symbolType, manIdx); } diff --git a/src/typechecker/TypeCheckerImplicit.cpp b/src/typechecker/TypeCheckerImplicit.cpp index a7ea99b27..8bb8501b5 100644 --- a/src/typechecker/TypeCheckerImplicit.cpp +++ b/src/typechecker/TypeCheckerImplicit.cpp @@ -203,7 +203,8 @@ void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope * createDefaultStructMethod(spiceStruct, DTOR_FUNCTION_NAME, {}); // Request memory runtime if we have fields, that are allocated on the heap - if (hasHeapFields) { + // The string runtime does not use it, but allocates manually to avoid circular dependencies + if (hasHeapFields && !sourceFile->isStringRT()) { SourceFile *memoryRT = sourceFile->requestRuntimeModule(MEMORY_RT); assert(memoryRT != nullptr); Scope *matchScope = memoryRT->globalScope.get(); diff --git a/src/typechecker/TypeCheckerPrepare.cpp b/src/typechecker/TypeCheckerPrepare.cpp index 9ddb3eba3..f56cd257c 100644 --- a/src/typechecker/TypeCheckerPrepare.cpp +++ b/src/typechecker/TypeCheckerPrepare.cpp @@ -569,8 +569,9 @@ std::any TypeChecker::visitAliasDefPrepare(AliasDefNode *node) { assert(node->entry != nullptr && node->aliasedTypeContainerEntry != nullptr); // Update type of alias entry - const SymbolType symbolType(TY_ALIAS, node->dataTypeString); - node->entry->updateType(symbolType, false); + SymbolType aliasType(TY_ALIAS, node->dataTypeString); + aliasType.specifiers = node->aliasSpecifiers; + node->entry->updateType(aliasType, false); // Update type of the aliased type container entry auto aliasedType = std::any_cast(visit(node->dataType())); diff --git a/std/io/file_linux.spice b/std/io/file_linux.spice index a74f05a74..f253c7fe0 100644 --- a/std/io/file_linux.spice +++ b/std/io/file_linux.spice @@ -1,3 +1,6 @@ +import "std/type/result"; +import "std/type/error"; + // File open modes public const string MODE_READ = "r"; public const string MODE_WRITE = "w"; @@ -20,9 +23,7 @@ const int SEEK_SET = 0; const int SEEK_CUR = 1; const int SEEK_END = 2; -public type FilePtr struct { - byte* ptr -} +public type FilePtr alias byte*; public type File struct { FilePtr* filePtr @@ -57,11 +58,9 @@ public f createFile(string path) { * * @return File pointer */ -public f openFile(string path, string mode) { +public f> openFile(string path, string mode) { FilePtr* fp = fopen(path, mode); - // Insert check for pointer being 0 and throw an exception - File openedFile = File { fp }; - return openedFile; + return fp != nil ? ok(fp) : err(fp, Error("Failed to open file '" + path + "'")); } /** @@ -117,14 +116,28 @@ public f File.getSize() { return size; } +/** + * Checks if the end of the file is reached. + * + * @return EOF reached / not reached + */ +public f File.isEOF() { + return this.readChar() == EOF; +} + /** * Reads a whole file from a given path. * * @return Content in form of a string */ -public f readFile(string path) { +public f> readFile(string path) { // Open the file in read mode - File file = openFile(path, MODE_READ); + Result fileResult = openFile(path, MODE_READ); + // Check for errors + if (fileResult.isErr()) { + return err(String(), fileResult.getErr()); + } + File file = fileResult.unwrap(); // Read from the file char by char int buffer; String output = String(); @@ -133,7 +146,7 @@ public f readFile(string path) { } // Close the file file.close(); - return output; + return ok(output); } /** @@ -141,14 +154,19 @@ public f readFile(string path) { * * @return Result code of the write operation: 0 = successful, -1 = failed */ -public f writeFile(string path, string content) { +public f> writeFile(string path, string content) { // Open the file in write mode - File file = openFile(path, MODE_WRITE); + Result fileResult = openFile(path, MODE_WRITE); + // Check for errors + if (fileResult.isErr()) { + return err(0, fileResult.getErr()); + } + File file = fileResult.unwrap(); // Write the string to the file int resultCode = file.writeString(content); // Close the file file.close(); - return resultCode; + return ok(resultCode); } /** @@ -156,14 +174,19 @@ public f writeFile(string path, string content) { * * @return File size in bytes */ -public f getFileSize(string path) { +public f> getFileSize(string path) { // Open the file in read mode - File file = openFile(path, MODE_READ); + Result fileResult = openFile(path, MODE_READ); + // Check for errors + if (fileResult.isErr()) { + return err(0l, fileResult.getErr()); + } + File file = fileResult.unwrap(); // Get the file size long size = file.getSize(); // Close the file file.close(); - return size; + return ok(size); } /** diff --git a/std/io/file_windows.spice b/std/io/file_windows.spice index f0199a02c..481a17670 100644 --- a/std/io/file_windows.spice +++ b/std/io/file_windows.spice @@ -1,3 +1,6 @@ +import "std/type/result"; +import "std/type/error"; + // File open modes public const string MODE_READ = "r"; public const string MODE_WRITE = "w"; @@ -20,9 +23,7 @@ const int SEEK_SET = 0; const int SEEK_CUR = 1; const int SEEK_END = 2; -public type FilePtr struct { - byte* ptr -} +type FilePtr alias byte*; public type File struct { FilePtr* filePtr @@ -57,11 +58,10 @@ public f createFile(string path) { * * @return File pointer */ -public f openFile(string path, string mode) { +public f> openFile(string path, string mode) { FilePtr* fp = fopen(path, mode); - // Insert check for pointer being 0 and throw an exception - File openedFile = File { fp }; - return openedFile; + File file = File{fp}; + return fp != nil ? ok(file) : err(file, Error("Failed to open file")); } /** @@ -117,14 +117,28 @@ public f File.getSize() { return size; } +/** + * Checks if the end of the file is reached. + * + * @return EOF reached / not reached + */ +public f File.isEOF() { + return this.readChar() == EOF; +} + /** * Reads a whole file from a given path. * * @return Content in form of a string */ -public f readFile(string path) { +public f> readFile(string path) { // Open the file in read mode - File file = openFile(path, MODE_READ); + Result fileResult = openFile(path, MODE_READ); + // Check for errors + if !fileResult.isOk() { + return err(String(), fileResult.getErr()); + } + File file = fileResult.unwrap(); // Read from the file char by char int buffer; String output = String(); @@ -133,7 +147,7 @@ public f readFile(string path) { } // Close the file file.close(); - return output; + return ok(output); } /** @@ -141,14 +155,19 @@ public f readFile(string path) { * * @return Result code of the write operation: 0 = successful, -1 = failed */ -public f writeFile(string path, string content) { +public f> writeFile(string path, string content) { // Open the file in write mode - File file = openFile(path, MODE_WRITE); + Result fileResult = openFile(path, MODE_WRITE); + // Check for errors + if !fileResult.isOk() { + return err(0, fileResult.getErr()); + } + File file = fileResult.unwrap(); // Write the string to the file int resultCode = file.writeString(content); // Close the file file.close(); - return resultCode; + return ok(resultCode); } /** @@ -156,14 +175,19 @@ public f writeFile(string path, string content) { * * @return File size in bytes */ -public f getFileSize(string path) { +public f> getFileSize(string path) { // Open the file in read mode - File file = openFile(path, MODE_READ); - // Get the file size + Result fileResult = openFile(path, MODE_READ); + // Check for errors + if !fileResult.isOk() { + return err(0l, fileResult.getErr()); + } + File file = fileResult.unwrap(); + // Get the file file long size = file.getSize(); // Close the file file.close(); - return size; + return ok(size); } /** diff --git a/std/runtime/memory_rt.spice b/std/runtime/memory_rt.spice index 25e491428..845155845 100644 --- a/std/runtime/memory_rt.spice +++ b/std/runtime/memory_rt.spice @@ -40,6 +40,9 @@ public f> sRealloc(heap byte* ptr, unsigned long size) { * @return A pointer to the copied block, or an error if the copy failed. */ public f> sCopy(heap byte* oldPtr, heap byte* newPtr, unsigned long size) { + if oldPtr == nil | newPtr == nil { + return err(nil, "Cannot copy from or to nil pointer!"); + } memcpy(newPtr, oldPtr, size); return ok(newPtr); } @@ -51,6 +54,7 @@ public f> sCopy(heap byte* oldPtr, heap byte* newPtr, unsigne * @param ptr The pointer to the block to free. */ public p sDealloc(heap byte*& ptr) { + if ptr == nil { return; } free(ptr); ptr = nil; // Zero out to prevent accidental double frees } \ No newline at end of file diff --git a/std/runtime/string_rt.spice b/std/runtime/string_rt.spice index f46775c35..dbe532908 100644 --- a/std/runtime/string_rt.spice +++ b/std/runtime/string_rt.spice @@ -1,6 +1,13 @@ #![core.compiler.alwaysKeepOnNameCollision = true] -import "std/type/result"; +import "std/type/error"; + +// Link external functions +// We intentionally do not use the memory_rt here to avoid dependency circles +ext f malloc(unsigned long); +ext f realloc(heap char*, unsigned long); +ext p free(heap char*); +ext p memcpy(heap char*, heap char*, unsigned long); // Constants const unsigned long INITIAL_ALLOC_COUNT = 5l; @@ -27,18 +34,13 @@ public p String.ctor(const string value = "") { this.length = getRawLength(value); this.capacity = this.length > INITIAL_ALLOC_COUNT ? this.length * RESIZE_FACTOR : INITIAL_ALLOC_COUNT; - // Allocate space for the initial number of elements unsafe { + // Allocate space for the initial number of elements unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator - Result allocResult = sAlloc(requiredBytes); - this.contents = (heap char*) allocResult.unwrap(); - } - - // Save initial value - unsafe { - for unsigned long i = 0l; i < this.length + 1l; i++ { // +1 because of null terminator - this.contents[i] = value[i]; - } + this.contents = malloc(requiredBytes); + this.checkForOOM(); + // Save initial value + memcpy(this.contents, (char*) value, this.length + 1l); // +1 because of null terminator } } @@ -46,15 +48,13 @@ public p String.ctor(const char value) { this.length = 1l; this.capacity = INITIAL_ALLOC_COUNT; - // Allocate space for the initial number of elements unsafe { + // Allocate space for the initial number of elements unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator - Result allocResult = sAlloc(requiredBytes); - this.contents = (heap char*) allocResult.unwrap(); - } + this.contents = malloc(requiredBytes); + this.checkForOOM(); - // Save initial value - unsafe { + // Save initial value this.contents[0] = value; this.contents[1] = '\0'; } @@ -64,16 +64,35 @@ public p String.ctor(const String& value) { this.length = value.length; this.capacity = value.capacity; - // Allocate space unsafe { + // Allocate space + unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator + this.contents = malloc(requiredBytes); + this.checkForOOM(); + + // Copy the contents from the other string + memcpy(this.contents, value.contents, value.length + 1l); // +1 because of null terminator + } +} + +public p String.ctor(IntLong initialSize) { + this.length = (unsigned long) initialSize; + this.capacity = initialSize > INITIAL_ALLOC_COUNT ? (unsigned long) initialSize * RESIZE_FACTOR : INITIAL_ALLOC_COUNT; + + unsafe { + // Allocate space for the initial number of elements unsigned long requiredBytes = this.capacity + 1l; // +1 because of null terminator - Result allocResult = sAlloc(requiredBytes); - this.contents = (heap char*) allocResult.unwrap(); + this.contents = malloc(requiredBytes); + this.checkForOOM(); + + // Save the initial value + this.contents[0] = '\0'; } +} - // Copy the contents from the other string +public p String.dtor() { unsafe { - sCopy((heap byte*) value.contents, (heap byte*) this.contents, value.length + 1l); // +1 because of null terminator + free(this.contents); } } @@ -443,11 +462,11 @@ public f String.replace( if needleLength != replacementLength { const heap char* oldSuffixAddr = startAddr + needleLength; const heap char* newSuffixAddr = startAddr + replacementLength; - sCopy((heap byte*) oldSuffixAddr, (heap byte*) newSuffixAddr, suffixLength + 1); // +1 because of null terminator + memcpy(newSuffixAddr, oldSuffixAddr, suffixLength + 1l); // +1 because of null terminator } // Replace needle with replacement - sCopy((heap byte*) replacement, (heap byte*) startAddr, replacementLength); + memcpy(startAddr, (char*) replacement, replacementLength); } // Update length @@ -529,7 +548,7 @@ public f String.getSubstring(unsigned IntLongShort startId */ public p String.reserve(unsigned IntLongShort charCount) { if charCount > this.capacity { - this.resize(charCount); + this.resize((unsigned long) charCount); } } @@ -538,18 +557,24 @@ public p String.reserve(unsigned IntLongShort charCount) { * * @param newLength new length of the string after resizing */ -p String.resize(unsigned IntLongShort newLength) { +p String.resize(unsigned long newLength) { // Allocate the new memory unsafe { heap char* oldAddress = this.contents; - unsigned long requiredBytes = newLength + 1; // +1 because of null terminator - Result allocResult = sRealloc((heap byte*) oldAddress, requiredBytes); - this.contents = (heap char*) allocResult.unwrap(); + unsigned long requiredBytes = newLength + 1l; // +1 because of null terminator + this.contents = realloc(oldAddress, requiredBytes); + this.checkForOOM(); } // Set new capacity this.capacity = newLength; } +p String.checkForOOM() { + if this.contents == nil { + panic(Error("Could not allocate enough memory for dynamic string object")); + } +} + // ======================================================= Static functions ====================================================== /** @@ -559,6 +584,9 @@ p String.resize(unsigned IntLongShort newLength) { * @return Length of the input string */ public f getRawLength(string input) { + // Handle nullptr gracefully + if (char*) input == nil { return 0l; } + // Otherwise count the chars until the null terminator result = 0l; while input[result] != '\0' { result++; diff --git a/std/type/byte.spice b/std/type/byte.spice index 5d849cea6..3a20fcb06 100644 --- a/std/type/byte.spice +++ b/std/type/byte.spice @@ -2,6 +2,9 @@ public const int SIZE = 8; public const int MIN_VALUE = 0; public const int MAX_VALUE = 255; +// External functions +ext f snprintf(char*, unsigned long, string, byte); + // Converts a byte to a double public f toDouble(byte input) { return 0.0 + ((int) input); @@ -28,9 +31,10 @@ public f toChar(byte input) { } // Converts a byte to a string -public f toString(byte input) { - // ToDo: Impmenet - return "0"; +public f toString(byte input) { + const unsigned int length = snprintf(nil, 0l, "%hhu", input); + result = String(length); + snprintf((char*) result.getRaw(), length + 1l, "%hhu", input); } // Converts a byte to a bool diff --git a/std/type/char.spice b/std/type/char.spice index 501d6e5a5..715e0e7f6 100644 --- a/std/type/char.spice +++ b/std/type/char.spice @@ -28,8 +28,9 @@ public f toByte(char input) { } // Converts a char to a string -public f toString(char input) { - return "0"; +public f toString(char input) { + result = String(); + result += input; } // Converts a char to a bool diff --git a/std/type/double.spice b/std/type/double.spice index 53e1f770a..9bcd55c85 100644 --- a/std/type/double.spice +++ b/std/type/double.spice @@ -2,6 +2,8 @@ public const int SIZE = 64; public const double MIN_VALUE = -1.7976931348623157e+308; public const double MAX_VALUE = 1.7976931348623157e+308; +ext f snprintf(char*, unsigned long, string, double); + // Converts a double to an int public f toInt(double input) { return (int) input; @@ -18,9 +20,10 @@ public f toLong(double input) { } // Converts a double to a string -public f toString(double input) { - // ToDo: Implement - return ""; +public f toString(double input) { + const unsigned int length = snprintf(nil, 0l, "%f", input); + result = String(length); // Assuming this length is enough + snprintf((char*) result.getRaw(), length + 1l, "%f", input); } // Converts a double to a boolean diff --git a/std/type/int.spice b/std/type/int.spice index 1175b34d0..68f03337f 100644 --- a/std/type/int.spice +++ b/std/type/int.spice @@ -2,6 +2,9 @@ public const int SIZE = 32; public const int MIN_VALUE = -2147483648; public const int MAX_VALUE = 2147483647; +// External functions +ext f snprintf(char*, unsigned long, string, int); + // Converts an int to a double public f toDouble(int input) { return 0.0 + input; @@ -29,20 +32,9 @@ public f toChar(int input) { // Converts an int to a string public f toString(const int input) { - if input == 0 { return String("0"); } - - String str; - bool isNeg = input < 0; - unsigned int uInput = isNeg ? -input : input; - - while (uInput != 0) { - str.append((char) (uInput % 10 + 48 /* ASCII for '0' */)); - uInput = uInput / 10; - } - if isNeg { str.append('-'); } - - str.reverse(); - return str; + const unsigned int length = snprintf(nil, 0l, "%d", input); + result = String(length); + snprintf((char*) result.getRaw(), length + 1l, "%d", input); } // Converts an int to a boolean diff --git a/std/type/long.spice b/std/type/long.spice index d11321773..cf573c9ef 100644 --- a/std/type/long.spice +++ b/std/type/long.spice @@ -2,9 +2,8 @@ public const int SIZE = 64; public const long MIN_VALUE = -9223372036854775808l; public const long MAX_VALUE = 9223372036854775807l; -const int N_SMALL = 100; -const string SMALLS_STRING_10 = "0123456789"; -const string SMALLS_STRING_100 = "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"; +// External functions +ext f snprintf(char*, unsigned long, string, long); // Converts a long to a double public f toDouble(long input) { @@ -32,9 +31,10 @@ public f toChar(long input) { } // Converts a long to a string -public f toString(long input) { - // ToDo: Implement (See https://github.com/golang/go/blob/master/src/strconv/itoa.go) - return ""; +public f toString(long input) { + const unsigned int length = snprintf(nil, 0l, "%ld", input); + result = String(length); + snprintf((char*) result.getRaw(), length + 1l, "%ld", input); } // Converts a long to a boolean diff --git a/std/type/result.spice b/std/type/result.spice index 23c8ac204..d9dd54778 100644 --- a/std/type/result.spice +++ b/std/type/result.spice @@ -30,6 +30,20 @@ public inline f Result.unwrap() { return this.data; } +/** + * Return the enclosed error object. + */ +public inline f Result.getErr() { + return this.error; +} + +/** + * Checks if the result contains any data. + */ +public inline f Result.isOk() { + return this.error.code == 0; +} + /** * Returns a result object with a value and no error. */ diff --git a/std/type/short.spice b/std/type/short.spice index 6ef074627..86dbe7c62 100644 --- a/std/type/short.spice +++ b/std/type/short.spice @@ -2,6 +2,9 @@ public const int SIZE = 16; public const short MIN_VALUE = -32768s; public const short MAX_VALUE = 32767s; +// External functions +ext f snprintf(char*, unsigned long, string, short); + // Converts a short to a double public f toDouble(short input) { return 0.0 + input; @@ -28,12 +31,13 @@ public f toChar(short input) { } // Converts a short to a string -public f toString(short input) { - // ToDo: Implement (See https://github.com/golang/go/blob/master/src/strconv/itoa.go) - return ""; +public f toString(short input) { + const unsigned int length = snprintf(nil, 0l, "%hd", input); + result = String(length); + snprintf((char*) result.getRaw(), length + 1l, "%hd", input); } -// Converts a v to a boolean +// Converts a short to a boolean public f toBool(short input) { return input >= 1; } diff --git a/std/type/string.spice b/std/type/string.spice index 73079f97a..970f10f71 100644 --- a/std/type/string.spice +++ b/std/type/string.spice @@ -1,33 +1,31 @@ // External declarations ext f strtol(string, char**, int); +ext f atoi(string, char**, int); +ext f strtod(string, char**); // Converts a string to a double public f toDouble(string input) { - // ToDo: implement - return 0.0; + return strtod(input, nil); } // Converts a string to an int public f toInt(string input, int base = 10) { - return (int) toLong(input, base); + return atoi(input, nil, base); } // Converts a string to a short public f toShort(string input, int base = 10) { - return (short) toLong(input, base); + return (short) atoi(input, nil, base); } // Converts a string to a long public f toLong(string input, int base = 10) { - char* endPtr = nil; - result = strtol(input, &endPtr, base); - // Check if the conversion was successful - if (((string) endPtr) == input || *endPtr != '\0') { return 0l; } + return strtol(input, nil, base); } // Converts a string to a byte public f toByte(string input, int base = 10) { - return (byte) ((int) toLong(input, base)); + return (byte) atoi(input, nil, base); } // Converts a string to a char diff --git a/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll b/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll index 86d90c41b..4e0baef64 100644 --- a/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll +++ b/test/test-files/irgenerator/debug-info/success-dbg-info-simple/ir-code.ll @@ -125,15 +125,15 @@ attributes #3 = { nofree nounwind } !30 = !DIDerivedType(tag: DW_TAG_member, name: "lng", scope: !28, file: !7, line: 2, baseType: !31, size: 64) !31 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) !32 = !DIDerivedType(tag: DW_TAG_member, name: "str", scope: !28, file: !7, line: 3, baseType: !33, size: 192, align: 8, offset: 64) -!33 = !DICompositeType(tag: DW_TAG_structure_type, name: "String", scope: !34, file: !34, line: 13, size: 192, align: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !35, identifier: "struct.String") +!33 = !DICompositeType(tag: DW_TAG_structure_type, name: "String", scope: !34, file: !34, line: 20, size: 192, align: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !35, identifier: "struct.String") !34 = !DIFile(filename: "string_rt.spice", directory: "C:\\Users\\Marc\\Documents\\JustForFunGitHubClonesFast\\spice\\std\\runtime") !35 = !{!36, !39, !41} -!36 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !33, file: !34, line: 14, baseType: !37, size: 64) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !33, file: !34, line: 21, baseType: !37, size: 64) !37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !38, size: 64) !38 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char) -!39 = !DIDerivedType(tag: DW_TAG_member, name: "capacity", scope: !33, file: !34, line: 15, baseType: !40, size: 64, offset: 64) +!39 = !DIDerivedType(tag: DW_TAG_member, name: "capacity", scope: !33, file: !34, line: 22, baseType: !40, size: 64, offset: 64) !40 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) -!41 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !33, file: !34, line: 16, baseType: !40, size: 64, offset: 128) +!41 = !DIDerivedType(tag: DW_TAG_member, name: "length", scope: !33, file: !34, line: 23, baseType: !40, size: 64, offset: 128) !42 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !28, file: !7, line: 4, baseType: !43, size: 32, offset: 256) !43 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !44 = !{} diff --git a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code-O2.ll b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code-O2.ll index 67e616215..b96309dfe 100644 --- a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code-O2.ll +++ b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code-O2.ll @@ -3,9 +3,9 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%struct.NumberIterator = type { %interface.Iterable.1, i16, i16, i16 } -%interface.Iterable.1 = type { ptr } -%struct.NumberIterator.2 = type { %interface.Iterable.1, i64, i64, i64 } +%struct.NumberIterator = type { %interface.Iterable, i16, i16, i16 } +%interface.Iterable = type { ptr } +%struct.NumberIterator.1 = type { %interface.Iterable, i64, i64, i64 } @printf.str.0 = private unnamed_addr constant [10 x i8] c"Short %d\0A\00", align 1 @printf.str.1 = private unnamed_addr constant [9 x i8] c"Long %d\0A\00", align 1 @@ -14,7 +14,7 @@ target triple = "x86_64-w64-windows-gnu" ; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @main() local_unnamed_addr #0 { %shortIterator = alloca %struct.NumberIterator, align 8 - %1 = alloca %struct.NumberIterator.2, align 8 + %1 = alloca %struct.NumberIterator.1, align 8 %2 = tail call %struct.NumberIterator @_Z5rangess(i16 3, i16 8) #2 %.fca.0.0.extract2 = extractvalue %struct.NumberIterator %2, 0, 0 store ptr %.fca.0.0.extract2, ptr %shortIterator, align 8 @@ -31,9 +31,9 @@ define dso_local i32 @main() local_unnamed_addr #0 { br i1 %3, label %foreach.body.L5.lr.ph, label %foreach.exit.L5 foreach.body.L5.lr.ph: ; preds = %0 - %.fca.1.gep = getelementptr inbounds %struct.NumberIterator.2, ptr %1, i64 0, i32 1 - %.fca.2.gep = getelementptr inbounds %struct.NumberIterator.2, ptr %1, i64 0, i32 2 - %.fca.3.gep = getelementptr inbounds %struct.NumberIterator.2, ptr %1, i64 0, i32 3 + %.fca.1.gep = getelementptr inbounds %struct.NumberIterator.1, ptr %1, i64 0, i32 1 + %.fca.2.gep = getelementptr inbounds %struct.NumberIterator.1, ptr %1, i64 0, i32 2 + %.fca.3.gep = getelementptr inbounds %struct.NumberIterator.1, ptr %1, i64 0, i32 3 br label %foreach.body.L5 foreach.body.L5: ; preds = %foreach.body.L5.lr.ph, %foreach.tail.L5 @@ -46,14 +46,14 @@ foreach.body.L5: ; preds = %foreach.body.L5.lr. br i1 %.not, label %foreach.tail.L5, label %if.then.L7 if.then.L7: ; preds = %foreach.body.L5 - %9 = call %struct.NumberIterator.2 @_Z5rangell(i64 1, i64 2) #2 - %.fca.0.0.extract = extractvalue %struct.NumberIterator.2 %9, 0, 0 + %9 = call %struct.NumberIterator.1 @_Z5rangell(i64 1, i64 2) #2 + %.fca.0.0.extract = extractvalue %struct.NumberIterator.1 %9, 0, 0 store ptr %.fca.0.0.extract, ptr %1, align 8 - %.fca.1.extract = extractvalue %struct.NumberIterator.2 %9, 1 + %.fca.1.extract = extractvalue %struct.NumberIterator.1 %9, 1 store i64 %.fca.1.extract, ptr %.fca.1.gep, align 8 - %.fca.2.extract = extractvalue %struct.NumberIterator.2 %9, 2 + %.fca.2.extract = extractvalue %struct.NumberIterator.1 %9, 2 store i64 %.fca.2.extract, ptr %.fca.2.gep, align 8 - %.fca.3.extract = extractvalue %struct.NumberIterator.2 %9, 3 + %.fca.3.extract = extractvalue %struct.NumberIterator.1 %9, 3 store i64 %.fca.3.extract, ptr %.fca.3.gep, align 8 %10 = call i1 @_ZN14NumberIteratorIlE7isValidEv(ptr nonnull %1) #2 br i1 %10, label %foreach.body.L8, label %foreach.tail.L5 @@ -83,7 +83,7 @@ declare ptr @_ZN14NumberIteratorIsE3getEv(ptr) local_unnamed_addr ; Function Attrs: nofree nounwind declare noundef i32 @printf(ptr nocapture noundef readonly, ...) local_unnamed_addr #1 -declare %struct.NumberIterator.2 @_Z5rangell(i64, i64) local_unnamed_addr +declare %struct.NumberIterator.1 @_Z5rangell(i64, i64) local_unnamed_addr declare i1 @_ZN14NumberIteratorIlE7isValidEv(ptr) local_unnamed_addr diff --git a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code.ll b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code.ll index 50bdad982..cfd536c41 100644 --- a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code.ll +++ b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-break/ir-code.ll @@ -3,9 +3,9 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%struct.NumberIterator = type { %interface.Iterable.1, i16, i16, i16 } -%interface.Iterable.1 = type { ptr } -%struct.NumberIterator.2 = type { %interface.Iterable.1, i64, i64, i64 } +%struct.NumberIterator = type { %interface.Iterable, i16, i16, i16 } +%interface.Iterable = type { ptr } +%struct.NumberIterator.1 = type { %interface.Iterable, i64, i64, i64 } @printf.str.0 = private unnamed_addr constant [10 x i8] c"Short %d\0A\00", align 1 @printf.str.1 = private unnamed_addr constant [9 x i8] c"Long %d\0A\00", align 1 @@ -16,7 +16,7 @@ define dso_local i32 @main() #0 { %result = alloca i32, align 4 %shortIterator = alloca %struct.NumberIterator, align 8 %s = alloca i16, align 2 - %1 = alloca %struct.NumberIterator.2, align 8 + %1 = alloca %struct.NumberIterator.1, align 8 %l = alloca ptr, align 8 %2 = alloca ptr, align 8 store i32 0, ptr %result, align 4 @@ -42,8 +42,8 @@ foreach.body.L5: ; preds = %foreach.head.L5 br i1 %13, label %if.then.L7, label %if.exit.L7 if.then.L7: ; preds = %foreach.body.L5 - %14 = call %struct.NumberIterator.2 @_Z5rangell(i64 1, i64 2) - store %struct.NumberIterator.2 %14, ptr %1, align 8 + %14 = call %struct.NumberIterator.1 @_Z5rangell(i64 1, i64 2) + store %struct.NumberIterator.1 %14, ptr %1, align 8 br label %foreach.head.L8 foreach.head.L8: ; preds = %foreach.tail.L8, %if.then.L7 @@ -87,7 +87,7 @@ declare ptr @_ZN14NumberIteratorIsE3getEv(ptr) ; Function Attrs: nofree nounwind declare noundef i32 @printf(ptr nocapture noundef readonly, ...) #1 -declare %struct.NumberIterator.2 @_Z5rangell(i64, i64) +declare %struct.NumberIterator.1 @_Z5rangell(i64, i64) declare i1 @_ZN14NumberIteratorIlE7isValidEv(ptr) diff --git a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code-O2.ll b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code-O2.ll index ba0b8844a..d49dd242e 100644 --- a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code-O2.ll +++ b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code-O2.ll @@ -3,9 +3,9 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%struct.NumberIterator = type { %interface.Iterable.1, i16, i16, i16 } -%interface.Iterable.1 = type { ptr } -%struct.NumberIterator.2 = type { %interface.Iterable.1, i64, i64, i64 } +%struct.NumberIterator = type { %interface.Iterable, i16, i16, i16 } +%interface.Iterable = type { ptr } +%struct.NumberIterator.1 = type { %interface.Iterable, i64, i64, i64 } @printf.str.0 = private unnamed_addr constant [10 x i8] c"Short %d\0A\00", align 1 @printf.str.1 = private unnamed_addr constant [9 x i8] c"Long %d\0A\00", align 1 @@ -14,7 +14,7 @@ target triple = "x86_64-w64-windows-gnu" ; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @main() local_unnamed_addr #0 { %shortIterator = alloca %struct.NumberIterator, align 8 - %1 = alloca %struct.NumberIterator.2, align 8 + %1 = alloca %struct.NumberIterator.1, align 8 %2 = tail call %struct.NumberIterator @_Z5rangess(i16 3, i16 8) #2 %.fca.0.0.extract2 = extractvalue %struct.NumberIterator %2, 0, 0 store ptr %.fca.0.0.extract2, ptr %shortIterator, align 8 @@ -31,9 +31,9 @@ define dso_local i32 @main() local_unnamed_addr #0 { br i1 %3, label %foreach.body.L5.lr.ph, label %foreach.exit.L5 foreach.body.L5.lr.ph: ; preds = %0 - %.fca.1.gep = getelementptr inbounds %struct.NumberIterator.2, ptr %1, i64 0, i32 1 - %.fca.2.gep = getelementptr inbounds %struct.NumberIterator.2, ptr %1, i64 0, i32 2 - %.fca.3.gep = getelementptr inbounds %struct.NumberIterator.2, ptr %1, i64 0, i32 3 + %.fca.1.gep = getelementptr inbounds %struct.NumberIterator.1, ptr %1, i64 0, i32 1 + %.fca.2.gep = getelementptr inbounds %struct.NumberIterator.1, ptr %1, i64 0, i32 2 + %.fca.3.gep = getelementptr inbounds %struct.NumberIterator.1, ptr %1, i64 0, i32 3 br label %foreach.body.L5 foreach.body.L5: ; preds = %foreach.body.L5.lr.ph, %foreach.tail.L5 @@ -46,14 +46,14 @@ foreach.body.L5: ; preds = %foreach.body.L5.lr. br i1 %.not, label %foreach.tail.L5, label %if.then.L7 if.then.L7: ; preds = %foreach.body.L5 - %9 = call %struct.NumberIterator.2 @_Z5rangell(i64 1, i64 2) #2 - %.fca.0.0.extract = extractvalue %struct.NumberIterator.2 %9, 0, 0 + %9 = call %struct.NumberIterator.1 @_Z5rangell(i64 1, i64 2) #2 + %.fca.0.0.extract = extractvalue %struct.NumberIterator.1 %9, 0, 0 store ptr %.fca.0.0.extract, ptr %1, align 8 - %.fca.1.extract = extractvalue %struct.NumberIterator.2 %9, 1 + %.fca.1.extract = extractvalue %struct.NumberIterator.1 %9, 1 store i64 %.fca.1.extract, ptr %.fca.1.gep, align 8 - %.fca.2.extract = extractvalue %struct.NumberIterator.2 %9, 2 + %.fca.2.extract = extractvalue %struct.NumberIterator.1 %9, 2 store i64 %.fca.2.extract, ptr %.fca.2.gep, align 8 - %.fca.3.extract = extractvalue %struct.NumberIterator.2 %9, 3 + %.fca.3.extract = extractvalue %struct.NumberIterator.1 %9, 3 store i64 %.fca.3.extract, ptr %.fca.3.gep, align 8 %10 = call i1 @_ZN14NumberIteratorIlE7isValidEv(ptr nonnull %1) #2 br i1 %10, label %foreach.body.L8, label %foreach.tail.L5 @@ -83,7 +83,7 @@ declare ptr @_ZN14NumberIteratorIsE3getEv(ptr) local_unnamed_addr ; Function Attrs: nofree nounwind declare noundef i32 @printf(ptr nocapture noundef readonly, ...) local_unnamed_addr #1 -declare %struct.NumberIterator.2 @_Z5rangell(i64, i64) local_unnamed_addr +declare %struct.NumberIterator.1 @_Z5rangell(i64, i64) local_unnamed_addr declare i1 @_ZN14NumberIteratorIlE7isValidEv(ptr) local_unnamed_addr diff --git a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code.ll b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code.ll index b1bc81bb1..272953c5d 100644 --- a/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code.ll +++ b/test/test-files/irgenerator/foreach-loops/success-foreach-loop-continue/ir-code.ll @@ -3,9 +3,9 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%struct.NumberIterator = type { %interface.Iterable.1, i16, i16, i16 } -%interface.Iterable.1 = type { ptr } -%struct.NumberIterator.2 = type { %interface.Iterable.1, i64, i64, i64 } +%struct.NumberIterator = type { %interface.Iterable, i16, i16, i16 } +%interface.Iterable = type { ptr } +%struct.NumberIterator.1 = type { %interface.Iterable, i64, i64, i64 } @printf.str.0 = private unnamed_addr constant [10 x i8] c"Short %d\0A\00", align 1 @printf.str.1 = private unnamed_addr constant [9 x i8] c"Long %d\0A\00", align 1 @@ -16,7 +16,7 @@ define dso_local i32 @main() #0 { %result = alloca i32, align 4 %shortIterator = alloca %struct.NumberIterator, align 8 %s = alloca i16, align 2 - %1 = alloca %struct.NumberIterator.2, align 8 + %1 = alloca %struct.NumberIterator.1, align 8 %l = alloca ptr, align 8 %2 = alloca ptr, align 8 store i32 0, ptr %result, align 4 @@ -42,8 +42,8 @@ foreach.body.L5: ; preds = %foreach.head.L5 br i1 %13, label %if.then.L7, label %if.exit.L7 if.then.L7: ; preds = %foreach.body.L5 - %14 = call %struct.NumberIterator.2 @_Z5rangell(i64 1, i64 2) - store %struct.NumberIterator.2 %14, ptr %1, align 8 + %14 = call %struct.NumberIterator.1 @_Z5rangell(i64 1, i64 2) + store %struct.NumberIterator.1 %14, ptr %1, align 8 br label %foreach.head.L8 foreach.head.L8: ; preds = %foreach.tail.L8, %if.then.L7 @@ -87,7 +87,7 @@ declare ptr @_ZN14NumberIteratorIsE3getEv(ptr) ; Function Attrs: nofree nounwind declare noundef i32 @printf(ptr nocapture noundef readonly, ...) #1 -declare %struct.NumberIterator.2 @_Z5rangell(i64, i64) +declare %struct.NumberIterator.1 @_Z5rangell(i64, i64) declare i1 @_ZN14NumberIteratorIlE7isValidEv(ptr) diff --git a/test/test-files/irgenerator/generics/success-nested-generic-structs/ir-code.ll b/test/test-files/irgenerator/generics/success-nested-generic-structs/ir-code.ll index 1cfed9a48..9c49011e3 100644 --- a/test/test-files/irgenerator/generics/success-nested-generic-structs/ir-code.ll +++ b/test/test-files/irgenerator/generics/success-nested-generic-structs/ir-code.ll @@ -3,14 +3,14 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%struct.Node.3 = type { ptr, double } +%struct.Node = type { ptr, double } ; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @main() #0 { %result = alloca i32, align 4 - %_node = alloca %struct.Node.3, align 8 + %_node = alloca %struct.Node, align 8 store i32 0, ptr %result, align 4 - store %struct.Node.3 zeroinitializer, ptr %_node, align 8 + store %struct.Node zeroinitializer, ptr %_node, align 8 %1 = load i32, ptr %result, align 4 ret i32 %1 } diff --git a/test/test-files/irgenerator/lambdas/success-captures/ir-code.ll b/test/test-files/irgenerator/lambdas/success-captures/ir-code.ll index d29e21d41..6da290c64 100644 --- a/test/test-files/irgenerator/lambdas/success-captures/ir-code.ll +++ b/test/test-files/irgenerator/lambdas/success-captures/ir-code.ll @@ -3,9 +3,6 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%anon.captures.0 = type { i32, i32 } -%anon.captures.0.0 = type { i32, i32 } - @anon.string.0 = private unnamed_addr constant [57 x i8] c"Assertion failed: Condition 'x == 6' evaluated to false.\00", align 1 @anon.string.1 = private unnamed_addr constant [58 x i8] c"Assertion failed: Condition 'foo2(x)' evaluated to false.\00", align 1 @anon.string.2 = private unnamed_addr constant [58 x i8] c"Assertion failed: Condition 'x == 11' evaluated to false.\00", align 1 @@ -16,10 +13,10 @@ define dso_local i32 @main() #0 { %result = alloca i32, align 4 %z = alloca i32, align 4 %w = alloca i32, align 4 - %captures = alloca %anon.captures.0, align 8 + %captures = alloca { i32, i32 }, align 8 %fat.ptr = alloca { ptr, ptr }, align 8 %foo1 = alloca { ptr, ptr }, align 8 - %captures1 = alloca %anon.captures.0.0, align 8 + %captures1 = alloca { i32, i32 }, align 8 %fat.ptr2 = alloca { ptr, ptr }, align 8 %foo2 = alloca { ptr, ptr }, align 8 %x = alloca i32, align 4 @@ -27,10 +24,10 @@ define dso_local i32 @main() #0 { store i32 2, ptr %z, align 4 store i32 3, ptr %w, align 4 %1 = load i32, ptr %w, align 4 - %2 = getelementptr inbounds %anon.captures.0, ptr %captures, i32 0, i32 0 + %2 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 0 store i32 %1, ptr %2, align 4 %3 = load i32, ptr %z, align 4 - %4 = getelementptr inbounds %anon.captures.0, ptr %captures, i32 0, i32 1 + %4 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 1 store i32 %3, ptr %4, align 4 %5 = getelementptr inbounds { ptr, ptr }, ptr %fat.ptr, i32 0, i32 0 store ptr @_Z14lambda.L4C20.0Ri, ptr %5, align 8 @@ -39,10 +36,10 @@ define dso_local i32 @main() #0 { %7 = load { ptr, ptr }, ptr %fat.ptr, align 8 store { ptr, ptr } %7, ptr %foo1, align 8 %8 = load i32, ptr %w, align 4 - %9 = getelementptr inbounds %anon.captures.0.0, ptr %captures1, i32 0, i32 0 + %9 = getelementptr inbounds { i32, i32 }, ptr %captures1, i32 0, i32 0 store i32 %8, ptr %9, align 4 %10 = load i32, ptr %z, align 4 - %11 = getelementptr inbounds %anon.captures.0.0, ptr %captures1, i32 0, i32 1 + %11 = getelementptr inbounds { i32, i32 }, ptr %captures1, i32 0, i32 1 store i32 %10, ptr %11, align 4 %12 = getelementptr inbounds { ptr, ptr }, ptr %fat.ptr2, i32 0, i32 0 store ptr @_Z14lambda.L7C26.0Ri, ptr %12, align 8 @@ -100,8 +97,8 @@ define private void @_Z14lambda.L4C20.0Ri(ptr noundef nonnull dereferenceable(8) store ptr %0, ptr %captures, align 8 store ptr %1, ptr %x, align 8 %3 = load ptr, ptr %captures, align 8 - %w = getelementptr inbounds %anon.captures.0, ptr %3, i32 0, i32 0 - %z = getelementptr inbounds %anon.captures.0, ptr %3, i32 0, i32 1 + %w = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 0 + %z = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 1 %4 = load i32, ptr %w, align 4 %5 = load i32, ptr %z, align 4 %6 = add i32 %5, %4 @@ -119,8 +116,8 @@ define private i1 @_Z14lambda.L7C26.0Ri(ptr noundef nonnull dereferenceable(8) % store ptr %0, ptr %captures, align 8 store ptr %1, ptr %x, align 8 %3 = load ptr, ptr %captures, align 8 - %w = getelementptr inbounds %anon.captures.0.0, ptr %3, i32 0, i32 0 - %z = getelementptr inbounds %anon.captures.0.0, ptr %3, i32 0, i32 1 + %w = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 0 + %z = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 1 %4 = load i32, ptr %w, align 4 %5 = load i32, ptr %z, align 4 %6 = add i32 %5, %4 diff --git a/test/test-files/irgenerator/lambdas/success-foreign-captures/ir-code.ll b/test/test-files/irgenerator/lambdas/success-foreign-captures/ir-code.ll index a23b01837..c78de40ca 100644 --- a/test/test-files/irgenerator/lambdas/success-foreign-captures/ir-code.ll +++ b/test/test-files/irgenerator/lambdas/success-foreign-captures/ir-code.ll @@ -3,9 +3,6 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%anon.captures.0 = type { i32, i32 } -%anon.captures.0.0 = type { i32, i32 } - @anon.string.0 = private unnamed_addr constant [57 x i8] c"Assertion failed: Condition 'x == 6' evaluated to false.\00", align 1 @anon.string.1 = private unnamed_addr constant [56 x i8] c"Assertion failed: Condition 'l2(x)' evaluated to false.\00", align 1 @anon.string.2 = private unnamed_addr constant [58 x i8] c"Assertion failed: Condition 'x == 11' evaluated to false.\00", align 1 @@ -70,20 +67,20 @@ define dso_local i32 @main() #2 { %result = alloca i32, align 4 %z = alloca i32, align 4 %w = alloca i32, align 4 - %captures = alloca %anon.captures.0, align 8 + %captures = alloca { i32, i32 }, align 8 %fat.ptr = alloca { ptr, ptr }, align 8 %foo1 = alloca { ptr, ptr }, align 8 - %captures1 = alloca %anon.captures.0.0, align 8 + %captures1 = alloca { i32, i32 }, align 8 %fat.ptr2 = alloca { ptr, ptr }, align 8 %foo2 = alloca { ptr, ptr }, align 8 store i32 0, ptr %result, align 4 store i32 2, ptr %z, align 4 store i32 3, ptr %w, align 4 %1 = load i32, ptr %w, align 4 - %2 = getelementptr inbounds %anon.captures.0, ptr %captures, i32 0, i32 0 + %2 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 0 store i32 %1, ptr %2, align 4 %3 = load i32, ptr %z, align 4 - %4 = getelementptr inbounds %anon.captures.0, ptr %captures, i32 0, i32 1 + %4 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 1 store i32 %3, ptr %4, align 4 %5 = getelementptr inbounds { ptr, ptr }, ptr %fat.ptr, i32 0, i32 0 store ptr @_Z15lambda.L12C20.0Ri, ptr %5, align 8 @@ -92,10 +89,10 @@ define dso_local i32 @main() #2 { %7 = load { ptr, ptr }, ptr %fat.ptr, align 8 store { ptr, ptr } %7, ptr %foo1, align 8 %8 = load i32, ptr %w, align 4 - %9 = getelementptr inbounds %anon.captures.0.0, ptr %captures1, i32 0, i32 0 + %9 = getelementptr inbounds { i32, i32 }, ptr %captures1, i32 0, i32 0 store i32 %8, ptr %9, align 4 %10 = load i32, ptr %z, align 4 - %11 = getelementptr inbounds %anon.captures.0.0, ptr %captures1, i32 0, i32 1 + %11 = getelementptr inbounds { i32, i32 }, ptr %captures1, i32 0, i32 1 store i32 %10, ptr %11, align 4 %12 = getelementptr inbounds { ptr, ptr }, ptr %fat.ptr2, i32 0, i32 0 store ptr @_Z15lambda.L15C26.0Ri, ptr %12, align 8 @@ -117,8 +114,8 @@ define private void @_Z15lambda.L12C20.0Ri(ptr noundef nonnull dereferenceable(8 store ptr %0, ptr %captures, align 8 store ptr %1, ptr %x, align 8 %3 = load ptr, ptr %captures, align 8 - %w = getelementptr inbounds %anon.captures.0, ptr %3, i32 0, i32 0 - %z = getelementptr inbounds %anon.captures.0, ptr %3, i32 0, i32 1 + %w = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 0 + %z = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 1 %4 = load i32, ptr %w, align 4 %5 = load i32, ptr %z, align 4 %6 = add i32 %5, %4 @@ -136,8 +133,8 @@ define private i1 @_Z15lambda.L15C26.0Ri(ptr noundef nonnull dereferenceable(8) store ptr %0, ptr %captures, align 8 store ptr %1, ptr %x, align 8 %3 = load ptr, ptr %captures, align 8 - %w = getelementptr inbounds %anon.captures.0.0, ptr %3, i32 0, i32 0 - %z = getelementptr inbounds %anon.captures.0.0, ptr %3, i32 0, i32 1 + %w = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 0 + %z = getelementptr inbounds { i32, i32 }, ptr %3, i32 0, i32 1 %4 = load i32, ptr %w, align 4 %5 = load i32, ptr %z, align 4 %6 = add i32 %5, %4 diff --git a/test/test-files/irgenerator/lambdas/success-multiple-visits/ir-code.ll b/test/test-files/irgenerator/lambdas/success-multiple-visits/ir-code.ll index 7de2ca2dd..6f2876fb6 100644 --- a/test/test-files/irgenerator/lambdas/success-multiple-visits/ir-code.ll +++ b/test/test-files/irgenerator/lambdas/success-multiple-visits/ir-code.ll @@ -3,25 +3,22 @@ source_filename = "source.spice" target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-w64-windows-gnu" -%anon.captures.0 = type { i32, i32 } -%anon.captures.0.0 = type { i32, i32 } - @printf.str.0 = private unnamed_addr constant [8 x i8] c"%d, %d\0A\00", align 1 @printf.str.1 = private unnamed_addr constant [8 x i8] c"%d, %d\0A\00", align 1 define private void @_Z4testv() { %t = alloca i32, align 4 %x = alloca i32, align 4 - %captures = alloca %anon.captures.0, align 8 + %captures = alloca { i32, i32 }, align 8 %fat.ptr = alloca { ptr, ptr }, align 8 %l = alloca { ptr, ptr }, align 8 store i32 123, ptr %t, align 4 store i32 456, ptr %x, align 4 %1 = load i32, ptr %t, align 4 - %2 = getelementptr inbounds %anon.captures.0, ptr %captures, i32 0, i32 0 + %2 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 0 store i32 %1, ptr %2, align 4 %3 = load i32, ptr %x, align 4 - %4 = getelementptr inbounds %anon.captures.0, ptr %captures, i32 0, i32 1 + %4 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 1 store i32 %3, ptr %4, align 4 %5 = getelementptr inbounds { ptr, ptr }, ptr %fat.ptr, i32 0, i32 0 store ptr @_Z14lambda.L3C13.0v, ptr %5, align 8 @@ -41,8 +38,8 @@ define private void @_Z14lambda.L3C13.0v(ptr noundef nonnull dereferenceable(8) %captures = alloca ptr, align 8 store ptr %0, ptr %captures, align 8 %2 = load ptr, ptr %captures, align 8 - %t = getelementptr inbounds %anon.captures.0, ptr %2, i32 0, i32 0 - %x = getelementptr inbounds %anon.captures.0, ptr %2, i32 0, i32 1 + %t = getelementptr inbounds { i32, i32 }, ptr %2, i32 0, i32 0 + %x = getelementptr inbounds { i32, i32 }, ptr %2, i32 0, i32 1 %3 = load i32, ptr %x, align 4 %4 = load i32, ptr %t, align 4 %5 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.0, i32 %3, i32 %4) @@ -55,16 +52,16 @@ declare noundef i32 @printf(ptr nocapture noundef readonly, ...) #0 define private void @_Z4testi(i32 %0) { %t = alloca i32, align 4 %x = alloca i32, align 4 - %captures = alloca %anon.captures.0.0, align 8 + %captures = alloca { i32, i32 }, align 8 %fat.ptr = alloca { ptr, ptr }, align 8 %l = alloca { ptr, ptr }, align 8 store i32 %0, ptr %t, align 4 store i32 456, ptr %x, align 4 %2 = load i32, ptr %t, align 4 - %3 = getelementptr inbounds %anon.captures.0.0, ptr %captures, i32 0, i32 0 + %3 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 0 store i32 %2, ptr %3, align 4 %4 = load i32, ptr %x, align 4 - %5 = getelementptr inbounds %anon.captures.0.0, ptr %captures, i32 0, i32 1 + %5 = getelementptr inbounds { i32, i32 }, ptr %captures, i32 0, i32 1 store i32 %4, ptr %5, align 4 %6 = getelementptr inbounds { ptr, ptr }, ptr %fat.ptr, i32 0, i32 0 store ptr @_Z14lambda.L3C13.1v, ptr %6, align 8 @@ -84,8 +81,8 @@ define private void @_Z14lambda.L3C13.1v(ptr noundef nonnull dereferenceable(8) %captures = alloca ptr, align 8 store ptr %0, ptr %captures, align 8 %2 = load ptr, ptr %captures, align 8 - %t = getelementptr inbounds %anon.captures.0.0, ptr %2, i32 0, i32 0 - %x = getelementptr inbounds %anon.captures.0.0, ptr %2, i32 0, i32 1 + %t = getelementptr inbounds { i32, i32 }, ptr %2, i32 0, i32 0 + %x = getelementptr inbounds { i32, i32 }, ptr %2, i32 0, i32 1 %3 = load i32, ptr %x, align 4 %4 = load i32, ptr %t, align 4 %5 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.1, i32 %3, i32 %4) diff --git a/test/test-files/std/type/bool-type-functions/source.spice b/test/test-files/std/type/bool-type-functions/source.spice index 3fabe7f69..f9e8e840d 100644 --- a/test/test-files/std/type/bool-type-functions/source.spice +++ b/test/test-files/std/type/bool-type-functions/source.spice @@ -32,10 +32,10 @@ f main() { assert asByte2 == (byte) 0; // toString() - //string asString1 = toString(true); - //assert asString1 == "true"; - //string asString2 = toString(false); - //assert asString2 == "false"; + string asString1 = toString(true); + assert asString1 == "true"; + string asString2 = toString(false); + assert asString2 == "false"; printf("All assertions succeeded"); } \ No newline at end of file diff --git a/test/test-files/std/type/byte-type-functions/source.spice b/test/test-files/std/type/byte-type-functions/source.spice index 769b1dda2..0e1da2b2e 100644 --- a/test/test-files/std/type/byte-type-functions/source.spice +++ b/test/test-files/std/type/byte-type-functions/source.spice @@ -18,8 +18,8 @@ f main() { assert asLong == 63l; // toString() - //string asString = toString((byte) 13); - //assert asString == "13"; + String asString = toString((byte) 13); + assert asString.getRaw() == "13"; // toBool() bool asBool1 = toBool((byte) 1); diff --git a/test/test-files/std/type/char-type-functions/source.spice b/test/test-files/std/type/char-type-functions/source.spice index 71ddb4e67..ca3b31886 100644 --- a/test/test-files/std/type/char-type-functions/source.spice +++ b/test/test-files/std/type/char-type-functions/source.spice @@ -18,8 +18,8 @@ f main() { assert asLong == 75l; // toString() - //string asString = toString('v'); - //assert asString == "v"; + String asString = toString('v'); + assert asString.getRaw() == "v"; // toBool() bool asBool1 = toBool('1'); diff --git a/test/test-files/std/type/double-type-functions/source.spice b/test/test-files/std/type/double-type-functions/source.spice index 02a366872..e05c1fc85 100644 --- a/test/test-files/std/type/double-type-functions/source.spice +++ b/test/test-files/std/type/double-type-functions/source.spice @@ -2,24 +2,20 @@ import "std/type/double"; f main() { // toInt() - //int asInt = toInt(123.54); - //assert asInt == 123; + int asInt = toInt(123.54); + assert asInt == 123; // toShort() - //short asShort = toShort(12.345); - //assert asShort == 12; + short asShort = toShort(12.345); + assert asShort == 12; // toLong() - //long asLong = toLong(534569.2345); - //assert asLong == 534569l; - - // toByte() - //long asByte = toLong(53.89); - //assert asByte == (byte) 53; + long asLong = toLong(534569.2345); + assert asLong == 534569l; // toString() - //string asString = toString(9.0); - //assert asString == "9.0"; + //String asString = toString(3.14); + //assert asString.getRaw() == "3.14"; // toBool() bool asBool1 = toBool(1.0); diff --git a/test/test-files/std/type/int-type-functions/source.spice b/test/test-files/std/type/int-type-functions/source.spice index 3cefc4750..81b01c016 100644 --- a/test/test-files/std/type/int-type-functions/source.spice +++ b/test/test-files/std/type/int-type-functions/source.spice @@ -22,9 +22,8 @@ f main() { assert asChar == 'B'; // toString() - //string asString = toString(12345); - //assert asString == "12345"; - //printf("Str: %s\n", asString); + String asString = toString(12345); + assert asString.getRaw() == "12345"; // toBool() bool asBool1 = toBool(1); diff --git a/test/test-files/std/type/long-type-functions/source.spice b/test/test-files/std/type/long-type-functions/source.spice index 346aae05f..5d952e20f 100644 --- a/test/test-files/std/type/long-type-functions/source.spice +++ b/test/test-files/std/type/long-type-functions/source.spice @@ -22,9 +22,8 @@ f main() { assert asChar == 'B'; // toString() - //string asString = toString(12345l); - //assert asString == "12345"; - //printf("Str: %s\n", asString); + String asString = toString(12345l); + assert asString.getRaw() == "12345"; // toBool() bool asBool1 = toBool(1l); diff --git a/test/test-files/std/type/short-type-functions/source.spice b/test/test-files/std/type/short-type-functions/source.spice index d00de422f..65c227566 100644 --- a/test/test-files/std/type/short-type-functions/source.spice +++ b/test/test-files/std/type/short-type-functions/source.spice @@ -22,9 +22,8 @@ f main() { assert asChar == 'B'; // toString() - //string asString = toString(15); - //assert asString == "15"; - //printf("Str: %s\n", asString); + String asString = toString(15s); + assert asString.getRaw() == "15"; // toBool() bool asBool1 = toBool(1s); diff --git a/test/test-files/std/type/string-type-functions/source.spice b/test/test-files/std/type/string-type-functions/source.spice index cd51aa97e..f8a3acce3 100644 --- a/test/test-files/std/type/string-type-functions/source.spice +++ b/test/test-files/std/type/string-type-functions/source.spice @@ -3,32 +3,27 @@ import "std/type/string"; f main() { // toDouble() double asDouble = toDouble("5.67"); - //assert asDouble == 5.67; + assert asDouble == 5.67; // toInt() int asInt = toInt("-6546"); - //assert asInt == -6546; + assert asInt == -6546; // toLong() long asLong = toLong("56"); - //assert asLong == 56l; + assert asLong == 56l; // toShort() short asShort = toShort("-12"); - //assert asShort == -12s; + assert asShort == -12s; // toByte() byte asByte = toByte("12"); - //assert asByte == (byte) 12; + assert asByte == (byte) 12; // toChar() char asChar = toChar("i"); - //assert asChar == 'i'; - - // toString() - //string asString = toString(15); - //assert asString == "15"; - //printf("Str: %s\n", asString); + assert asChar == 'i'; // toBool() bool asBool1 = toBool("true"); diff --git a/test/test-files/typechecker/foreach-loops/success-foreach-item-type-inference/symbol-table.json b/test/test-files/typechecker/foreach-loops/success-foreach-item-type-inference/symbol-table.json index bad3f223c..b60928600 100644 --- a/test/test-files/typechecker/foreach-loops/success-foreach-item-type-inference/symbol-table.json +++ b/test/test-files/typechecker/foreach-loops/success-foreach-item-type-inference/symbol-table.json @@ -336,7 +336,7 @@ "name": "this.Iterable", "orderIndex": 0, "state": "declared", - "type": "public std/iterator/iterable::Iterable" + "type": "public std/iterator/iterable::Iterable" } ] }, @@ -565,7 +565,7 @@ "name": "this.Iterable", "orderIndex": 0, "state": "declared", - "type": "public std/iterator/iterable::Iterable" + "type": "public std/iterator/iterable::Iterable" } ] } diff --git a/test/test-files/typechecker/methods/error-method-on-field-without-this/exception.out b/test/test-files/typechecker/methods/error-method-on-field-without-this/exception.out new file mode 100644 index 000000000..429508bcc --- /dev/null +++ b/test/test-files/typechecker/methods/error-method-on-field-without-this/exception.out @@ -0,0 +1,8 @@ +[Error|Compiler]: +Unresolved soft errors: There are unresolved errors. Please fix them and recompile. + +[Error|Semantic] ./test-files/typechecker/methods/error-method-on-field-without-this/source.spice:12:5: +Referenced undefined variable: The symbol 'a' could not be found. Missing 'this.' prefix? + +12 a.foo(); + ^^^^^^^ \ No newline at end of file diff --git a/test/test-files/typechecker/methods/error-method-on-field-without-this/source.spice b/test/test-files/typechecker/methods/error-method-on-field-without-this/source.spice new file mode 100644 index 000000000..fe7fa3259 --- /dev/null +++ b/test/test-files/typechecker/methods/error-method-on-field-without-this/source.spice @@ -0,0 +1,18 @@ +type A struct {} + +p A.foo() { + printf("A.foo\n"); +} + +type B struct { + A a +} + +p B.callFooOnA() { + a.foo(); +} + +f main() { + B b; + b.callFooOnA(); +} \ No newline at end of file