From 20be0899e8fc0250bda07b4cc4cd9c988ff0b19a Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sat, 8 Oct 2022 23:44:02 +0200 Subject: [PATCH] Fix bugs and extend string runtime (#209) * Fix bug and extend http std * Fix bug & extend string runtime * Enable ccache for CI * Fix bug in test runner --- .github/workflows/ci-cpp.yml | 12 +- .github/workflows/codeql-analysis.yml | 13 +- .github/workflows/publish.yml | 15 +- media/test-project/os-test.spice | 56 ++-- src/analyzer/AnalyzerVisitor.cpp | 11 +- src/analyzer/OpRuleManager.cpp | 9 +- src/generator/GeneratorVisitor.cpp | 10 +- src/generator/OpRuleConversionsManager.cpp | 6 + src/generator/StdFunctionManager.cpp | 4 +- src/generator/StdFunctionManager.h | 4 +- src/symbol/Function.cpp | 4 +- src/symbol/Function.h | 1 + src/symbol/Struct.cpp | 4 +- src/symbol/Struct.h | 1 + std/net/http.spice | 5 +- std/net/socket_linux.spice | 35 ++- std/runtime/string_rt.spice | 7 + test/TestRunner.cpp | 9 +- test/TestUtil.cpp | 28 +- test/TestUtil.h | 2 +- .../std/examples/dijkstra/source.spice | 20 +- .../std/examples/graph-coloring/source.spice | 6 +- .../std/examples/sudoku/source.spice | 6 +- .../runtime/string-basic-operations/cout.out | 5 +- .../string-basic-operations/ir-code-O2.ll | 56 ++-- .../string-basic-operations/source.spice | 8 +- .../std/runtime/string-char-ctor/cout.out | 3 +- .../runtime/string-char-ctor/ir-code-O2.ll | 23 +- .../std/runtime/string-char-ctor/source.spice | 2 +- .../std/runtime/string-operators/cout.out | 5 + .../runtime/string-operators/ir-code-O2.ll | 287 +++++++++++++----- .../std/runtime/string-operators/source.spice | 10 + 32 files changed, 445 insertions(+), 222 deletions(-) diff --git a/.github/workflows/ci-cpp.yml b/.github/workflows/ci-cpp.yml index 39d768950..2d0fdb957 100644 --- a/.github/workflows/ci-cpp.yml +++ b/.github/workflows/ci-cpp.yml @@ -35,6 +35,9 @@ jobs: - name: Setup Mold uses: rui314/setup-mold@v1 + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1 + - name: Setup Gcovr run: sudo pip install gcovr @@ -53,8 +56,8 @@ jobs: git clone --depth 1 --branch llvmorg-15.0.2 https://github.com/llvm/llvm-project llvm mkdir ./llvm/build cd ./llvm/build - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -GNinja ../llvm - cmake --build . + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -GNinja ../llvm + cmake --build . -j$(nproc) - name: Download Libs run: | @@ -65,10 +68,11 @@ jobs: env: LLVM_DIR: /home/runner/work/spice/llvm/build/lib/cmake/llvm run: | + echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH mkdir ./bin cd ./bin - cmake -DCMAKE_BUILD_TYPE=Debug -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 + 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) - name: Run Test target env: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a17094ce3..c7e5bedf3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,6 +31,9 @@ jobs: - name: Setup Mold uses: rui314/setup-mold@v1 + - name: Setup CCache + uses: hendrikmuhs/ccache-action@v1 + - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: @@ -46,12 +49,13 @@ jobs: - name: Setup LLVM if: steps.cache-llvm.outputs.cache-hit != 'true' run: | + echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH cd .. git clone --depth 1 --branch llvmorg-15.0.2 https://github.com/llvm/llvm-project llvm mkdir ./llvm/build cd ./llvm/build - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -GNinja ../llvm - cmake --build . + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -GNinja ../llvm + cmake --build . -j$(nproc) - name: Download Libs run: | @@ -62,10 +66,11 @@ jobs: env: LLVM_DIR: /home/runner/work/spice/llvm/build/lib/cmake/llvm run: | + echo "/usr/lib/ccache:/usr/local/opt/ccache/libexec" >> $GITHUB_PATH mkdir ./bin cd ./bin - cmake -DCMAKE_BUILD_TYPE=Release -DSPICE_BUILT_BY="ghactions" -DSPICE_LINK_STATIC=OFF -DSPICE_DEV_COMPILE=ON -GNinja -Wattributes .. - cmake --build . --target Spice_test + 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) - 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 74a670f72..5ac65670d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -53,12 +53,7 @@ jobs: mkdir ./llvm/build cd ./llvm/build cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -GNinja -Wno-dev -Wattributes ../llvm - - - name: Setup LLVM - Build - if: steps.cache-llvm.outputs.cache-hit != 'true' - run: | - cd ./llvm/build - cmake --build . + cmake --build . -j$(nproc) - name: Download Libs run: | @@ -72,7 +67,7 @@ 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 + cmake --build . --target Spice_run -j$(nproc) - name: Process build output working-directory: bin @@ -136,7 +131,7 @@ jobs: mkdir ./llvm/build cd ./llvm/build cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -GNinja -Wno-dev -Wattributes ../llvm - cmake --build . + cmake --build . -j$(nproc) - name: Download Libs run: .\setup-libs.bat @@ -151,7 +146,7 @@ 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 + cmake --build . --target Spice_run -j$(nproc) - name: Process build output working-directory: bin @@ -359,4 +354,4 @@ jobs: identifier: ChilliBits.Spice version: ${{ github.ref_name }} release-tag: ${{ github.ref_name }} - token: ${{ secrets.CR_PAT }} + token: ${{ secrets.CR_PAT }} \ No newline at end of file diff --git a/media/test-project/os-test.spice b/media/test-project/os-test.spice index bdd5d425a..dcb4fb652 100644 --- a/media/test-project/os-test.spice +++ b/media/test-project/os-test.spice @@ -1,28 +1,38 @@ -const int SIZE = 9; - -p print(int[][] grid) { - for int i = 0; i < size; i++ { - for int j = 0; j < size; j++ { - printf("%d ", grid[i][j]); - } - printf("\n"); - } -} +import "std/runtime/string_rt" as _rt_str; f main() { - int[SIZE][SIZE] grid = { - { 3, 0, 6, 5, 0, 8, 4, 0, 0 }, - { 5, 2, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 8, 7, 0, 0, 0, 0, 3, 1 }, - { 0, 0, 3, 0, 1, 0, 0, 8, 0 }, - { 9, 0, 0, 8, 6, 3, 0, 0, 5 }, - { 0, 5, 0, 0, 9, 0, 6, 0, 0 }, - { 1, 3, 0, 0, 0, 0, 2, 5, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 7, 4 }, - { 0, 0, 5, 2, 0, 6, 3, 0, 0 } - }; - - print(grid); + _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()); } /*import "std/net/http" as http; diff --git a/src/analyzer/AnalyzerVisitor.cpp b/src/analyzer/AnalyzerVisitor.cpp index 164160a8b..a2e2f676b 100644 --- a/src/analyzer/AnalyzerVisitor.cpp +++ b/src/analyzer/AnalyzerVisitor.cpp @@ -1911,7 +1911,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { throw SemanticError(node->codeLoc, REFERENCED_UNDEFINED_FUNCTION, "Symbol '" + scopePath.getScopePrefix() + identifier + "' was used before defined"); thisType = symbolEntry->type.getBaseType(); - } else if (symbolEntry != nullptr && symbolEntry->type.getBaseType().is(TY_STRUCT)) { + } else if (symbolEntry != nullptr && symbolEntry->type.getBaseType().is(TY_STRUCT)) { // last fragment is a struct // Get the concrete template types std::vector concreteTemplateTypes; if (node->isGeneric) { @@ -1937,7 +1937,7 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { functionName = CTOR_VARIABLE_NAME; constructorCall = true; - } else { + } else { // last fragment is no struct functionName = identifier; continue; } @@ -1961,6 +1961,8 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { argTypes.push_back(any_cast(visit(arg))); } + scopePath = scopePathBackup; + // Set to root scope if it did not change if (accessScope == currentScope) accessScope = rootScope; @@ -2018,8 +2020,9 @@ std::any AnalyzerVisitor::visitFunctionCall(FunctionCallNode *node) { // If the return type is an external struct, initialize it if (!scopePathBackup.isEmpty() && returnType.is(TY_STRUCT) && scopePathBackup.getCurrentScope()->isImported(currentScope)) { - SymbolType symbolType = initExtStruct(currentScope, scopePathBackup.getScopePrefix(false), returnType.getSubType(), - returnType.getTemplateTypes(), node->codeLoc); + std::string scopePrefix = scopePathBackup.getScopePrefix(!spiceFunc->isGenericSubstantiation); + SymbolType symbolType = + initExtStruct(currentScope, scopePrefix, returnType.getSubType(), returnType.getTemplateTypes(), node->codeLoc); return node->setEvaluatedSymbolType(symbolType); } diff --git a/src/analyzer/OpRuleManager.cpp b/src/analyzer/OpRuleManager.cpp index 6120154c3..4031aaec1 100644 --- a/src/analyzer/OpRuleManager.cpp +++ b/src/analyzer/OpRuleManager.cpp @@ -179,13 +179,8 @@ SymbolType OpRuleManager::getPlusResultType(const AstNode *declNode, const Symbo } // Allow string + string - if (lhs.is(TY_STRING) && rhs.is(TY_STRING)) { - if (!lhs.isStringStruct() && !rhs.isStringStruct()) { // If lhs and rhs are raw strings -> insert anon symbol - return analyzer->insertAnonStringStructSymbol(declNode); - } else { // Otherwise just return the type - return SymbolType(TY_STRING, "", {.isStringStruct = true}, {}); - } - } + if (lhs.is(TY_STRING) && rhs.is(TY_STRING)) + return analyzer->insertAnonStringStructSymbol(declNode); return validateBinaryOperation(declNode->codeLoc, PLUS_OP_RULES, "+", lhs, rhs); } diff --git a/src/generator/GeneratorVisitor.cpp b/src/generator/GeneratorVisitor.cpp index b567c40f3..a7fee4f16 100644 --- a/src/generator/GeneratorVisitor.cpp +++ b/src/generator/GeneratorVisitor.cpp @@ -1988,11 +1988,12 @@ std::any GeneratorVisitor::visitAdditiveExpr(AdditiveExprNode *node) { PtrAndValue result = {nullptr, nullptr}; switch (opQueue.front().first) { case AdditiveExprNode::OP_PLUS: - if (rhsSymbolType.isStringStruct()) { - rhs = materializeString(resolveAddress(rhsOperand)); - } else { - rhs = resolveValue(rhsOperand); + if (lhsSymbolType.isStringStruct()) { + llvm::Value *lhsPtr = insertAlloca(lhs->getType()); + builder->CreateStore(lhs, lhsPtr); + lhs = materializeString(lhsPtr); } + rhs = rhsSymbolType.isStringStruct() ? materializeString(resolveAddress(rhsOperand)) : resolveValue(rhsOperand); result = conversionsManager->getPlusInst(lhs, rhs, lhsSymbolType, rhsSymbolType, currentScope, rhsOperand->codeLoc); break; case AdditiveExprNode::OP_MINUS: @@ -3102,7 +3103,6 @@ bool GeneratorVisitor::insertDestructorCall(const CodeLoc &codeLoc, SymbolTableE } llvm::Value *GeneratorVisitor::materializeString(llvm::Value *stringStructPtr) { - // assert(stringStructPtr->getType()->isPointerTy()); llvm::Value *rawStringValue = builder->CreateCall(stdFunctionManager->getStringGetRawFct(), stringStructPtr); return rawStringValue; } diff --git a/src/generator/OpRuleConversionsManager.cpp b/src/generator/OpRuleConversionsManager.cpp index dc5cfc3da..490a7bed5 100644 --- a/src/generator/OpRuleConversionsManager.cpp +++ b/src/generator/OpRuleConversionsManager.cpp @@ -1045,6 +1045,12 @@ PtrAndValue OpRuleConversionsManager::getPlusInst(llvm::Value *lhsV, llvm::Value case COMB(TY_CHAR, TY_CHAR): return {.value = builder->CreateAdd(lhsV, rhsV)}; case COMB(TY_STRING, TY_STRING): { + /*llvm::Function *getRawFct = stdFunctionManager->getStringGetRawFct(); + if (lhsSTy.isStringStruct()) + lhsV = builder->CreateCall(getRawFct, lhsV); + if (rhsSTy.isStringStruct()) + rhsV = builder->CreateCall(getRawFct, rhsV);*/ + // Generate call to the constructor ctor(string, string) of the String struct llvm::Function *opFct = stdFunctionManager->getStringCtorStringStringFct(); llvm::Value *thisPtr = generator->insertAlloca(StdFunctionManager::getStringStructType(*context)); diff --git a/src/generator/StdFunctionManager.cpp b/src/generator/StdFunctionManager.cpp index ee7d969d6..18d11d8b5 100644 --- a/src/generator/StdFunctionManager.cpp +++ b/src/generator/StdFunctionManager.cpp @@ -76,7 +76,7 @@ llvm::Function *StdFunctionManager::getStringMulOpShortFct() const { return getProcedure("_mp__String__opMul__short", {builder->getPtrTy(), builder->getInt16Ty()}); } -llvm::Function *StdFunctionManager::getFunction(const std::string functionName, llvm::Type *returnType, +llvm::Function *StdFunctionManager::getFunction(const std::string &functionName, llvm::Type *returnType, llvm::ArrayRef args, bool varArg) const { llvm::Function *opFct = module->getFunction(functionName); if (opFct != nullptr) @@ -86,7 +86,7 @@ llvm::Function *StdFunctionManager::getFunction(const std::string functionName, return module->getFunction(functionName); } -llvm::Function *StdFunctionManager::getProcedure(const std::string procedureName, llvm::ArrayRef args, +llvm::Function *StdFunctionManager::getProcedure(const std::string &procedureName, llvm::ArrayRef args, bool varArg) const { return getFunction(procedureName, builder->getVoidTy(), args, varArg); } \ No newline at end of file diff --git a/src/generator/StdFunctionManager.h b/src/generator/StdFunctionManager.h index 41b69248b..ab63121a3 100644 --- a/src/generator/StdFunctionManager.h +++ b/src/generator/StdFunctionManager.h @@ -40,8 +40,8 @@ class StdFunctionManager { llvm::Module *module; // Private methods - llvm::Function *getFunction(std::string functionName, llvm::Type *returnType, llvm::ArrayRef args, + llvm::Function *getFunction(const std::string &functionName, llvm::Type *returnType, llvm::ArrayRef args, bool varArg = false) const; - [[nodiscard]] llvm::Function *getProcedure(std::string procedureName, llvm::ArrayRef args, + [[nodiscard]] llvm::Function *getProcedure(const std::string &procedureName, llvm::ArrayRef args, bool varArg = false) const; }; \ No newline at end of file diff --git a/src/symbol/Function.cpp b/src/symbol/Function.cpp index 6e82aed67..d03c0408a 100644 --- a/src/symbol/Function.cpp +++ b/src/symbol/Function.cpp @@ -228,7 +228,9 @@ Function Function::substantiateGenerics(const ParamList &concreteParamList, cons // Substantiate return type SymbolType newReturnType = returnType.is(TY_GENERIC) ? concreteGenericTypes.at(returnType.getSubType()) : returnType; - return Function(name, specifiers, concreteThisType, newReturnType, concreteParamList, {}, declNode); + Function substantiatedFunction(name, specifiers, concreteThisType, newReturnType, concreteParamList, {}, declNode); + substantiatedFunction.isGenericSubstantiation = true; + return substantiatedFunction; } /** diff --git a/src/symbol/Function.h b/src/symbol/Function.h index 42cfbd08c..42260745f 100644 --- a/src/symbol/Function.h +++ b/src/symbol/Function.h @@ -47,6 +47,7 @@ class Function { [[nodiscard]] const CodeLoc &getDeclCodeLoc() const; // Public members + bool isGenericSubstantiation = false; bool isAlreadyAnalyzed = false; bool isUsed = false; diff --git a/src/symbol/Struct.cpp b/src/symbol/Struct.cpp index 177d9594d..ff1c9a9f9 100644 --- a/src/symbol/Struct.cpp +++ b/src/symbol/Struct.cpp @@ -122,7 +122,9 @@ Struct Struct::substantiateGenerics(const std::vector &concreteTempl } } - return Struct(name, specifiers, currentFieldTypes, concreteTemplateTypesGeneric, declNode); + Struct substantiatedStruct(name, specifiers, currentFieldTypes, concreteTemplateTypesGeneric, declNode); + substantiatedStruct.isGenericSubstantiation = true; + return substantiatedStruct; } /** diff --git a/src/symbol/Struct.h b/src/symbol/Struct.h index 7474ce56e..ba08b1d8c 100644 --- a/src/symbol/Struct.h +++ b/src/symbol/Struct.h @@ -43,6 +43,7 @@ class Struct { static std::string getSignature(const std::string &structName, const std::vector &concreteTemplateTypes); // Public members + bool isGenericSubstantiation = false; bool isUsed = false; private: diff --git a/std/net/http.spice b/std/net/http.spice index 3a67352d9..886b669d4 100644 --- a/std/net/http.spice +++ b/std/net/http.spice @@ -24,7 +24,7 @@ public type HttpServer struct { */ public p HttpServer.ctor(unsigned short port = HTTP_PORT_DEFAULT) { this.port = port; - initialized = true; + this.initialized = true; } /** @@ -35,10 +35,11 @@ public f HttpServer.start() { if !this.initialized { return false; } // Setup TCP socket - this.socket = sock.openServerSocket(port, CONNECTIONS_LIMIT); + this.socket = sock.openServerSocket(this.port, CONNECTIONS_LIMIT); } public f HttpServer.serve(string path, string htmlContent) { + return false; } \ No newline at end of file diff --git a/std/net/socket_linux.spice b/std/net/socket_linux.spice index 1cf92b168..0ed09f7fa 100644 --- a/std/net/socket_linux.spice +++ b/std/net/socket_linux.spice @@ -16,12 +16,12 @@ type SockAddrIn struct { } public type Socket struct { - unsigned long sockFd // Actual socket - unsigned long connFd // Current connection + unsigned int sockFd // Actual socket + unsigned int connFd // Current connection public short errorCode } -public const short ERROR_SOCKET = -1s; +public const short ERROR_OPEN = -1s; public const short ERROR_BIND = -2s; public const short ERROR_LISTEN = -3s; public const short ERROR_ACCEPT = -4s; @@ -49,10 +49,10 @@ public p Socket.dtor() { * * @return Connection file descriptor */ -public f Socket.acceptConnection() { +public f Socket.acceptConnection() { SockAddrIn cliAddr = SockAddrIn {}; - this.connFd = (long) accept((int) this.sockFd, &cliAddr, 16 /* hardcoded sizeof(cliAddr) */); - if this.connFd == -1l { + this.connFd = accept(this.sockFd, &cliAddr, 16 /* hardcoded sizeof(cliAddr) */); + if this.connFd == -1 { //result.errorCode = ERROR_ACCEPT; return -1; } @@ -60,9 +60,8 @@ public f Socket.acceptConnection() { } public f Socket.write(string message) { - //if message.empty() { return 0; } ToDo: Comment out when the empty method on string type is implemented - //return write(this.connFd, content, message.length() * 8); // ToDo: Comment out when the length method on string type is implemented - return 0l; + if message.isEmpty() { return 0; } + return write(this.connFd, content, message.getLength() * 8); } public f Socket.write(byte[] content) { @@ -93,11 +92,11 @@ public f Socket.close() { * @return Socket file descriptor */ public f openServerSocket(unsigned short port, int maxWaitingConnections = 5) { - Socket s = Socket { socket(AF_INET, SOCK_STREAM, IPPROTO_IP), 0l, 0s }; + Socket s = Socket { socket(AF_INET, SOCK_STREAM, IPPROTO_IP), 0, 0s }; // Cancel on failure - if s.sockFd == -1l { - s.errorCode = ERROR_SOCKET; + if s.sockFd == -1 { + s.errorCode = ERROR_OPEN; return s; } @@ -128,13 +127,13 @@ public f openServerSocket(unsigned short port, int maxWaitingConnections * * @return Socket file descriptor */ -public f openClientSocket(string host, unsigned short port) { - Socket s = Socket { socket(AF_INET, SOCK_STREAM, IPPROTO_IP), 0l, 0s }; +public f openClientSocket(string host, unsigned short port) { + Socket s = Socket { socket(AF_INET, SOCK_STREAM, IPPROTO_IP), 0, 0s }; // Cancel on failure - if s.sockFd == -1l { - s.errorCode = ERROR_SOCKET; - return -1l; + if s.sockFd == -1 { + s.errorCode = ERROR_OPEN; + return -1; } InAddr inAddr = InAddr { inet_addr(host) }; @@ -143,7 +142,7 @@ public f openClientSocket(string host, unsigned short port) { int connectResult = connect((int) s.sockFd, &cliAddr, 16 /* hardcoded sizeof(cliAddr) */); if connectResult != 0 { s.errorCode = ERROR_CONNECT; - return -1l; + return -1; } return s.sockFd; diff --git a/std/runtime/string_rt.spice b/std/runtime/string_rt.spice index 11a2fd8fb..ed76cf299 100644 --- a/std/runtime/string_rt.spice +++ b/std/runtime/string_rt.spice @@ -218,6 +218,13 @@ public inline f String.getLength() { return this.length; } +/** + * Check if the string is empty + */ +public inline f String.isEmpty() { + return this.length == 0; +} + /** * Retrieve the current capacity of the string * diff --git a/test/TestRunner.cpp b/test/TestRunner.cpp index 964abef1c..6bdee6afe 100644 --- a/test/TestRunner.cpp +++ b/test/TestRunner.cpp @@ -143,14 +143,9 @@ void execTestCase(const TestCase &testCase) { return result.output; }); } catch (LexerParserError &error) { - std::string errorWhat = error.what(); - CommonUtil::replaceAll(errorWhat, "\\", "/"); - TestUtil::checkRefMatch(testCase.testPath + FileUtil::DIR_SEPARATOR + REF_NAME_ERROR_OUTPUT, [&]() { return errorWhat; }); + TestUtil::handleError(testCase, error); } catch (SemanticError &error) { - // Check if the exception message matches the expected output - std::string errorWhat = error.what(); - CommonUtil::replaceAll(errorWhat, "\\", "/"); - TestUtil::checkRefMatch(testCase.testPath + FileUtil::DIR_SEPARATOR + REF_NAME_ERROR_OUTPUT, [&]() { return errorWhat; }); + TestUtil::handleError(testCase, error); } SUCCEED(); diff --git a/test/TestUtil.cpp b/test/TestUtil.cpp index d3b89a3ee..6065a5c1f 100644 --- a/test/TestUtil.cpp +++ b/test/TestUtil.cpp @@ -5,10 +5,10 @@ #include "TestUtil.h" #include -#include #include +#include #include #ifdef OS_UNIX @@ -63,6 +63,25 @@ void TestUtil::checkRefMatch(const std::string &refPath, GetOutputFct getActualO } } +/** + * Handle an test error + * + * @param testCase Testcase which has produced the error + * @param error Exception with error message + */ +void TestUtil::handleError(const TestCase &testCase, const std::exception &error) { + std::string errorWhat = error.what(); + CommonUtil::replaceAll(errorWhat, "\\", "/"); + + // Fail if no ref file exists + std::string refPath = testCase.testPath + FileUtil::DIR_SEPARATOR + REF_NAME_ERROR_OUTPUT; + if (!FileUtil::fileExists(refPath)) + FAIL() << "Expected no error, but got: " + errorWhat; + + // Check if the exception message matches the expected output + TestUtil::checkRefMatch(testCase.testPath + FileUtil::DIR_SEPARATOR + REF_NAME_ERROR_OUTPUT, [&]() { return errorWhat; }); +} + /** * Get subdirectories of the given path * @@ -143,13 +162,6 @@ std::string TestUtil::getDefaultExecutableName() { return executableName; } -/** - * Check if the update refs mode is enabled - * - * @return Enabled or not - */ -bool TestUtil::isUpdateRefsEnabled() { return updateRefs; } - bool TestUtil::isDisabled(const TestCase &testCase) { // Check if disabled std::string disabledFile = testCase.testPath + FileUtil::DIR_SEPARATOR + CTL_SKIP_DISABLED; diff --git a/test/TestUtil.h b/test/TestUtil.h index 347edf4ff..bc6300cef 100644 --- a/test/TestUtil.h +++ b/test/TestUtil.h @@ -60,12 +60,12 @@ class TestUtil { static void checkRefMatch( const std::string &refPath, GetOutputFct getActualOutput, ModifyOutputFct modifyOutput = [](std::string &, std::string &) {}); + static void handleError(const TestCase &testCase, const std::exception &error); static std::vector getSubdirs(const std::string &basePath); static std::string getFileContent(const std::string &filePath); static std::vector getFileContentLinesVector(const std::string &filePath); static std::string toCamelCase(std::string input); static std::string getDefaultExecutableName(); - static bool isUpdateRefsEnabled(); static bool isDisabled(const TestCase &testCase); }; diff --git a/test/test-files/std/examples/dijkstra/source.spice b/test/test-files/std/examples/dijkstra/source.spice index 8509db545..d874e72c9 100644 --- a/test/test-files/std/examples/dijkstra/source.spice +++ b/test/test-files/std/examples/dijkstra/source.spice @@ -1,12 +1,12 @@ import "std/type/int" as integer; -const int vertexCount = 9; +const int VERTEX_COUNT = 9; f minDistance(int[] dist, bool[] sptSet) { int min = integer::MAX_VALUE; int minIndex; - for int v = 0; v < vertexCount; v++ { + for int v = 0; v < VERTEX_COUNT; v++ { if !sptSet[v] && dist[v] <= min { min = dist[v]; minIndex = v; @@ -18,17 +18,17 @@ f minDistance(int[] dist, bool[] sptSet) { p printSolution(int[] dist) { printf("Vertex \t\t Distance from source\n"); - for int i = 0; i < vertexCount; i++ { + for int i = 0; i < VERTEX_COUNT; i++ { printf("%d \t\t %d\n", i, dist[i]); } } -p dijkstra(int[vertexCount][vertexCount] graph, int src) { - int[vertexCount] dist; - bool[vertexCount] sptSet; +p dijkstra(int[][] graph, int src) { + int[VERTEX_COUNT] dist; + bool[VERTEX_COUNT] sptSet; // Fill with default values - for int i = 0; i < vertexCount; i++ { + for int i = 0; i < VERTEX_COUNT; i++ { dist[i] = integer::MAX_VALUE; sptSet[i] = false; } @@ -36,10 +36,10 @@ p dijkstra(int[vertexCount][vertexCount] graph, int src) { // Set distance to starting node to 0 dist[src] = 0; - for int count = 0; count < vertexCount - 1; count++ { + for int count = 0; count < VERTEX_COUNT - 1; count++ { int u = minDistance(dist, sptSet); sptSet[u] = true; - for int v = 0; v < vertexCount; v++ { + for int v = 0; v < VERTEX_COUNT; v++ { if (!sptSet[v] && graph[u][v] != 0 && dist[u] != integer::MAX_VALUE && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; @@ -52,7 +52,7 @@ p dijkstra(int[vertexCount][vertexCount] graph, int src) { } f main() { - int[vertexCount][vertexCount] graph = { + int[VERTEX_COUNT][VERTEX_COUNT] graph = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 }, { 4, 0, 8, 0, 0, 0, 0, 11, 0 }, { 0, 8, 0, 7, 0, 4, 0, 0, 2 }, diff --git a/test/test-files/std/examples/graph-coloring/source.spice b/test/test-files/std/examples/graph-coloring/source.spice index 0c4afd7b3..0cee783ba 100644 --- a/test/test-files/std/examples/graph-coloring/source.spice +++ b/test/test-files/std/examples/graph-coloring/source.spice @@ -8,7 +8,7 @@ p printSolution(int[] color) { printf("\n"); } -f isSafe(bool[VERTEX_COUNT][VERTEX_COUNT] graph, int[] color) { +f isSafe(bool[][] graph, int[] color) { for int i = 0; i < VERTEX_COUNT; i++ { for int j = i + 1; j < VERTEX_COUNT; j++ { if graph[i][j] && color[j] == color[i] { @@ -20,10 +20,10 @@ f isSafe(bool[VERTEX_COUNT][VERTEX_COUNT] graph, int[] color) { } f graphColoring( - bool[VERTEX_COUNT][VERTEX_COUNT] graph, + bool[][] graph, int m, int i, - int[VERTEX_COUNT] color + int[] color ) { // If current index reached the end if i == VERTEX_COUNT { diff --git a/test/test-files/std/examples/sudoku/source.spice b/test/test-files/std/examples/sudoku/source.spice index ec2260123..54090c0c1 100644 --- a/test/test-files/std/examples/sudoku/source.spice +++ b/test/test-files/std/examples/sudoku/source.spice @@ -1,6 +1,6 @@ const int size = 9; -p print(int[size][size] grid) { +p print(int[][] grid) { for int i = 0; i < size; i++ { for int j = 0; j < size; j++ { printf("%d ", grid[i][j]); @@ -9,7 +9,7 @@ p print(int[size][size] grid) { } } -f isSafe(int[size][size] grid, int row, int col, int num) { +f isSafe(int[][] grid, int row, int col, int num) { // Check if we find the same num in the similar row -> return false for int x = 0; x <= size - 1; x++ { if grid[row][x] == num { @@ -39,7 +39,7 @@ f isSafe(int[size][size] grid, int row, int col, int num) { return true; } -f solveSudoku(int[size][size] grid, int row, int col) { +f solveSudoku(int[][] grid, int row, int col) { // Check if we have reached the second last row and the last column. // We return true to avoid further backtracking if row == size - 1 && col == size { return true; } diff --git a/test/test-files/std/runtime/string-basic-operations/cout.out b/test/test-files/std/runtime/string-basic-operations/cout.out index 8d1ae3e16..33e4d277e 100644 --- a/test/test-files/std/runtime/string-basic-operations/cout.out +++ b/test/test-files/std/runtime/string-basic-operations/cout.out @@ -24,4 +24,7 @@ Capacity: 23 Content: Length: 0 -Capacity: 99 \ No newline at end of file +Capacity: 99 + +Empty: 1 +Empty: 0 \ No newline at end of file diff --git a/test/test-files/std/runtime/string-basic-operations/ir-code-O2.ll b/test/test-files/std/runtime/string-basic-operations/ir-code-O2.ll index 70ffc6aeb..bffcf3e4e 100644 --- a/test/test-files/std/runtime/string-basic-operations/ir-code-O2.ll +++ b/test/test-files/std/runtime/string-basic-operations/ir-code-O2.ll @@ -11,42 +11,44 @@ target triple = "x86_64-w64-windows-gnu" @3 = private unnamed_addr constant [15 x i8] c"Hello World!?!\00", align 1 @4 = private unnamed_addr constant [16 x i8] c"Not Equals: %d\0A\00", align 1 @5 = private unnamed_addr constant [14 x i8] c"Hello World!!\00", align 1 -@6 = private unnamed_addr constant [15 x i8] c"Capacity: %d\0A\0A\00", align 1 -@7 = private unnamed_addr constant [13 x i8] c"Content: %s\0A\00", align 1 -@8 = private unnamed_addr constant [12 x i8] c"Length: %d\0A\00", align 1 -@9 = private unnamed_addr constant [13 x i8] c"Capacity: %d\00", align 1 +@6 = private unnamed_addr constant [13 x i8] c"Content: %s\0A\00", align 1 +@7 = private unnamed_addr constant [12 x i8] c"Length: %d\0A\00", align 1 +@8 = private unnamed_addr constant [15 x i8] c"Capacity: %d\0A\0A\00", align 1 +@9 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1 +@10 = private unnamed_addr constant [11 x i8] c"Empty: %d\0A\00", align 1 +@11 = private unnamed_addr constant [10 x i8] c"Empty: %d\00", align 1 define i32 @main() local_unnamed_addr { entry.l3: %s = alloca %_s__String__charptr_long_long, align 8 call void @_mp__String__ctor__string(ptr nonnull %s, ptr nonnull @0) %0 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %1 = call i32 (ptr, ...) @printf(ptr nonnull @7, ptr %0) + %1 = call i32 (ptr, ...) @printf(ptr nonnull @6, ptr %0) %2 = call i64 @_mf__String__getLength(ptr nonnull %s) - %3 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %2) + %3 = call i32 (ptr, ...) @printf(ptr nonnull @7, i64 %2) %4 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %5 = call i32 (ptr, ...) @printf(ptr nonnull @6, i64 %4) + %5 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %4) call void @_mp__String__append__string(ptr nonnull %s, ptr nonnull @1) %6 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %7 = call i32 (ptr, ...) @printf(ptr nonnull @7, ptr %6) + %7 = call i32 (ptr, ...) @printf(ptr nonnull @6, ptr %6) %8 = call i64 @_mf__String__getLength(ptr nonnull %s) - %9 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %8) + %9 = call i32 (ptr, ...) @printf(ptr nonnull @7, i64 %8) %10 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %11 = call i32 (ptr, ...) @printf(ptr nonnull @6, i64 %10) + %11 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %10) call void @_mp__String__append__char(ptr nonnull %s, i8 63) %12 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %13 = call i32 (ptr, ...) @printf(ptr nonnull @7, ptr %12) + %13 = call i32 (ptr, ...) @printf(ptr nonnull @6, ptr %12) %14 = call i64 @_mf__String__getLength(ptr nonnull %s) - %15 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %14) + %15 = call i32 (ptr, ...) @printf(ptr nonnull @7, i64 %14) %16 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %17 = call i32 (ptr, ...) @printf(ptr nonnull @6, i64 %16) + %17 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %16) call void @_mp__String__append__char(ptr nonnull %s, i8 33) %18 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %19 = call i32 (ptr, ...) @printf(ptr nonnull @7, ptr %18) + %19 = call i32 (ptr, ...) @printf(ptr nonnull @6, ptr %18) %20 = call i64 @_mf__String__getLength(ptr nonnull %s) - %21 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %20) + %21 = call i32 (ptr, ...) @printf(ptr nonnull @7, i64 %20) %22 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %23 = call i32 (ptr, ...) @printf(ptr nonnull @6, i64 %22) + %23 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %22) %24 = call i1 @_mf__String__opEquals__string(ptr nonnull %s, ptr nonnull @3) %25 = zext i1 %24 to i32 %26 = call i32 (ptr, ...) @printf(ptr nonnull @2, i32 %25) @@ -61,18 +63,26 @@ entry.l3: %35 = call i32 (ptr, ...) @printf(ptr nonnull @4, i32 %34) call void @_mp__String__clear(ptr nonnull %s) %36 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %37 = call i32 (ptr, ...) @printf(ptr nonnull @7, ptr %36) + %37 = call i32 (ptr, ...) @printf(ptr nonnull @6, ptr %36) %38 = call i64 @_mf__String__getLength(ptr nonnull %s) - %39 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %38) + %39 = call i32 (ptr, ...) @printf(ptr nonnull @7, i64 %38) %40 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %41 = call i32 (ptr, ...) @printf(ptr nonnull @6, i64 %40) + %41 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %40) call void @_mp__String__reserve__long(ptr nonnull %s, i64 100) %42 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %43 = call i32 (ptr, ...) @printf(ptr nonnull @7, ptr %42) + %43 = call i32 (ptr, ...) @printf(ptr nonnull @6, ptr %42) %44 = call i64 @_mf__String__getLength(ptr nonnull %s) - %45 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %44) + %45 = call i32 (ptr, ...) @printf(ptr nonnull @7, i64 %44) %46 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %47 = call i32 (ptr, ...) @printf(ptr nonnull @9, i64 %46) + %47 = call i32 (ptr, ...) @printf(ptr nonnull @8, i64 %46) + call void @_mp__String__ctor__string(ptr nonnull %s, ptr nonnull @9) + %48 = call i1 @_mf__String__isEmpty(ptr nonnull %s) + %49 = zext i1 %48 to i32 + %50 = call i32 (ptr, ...) @printf(ptr nonnull @10, i32 %49) + call void @_mp__String__append__char(ptr nonnull %s, i8 97) + %51 = call i1 @_mf__String__isEmpty(ptr nonnull %s) + %52 = zext i1 %51 to i32 + %53 = call i32 (ptr, ...) @printf(ptr nonnull @11, i32 %52) ret i32 0 } @@ -99,4 +109,6 @@ declare void @_mp__String__clear(ptr) local_unnamed_addr declare void @_mp__String__reserve__long(ptr, i64) local_unnamed_addr +declare i1 @_mf__String__isEmpty(ptr) local_unnamed_addr + attributes #0 = { nofree nounwind } diff --git a/test/test-files/std/runtime/string-basic-operations/source.spice b/test/test-files/std/runtime/string-basic-operations/source.spice index 4a1d45039..aefacb3d1 100644 --- a/test/test-files/std/runtime/string-basic-operations/source.spice +++ b/test/test-files/std/runtime/string-basic-operations/source.spice @@ -1,3 +1,5 @@ +import "std/runtime/string_rt" as _rt_str; + f main() { _rt_str::String s = _rt_str::String("Hello "); printf("Content: %s\n", s.getRaw()); @@ -26,5 +28,9 @@ f main() { s.reserve(100l); printf("Content: %s\n", s.getRaw()); printf("Length: %d\n", s.getLength()); - printf("Capacity: %d", s.getCapacity()); + 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()); } \ No newline at end of file diff --git a/test/test-files/std/runtime/string-char-ctor/cout.out b/test/test-files/std/runtime/string-char-ctor/cout.out index 683b6258c..9b1a767f0 100644 --- a/test/test-files/std/runtime/string-char-ctor/cout.out +++ b/test/test-files/std/runtime/string-char-ctor/cout.out @@ -4,5 +4,4 @@ Capacity: 4 Content: Hello Length: 5 -Capacity: 9 - +Capacity: 9 \ No newline at end of file diff --git a/test/test-files/std/runtime/string-char-ctor/ir-code-O2.ll b/test/test-files/std/runtime/string-char-ctor/ir-code-O2.ll index c36a9474e..be8e19cb4 100644 --- a/test/test-files/std/runtime/string-char-ctor/ir-code-O2.ll +++ b/test/test-files/std/runtime/string-char-ctor/ir-code-O2.ll @@ -5,28 +5,29 @@ target triple = "x86_64-w64-windows-gnu" %_s__String__charptr_long_long = type { ptr, i64, i64 } -@0 = private unnamed_addr constant [5 x i8] c"ello\00", align 1 -@1 = private unnamed_addr constant [13 x i8] c"Content: %s\0A\00", align 1 -@2 = private unnamed_addr constant [12 x i8] c"Length: %d\0A\00", align 1 -@3 = private unnamed_addr constant [15 x i8] c"Capacity: %d\0A\0A\00", align 1 +@0 = private unnamed_addr constant [15 x i8] c"Capacity: %d\0A\0A\00", align 1 +@1 = private unnamed_addr constant [5 x i8] c"ello\00", align 1 +@2 = private unnamed_addr constant [13 x i8] c"Content: %s\0A\00", align 1 +@3 = private unnamed_addr constant [12 x i8] c"Length: %d\0A\00", align 1 +@4 = private unnamed_addr constant [13 x i8] c"Capacity: %d\00", align 1 define i32 @main() local_unnamed_addr { entry.l3: %s = alloca %_s__String__charptr_long_long, align 8 call void @_mp__String__ctor__char(ptr nonnull %s, i8 72) %0 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %1 = call i32 (ptr, ...) @printf(ptr nonnull @1, ptr %0) + %1 = call i32 (ptr, ...) @printf(ptr nonnull @2, ptr %0) %2 = call i64 @_mf__String__getLength(ptr nonnull %s) - %3 = call i32 (ptr, ...) @printf(ptr nonnull @2, i64 %2) + %3 = call i32 (ptr, ...) @printf(ptr nonnull @3, i64 %2) %4 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %5 = call i32 (ptr, ...) @printf(ptr nonnull @3, i64 %4) - call void @_mp__String__append__string(ptr nonnull %s, ptr nonnull @0) + %5 = call i32 (ptr, ...) @printf(ptr nonnull @0, i64 %4) + call void @_mp__String__append__string(ptr nonnull %s, ptr nonnull @1) %6 = call ptr @_mf__String__getRaw(ptr nonnull %s) - %7 = call i32 (ptr, ...) @printf(ptr nonnull @1, ptr %6) + %7 = call i32 (ptr, ...) @printf(ptr nonnull @2, ptr %6) %8 = call i64 @_mf__String__getLength(ptr nonnull %s) - %9 = call i32 (ptr, ...) @printf(ptr nonnull @2, i64 %8) + %9 = call i32 (ptr, ...) @printf(ptr nonnull @3, i64 %8) %10 = call i64 @_mf__String__getCapacity(ptr nonnull %s) - %11 = call i32 (ptr, ...) @printf(ptr nonnull @3, i64 %10) + %11 = call i32 (ptr, ...) @printf(ptr nonnull @4, i64 %10) ret i32 0 } diff --git a/test/test-files/std/runtime/string-char-ctor/source.spice b/test/test-files/std/runtime/string-char-ctor/source.spice index 9ac8e2422..ec48acc0a 100644 --- a/test/test-files/std/runtime/string-char-ctor/source.spice +++ b/test/test-files/std/runtime/string-char-ctor/source.spice @@ -8,5 +8,5 @@ f main() { s.append("ello"); printf("Content: %s\n", s.getRaw()); printf("Length: %d\n", s.getLength()); - printf("Capacity: %d\n\n", s.getCapacity()); + printf("Capacity: %d", s.getCapacity()); } \ No newline at end of file diff --git a/test/test-files/std/runtime/string-operators/cout.out b/test/test-files/std/runtime/string-operators/cout.out index 70658e8fb..55ae20ba5 100644 --- a/test/test-files/std/runtime/string-operators/cout.out +++ b/test/test-files/std/runtime/string-operators/cout.out @@ -1,5 +1,10 @@ Result: Hello World! Result: Hello World! +Result: Hello World! Hi! +Result: Hi! Hello World! +Result: Hello World!Hello World! +Result: Hello World! Hello World! +Result: Prefix Hello World! Suffix Result: HiHiHiHi Result: Hello Hello Hello Hello Hello Result: aaaaaaaaaaaaaaaaaaaa diff --git a/test/test-files/std/runtime/string-operators/ir-code-O2.ll b/test/test-files/std/runtime/string-operators/ir-code-O2.ll index c15ba551c..ff83b6365 100644 --- a/test/test-files/std/runtime/string-operators/ir-code-O2.ll +++ b/test/test-files/std/runtime/string-operators/ir-code-O2.ll @@ -6,16 +6,21 @@ target triple = "x86_64-w64-windows-gnu" %_s__String__charptr_long_long = type { ptr, i64, i64 } @0 = private unnamed_addr constant [7 x i8] c"World!\00", align 1 -@1 = private unnamed_addr constant [7 x i8] c"Hello \00", align 1 -@2 = private unnamed_addr constant [11 x i8] c"Equal: %d\0A\00", align 1 -@3 = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1 -@4 = private unnamed_addr constant [19 x i8] c"Hello Programmers!\00", align 1 -@5 = private unnamed_addr constant [6 x i8] c"Hell2\00", align 1 -@6 = private unnamed_addr constant [15 x i8] c"Non-equal: %d\0A\00", align 1 -@7 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1 -@8 = private unnamed_addr constant [8 x i8] c" World!\00", align 1 -@9 = private unnamed_addr constant [3 x i8] c"Hi\00", align 1 -@10 = private unnamed_addr constant [12 x i8] c"Result: %s\0A\00", align 1 +@1 = private unnamed_addr constant [5 x i8] c" Hi!\00", align 1 +@2 = private unnamed_addr constant [5 x i8] c"Hi! \00", align 1 +@3 = private unnamed_addr constant [2 x i8] c" \00", align 1 +@4 = private unnamed_addr constant [8 x i8] c"Prefix \00", align 1 +@5 = private unnamed_addr constant [8 x i8] c" Suffix\00", align 1 +@6 = private unnamed_addr constant [7 x i8] c"Hello \00", align 1 +@7 = private unnamed_addr constant [11 x i8] c"Equal: %d\0A\00", align 1 +@8 = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1 +@9 = private unnamed_addr constant [19 x i8] c"Hello Programmers!\00", align 1 +@10 = private unnamed_addr constant [6 x i8] c"Hell2\00", align 1 +@11 = private unnamed_addr constant [15 x i8] c"Non-equal: %d\0A\00", align 1 +@12 = private unnamed_addr constant [6 x i8] c"Hello\00", align 1 +@13 = private unnamed_addr constant [8 x i8] c" World!\00", align 1 +@14 = private unnamed_addr constant [3 x i8] c"Hi\00", align 1 +@15 = private unnamed_addr constant [12 x i8] c"Result: %s\0A\00", align 1 define i32 @main() local_unnamed_addr { entry.l1: @@ -30,76 +35,220 @@ entry.l1: %8 = alloca %_s__String__charptr_long_long, align 8 %9 = alloca %_s__String__charptr_long_long, align 8 %10 = alloca %_s__String__charptr_long_long, align 8 - call void @_mp__String__ctor__string_string(ptr nonnull %0, ptr nonnull @1, ptr nonnull @0) - %.fca.0.load64 = load ptr, ptr %0, align 8 - %.fca.1.gep66 = getelementptr inbounds %_s__String__charptr_long_long, ptr %0, i64 0, i32 1 + %11 = alloca %_s__String__charptr_long_long, align 8 + %12 = alloca %_s__String__charptr_long_long, align 8 + %13 = alloca %_s__String__charptr_long_long, align 8 + %14 = alloca %_s__String__charptr_long_long, align 8 + %15 = alloca %_s__String__charptr_long_long, align 8 + %16 = alloca %_s__String__charptr_long_long, align 8 + %17 = alloca %_s__String__charptr_long_long, align 8 + %18 = alloca %_s__String__charptr_long_long, align 8 + %19 = alloca %_s__String__charptr_long_long, align 8 + %20 = alloca %_s__String__charptr_long_long, align 8 + %21 = alloca %_s__String__charptr_long_long, align 8 + %22 = alloca %_s__String__charptr_long_long, align 8 + %23 = alloca %_s__String__charptr_long_long, align 8 + %24 = alloca %_s__String__charptr_long_long, align 8 + %25 = alloca %_s__String__charptr_long_long, align 8 + %26 = alloca %_s__String__charptr_long_long, align 8 + %27 = alloca %_s__String__charptr_long_long, align 8 + call void @_mp__String__ctor__string_string(ptr nonnull %0, ptr nonnull @6, ptr nonnull @0) + %.fca.0.load214 = load ptr, ptr %0, align 8 + %.fca.1.gep216 = getelementptr inbounds %_s__String__charptr_long_long, ptr %0, i64 0, i32 1 + %.fca.1.load217 = load i64, ptr %.fca.1.gep216, align 8 + %.fca.2.gep219 = getelementptr inbounds %_s__String__charptr_long_long, ptr %0, i64 0, i32 2 + %.fca.2.load220 = load i64, ptr %.fca.2.gep219, align 8 + store ptr %.fca.0.load214, ptr %1, align 8 + %.fca.1.gep210 = getelementptr inbounds %_s__String__charptr_long_long, ptr %1, i64 0, i32 1 + store i64 %.fca.1.load217, ptr %.fca.1.gep210, align 8 + %.fca.2.gep212 = getelementptr inbounds %_s__String__charptr_long_long, ptr %1, i64 0, i32 2 + store i64 %.fca.2.load220, ptr %.fca.2.gep212, align 8 + %28 = call ptr @_mf__String__getRaw(ptr nonnull %1) + %29 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %28) + call void @_mp__String__ctor__string_string(ptr nonnull %2, ptr nonnull @6, ptr nonnull @0) + %.fca.0.load199 = load ptr, ptr %2, align 8 + %.fca.1.gep201 = getelementptr inbounds %_s__String__charptr_long_long, ptr %2, i64 0, i32 1 + %.fca.1.load202 = load i64, ptr %.fca.1.gep201, align 8 + %.fca.2.gep204 = getelementptr inbounds %_s__String__charptr_long_long, ptr %2, i64 0, i32 2 + %.fca.2.load205 = load i64, ptr %.fca.2.gep204, align 8 + store ptr %.fca.0.load199, ptr %3, align 8 + %.fca.1.gep168 = getelementptr inbounds %_s__String__charptr_long_long, ptr %3, i64 0, i32 1 + store i64 %.fca.1.load202, ptr %.fca.1.gep168, align 8 + %.fca.2.gep170 = getelementptr inbounds %_s__String__charptr_long_long, ptr %3, i64 0, i32 2 + store i64 %.fca.2.load205, ptr %.fca.2.gep170, align 8 + %30 = call ptr @_mf__String__getRaw(ptr nonnull %3) + %31 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %30) + %.fca.0.load172 = load ptr, ptr %3, align 8 + %.fca.1.load175 = load i64, ptr %.fca.1.gep168, align 8 + %.fca.2.load178 = load i64, ptr %.fca.2.gep170, align 8 + store ptr %.fca.0.load172, ptr %4, align 8 + %.fca.1.gep162 = getelementptr inbounds %_s__String__charptr_long_long, ptr %4, i64 0, i32 1 + store i64 %.fca.1.load175, ptr %.fca.1.gep162, align 8 + %.fca.2.gep164 = getelementptr inbounds %_s__String__charptr_long_long, ptr %4, i64 0, i32 2 + store i64 %.fca.2.load178, ptr %.fca.2.gep164, align 8 + %32 = call ptr @_mf__String__getRaw(ptr nonnull %4) + call void @_mp__String__ctor__string_string(ptr nonnull %5, ptr %32, ptr nonnull @1) + %.fca.0.load151 = load ptr, ptr %5, align 8 + %.fca.1.gep153 = getelementptr inbounds %_s__String__charptr_long_long, ptr %5, i64 0, i32 1 + %.fca.1.load154 = load i64, ptr %.fca.1.gep153, align 8 + %.fca.2.gep156 = getelementptr inbounds %_s__String__charptr_long_long, ptr %5, i64 0, i32 2 + %.fca.2.load157 = load i64, ptr %.fca.2.gep156, align 8 + store ptr %.fca.0.load151, ptr %6, align 8 + %.fca.1.gep147 = getelementptr inbounds %_s__String__charptr_long_long, ptr %6, i64 0, i32 1 + store i64 %.fca.1.load154, ptr %.fca.1.gep147, align 8 + %.fca.2.gep149 = getelementptr inbounds %_s__String__charptr_long_long, ptr %6, i64 0, i32 2 + store i64 %.fca.2.load157, ptr %.fca.2.gep149, align 8 + %33 = call ptr @_mf__String__getRaw(ptr nonnull %6) + %34 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %33) + %35 = call ptr @_mf__String__getRaw(ptr nonnull %3) + call void @_mp__String__ctor__string_string(ptr nonnull %7, ptr nonnull @2, ptr %35) + %.fca.0.load136 = load ptr, ptr %7, align 8 + %.fca.1.gep138 = getelementptr inbounds %_s__String__charptr_long_long, ptr %7, i64 0, i32 1 + %.fca.1.load139 = load i64, ptr %.fca.1.gep138, align 8 + %.fca.2.gep141 = getelementptr inbounds %_s__String__charptr_long_long, ptr %7, i64 0, i32 2 + %.fca.2.load142 = load i64, ptr %.fca.2.gep141, align 8 + store ptr %.fca.0.load136, ptr %8, align 8 + %.fca.1.gep132 = getelementptr inbounds %_s__String__charptr_long_long, ptr %8, i64 0, i32 1 + store i64 %.fca.1.load139, ptr %.fca.1.gep132, align 8 + %.fca.2.gep134 = getelementptr inbounds %_s__String__charptr_long_long, ptr %8, i64 0, i32 2 + store i64 %.fca.2.load142, ptr %.fca.2.gep134, align 8 + %36 = call ptr @_mf__String__getRaw(ptr nonnull %8) + %37 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %36) + %.fca.0.load181 = load ptr, ptr %3, align 8 + %.fca.1.load184 = load i64, ptr %.fca.1.gep168, align 8 + %.fca.2.load187 = load i64, ptr %.fca.2.gep170, align 8 + store ptr %.fca.0.load181, ptr %9, align 8 + %.fca.1.gep126 = getelementptr inbounds %_s__String__charptr_long_long, ptr %9, i64 0, i32 1 + store i64 %.fca.1.load184, ptr %.fca.1.gep126, align 8 + %.fca.2.gep128 = getelementptr inbounds %_s__String__charptr_long_long, ptr %9, i64 0, i32 2 + store i64 %.fca.2.load187, ptr %.fca.2.gep128, align 8 + %38 = call ptr @_mf__String__getRaw(ptr nonnull %9) + %39 = call ptr @_mf__String__getRaw(ptr nonnull %3) + call void @_mp__String__ctor__string_string(ptr nonnull %10, ptr %38, ptr %39) + %.fca.0.load115 = load ptr, ptr %10, align 8 + %.fca.1.gep117 = getelementptr inbounds %_s__String__charptr_long_long, ptr %10, i64 0, i32 1 + %.fca.1.load118 = load i64, ptr %.fca.1.gep117, align 8 + %.fca.2.gep120 = getelementptr inbounds %_s__String__charptr_long_long, ptr %10, i64 0, i32 2 + %.fca.2.load121 = load i64, ptr %.fca.2.gep120, align 8 + store ptr %.fca.0.load115, ptr %11, align 8 + %.fca.1.gep111 = getelementptr inbounds %_s__String__charptr_long_long, ptr %11, i64 0, i32 1 + store i64 %.fca.1.load118, ptr %.fca.1.gep111, align 8 + %.fca.2.gep113 = getelementptr inbounds %_s__String__charptr_long_long, ptr %11, i64 0, i32 2 + store i64 %.fca.2.load121, ptr %.fca.2.gep113, align 8 + %40 = call ptr @_mf__String__getRaw(ptr nonnull %11) + %41 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %40) + %.fca.0.load190 = load ptr, ptr %3, align 8 + %.fca.1.load193 = load i64, ptr %.fca.1.gep168, align 8 + %.fca.2.load196 = load i64, ptr %.fca.2.gep170, align 8 + store ptr %.fca.0.load190, ptr %12, align 8 + %.fca.1.gep105 = getelementptr inbounds %_s__String__charptr_long_long, ptr %12, i64 0, i32 1 + store i64 %.fca.1.load193, ptr %.fca.1.gep105, align 8 + %.fca.2.gep107 = getelementptr inbounds %_s__String__charptr_long_long, ptr %12, i64 0, i32 2 + store i64 %.fca.2.load196, ptr %.fca.2.gep107, align 8 + %42 = call ptr @_mf__String__getRaw(ptr nonnull %12) + call void @_mp__String__ctor__string_string(ptr nonnull %13, ptr %42, ptr nonnull @3) + %.fca.0.load94 = load ptr, ptr %13, align 8 + %.fca.1.gep96 = getelementptr inbounds %_s__String__charptr_long_long, ptr %13, i64 0, i32 1 + %.fca.1.load97 = load i64, ptr %.fca.1.gep96, align 8 + %.fca.2.gep99 = getelementptr inbounds %_s__String__charptr_long_long, ptr %13, i64 0, i32 2 + %.fca.2.load100 = load i64, ptr %.fca.2.gep99, align 8 + store ptr %.fca.0.load94, ptr %14, align 8 + %.fca.1.gep90 = getelementptr inbounds %_s__String__charptr_long_long, ptr %14, i64 0, i32 1 + store i64 %.fca.1.load97, ptr %.fca.1.gep90, align 8 + %.fca.2.gep92 = getelementptr inbounds %_s__String__charptr_long_long, ptr %14, i64 0, i32 2 + store i64 %.fca.2.load100, ptr %.fca.2.gep92, align 8 + %43 = call ptr @_mf__String__getRaw(ptr nonnull %14) + %44 = call ptr @_mf__String__getRaw(ptr nonnull %3) + call void @_mp__String__ctor__string_string(ptr nonnull %15, ptr %43, ptr %44) + %.fca.0.load79 = load ptr, ptr %15, align 8 + %.fca.1.gep81 = getelementptr inbounds %_s__String__charptr_long_long, ptr %15, i64 0, i32 1 + %.fca.1.load82 = load i64, ptr %.fca.1.gep81, align 8 + %.fca.2.gep84 = getelementptr inbounds %_s__String__charptr_long_long, ptr %15, i64 0, i32 2 + %.fca.2.load85 = load i64, ptr %.fca.2.gep84, align 8 + store ptr %.fca.0.load79, ptr %16, align 8 + %.fca.1.gep75 = getelementptr inbounds %_s__String__charptr_long_long, ptr %16, i64 0, i32 1 + store i64 %.fca.1.load82, ptr %.fca.1.gep75, align 8 + %.fca.2.gep77 = getelementptr inbounds %_s__String__charptr_long_long, ptr %16, i64 0, i32 2 + store i64 %.fca.2.load85, ptr %.fca.2.gep77, align 8 + %45 = call ptr @_mf__String__getRaw(ptr nonnull %16) + %46 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %45) + %47 = call ptr @_mf__String__getRaw(ptr nonnull %3) + call void @_mp__String__ctor__string_string(ptr nonnull %17, ptr nonnull @4, ptr %47) + %.fca.0.load64 = load ptr, ptr %17, align 8 + %.fca.1.gep66 = getelementptr inbounds %_s__String__charptr_long_long, ptr %17, i64 0, i32 1 %.fca.1.load67 = load i64, ptr %.fca.1.gep66, align 8 - %.fca.2.gep69 = getelementptr inbounds %_s__String__charptr_long_long, ptr %0, i64 0, i32 2 + %.fca.2.gep69 = getelementptr inbounds %_s__String__charptr_long_long, ptr %17, i64 0, i32 2 %.fca.2.load70 = load i64, ptr %.fca.2.gep69, align 8 - store ptr %.fca.0.load64, ptr %1, align 8 - %.fca.1.gep60 = getelementptr inbounds %_s__String__charptr_long_long, ptr %1, i64 0, i32 1 + store ptr %.fca.0.load64, ptr %18, align 8 + %.fca.1.gep60 = getelementptr inbounds %_s__String__charptr_long_long, ptr %18, i64 0, i32 1 store i64 %.fca.1.load67, ptr %.fca.1.gep60, align 8 - %.fca.2.gep62 = getelementptr inbounds %_s__String__charptr_long_long, ptr %1, i64 0, i32 2 + %.fca.2.gep62 = getelementptr inbounds %_s__String__charptr_long_long, ptr %18, i64 0, i32 2 store i64 %.fca.2.load70, ptr %.fca.2.gep62, align 8 - %11 = call ptr @_mf__String__getRaw(ptr nonnull %1) - %12 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %11) - call void @_mp__String__ctor__string_string(ptr nonnull %2, ptr nonnull @1, ptr nonnull @0) - %.fca.0.load49 = load ptr, ptr %2, align 8 - %.fca.1.gep51 = getelementptr inbounds %_s__String__charptr_long_long, ptr %2, i64 0, i32 1 + %48 = call ptr @_mf__String__getRaw(ptr nonnull %18) + call void @_mp__String__ctor__string_string(ptr nonnull %19, ptr %48, ptr nonnull @5) + %.fca.0.load49 = load ptr, ptr %19, align 8 + %.fca.1.gep51 = getelementptr inbounds %_s__String__charptr_long_long, ptr %19, i64 0, i32 1 %.fca.1.load52 = load i64, ptr %.fca.1.gep51, align 8 - %.fca.2.gep54 = getelementptr inbounds %_s__String__charptr_long_long, ptr %2, i64 0, i32 2 + %.fca.2.gep54 = getelementptr inbounds %_s__String__charptr_long_long, ptr %19, i64 0, i32 2 %.fca.2.load55 = load i64, ptr %.fca.2.gep54, align 8 - store ptr %.fca.0.load49, ptr %3, align 8 - %.fca.1.gep46 = getelementptr inbounds %_s__String__charptr_long_long, ptr %3, i64 0, i32 1 + store ptr %.fca.0.load49, ptr %20, align 8 + %.fca.1.gep46 = getelementptr inbounds %_s__String__charptr_long_long, ptr %20, i64 0, i32 1 store i64 %.fca.1.load52, ptr %.fca.1.gep46, align 8 - %.fca.2.gep47 = getelementptr inbounds %_s__String__charptr_long_long, ptr %3, i64 0, i32 2 + %.fca.2.gep47 = getelementptr inbounds %_s__String__charptr_long_long, ptr %20, i64 0, i32 2 store i64 %.fca.2.load55, ptr %.fca.2.gep47, align 8 - %13 = call ptr @_mf__String__getRaw(ptr nonnull %3) - %14 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %13) - call void @_mp__String__ctor__string(ptr nonnull %4, ptr nonnull @9) - call void @_mp__String__opMul__short(ptr nonnull %4, i16 4) - %15 = call ptr @_mf__String__getRaw(ptr nonnull %4) - %16 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %15) - call void @_mp__String__ctor__string(ptr nonnull %5, ptr nonnull @1) - call void @_mp__String__opMul__int(ptr nonnull %5, i32 5) - %17 = call ptr @_mf__String__getRaw(ptr nonnull %5) - %18 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %17) - call void @_mp__String__ctor__char(ptr nonnull %6, i8 97) - call void @_mp__String__opMul__int(ptr nonnull %6, i32 20) - %19 = call ptr @_mf__String__getRaw(ptr nonnull %6) - %20 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %19) - call void @_mp__String__ctor__char(ptr nonnull %7, i8 99) - call void @_mp__String__opMul__int(ptr nonnull %7, i32 2) - call void @_mp__String__opMul__int(ptr nonnull %7, i32 7) - %21 = call ptr @_mf__String__getRaw(ptr nonnull %7) - %22 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %21) - %23 = call i32 (ptr, ...) @printf(ptr nonnull @2, i32 zext (i1 icmp eq (ptr @3, ptr @4) to i32)) - %24 = call i32 (ptr, ...) @printf(ptr nonnull @2, i32 zext (i1 icmp eq (ptr @7, ptr @5) to i32)) - %25 = call i32 (ptr, ...) @printf(ptr nonnull @2, i32 1) - %26 = call i32 (ptr, ...) @printf(ptr nonnull @6, i32 zext (i1 icmp ne (ptr @3, ptr @4) to i32)) - %27 = call i32 (ptr, ...) @printf(ptr nonnull @6, i32 zext (i1 icmp ne (ptr @7, ptr @5) to i32)) - %28 = call i32 (ptr, ...) @printf(ptr nonnull @6, i32 0) - call void @_mp__String__ctor__string(ptr nonnull %8, ptr nonnull @7) - call void @_mp__String__append__char(ptr nonnull %8, i8 108) - %29 = call ptr @_mf__String__getRaw(ptr nonnull %8) - %30 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %29) - call void @_mp__String__ctor__string(ptr nonnull %9, ptr nonnull @9) - call void @_mp__String__append__string(ptr nonnull %9, ptr nonnull @8) - %31 = call ptr @_mf__String__getRaw(ptr nonnull %9) - %32 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %31) - call void @_mp__String__ctor__string(ptr nonnull %10, ptr nonnull @9) - call void @_mp__String__opMul__int(ptr nonnull %10, i32 3) - %33 = call ptr @_mf__String__getRaw(ptr nonnull %10) - %34 = call i32 (ptr, ...) @printf(ptr nonnull @10, ptr %33) - call void @_mp__String__dtor(ptr nonnull %6) - call void @_mp__String__dtor(ptr nonnull %7) - call void @_mp__String__dtor(ptr nonnull %8) - call void @_mp__String__dtor(ptr nonnull %9) - call void @_mp__String__dtor(ptr nonnull %10) + %49 = call ptr @_mf__String__getRaw(ptr nonnull %20) + %50 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %49) + call void @_mp__String__ctor__string(ptr nonnull %21, ptr nonnull @14) + call void @_mp__String__opMul__short(ptr nonnull %21, i16 4) + %51 = call ptr @_mf__String__getRaw(ptr nonnull %21) + %52 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %51) + call void @_mp__String__ctor__string(ptr nonnull %22, ptr nonnull @6) + call void @_mp__String__opMul__int(ptr nonnull %22, i32 5) + %53 = call ptr @_mf__String__getRaw(ptr nonnull %22) + %54 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %53) + call void @_mp__String__ctor__char(ptr nonnull %23, i8 97) + call void @_mp__String__opMul__int(ptr nonnull %23, i32 20) + %55 = call ptr @_mf__String__getRaw(ptr nonnull %23) + %56 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %55) + call void @_mp__String__ctor__char(ptr nonnull %24, i8 99) + call void @_mp__String__opMul__int(ptr nonnull %24, i32 2) + call void @_mp__String__opMul__int(ptr nonnull %24, i32 7) + %57 = call ptr @_mf__String__getRaw(ptr nonnull %24) + %58 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %57) + %59 = call i32 (ptr, ...) @printf(ptr nonnull @7, i32 zext (i1 icmp eq (ptr @8, ptr @9) to i32)) + %60 = call i32 (ptr, ...) @printf(ptr nonnull @7, i32 zext (i1 icmp eq (ptr @12, ptr @10) to i32)) + %61 = call i32 (ptr, ...) @printf(ptr nonnull @7, i32 1) + %62 = call i32 (ptr, ...) @printf(ptr nonnull @11, i32 zext (i1 icmp ne (ptr @8, ptr @9) to i32)) + %63 = call i32 (ptr, ...) @printf(ptr nonnull @11, i32 zext (i1 icmp ne (ptr @12, ptr @10) to i32)) + %64 = call i32 (ptr, ...) @printf(ptr nonnull @11, i32 0) + call void @_mp__String__ctor__string(ptr nonnull %25, ptr nonnull @12) + call void @_mp__String__append__char(ptr nonnull %25, i8 108) + %65 = call ptr @_mf__String__getRaw(ptr nonnull %25) + %66 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %65) + call void @_mp__String__ctor__string(ptr nonnull %26, ptr nonnull @14) + call void @_mp__String__append__string(ptr nonnull %26, ptr nonnull @13) + %67 = call ptr @_mf__String__getRaw(ptr nonnull %26) + %68 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %67) + call void @_mp__String__ctor__string(ptr nonnull %27, ptr nonnull @14) + call void @_mp__String__opMul__int(ptr nonnull %27, i32 3) + %69 = call ptr @_mf__String__getRaw(ptr nonnull %27) + %70 = call i32 (ptr, ...) @printf(ptr nonnull @15, ptr %69) + call void @_mp__String__dtor(ptr nonnull %17) + call void @_mp__String__dtor(ptr nonnull %19) + call void @_mp__String__dtor(ptr nonnull %21) + call void @_mp__String__dtor(ptr nonnull %22) + call void @_mp__String__dtor(ptr nonnull %23) + call void @_mp__String__dtor(ptr nonnull %24) + call void @_mp__String__dtor(ptr nonnull %25) + call void @_mp__String__dtor(ptr nonnull %26) call void @_mp__String__dtor(ptr nonnull %0) + call void @_mp__String__dtor(ptr nonnull %27) call void @_mp__String__dtor(ptr nonnull %2) - call void @_mp__String__dtor(ptr nonnull %4) call void @_mp__String__dtor(ptr nonnull %5) + call void @_mp__String__dtor(ptr nonnull %7) + call void @_mp__String__dtor(ptr nonnull %10) + call void @_mp__String__dtor(ptr nonnull %13) + call void @_mp__String__dtor(ptr nonnull %15) ret i32 0 } diff --git a/test/test-files/std/runtime/string-operators/source.spice b/test/test-files/std/runtime/string-operators/source.spice index b1909bbf0..74249aaff 100644 --- a/test/test-files/std/runtime/string-operators/source.spice +++ b/test/test-files/std/runtime/string-operators/source.spice @@ -3,6 +3,12 @@ f main() { printf("Result: %s\n", "Hello " + "World!"); string s1 = "Hello " + "World!"; printf("Result: %s\n", s1); + printf("Result: %s\n", s1 + " Hi!"); + printf("Result: %s\n", "Hi! " + s1); + printf("Result: %s\n", s1 + s1); + printf("Result: %s\n", s1 + " " + s1); + printf("Result: %s\n", "Prefix " + s1 + " Suffix"); + // Mul printf("Result: %s\n", 4s * "Hi"); string s2 = "Hello " * 5; @@ -10,14 +16,17 @@ f main() { printf("Result: %s\n", 20 * 'a'); string s3 = 2 * 'c' * 7; printf("Result: %s\n", s3); + // Equals printf("Equal: %d\n", "Hello World!" == "Hello Programmers!"); printf("Equal: %d\n", "Hello" == "Hell2"); printf("Equal: %d\n", "Hello" == "Hello"); + // Not equals printf("Non-equal: %d\n", "Hello World!" != "Hello Programmers!"); printf("Non-equal: %d\n", "Hello" != "Hell2"); printf("Non-equal: %d\n", "Hello" != "Hello"); + // PlusEquals string s4 = "Hello"; s4 += 'l'; @@ -25,6 +34,7 @@ f main() { string s5 = "Hi"; s5 += " World!"; printf("Result: %s\n", s5); + // MulEquals string s6 = "Hi"; s6 *= 3;