From a3760b8587a0238563d817a8129da9ad9790fb58 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sun, 9 Oct 2022 07:30:52 +0200 Subject: [PATCH] Allow immediate access to struct return values (#210) * Rebase * Fix bug & extend string runtime * Fix bug in test runner * Tweak build configuration * Add stub for fastbuild * Allow direct member access on return values of method calls * Allow direct method calls on return values of method calls * Add run configurations --- .github/workflows/ci-cpp.yml | 6 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/publish.yml | 8 +- .gitignore | 3 + .run/Spice_run.run.xml | 11 --- .run/Spice_test.run.xml | 11 --- .run/spice.run.xml | 11 +++ .run/spicetest.run.xml | 12 +++ build.bat | 4 +- build.sh | 4 +- media/test-project/os-test.spice | 71 +++++++++-------- src/CMakeLists.txt | 6 +- src/analyzer/AnalyzerVisitor.cpp | 27 ++++--- src/config.bff | 8 ++ src/fbuild.bff | 26 ++++++ src/generator/GeneratorVisitor.cpp | 18 ++++- src/generator/GeneratorVisitor.h | 3 +- src/symbol/SymbolTable.cpp | 2 +- test/CMakeLists.txt | 6 +- test/TestRunner.cpp | 1 - .../cout.out | 2 + .../ir-code.ll | 71 +++++++++++++++++ .../source.spice | 35 ++++++++ .../structs/success-constructors/cout.out | 4 +- .../structs/success-constructors/ir-code.ll | 79 ++++++++++++++++--- .../structs/success-constructors/source.spice | 14 +++- 26 files changed, 338 insertions(+), 107 deletions(-) delete mode 100644 .run/Spice_run.run.xml delete mode 100644 .run/Spice_test.run.xml create mode 100644 .run/spice.run.xml create mode 100644 .run/spicetest.run.xml create mode 100644 src/config.bff create mode 100644 src/fbuild.bff create mode 100644 test/test-files/generator/methods/success-method-call-on-return-value/cout.out create mode 100644 test/test-files/generator/methods/success-method-call-on-return-value/ir-code.ll create mode 100644 test/test-files/generator/methods/success-method-call-on-return-value/source.spice diff --git a/.github/workflows/ci-cpp.yml b/.github/workflows/ci-cpp.yml index 2d0fdb957..c806638af 100644 --- a/.github/workflows/ci-cpp.yml +++ b/.github/workflows/ci-cpp.yml @@ -72,14 +72,14 @@ jobs: mkdir ./bin cd ./bin cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DSPICE_IS_GH_ACTIONS=ON -DSPICE_BUILT_BY="ghactions" -DSPICE_LINK_STATIC=OFF -DSPICE_DEV_COMPILE=ON -DSPICE_RUN_COVERAGE=ON -GNinja -Wattributes .. - cmake --build . --target Spice_test -j$(nproc) + cmake --build . --target spicetest -j$(nproc) - name: Run Test target env: SPICE_STD_DIR: /home/runner/work/spice/spice/std run: | cd ./bin/test - ./Spice_test false + ./spicetest false - name: Generate coverage report run: | @@ -109,6 +109,6 @@ jobs: # SPICE_STD_DIR: /home/runner/work/spice/spice/std # run: | # cd ./bin/test -# ./Spice_test true +# ./spicetest true # git status --porcelain # git diff --exit-code \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c7e5bedf3..feb6de888 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -70,7 +70,7 @@ jobs: mkdir ./bin cd ./bin cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DSPICE_BUILT_BY="ghactions" -DSPICE_LINK_STATIC=OFF -DSPICE_DEV_COMPILE=ON -GNinja -Wattributes .. - cmake --build . --target Spice_test -j$(nproc) + cmake --build . --target spicetest -j$(nproc) - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5ac65670d..efd6aeb72 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -67,12 +67,12 @@ jobs: mkdir ./bin cd ./bin cmake -GNinja -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DSPICE_LINK_STATIC=OFF -DSPICE_VERSION="${{ steps.get_version.outputs.version }}" -DSPICE_BUILT_BY="ghactions" -DCMAKE_CXX_FLAGS_RELEASE="-O2" .. - cmake --build . --target Spice_run -j$(nproc) + cmake --build . --target spice -j$(nproc) - name: Process build output working-directory: bin run: | - mv ./src/Spice_run spice + mv ./src/spice spice chmod +x spice - name: Upload artifact @@ -146,11 +146,11 @@ jobs: mkdir ./bin cd ./bin cmake -GNinja -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DSPICE_LINK_STATIC=ON -DSPICE_VERSION="${{ steps.get_version.outputs.version }}" -DSPICE_BUILT_BY="ghactions" -DCMAKE_CXX_FLAGS_RELEASE="-O2" .. - cmake --build . --target Spice_run -j$(nproc) + cmake --build . --target spice -j$(nproc) - name: Process build output working-directory: bin - run: mv ./src/Spice_run.exe spice.exe + run: mv ./src/spice.exe spice.exe - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/.gitignore b/.gitignore index 253e3959d..932ddc2e2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ media/test-project/*.exe # LLVM /llvm + +# FASTBuild +*.fdb \ No newline at end of file diff --git a/.run/Spice_run.run.xml b/.run/Spice_run.run.xml deleted file mode 100644 index 67ebee1e4..000000000 --- a/.run/Spice_run.run.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.run/Spice_test.run.xml b/.run/Spice_test.run.xml deleted file mode 100644 index 6eb8d40c7..000000000 --- a/.run/Spice_test.run.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.run/spice.run.xml b/.run/spice.run.xml new file mode 100644 index 000000000..ec6c5204e --- /dev/null +++ b/.run/spice.run.xml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.run/spicetest.run.xml b/.run/spicetest.run.xml new file mode 100644 index 000000000..9e36e34b2 --- /dev/null +++ b/.run/spicetest.run.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/build.bat b/build.bat index 22c454f1c..284832b27 100644 --- a/build.bat +++ b/build.bat @@ -7,6 +7,6 @@ REM - Build mkdir bin 2> NUL pushd bin cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -GNinja -DCMAKE_CXX_FLAGS_RELEASE="-O2" .. -cmake --build . --target Spice_run -move src\Spice_run.exe spice.exe +cmake --build . --target spice +move src\spice.exe spice.exe popd \ No newline at end of file diff --git a/build.sh b/build.sh index 98c8dbb0c..9b9291493 100644 --- a/build.sh +++ b/build.sh @@ -8,6 +8,6 @@ export LLVM_DIR=./llvm/build-release/lib/cmake/llvm ( cd ./bin || exit cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -GNinja -DCMAKE_CXX_FLAGS_RELEASE="-O2" .. - cmake --build . --target Spice_run - mv ./src/Spice_run spice + cmake --build . --target spice + mv ./src/spice spice ) \ No newline at end of file diff --git a/media/test-project/os-test.spice b/media/test-project/os-test.spice index dcb4fb652..3ec5e00f1 100644 --- a/media/test-project/os-test.spice +++ b/media/test-project/os-test.spice @@ -1,40 +1,45 @@ -import "std/runtime/string_rt" as _rt_str; +type Stamp struct { + double value + bool glued +} + +p Stamp.print() { + printf("Value: %f, glued: %d", this.value, this.glued); +} + +type Letter struct { + string content + Stamp stamp +} + +f Letter.getContent() { + return this.content; +} + +p Letter.setContent(string text) { + this.content = text; +} + +f Letter.getStamp() { + return this.stamp; +} + +p Letter.setStamp(Stamp stamp) { + this.stamp = stamp; +} f main() { - _rt_str::String s = _rt_str::String("Hello "); - printf("Content: %s\n", s.getRaw()); - printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); - s.append("World!"); - printf("Content: %s\n", s.getRaw()); - printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); - s.append('?'); - printf("Content: %s\n", s.getRaw()); - printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); - s.append('!'); - printf("Content: %s\n", s.getRaw()); - printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); - printf("Equals: %d\n", s.opEquals("Hello World!?!")); - printf("Equals: %d\n", s.opEquals("Hello World!!")); - printf("Not Equals: %d\n", s.opNotEquals("Hello World!?!")); - printf("Not Equals: %d\n", s.opNotEquals("Hello World!!")); - s.clear(); - printf("Content: %s\n", s.getRaw()); - printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); - s.reserve(100l); - printf("Content: %s\n", s.getRaw()); - printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); - s = _rt_str::String(""); - printf("Empty: %d\n", s.isEmpty()); - s.append('a'); - printf("Empty: %d", s.isEmpty()); + dyn letter = Letter{ "", Stamp{ 3.4, false } }; + printf("Stamp glued: %f\n", letter.getStamp().value); + letter.getStamp().print(); } +/*import "std/runtime/string_rt" as _rt_str; + +f main() { + printf("%d", _rt_str::String("Test").isEmpty()); +}*/ + /*import "std/net/http" as http; f main() { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7185d2d06..231261654 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,11 +74,11 @@ set(SOURCES util/CompilerWarning.cpp util/CompilerWarning.h) -add_executable(${CMAKE_PROJECT_NAME}_run ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) +add_executable(spice ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) # Include Antlr components include_directories(${ANTLR_Spice_OUTPUT_DIR}) include_directories(../lib/antlr4/runtime/Cpp/runtime/src) -target_link_libraries(${CMAKE_PROJECT_NAME}_run antlr4_static ${LLVM_LIBS}) -add_library(${CMAKE_PROJECT_NAME}_lib STATIC ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) \ No newline at end of file +target_link_libraries(spice antlr4_static ${LLVM_LIBS}) +add_library(spicelib STATIC ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) \ No newline at end of file diff --git a/src/analyzer/AnalyzerVisitor.cpp b/src/analyzer/AnalyzerVisitor.cpp index a2e2f676b..a7407eb65 100644 --- a/src/analyzer/AnalyzerVisitor.cpp +++ b/src/analyzer/AnalyzerVisitor.cpp @@ -1685,7 +1685,7 @@ std::any AnalyzerVisitor::visitPostfixUnaryExpr(PostfixUnaryExprNode *node) { } case PostfixUnaryExprNode::OP_MEMBER_ACCESS: { // Check if lhs is struct - if (!lhs.isBaseType(TY_STRUCT) && !lhs.isBaseType(TY_ENUM)) + if (!lhs.isBaseType(TY_STRUCT) && !lhs.isOneOf({TY_ENUM, TY_STRING})) throw SemanticError(node->codeLoc, MEMBER_ACCESS_ONLY_STRUCTS, "Cannot apply member access operator on " + lhs.getName()); PostfixUnaryExprNode *rhs = node->postfixUnaryExpr()[memberAccessCounter++]; @@ -1900,7 +1900,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { SymbolTable *accessScope = scopePath.getCurrentScope() ? scopePath.getCurrentScope() : currentScope; std::string functionName; - SymbolType thisType = SymbolType(TY_DYN); + SymbolType thisType = currentThisType; bool constructorCall = false; for (unsigned int i = 0; i < node->functionNameFragments.size(); i++) { std::string identifier = node->functionNameFragments[i]; @@ -2008,7 +2008,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { // Add anonymous symbol to keep track of de-allocation currentScope->insertAnonymous(thisType, node); // Return struct type on constructor call - return node->setEvaluatedSymbolType(thisType); + return currentThisType = node->setEvaluatedSymbolType(thisType); } // If the callee is a procedure, return type bool @@ -2018,15 +2018,22 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { // Retrieve the return type of the function SymbolType returnType = spiceFunc->getReturnType(); - // If the return type is an external struct, initialize it - if (!scopePathBackup.isEmpty() && returnType.is(TY_STRUCT) && scopePathBackup.getCurrentScope()->isImported(currentScope)) { - std::string scopePrefix = scopePathBackup.getScopePrefix(!spiceFunc->isGenericSubstantiation); - SymbolType symbolType = - initExtStruct(currentScope, scopePrefix, returnType.getSubType(), returnType.getTemplateTypes(), node->codeLoc); - return node->setEvaluatedSymbolType(symbolType); + if (returnType.is(TY_STRUCT)) { + // Add struct scope to scope path + std::string structSignature = Struct::getSignature(returnType.getSubType(), returnType.getTemplateTypes()); + SymbolTable *newAccessScope = accessScope->lookupTable(STRUCT_SCOPE_PREFIX + structSignature); + scopePath.pushFragment(returnType.getSubType(), newAccessScope); + + // If the return type is an external struct, initialize it + if (!scopePathBackup.isEmpty() && scopePathBackup.getCurrentScope()->isImported(currentScope)) { + std::string scopePrefix = scopePathBackup.getScopePrefix(!spiceFunc->isGenericSubstantiation); + SymbolType symbolType = + initExtStruct(currentScope, scopePrefix, returnType.getSubType(), returnType.getTemplateTypes(), node->codeLoc); + return currentThisType = node->setEvaluatedSymbolType(symbolType); + } } - return node->setEvaluatedSymbolType(returnType); + return currentThisType = node->setEvaluatedSymbolType(returnType); } std::any AnalyzerVisitor::visitArrayInitialization(ArrayInitializationNode *node) { diff --git a/src/config.bff b/src/config.bff new file mode 100644 index 000000000..ee48125e8 --- /dev/null +++ b/src/config.bff @@ -0,0 +1,8 @@ +#once + +.Compiler = 'D:\mingw64\bin\g++.exe' +.CompilerOptions = '%1 -c -o %2' +.Linker = 'D:\mingw64\bin\ld.exe' +.LinkerOptions = '-o %2 %1' +.Librarian = 'D:\mingw64\bin\ld.exe' +.LibrarianOptions = '-o %2 %1' \ No newline at end of file diff --git a/src/fbuild.bff b/src/fbuild.bff new file mode 100644 index 000000000..c603c02d5 --- /dev/null +++ b/src/fbuild.bff @@ -0,0 +1,26 @@ +; Compiler configuration +#include "config.bff" + +; Compile all .cpp files in the src dir +ObjectList('Spice') +{ + .CompilerInputPath = '/' + .CompilerOutputPath = '../build/' +} + +Library('antlr') +{ + .CompilerInputPath = '../lib/antlr4/runtime/Cpp/runtime/src' + .CompilerOutputPath = '../build/antlr/' + .LibrarianOutput = '../build/antlr.lib' +} + +; Link the executable +Executable('spice-run') +{ + .Libraries = { 'Spice' } + .LinkerOutput = '../bin/spice.exe' +} + +; Create a default target +Alias('all') { .Targets = { 'spice-run' } } \ No newline at end of file diff --git a/src/generator/GeneratorVisitor.cpp b/src/generator/GeneratorVisitor.cpp index a7fee4f16..c3f358dcd 100644 --- a/src/generator/GeneratorVisitor.cpp +++ b/src/generator/GeneratorVisitor.cpp @@ -2573,8 +2573,8 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) { bool constructorCall = false; // Load the 'this' value if it is a pointer - llvm::Value *thisValuePtr = nullptr; - SymbolType thisSymbolType; + llvm::Value *thisValuePtr = currentThisValuePtr; + SymbolType thisSymbolType = currentSymbolType; for (unsigned int i = 0; i < node->functionNameFragments.size(); i++) { std::string identifier = node->functionNameFragments[i]; SymbolTableEntry *symbolEntry = accessScope->lookup(identifier); @@ -2695,6 +2695,14 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) { // Create the function call llvm::Value *resultValue = builder->CreateCall(fct, argValues); + SymbolType returnSymbolType = spiceFunc->getReturnType(); + if (returnSymbolType.isBaseType(TY_STRUCT)) { + // Add struct scope to scope path + std::string structSignature = Struct::getSignature(returnSymbolType.getSubType(), returnSymbolType.getTemplateTypes()); + SymbolTable *newAccessScope = accessScope->lookupTable(STRUCT_SCOPE_PREFIX + structSignature); + scopePath.pushFragment(returnSymbolType.getSubType(), newAccessScope); + } + // Consider constructor calls if (constructorCall) { // Update mem-address of anonymous symbol @@ -2703,7 +2711,9 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) { anonEntry->updateAddress(thisValuePtr); // Return pointer to this value - return thisValuePtr; + currentSymbolType = anonEntry->type; + structAccessType = currentSymbolType.toLLVMType(*context, accessScope); + return currentThisValuePtr = structAccessAddress = thisValuePtr; } else if (!resultValue->getType()->isSized()) { // Set return type bool for procedures resultValue = builder->getTrue(); @@ -2711,7 +2721,7 @@ std::any GeneratorVisitor::visitFunctionCall(FunctionCallNode *node) { llvm::Value *resultPtr = insertAlloca(resultValue->getType()); builder->CreateStore(resultValue, resultPtr); - return resultPtr; + return currentThisValuePtr = structAccessAddress = resultPtr; } std::any GeneratorVisitor::visitArrayInitialization(ArrayInitializationNode *node) { diff --git a/src/generator/GeneratorVisitor.h b/src/generator/GeneratorVisitor.h index 242a4933d..12e193496 100644 --- a/src/generator/GeneratorVisitor.h +++ b/src/generator/GeneratorVisitor.h @@ -108,7 +108,7 @@ class GeneratorVisitor : public AstVisitor { std::unique_ptr stdFunctionManager; std::unique_ptr conversionsManager; const std::string &objectFile; - llvm::TargetMachine *targetMachine{}; + llvm::TargetMachine *targetMachine; const CliOptions &cliOptions; const LinkerInterface &linker; bool requiresMainFct = true; @@ -119,6 +119,7 @@ class GeneratorVisitor : public AstVisitor { SymbolTable *currentScope; SymbolTable *rootScope; SymbolType currentSymbolType = SymbolType(TY_INVALID); + llvm::Value *currentThisValuePtr = nullptr; ScopePath scopePath; ThreadFactory &threadFactory; bool blockAlreadyTerminated = false; diff --git a/src/symbol/SymbolTable.cpp b/src/symbol/SymbolTable.cpp index e5278d6dc..d8c63b9aa 100644 --- a/src/symbol/SymbolTable.cpp +++ b/src/symbol/SymbolTable.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2021-2022 ChilliBits. All rights reserved. -#include "symbol/SymbolTable.h" +#include "SymbolTable.h" #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0df8c160f..20d3024b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,14 +8,14 @@ set(SOURCES TestUtil.cpp TestUtil.h) -add_executable(${CMAKE_PROJECT_NAME}_test ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) +add_executable(spicetest ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS}) # Include Antlr components include_directories(${ANTLR_Spice_OUTPUT_DIR}) include_directories(../lib/antlr4/runtime/Cpp/runtime/src) -add_test(NAME ${CMAKE_PROJECT_NAME}_test COMMAND ${CMAKE_PROJECT_NAME}_test) -target_link_libraries(${CMAKE_PROJECT_NAME}_test PUBLIC ${CMAKE_PROJECT_NAME}_lib gtest antlr4_static ${LLVM_LIBS}) +add_test(NAME spicetest COMMAND spicetest) +target_link_libraries(spicetest PUBLIC spicelib gtest antlr4_static ${LLVM_LIBS}) # Test files file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/test-files ${CMAKE_CURRENT_BINARY_DIR}/test-files SYMBOLIC) \ No newline at end of file diff --git a/test/TestRunner.cpp b/test/TestRunner.cpp index 6bdee6afe..fb0414fc6 100644 --- a/test/TestRunner.cpp +++ b/test/TestRunner.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/test/test-files/generator/methods/success-method-call-on-return-value/cout.out b/test/test-files/generator/methods/success-method-call-on-return-value/cout.out new file mode 100644 index 000000000..e2b4e3149 --- /dev/null +++ b/test/test-files/generator/methods/success-method-call-on-return-value/cout.out @@ -0,0 +1,2 @@ +Stamp glued: 1 +Value: 3.400000, glued: 1 \ No newline at end of file diff --git a/test/test-files/generator/methods/success-method-call-on-return-value/ir-code.ll b/test/test-files/generator/methods/success-method-call-on-return-value/ir-code.ll new file mode 100644 index 000000000..3e73852b5 --- /dev/null +++ b/test/test-files/generator/methods/success-method-call-on-return-value/ir-code.ll @@ -0,0 +1,71 @@ +; ModuleID = 'source.spice' +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" + +%_s__Stamp__double_bool = type { double, i1 } +%_s__Letter__string_Stamp = type { ptr, %_s__Stamp__double_bool } + +@0 = private unnamed_addr constant [21 x i8] c"Value: %f, glued: %d\00", align 1 +@1 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 +@2 = private unnamed_addr constant [17 x i8] c"Stamp glued: %d\0A\00", align 1 + +define internal void @_mp__Stamp__print(ptr %0) { +entry.l6: + %this = alloca ptr, align 8 + store ptr %0, ptr %this, align 8 + %1 = load ptr, ptr %this, align 8 + %2 = getelementptr inbounds %_s__Stamp__double_bool, ptr %1, i32 0, i32 0 + %3 = load double, ptr %2, align 8 + %4 = load ptr, ptr %this, align 8 + %5 = getelementptr inbounds %_s__Stamp__double_bool, ptr %4, i32 0, i32 1 + %6 = load i1, ptr %5, align 1 + %7 = zext i1 %6 to i32 + %8 = call i32 (ptr, ...) @printf(ptr @0, double %3, i32 %7) + ret void +} + +declare i32 @printf(ptr, ...) + +define internal %_s__Stamp__double_bool @_mf__Letter__getStamp(ptr %0) { +entry.l23: + %this = alloca ptr, align 8 + %result = alloca %_s__Stamp__double_bool, align 8 + store ptr %0, ptr %this, align 8 + %1 = load ptr, ptr %this, align 8 + %2 = getelementptr inbounds %_s__Letter__string_Stamp, ptr %1, i32 0, i32 1 + %3 = load %_s__Stamp__double_bool, ptr %2, align 8 + ret %_s__Stamp__double_bool %3 +} + +define i32 @main() { +entry.l31: + %result = alloca i32, align 4 + %0 = alloca %_s__Letter__string_Stamp, align 8 + %1 = alloca %_s__Stamp__double_bool, align 8 + %2 = alloca %_s__Stamp__double_bool, align 8 + %3 = alloca %_s__Stamp__double_bool, align 8 + %4 = alloca i1, align 1 + store i32 0, ptr %result, align 4 + %5 = getelementptr inbounds %_s__Letter__string_Stamp, ptr %0, i32 0, i32 0 + store ptr @1, ptr %5, align 8 + %6 = getelementptr inbounds %_s__Stamp__double_bool, ptr %1, i32 0, i32 0 + store double 3.400000e+00, ptr %6, align 8 + %7 = getelementptr inbounds %_s__Stamp__double_bool, ptr %1, i32 0, i32 1 + store i1 true, ptr %7, align 1 + %8 = load %_s__Stamp__double_bool, ptr %1, align 8 + %9 = getelementptr inbounds %_s__Letter__string_Stamp, ptr %0, i32 0, i32 1 + store %_s__Stamp__double_bool %8, ptr %9, align 8 + %10 = call %_s__Stamp__double_bool @_mf__Letter__getStamp(ptr %0) + store %_s__Stamp__double_bool %10, ptr %2, align 8 + %11 = getelementptr inbounds %_s__Stamp__double_bool, ptr %2, i32 0, i32 1 + %12 = load i1, ptr %11, align 1 + %13 = zext i1 %12 to i32 + %14 = call i32 (ptr, ...) @printf(ptr @2, i32 %13) + %15 = call %_s__Stamp__double_bool @_mf__Letter__getStamp(ptr %0) + store %_s__Stamp__double_bool %15, ptr %3, align 8 + call void @_mp__Stamp__print(ptr %3) + store i1 true, ptr %4, align 1 + %16 = load i32, ptr %result, align 4 + ret i32 %16 +} diff --git a/test/test-files/generator/methods/success-method-call-on-return-value/source.spice b/test/test-files/generator/methods/success-method-call-on-return-value/source.spice new file mode 100644 index 000000000..ad64407c5 --- /dev/null +++ b/test/test-files/generator/methods/success-method-call-on-return-value/source.spice @@ -0,0 +1,35 @@ +type Stamp struct { + double value + bool glued +} + +p Stamp.print() { + printf("Value: %f, glued: %d", this.value, this.glued); +} + +type Letter struct { + string content + Stamp stamp +} + +f Letter.getContent() { + return this.content; +} + +p Letter.setContent(string text) { + this.content = text; +} + +f Letter.getStamp() { + return this.stamp; +} + +p Letter.setStamp(Stamp stamp) { + this.stamp = stamp; +} + +f main() { + dyn letter = Letter{ "", Stamp{ 3.4, true } }; + printf("Stamp glued: %d\n", letter.getStamp().glued); + letter.getStamp().print(); +} \ No newline at end of file diff --git a/test/test-files/generator/structs/success-constructors/cout.out b/test/test-files/generator/structs/success-constructors/cout.out index ea2787c77..d9ae66ba2 100644 --- a/test/test-files/generator/structs/success-constructors/cout.out +++ b/test/test-files/generator/structs/success-constructors/cout.out @@ -1 +1,3 @@ -Fields: 0, Test string \ No newline at end of file +Fields: 0, Test string +Fields: 0, Another message +Message: Hello World! diff --git a/test/test-files/generator/structs/success-constructors/ir-code.ll b/test/test-files/generator/structs/success-constructors/ir-code.ll index dc7fdb6d7..3f7d8b363 100644 --- a/test/test-files/generator/structs/success-constructors/ir-code.ll +++ b/test/test-files/generator/structs/success-constructors/ir-code.ll @@ -6,35 +6,88 @@ target triple = "x86_64-w64-windows-gnu" %_s__Vector__bool_string = type { i1, ptr } @0 = private unnamed_addr constant [12 x i8] c"Test string\00", align 1 -@1 = private unnamed_addr constant [15 x i8] c"Fields: %d, %s\00", align 1 +@1 = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1 +@2 = private unnamed_addr constant [16 x i8] c"Fields: %d, %s\0A\00", align 1 +@3 = private unnamed_addr constant [16 x i8] c"Another message\00", align 1 +@4 = private unnamed_addr constant [16 x i8] c"Fields: %d, %s\0A\00", align 1 +@5 = private unnamed_addr constant [13 x i8] c"Message: %s\0A\00", align 1 define internal void @_mp__Vector__ctor(ptr %0) { entry.l6: %this = alloca ptr, align 8 + %msg = alloca ptr, align 8 store ptr %0, ptr %this, align 8 + store ptr @0, ptr %msg, align 8 %1 = load ptr, ptr %this, align 8 %2 = getelementptr inbounds %_s__Vector__bool_string, ptr %1, i32 0, i32 0 store i1 false, ptr %2, align 1 - %3 = load ptr, ptr %this, align 8 - %4 = getelementptr inbounds %_s__Vector__bool_string, ptr %3, i32 0, i32 1 - store ptr @0, ptr %4, align 8 + %3 = load ptr, ptr %msg, align 8 + %4 = load ptr, ptr %this, align 8 + %5 = getelementptr inbounds %_s__Vector__bool_string, ptr %4, i32 0, i32 1 + store ptr %3, ptr %5, align 8 ret void } -define i32 @main() { +define internal void @_mp__Vector__ctor__string(ptr %0, ptr %1) { +entry.l6: + %this = alloca ptr, align 8 + %msg = alloca ptr, align 8 + store ptr %0, ptr %this, align 8 + store ptr %1, ptr %msg, align 8 + %2 = load ptr, ptr %this, align 8 + %3 = getelementptr inbounds %_s__Vector__bool_string, ptr %2, i32 0, i32 0 + store i1 false, ptr %3, align 1 + %4 = load ptr, ptr %msg, align 8 + %5 = load ptr, ptr %this, align 8 + %6 = getelementptr inbounds %_s__Vector__bool_string, ptr %5, i32 0, i32 1 + store ptr %4, ptr %6, align 8 + ret void +} + +define internal ptr @_mf__Vector__test(ptr %0) { entry.l11: + %this = alloca ptr, align 8 + %result = alloca ptr, align 8 + %1 = alloca ptr, align 8 + store ptr %0, ptr %this, align 8 + store ptr @1, ptr %1, align 8 + %2 = load ptr, ptr %1, align 8 + ret ptr %2 +} + +define i32 @main() { +entry.l15: %result = alloca i32, align 4 %vec = alloca %_s__Vector__bool_string, align 8 + %vec1 = alloca ptr, align 8 + %0 = alloca %_s__Vector__bool_string, align 8 + %1 = alloca ptr, align 8 store i32 0, ptr %result, align 4 call void @_mp__Vector__ctor(ptr %vec) - %0 = getelementptr inbounds %_s__Vector__bool_string, ptr %vec, i32 0, i32 0 - %1 = load i1, ptr %0, align 1 - %2 = zext i1 %1 to i32 - %3 = getelementptr inbounds %_s__Vector__bool_string, ptr %vec, i32 0, i32 1 - %4 = load ptr, ptr %3, align 8 - %5 = call i32 (ptr, ...) @printf(ptr @1, i32 %2, ptr %4) - %6 = load i32, ptr %result, align 4 - ret i32 %6 + %2 = getelementptr inbounds %_s__Vector__bool_string, ptr %vec, i32 0, i32 0 + %3 = load i1, ptr %2, align 1 + %4 = zext i1 %3 to i32 + %5 = getelementptr inbounds %_s__Vector__bool_string, ptr %vec, i32 0, i32 1 + %6 = load ptr, ptr %5, align 8 + %7 = call i32 (ptr, ...) @printf(ptr @2, i32 %4, ptr %6) + store ptr @3, ptr %vec1, align 8 + %8 = load ptr, ptr %vec1, align 8 + call void @_mp__Vector__ctor__string(ptr %vec, ptr %8) + %9 = load %_s__Vector__bool_string, ptr %vec, align 8 + store %_s__Vector__bool_string %9, ptr %vec, align 8 + %10 = getelementptr inbounds %_s__Vector__bool_string, ptr %vec, i32 0, i32 0 + %11 = load i1, ptr %10, align 1 + %12 = zext i1 %11 to i32 + %13 = getelementptr inbounds %_s__Vector__bool_string, ptr %vec, i32 0, i32 1 + %14 = load ptr, ptr %13, align 8 + %15 = call i32 (ptr, ...) @printf(ptr @4, i32 %12, ptr %14) + call void @_mp__Vector__ctor(ptr %0) + %16 = call ptr @_mf__Vector__test(ptr %0) + store ptr %16, ptr %1, align 8 + %17 = load ptr, ptr %1, align 8 + %18 = call i32 (ptr, ...) @printf(ptr @5, ptr %17) + %19 = load i32, ptr %result, align 4 + ret i32 %19 } declare i32 @printf(ptr, ...) diff --git a/test/test-files/generator/structs/success-constructors/source.spice b/test/test-files/generator/structs/success-constructors/source.spice index 123f5be7a..19e34fd92 100644 --- a/test/test-files/generator/structs/success-constructors/source.spice +++ b/test/test-files/generator/structs/success-constructors/source.spice @@ -3,12 +3,20 @@ type Vector struct { string field2 } -p Vector.ctor() { +p Vector.ctor(string msg = "Test string") { this.field1 = false; - this.field2 = "Test string"; + this.field2 = msg; +} + +f Vector.test() { + return "Hello World!"; } f main() { dyn vec = Vector(); - printf("Fields: %d, %s", vec.field1, vec.field2); + printf("Fields: %d, %s\n", vec.field1, vec.field2); + vec = Vector("Another message"); + printf("Fields: %d, %s\n", vec.field1, vec.field2); + + printf("Message: %s\n", Vector().test()); } \ No newline at end of file