From 0ed43ebe5fe397ac7aa5fcfc3138a70314fb025b Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 14:29:42 +0100 Subject: [PATCH 01/12] Prepare initial C++ transpiler architecture --- CMakeLists.txt | 31 +++++++++++++------ src/engine/internal/codegen/CMakeLists.txt | 6 +++- .../internal/codegen/codebuilderfactory.cpp | 12 +++++++ .../internal/codegen/cpp/CMakeLists.txt | 3 ++ test/CMakeLists.txt | 7 ++++- test/cpp/CMakeLists.txt | 14 +++++++++ test/cpp/main.cpp | 1 + 7 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 src/engine/internal/codegen/cpp/CMakeLists.txt create mode 100644 test/cpp/CMakeLists.txt create mode 100644 test/cpp/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bb3cb6ff7..729364652 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,8 @@ option(LIBSCRATCHCPP_ENABLE_CODE_ANALYZER "Analyze Scratch scripts to enable var option(LIBSCRATCHCPP_LLVM_INTEGER_SUPPORT "Use integers when possible to enable various optimizations" ON) option(LIBSCRATCHCPP_ENABLE_SANITIZER "Enable sanitizer to detect memory issues" OFF) +set(LIBSCRATCHCPP_CODEGEN_BACKEND "llvm" CACHE STRING "The backend used for code generation") + if (LIBSCRATCHCPP_ENABLE_SANITIZER) set(SANITIZER_FLAGS "-fsanitize=undefined -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_CFLAGS ${CMAKE_CFLAGS} ${SANITIZER_FLAGS}) @@ -130,20 +132,29 @@ if (LIBSCRATCHCPP_NETWORK_SUPPORT) endif() # LLVM -include(build/HunterPackages.cmake) -include(build/LLVM.cmake) -target_link_libraries(scratchcpp PRIVATE LLVM) +if (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "llvm") + include(build/HunterPackages.cmake) + include(build/LLVM.cmake) + target_link_libraries(scratchcpp PRIVATE LLVM) -if(LIBSCRATCHCPP_PRINT_LLVM_IR) - target_compile_definitions(scratchcpp PRIVATE PRINT_LLVM_IR) -endif() + target_compile_definitions(scratchcpp PRIVATE CODEGEN_BACKEND_LLVM) + + if(LIBSCRATCHCPP_PRINT_LLVM_IR) + target_compile_definitions(scratchcpp PRIVATE PRINT_LLVM_IR) + endif() -if(LIBSCRATCHCPP_ENABLE_CODE_ANALYZER) - target_compile_definitions(scratchcpp PRIVATE ENABLE_CODE_ANALYZER) + if(LIBSCRATCHCPP_ENABLE_CODE_ANALYZER) + target_compile_definitions(scratchcpp PRIVATE ENABLE_CODE_ANALYZER) + endif() + + if(LIBSCRATCHCPP_LLVM_INTEGER_SUPPORT) + target_compile_definitions(scratchcpp PRIVATE LLVM_INTEGER_SUPPORT) + endif() endif() -if(LIBSCRATCHCPP_LLVM_INTEGER_SUPPORT) - target_compile_definitions(scratchcpp PRIVATE LLVM_INTEGER_SUPPORT) +# C++ transpiler +if (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") + target_compile_definitions(scratchcpp PRIVATE CODEGEN_BACKEND_CPP) endif() # Macros diff --git a/src/engine/internal/codegen/CMakeLists.txt b/src/engine/internal/codegen/CMakeLists.txt index bb278efb3..aa21b06fe 100644 --- a/src/engine/internal/codegen/CMakeLists.txt +++ b/src/engine/internal/codegen/CMakeLists.txt @@ -15,4 +15,8 @@ target_sources(scratchcpp optimizationutils.h ) -add_subdirectory(llvm) +if (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "llvm") + add_subdirectory(llvm) +elseif (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") + add_subdirectory(cpp) +endif() diff --git a/src/engine/internal/codegen/codebuilderfactory.cpp b/src/engine/internal/codegen/codebuilderfactory.cpp index fc2985de5..b40c77be7 100644 --- a/src/engine/internal/codegen/codebuilderfactory.cpp +++ b/src/engine/internal/codegen/codebuilderfactory.cpp @@ -1,8 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 #include "codebuilderfactory.h" + +#ifdef CODEGEN_BACKEND_LLVM #include "llvm/llvmcodebuilder.h" #include "llvm/llvmcompilercontext.h" +#elif defined(CODEGEN_BACKEND_CPP) +#endif using namespace libscratchcpp; @@ -15,12 +19,20 @@ std::shared_ptr CodeBuilderFactory::instance() std::shared_ptr CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) const { +#ifdef CODEGEN_BACKEND_LLVM assert(dynamic_cast(ctx)); return std::make_shared(static_cast(ctx), procedurePrototype, codeType); +#elif defined(CODEGEN_BACKEND_CPP) + return nullptr; +#endif } std::shared_ptr CodeBuilderFactory::createCtx(IEngine *engine, Target *target, const std::unordered_set &unsafeConstants) const { +#ifdef CODEGEN_BACKEND_LLVM auto ptr = std::make_shared(engine, target, unsafeConstants); return ptr; +#elif defined(CODEGEN_BACKEND_CPP) + return nullptr; +#endif } diff --git a/src/engine/internal/codegen/cpp/CMakeLists.txt b/src/engine/internal/codegen/cpp/CMakeLists.txt new file mode 100644 index 000000000..968f205cd --- /dev/null +++ b/src/engine/internal/codegen/cpp/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(scratchcpp + PRIVATE +) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f6cf9531d..c0d6b442c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,6 +37,11 @@ add_subdirectory(audio) add_subdirectory(compiler) add_subdirectory(blocks) add_subdirectory(executioncontext) -add_subdirectory(llvm) add_subdirectory(promise) add_subdirectory(test_api) + +if (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "llvm") + add_subdirectory(llvm) +elseif (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") + add_subdirectory(cpp) +endif() diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt new file mode 100644 index 000000000..8b3acc424 --- /dev/null +++ b/test/cpp/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable( + cpp_test + main.cpp +) + +target_link_libraries( + cpp_test + GTest::gtest_main + GTest::gmock_main + scratchcpp + scratchcpp_mocks +) + +gtest_discover_tests(cpp_test) diff --git a/test/cpp/main.cpp b/test/cpp/main.cpp new file mode 100644 index 000000000..1898d06dd --- /dev/null +++ b/test/cpp/main.cpp @@ -0,0 +1 @@ +#include "../common.h" From 96656238391dad9f489c8004ac0dff683a29d861 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 14:35:54 +0100 Subject: [PATCH 02/12] Disable some tests in C++ transpiler builds --- test/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c0d6b442c..2ef228dba 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -17,7 +17,9 @@ include(GoogleTest) add_subdirectory(mocks) add_subdirectory(zip) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") add_subdirectory(load_project) +endif() add_subdirectory(project) add_subdirectory(thread) add_subdirectory(scratch_classes) @@ -26,8 +28,10 @@ add_subdirectory(scratchconfiguration) add_subdirectory(assets) add_subdirectory(script) add_subdirectory(extensions) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") add_subdirectory(codegen) add_subdirectory(engine) +endif() add_subdirectory(clock) add_subdirectory(timer) add_subdirectory(randomgenerator) @@ -35,10 +39,14 @@ add_subdirectory(rect) add_subdirectory(network) add_subdirectory(audio) add_subdirectory(compiler) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") add_subdirectory(blocks) +endif() add_subdirectory(executioncontext) add_subdirectory(promise) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") add_subdirectory(test_api) +endif() if (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "llvm") add_subdirectory(llvm) From 26063a92ddf8730e0360d9a233fcc4394c8b15eb Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 14:57:01 +0100 Subject: [PATCH 03/12] Add codegen backends to unit tests workflow --- .github/workflows/utests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/utests.yml b/.github/workflows/utests.yml index a72d07e28..eebc4d697 100644 --- a/.github/workflows/utests.yml +++ b/.github/workflows/utests.yml @@ -13,6 +13,10 @@ jobs: build: runs-on: ubuntu-latest + strategy: + matrix: + codegen_backend: ['llvm', 'cpp'] + steps: - uses: actions/checkout@v3 with: @@ -24,7 +28,7 @@ jobs: sudo apt-get install -y nlohmann-json3-dev libutfcpp-dev shell: bash - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLIBSCRATCHCPP_BUILD_UNIT_TESTS=ON -DLIBSCRATCHCPP_ENABLE_SANITIZER=ON + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLIBSCRATCHCPP_BUILD_UNIT_TESTS=ON -DLIBSCRATCHCPP_ENABLE_SANITIZER=ON -DLIBSCRATCHCPP_CODEGEN_BACKEND=${{ matrix.codegen_backend }} - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j$(nproc --all) From a2bff342fe5c9f3358a4673b09af71171de2f74e Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 20:04:44 +0100 Subject: [PATCH 04/12] Add initial C++ transpiler classes --- .../internal/codegen/codebuilderfactory.cpp | 8 +- .../internal/codegen/cpp/CMakeLists.txt | 12 + .../internal/codegen/cpp/cppcodebuilder.cpp | 336 ++++++++++++++++++ .../internal/codegen/cpp/cppcodebuilder.h | 112 ++++++ .../codegen/cpp/cppcompilercontext.cpp | 10 + .../internal/codegen/cpp/cppcompilercontext.h | 16 + src/engine/internal/codegen/cpp/cppconstant.h | 27 ++ .../codegen/cpp/cppexecutablecode.cpp | 44 +++ .../internal/codegen/cpp/cppexecutablecode.h | 31 ++ .../codegen/cpp/cppexecutioncontext.cpp | 11 + .../codegen/cpp/cppexecutioncontext.h | 21 ++ .../internal/codegen/cpp/cppinstruction.h | 19 + .../internal/codegen/cpp/cppinstructionlist.h | 14 + src/engine/internal/codegen/cpp/cppvalue.h | 31 ++ 14 files changed, 690 insertions(+), 2 deletions(-) create mode 100644 src/engine/internal/codegen/cpp/cppcodebuilder.cpp create mode 100644 src/engine/internal/codegen/cpp/cppcodebuilder.h create mode 100644 src/engine/internal/codegen/cpp/cppcompilercontext.cpp create mode 100644 src/engine/internal/codegen/cpp/cppcompilercontext.h create mode 100644 src/engine/internal/codegen/cpp/cppconstant.h create mode 100644 src/engine/internal/codegen/cpp/cppexecutablecode.cpp create mode 100644 src/engine/internal/codegen/cpp/cppexecutablecode.h create mode 100644 src/engine/internal/codegen/cpp/cppexecutioncontext.cpp create mode 100644 src/engine/internal/codegen/cpp/cppexecutioncontext.h create mode 100644 src/engine/internal/codegen/cpp/cppinstruction.h create mode 100644 src/engine/internal/codegen/cpp/cppinstructionlist.h create mode 100644 src/engine/internal/codegen/cpp/cppvalue.h diff --git a/src/engine/internal/codegen/codebuilderfactory.cpp b/src/engine/internal/codegen/codebuilderfactory.cpp index b40c77be7..beca57c22 100644 --- a/src/engine/internal/codegen/codebuilderfactory.cpp +++ b/src/engine/internal/codegen/codebuilderfactory.cpp @@ -6,6 +6,8 @@ #include "llvm/llvmcodebuilder.h" #include "llvm/llvmcompilercontext.h" #elif defined(CODEGEN_BACKEND_CPP) +#include "cpp/cppcodebuilder.h" +#include "cpp/cppcompilercontext.h" #endif using namespace libscratchcpp; @@ -23,7 +25,8 @@ std::shared_ptr CodeBuilderFactory::create(CompilerContext *ctx, B assert(dynamic_cast(ctx)); return std::make_shared(static_cast(ctx), procedurePrototype, codeType); #elif defined(CODEGEN_BACKEND_CPP) - return nullptr; + assert(dynamic_cast(ctx)); + return std::make_shared(static_cast(ctx), procedurePrototype, codeType); #endif } @@ -33,6 +36,7 @@ std::shared_ptr CodeBuilderFactory::createCtx(IEngine *engine, auto ptr = std::make_shared(engine, target, unsafeConstants); return ptr; #elif defined(CODEGEN_BACKEND_CPP) - return nullptr; + auto ptr = std::make_shared(engine, target, unsafeConstants); + return ptr; #endif } diff --git a/src/engine/internal/codegen/cpp/CMakeLists.txt b/src/engine/internal/codegen/cpp/CMakeLists.txt index 968f205cd..bf3e34349 100644 --- a/src/engine/internal/codegen/cpp/CMakeLists.txt +++ b/src/engine/internal/codegen/cpp/CMakeLists.txt @@ -1,3 +1,15 @@ target_sources(scratchcpp PRIVATE + cppcompilercontext.cpp + cppcompilercontext.h + cppexecutablecode.cpp + cppexecutablecode.h + cppexecutioncontext.cpp + cppexecutioncontext.h + cppinstruction.h + cppinstructionlist.h + cppvalue.h + cppconstant.h + cppcodebuilder.cpp + cppcodebuilder.h ) diff --git a/src/engine/internal/codegen/cpp/cppcodebuilder.cpp b/src/engine/internal/codegen/cpp/cppcodebuilder.cpp new file mode 100644 index 000000000..bd1ad96cd --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcodebuilder.cpp @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include "cppcodebuilder.h" + +using namespace libscratchcpp; + +CppCodeBuilder::CppCodeBuilder(CppCompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) : + m_ctx(ctx), + m_procedurePrototype(procedurePrototype), + m_codeType(codeType) +{ +} + +std::shared_ptr CppCodeBuilder::build() +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) +{ + return nullptr; +} + +CompilerConstant *CppCodeBuilder::addConstValue(const Value &value) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addStringChar(CompilerValue *string, CompilerValue *index) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addStringLength(CompilerValue *string) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addLoopIndex() +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addLocalVariableValue(CompilerLocalVariable *variable) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addVariableValue(Variable *variable) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addListContents(List *list) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addListItem(List *list, CompilerValue *index) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addListItemIndex(List *list, CompilerValue *item) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addListContains(List *list, CompilerValue *item) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addListSize(List *list) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::addProcedureArgument(const std::string &name) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createAdd(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createSub(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createMul(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createDiv(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createRandom(CompilerValue *from, CompilerValue *to) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createRandomInt(CompilerValue *from, CompilerValue *to) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createCmpGT(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createCmpLT(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createStrCmpEQ(CompilerValue *string1, CompilerValue *string2, bool caseSensitive) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createAnd(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createOr(CompilerValue *operand1, CompilerValue *operand2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createNot(CompilerValue *operand) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createMod(CompilerValue *num1, CompilerValue *num2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createRound(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createAbs(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createFloor(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createCeil(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createSqrt(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createSin(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createCos(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createTan(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createAsin(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createAcos(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createAtan(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createLn(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createLog10(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createExp(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createExp10(CompilerValue *num) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createStringConcat(CompilerValue *string1, CompilerValue *string2) +{ + return nullptr; +} + +CompilerValue *CppCodeBuilder::createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType) +{ + return nullptr; +} + +CompilerLocalVariable *CppCodeBuilder::createLocalVariable(Compiler::StaticType type) +{ + return nullptr; +} + +void CppCodeBuilder::createLocalVariableWrite(CompilerLocalVariable *variable, CompilerValue *value) +{ +} + +void CppCodeBuilder::createVariableWrite(Variable *variable, CompilerValue *value) +{ +} + +void CppCodeBuilder::createListClear(List *list) +{ +} + +void CppCodeBuilder::createListRemove(List *list, CompilerValue *index) +{ +} + +void CppCodeBuilder::createListAppend(List *list, CompilerValue *item) +{ +} + +void CppCodeBuilder::createListInsert(List *list, CompilerValue *index, CompilerValue *item) +{ +} + +void CppCodeBuilder::createListReplace(List *list, CompilerValue *index, CompilerValue *item) +{ +} + +void CppCodeBuilder::beginIfStatement(CompilerValue *cond) +{ +} + +void CppCodeBuilder::beginElseBranch() +{ +} + +void CppCodeBuilder::endIf() +{ +} + +void CppCodeBuilder::beginRepeatLoop(CompilerValue *count) +{ +} + +void CppCodeBuilder::beginWhileLoop(CompilerValue *cond) +{ +} + +void CppCodeBuilder::beginRepeatUntilLoop(CompilerValue *cond) +{ +} + +void CppCodeBuilder::beginLoopCondition() +{ +} + +void CppCodeBuilder::endLoop() +{ +} + +void CppCodeBuilder::yield() +{ +} + +void CppCodeBuilder::createStop() +{ +} + +void CppCodeBuilder::createThreadStop() +{ +} + +void CppCodeBuilder::invalidateTarget() +{ +} + +void CppCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) +{ +} + +void CppCodeBuilder::createPrint(CompilerValue *string) +{ +} diff --git a/src/engine/internal/codegen/cpp/cppcodebuilder.h b/src/engine/internal/codegen/cpp/cppcodebuilder.h new file mode 100644 index 000000000..ed98b9616 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcodebuilder.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../icodebuilder.h" + +namespace libscratchcpp +{ + +class CppCompilerContext; + +class CppCodeBuilder : public ICodeBuilder +{ + public: + CppCodeBuilder(CppCompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType codeType = Compiler::CodeType::Script); + + private: + CppCompilerContext *m_ctx = nullptr; + BlockPrototype *m_procedurePrototype = nullptr; + Compiler::CodeType m_codeType = Compiler::CodeType::Script; + + std::shared_ptr build() override; + + CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override; + CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override; + CompilerValue *addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override; + CompilerConstant *addConstValue(const Value &value) override; + CompilerValue *addStringChar(CompilerValue *string, CompilerValue *index) override; + CompilerValue *addStringLength(CompilerValue *string) override; + CompilerValue *addLoopIndex() override; + CompilerValue *addLocalVariableValue(CompilerLocalVariable *variable) override; + CompilerValue *addVariableValue(Variable *variable) override; + CompilerValue *addListContents(List *list) override; + CompilerValue *addListItem(List *list, CompilerValue *index) override; + CompilerValue *addListItemIndex(List *list, CompilerValue *item) override; + CompilerValue *addListContains(List *list, CompilerValue *item) override; + CompilerValue *addListSize(List *list) override; + CompilerValue *addProcedureArgument(const std::string &name) override; + + CompilerValue *createAdd(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createSub(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createMul(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createDiv(CompilerValue *operand1, CompilerValue *operand2) override; + + CompilerValue *createRandom(CompilerValue *from, CompilerValue *to) override; + CompilerValue *createRandomInt(CompilerValue *from, CompilerValue *to) override; + + CompilerValue *createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createCmpGT(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createCmpLT(CompilerValue *operand1, CompilerValue *operand2) override; + + CompilerValue *createStrCmpEQ(CompilerValue *string1, CompilerValue *string2, bool caseSensitive) override; + + CompilerValue *createAnd(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createOr(CompilerValue *operand1, CompilerValue *operand2) override; + CompilerValue *createNot(CompilerValue *operand) override; + + CompilerValue *createMod(CompilerValue *num1, CompilerValue *num2) override; + CompilerValue *createRound(CompilerValue *num) override; + CompilerValue *createAbs(CompilerValue *num) override; + CompilerValue *createFloor(CompilerValue *num) override; + CompilerValue *createCeil(CompilerValue *num) override; + CompilerValue *createSqrt(CompilerValue *num) override; + CompilerValue *createSin(CompilerValue *num) override; + CompilerValue *createCos(CompilerValue *num) override; + CompilerValue *createTan(CompilerValue *num) override; + CompilerValue *createAsin(CompilerValue *num) override; + CompilerValue *createAcos(CompilerValue *num) override; + CompilerValue *createAtan(CompilerValue *num) override; + CompilerValue *createLn(CompilerValue *num) override; + CompilerValue *createLog10(CompilerValue *num) override; + CompilerValue *createExp(CompilerValue *num) override; + CompilerValue *createExp10(CompilerValue *num) override; + + CompilerValue *createStringConcat(CompilerValue *string1, CompilerValue *string2) override; + + CompilerValue *createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType) override; + + CompilerLocalVariable *createLocalVariable(Compiler::StaticType type) override; + void createLocalVariableWrite(CompilerLocalVariable *variable, CompilerValue *value) override; + + void createVariableWrite(Variable *variable, CompilerValue *value) override; + + void createListClear(List *list) override; + void createListRemove(List *list, CompilerValue *index) override; + void createListAppend(List *list, CompilerValue *item) override; + void createListInsert(List *list, CompilerValue *index, CompilerValue *item) override; + void createListReplace(List *list, CompilerValue *index, CompilerValue *item) override; + + void beginIfStatement(CompilerValue *cond) override; + void beginElseBranch() override; + void endIf() override; + + void beginRepeatLoop(CompilerValue *count) override; + void beginWhileLoop(CompilerValue *cond) override; + void beginRepeatUntilLoop(CompilerValue *cond) override; + void beginLoopCondition() override; + void endLoop() override; + + void yield() override; + + void createStop() override; + void createThreadStop() override; + + void invalidateTarget() override; + + void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) override; + + void createPrint(CompilerValue *string) override; +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppcompilercontext.cpp b/src/engine/internal/codegen/cpp/cppcompilercontext.cpp new file mode 100644 index 000000000..5837fa657 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcompilercontext.cpp @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include "cppcompilercontext.h" + +using namespace libscratchcpp; + +CppCompilerContext::CppCompilerContext(IEngine *engine, Target *target, const std::unordered_set &unsafeConstants) : + CompilerContext(engine, target, unsafeConstants) +{ +} diff --git a/src/engine/internal/codegen/cpp/cppcompilercontext.h b/src/engine/internal/codegen/cpp/cppcompilercontext.h new file mode 100644 index 000000000..3831efcee --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcompilercontext.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace libscratchcpp +{ + +class CppCompilerContext : public CompilerContext +{ + public: + CppCompilerContext(IEngine *engine, Target *target, const std::unordered_set &unsafeConstants = {}); +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppconstant.h b/src/engine/internal/codegen/cpp/cppconstant.h new file mode 100644 index 000000000..0250e4942 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppconstant.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "cppvalue.h" + +namespace libscratchcpp +{ + +struct CppConstant + : public CompilerConstant + , public CppValue +{ + CppConstant(Compiler::StaticType type, const Value &value) : + CompilerValue(type), + CompilerConstant(type, value), + CppValue(type) + { + isRawValue = true; // all constants can be read directly + } + + const Value &constValue() const override final { return CompilerConstant::value(); } +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppexecutablecode.cpp b/src/engine/internal/codegen/cpp/cppexecutablecode.cpp new file mode 100644 index 000000000..59ee58cc1 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutablecode.cpp @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include "cppexecutablecode.h" + +using namespace libscratchcpp; + +CppExecutableCode::CppExecutableCode(CppCompilerContext *ctx) : + m_ctx(ctx) +{ +} + +void CppExecutableCode::run(ExecutionContext *context) +{ +} + +ValueData CppExecutableCode::runReporter(ExecutionContext *context) +{ + return ValueData(); +} + +bool CppExecutableCode::runPredicate(ExecutionContext *context) +{ + return false; +} + +void CppExecutableCode::kill(ExecutionContext *context) +{ +} + +void CppExecutableCode::reset(ExecutionContext *context) +{ +} + +bool CppExecutableCode::isFinished(ExecutionContext *context) const +{ + return true; +} + +std::shared_ptr CppExecutableCode::createExecutionContext(Thread *thread) const +{ + return nullptr; +} diff --git a/src/engine/internal/codegen/cpp/cppexecutablecode.h b/src/engine/internal/codegen/cpp/cppexecutablecode.h new file mode 100644 index 000000000..48f89f9f3 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutablecode.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace libscratchcpp +{ + +class CppCompilerContext; + +class CppExecutableCode : public ExecutableCode +{ + public: + CppExecutableCode(CppCompilerContext *ctx); + + void run(ExecutionContext *context) override; + ValueData runReporter(ExecutionContext *context) override; + bool runPredicate(ExecutionContext *context) override; + void kill(ExecutionContext *context) override; + void reset(ExecutionContext *context) override; + + bool isFinished(ExecutionContext *context) const override; + + std::shared_ptr createExecutionContext(Thread *thread) const override; + + private: + CppCompilerContext *m_ctx = nullptr; +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp b/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp new file mode 100644 index 000000000..f25732098 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include "cppexecutioncontext.h" + +using namespace libscratchcpp; + +CppExecutionContext::CppExecutionContext(CppCompilerContext *ctx, Thread *thread) : + ExecutionContext(thread), + m_ctx(ctx) +{ +} diff --git a/src/engine/internal/codegen/cpp/cppexecutioncontext.h b/src/engine/internal/codegen/cpp/cppexecutioncontext.h new file mode 100644 index 000000000..0857953b8 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace libscratchcpp +{ + +class CppCompilerContext; + +class CppExecutionContext : public ExecutionContext +{ + public: + CppExecutionContext(CppCompilerContext *ctx, Thread *thread); + + private: + CppCompilerContext *m_ctx = nullptr; +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppinstruction.h b/src/engine/internal/codegen/cpp/cppinstruction.h new file mode 100644 index 000000000..e554e6663 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppinstruction.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "../instruction.h" +#include "cppvalue.h" + +namespace libscratchcpp +{ + +struct CppInstruction : Instruction +{ + using Type = Instruction::Type; + using Instruction::Instruction; // inherit constructor +}; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppinstructionlist.h b/src/engine/internal/codegen/cpp/cppinstructionlist.h new file mode 100644 index 000000000..be65a6767 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppinstructionlist.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../instructionlist.h" + +namespace libscratchcpp +{ + +struct CppInstruction; + +using CppInstructionList = InstructionList; + +} // namespace libscratchcpp diff --git a/src/engine/internal/codegen/cpp/cppvalue.h b/src/engine/internal/codegen/cpp/cppvalue.h new file mode 100644 index 000000000..77f6d7824 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppvalue.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include + +namespace libscratchcpp +{ + +class CppInstruction; + +struct CppValue : public virtual CompilerValue +{ + CppValue(Compiler::StaticType type) : + CompilerValue(type) + { + } + + virtual const Value &constValue() const + { + static const Value null = Value(); + return null; + } + + bool isRawValue = false; + + std::shared_ptr instruction; +}; + +} // namespace libscratchcpp From b9f31dfef67d3aeb2ab54a05c88a821bb85b076a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 20:49:30 +0100 Subject: [PATCH 05/12] Add CppExecutionContext test --- .../internal/codegen/cpp/cppcompilercontext.h | 4 +++- .../internal/codegen/cpp/cppexecutioncontext.h | 4 +++- test/cpp/CMakeLists.txt | 1 + test/cpp/cppexecutioncontext_test.cpp | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/cpp/cppexecutioncontext_test.cpp diff --git a/src/engine/internal/codegen/cpp/cppcompilercontext.h b/src/engine/internal/codegen/cpp/cppcompilercontext.h index 3831efcee..15b62cd88 100644 --- a/src/engine/internal/codegen/cpp/cppcompilercontext.h +++ b/src/engine/internal/codegen/cpp/cppcompilercontext.h @@ -4,10 +4,12 @@ #include +#include "test_export.h" + namespace libscratchcpp { -class CppCompilerContext : public CompilerContext +class LIBSCRATCHCPP_TEST_EXPORT CppCompilerContext : public CompilerContext { public: CppCompilerContext(IEngine *engine, Target *target, const std::unordered_set &unsafeConstants = {}); diff --git a/src/engine/internal/codegen/cpp/cppexecutioncontext.h b/src/engine/internal/codegen/cpp/cppexecutioncontext.h index 0857953b8..59bc0a0d3 100644 --- a/src/engine/internal/codegen/cpp/cppexecutioncontext.h +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.h @@ -4,12 +4,14 @@ #include +#include "test_export.h" + namespace libscratchcpp { class CppCompilerContext; -class CppExecutionContext : public ExecutionContext +class LIBSCRATCHCPP_TEST_EXPORT CppExecutionContext : public ExecutionContext { public: CppExecutionContext(CppCompilerContext *ctx, Thread *thread); diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt index 8b3acc424..029e662e9 100644 --- a/test/cpp/CMakeLists.txt +++ b/test/cpp/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable( cpp_test main.cpp + cppexecutioncontext_test.cpp ) target_link_libraries( diff --git a/test/cpp/cppexecutioncontext_test.cpp b/test/cpp/cppexecutioncontext_test.cpp new file mode 100644 index 000000000..5b463cc3a --- /dev/null +++ b/test/cpp/cppexecutioncontext_test.cpp @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +using namespace libscratchcpp; + +TEST(CppExecutionContextTest, Constructor) +{ + Thread thread(nullptr, nullptr, nullptr); + CppCompilerContext compilerCtx(nullptr, nullptr); + CppExecutionContext ctx(&compilerCtx, &thread); + ASSERT_EQ(ctx.thread(), &thread); +} From 9e8c3e4e1978b364506b72687fa78116d6ff65d7 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:24:16 +0100 Subject: [PATCH 06/12] Add finished property to CppExecutionContext --- .../internal/codegen/cpp/cppexecutioncontext.cpp | 10 ++++++++++ src/engine/internal/codegen/cpp/cppexecutioncontext.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp b/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp index f25732098..3ed4b96de 100644 --- a/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp @@ -9,3 +9,13 @@ CppExecutionContext::CppExecutionContext(CppCompilerContext *ctx, Thread *thread m_ctx(ctx) { } + +bool CppExecutionContext::finished() const +{ + return m_finished; +} + +void CppExecutionContext::setFinished(bool finished) +{ + m_finished = finished; +} diff --git a/src/engine/internal/codegen/cpp/cppexecutioncontext.h b/src/engine/internal/codegen/cpp/cppexecutioncontext.h index 59bc0a0d3..60886061d 100644 --- a/src/engine/internal/codegen/cpp/cppexecutioncontext.h +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.h @@ -16,8 +16,12 @@ class LIBSCRATCHCPP_TEST_EXPORT CppExecutionContext : public ExecutionContext public: CppExecutionContext(CppCompilerContext *ctx, Thread *thread); + bool finished() const; + void setFinished(bool finished); + private: CppCompilerContext *m_ctx = nullptr; + bool m_finished = false; }; } // namespace libscratchcpp From 4fa58f5709ba627dc56aa4d808cda55e6c7f23f1 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:24:48 +0100 Subject: [PATCH 07/12] Add initial CppExecutableCode implementation --- .../codegen/cpp/cppexecutablecode.cpp | 71 +++++- .../internal/codegen/cpp/cppexecutablecode.h | 28 ++- test/cpp/CMakeLists.txt | 2 + test/cpp/cppexecutablecode_test.cpp | 216 ++++++++++++++++++ test/cpp/cppexecutablecodemock.h | 23 ++ 5 files changed, 328 insertions(+), 12 deletions(-) create mode 100644 test/cpp/cppexecutablecode_test.cpp create mode 100644 test/cpp/cppexecutablecodemock.h diff --git a/src/engine/internal/codegen/cpp/cppexecutablecode.cpp b/src/engine/internal/codegen/cpp/cppexecutablecode.cpp index 59ee58cc1..2fc611f19 100644 --- a/src/engine/internal/codegen/cpp/cppexecutablecode.cpp +++ b/src/engine/internal/codegen/cpp/cppexecutablecode.cpp @@ -1,44 +1,107 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include +#include +#include +#include #include "cppexecutablecode.h" +#include "cppcompilercontext.h" +#include "cppexecutioncontext.h" using namespace libscratchcpp; CppExecutableCode::CppExecutableCode(CppCompilerContext *ctx) : m_ctx(ctx) { + assert(m_ctx); } void CppExecutableCode::run(ExecutionContext *context) { + CppExecutionContext *ctx = getContext(context); + + if (ctx->finished()) + return; + + auto promise = ctx->promise(); + + if (promise) { + if (promise->isResolved()) + ctx->setPromise(nullptr); + else + return; + } + + // TODO: Add support for coroutines + // TODO: Add support for end thread sentinel value + Target *target = ctx->thread()->target(); + runScript(context, target, target->variableData(), target->listData()); + ctx->setFinished(true); } ValueData CppExecutableCode::runReporter(ExecutionContext *context) { - return ValueData(); + Target *target = context->thread()->target(); + return runReporter(context, target, target->variableData(), target->listData()); } bool CppExecutableCode::runPredicate(ExecutionContext *context) { - return false; + Target *target = context->thread()->target(); + return runPredicate(context, target, target->variableData(), target->listData()); } void CppExecutableCode::kill(ExecutionContext *context) { + CppExecutionContext *ctx = getContext(context); + // TODO: Add support for coroutines + // NOTE: Do not destroy coroutine, it will be destroyed later + // (really bad things happen when a coroutine destroys itself...) + // The code is finished and the coroutine won't be used again until reset() is called + ctx->setFinished(true); + ctx->setPromise(nullptr); } void CppExecutableCode::reset(ExecutionContext *context) { + CppExecutionContext *ctx = getContext(context); + + // TODO: Add support for coroutines + ctx->setFinished(false); + ctx->setPromise(nullptr); } bool CppExecutableCode::isFinished(ExecutionContext *context) const { - return true; + return getContext(context)->finished(); } std::shared_ptr CppExecutableCode::createExecutionContext(Thread *thread) const { - return nullptr; + return std::make_shared(m_ctx, thread); +} + +void CppExecutableCode::runScript(ExecutionContext *ctx, Target *target, ValueData **targetVariables, List **targetLists) +{ + // Generated code overrides this +} + +ValueData CppExecutableCode::runReporter(ExecutionContext *ctx, Target *target, ValueData **targetVariables, List **targetLists) +{ + // Generated code overrides this + return ValueData(); +} + +bool CppExecutableCode::runPredicate(ExecutionContext *ctx, Target *target, ValueData **targetVariables, List **targetLists) +{ + // Generated code overrides this + return false; +} + +CppExecutionContext *CppExecutableCode::getContext(ExecutionContext *context) +{ + assert(dynamic_cast(context)); + return static_cast(context); } diff --git a/src/engine/internal/codegen/cpp/cppexecutablecode.h b/src/engine/internal/codegen/cpp/cppexecutablecode.h index 48f89f9f3..97ce1f0a0 100644 --- a/src/engine/internal/codegen/cpp/cppexecutablecode.h +++ b/src/engine/internal/codegen/cpp/cppexecutablecode.h @@ -4,27 +4,39 @@ #include +#include "test_export.h" + namespace libscratchcpp { +class Target; +class List; class CppCompilerContext; +class CppExecutionContext; -class CppExecutableCode : public ExecutableCode +class LIBSCRATCHCPP_TEST_EXPORT CppExecutableCode : public ExecutableCode { public: CppExecutableCode(CppCompilerContext *ctx); - void run(ExecutionContext *context) override; - ValueData runReporter(ExecutionContext *context) override; - bool runPredicate(ExecutionContext *context) override; - void kill(ExecutionContext *context) override; - void reset(ExecutionContext *context) override; + virtual void run(ExecutionContext *context) override final; + virtual ValueData runReporter(ExecutionContext *context) override final; + virtual bool runPredicate(ExecutionContext *context) override final; + virtual void kill(ExecutionContext *context) override final; + virtual void reset(ExecutionContext *context) override final; + + virtual bool isFinished(ExecutionContext *context) const override final; - bool isFinished(ExecutionContext *context) const override; + virtual std::shared_ptr createExecutionContext(Thread *thread) const override final; - std::shared_ptr createExecutionContext(Thread *thread) const override; + protected: + virtual void runScript(ExecutionContext *ctx, Target *target, ValueData **targetVariables, List **targetLists); + virtual ValueData runReporter(ExecutionContext *ctx, Target *target, ValueData **targetVariables, List **targetLists); + virtual bool runPredicate(ExecutionContext *ctx, Target *target, ValueData **targetVariables, List **targetLists); private: + static CppExecutionContext *getContext(ExecutionContext *context); + CppCompilerContext *m_ctx = nullptr; }; diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt index 029e662e9..04f3e1897 100644 --- a/test/cpp/CMakeLists.txt +++ b/test/cpp/CMakeLists.txt @@ -2,6 +2,8 @@ add_executable( cpp_test main.cpp cppexecutioncontext_test.cpp + cppexecutablecode_test.cpp + cppexecutablecodemock.h ) target_link_libraries( diff --git a/test/cpp/cppexecutablecode_test.cpp b/test/cpp/cppexecutablecode_test.cpp new file mode 100644 index 000000000..170ad438b --- /dev/null +++ b/test/cpp/cppexecutablecode_test.cpp @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cppexecutablecodemock.h" + +using namespace libscratchcpp; + +using ::testing::Return; + +class CppExecutableCodeTest : public testing::Test +{ + public: + void SetUp() override + { + m_target.setName("test"); + m_ctx = std::make_unique(&m_engine, &m_target); + m_code = std::make_shared(m_ctx.get()); + + m_script = std::make_unique