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) 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..0af46fb73 100644 --- a/src/engine/internal/codegen/CMakeLists.txt +++ b/src/engine/internal/codegen/CMakeLists.txt @@ -13,6 +13,12 @@ target_sources(scratchcpp codeanalyzer.h optimizationutils.cpp optimizationutils.h + typeutils.cpp + typeutils.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..beca57c22 100644 --- a/src/engine/internal/codegen/codebuilderfactory.cpp +++ b/src/engine/internal/codegen/codebuilderfactory.cpp @@ -1,8 +1,14 @@ // 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) +#include "cpp/cppcodebuilder.h" +#include "cpp/cppcompilercontext.h" +#endif using namespace libscratchcpp; @@ -15,12 +21,22 @@ 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) + assert(dynamic_cast(ctx)); + return std::make_shared(static_cast(ctx), procedurePrototype, codeType); +#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) + 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 new file mode 100644 index 000000000..bf3e34349 --- /dev/null +++ b/src/engine/internal/codegen/cpp/CMakeLists.txt @@ -0,0 +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..482e0e2af --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcodebuilder.cpp @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include "cppcodebuilder.h" +#include "cppexecutablecode.h" +#include "cppconstant.h" +#include "../typeutils.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 std::make_shared(m_ctx); +} + +CompilerValue *CppCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) +{ + return addConstValue(Value()); +} + +CompilerConstant *CppCodeBuilder::addConstValue(const Value &value) +{ + auto constValue = std::make_shared(TypeUtils::mapType(value.type()), value); + auto genericValue = std::static_pointer_cast(constValue); + return static_cast(static_cast(addValue(genericValue, nullptr))); +} + +CompilerValue *CppCodeBuilder::addStringChar(CompilerValue *string, CompilerValue *index) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addStringLength(CompilerValue *string) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addLoopIndex() +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addLocalVariableValue(CompilerLocalVariable *variable) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addVariableValue(Variable *variable) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addListContents(List *list) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addListItem(List *list, CompilerValue *index) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addListItemIndex(List *list, CompilerValue *item) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addListContains(List *list, CompilerValue *item) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addListSize(List *list) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::addProcedureArgument(const std::string &name) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createAdd(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createSub(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createMul(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createDiv(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createRandom(CompilerValue *from, CompilerValue *to) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createRandomInt(CompilerValue *from, CompilerValue *to) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createCmpEQ(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createCmpGT(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createCmpLT(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createStrCmpEQ(CompilerValue *string1, CompilerValue *string2, bool caseSensitive) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createAnd(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createOr(CompilerValue *operand1, CompilerValue *operand2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createNot(CompilerValue *operand) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createMod(CompilerValue *num1, CompilerValue *num2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createRound(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createAbs(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createFloor(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createCeil(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createSqrt(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createSin(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createCos(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createTan(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createAsin(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createAcos(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createAtan(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createLn(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createLog10(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createExp(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createExp10(CompilerValue *num) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createStringConcat(CompilerValue *string1, CompilerValue *string2) +{ + return addConstValue(Value()); +} + +CompilerValue *CppCodeBuilder::createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType) +{ + return addConstValue(Value()); +} + +CompilerLocalVariable *CppCodeBuilder::createLocalVariable(Compiler::StaticType type) +{ + // TODO: Complete this + CompilerValue *ptr = addConstValue(Value()); + auto var = std::make_shared(ptr); + m_localVars.push_back(var); + return var.get(); +} + +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) +{ +} + +CppValue *CppCodeBuilder::addValue(std::shared_ptr value, std::shared_ptr ins) +{ + value->instruction = ins; + m_values.push_back(value); + return value.get(); +} diff --git a/src/engine/internal/codegen/cpp/cppcodebuilder.h b/src/engine/internal/codegen/cpp/cppcodebuilder.h new file mode 100644 index 000000000..ef08d8245 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcodebuilder.h @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../icodebuilder.h" + +namespace libscratchcpp +{ + +class CppCompilerContext; +class CppValue; +class CppInstruction; + +class CppCodeBuilder : public ICodeBuilder +{ + public: + CppCodeBuilder(CppCompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType 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; + + private: + CppValue *addValue(std::shared_ptr value, std::shared_ptr ins); + + CppCompilerContext *m_ctx = nullptr; + BlockPrototype *m_procedurePrototype = nullptr; + Compiler::CodeType m_codeType = Compiler::CodeType::Script; + + std::vector> m_values; + std::vector> m_localVars; +}; + +} // 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..15b62cd88 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppcompilercontext.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "test_export.h" + +namespace libscratchcpp +{ + +class LIBSCRATCHCPP_TEST_EXPORT 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..2fc611f19 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutablecode.cpp @@ -0,0 +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) +{ + Target *target = context->thread()->target(); + return runReporter(context, target, target->variableData(), target->listData()); +} + +bool CppExecutableCode::runPredicate(ExecutionContext *context) +{ + 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 getContext(context)->finished(); +} + +std::shared_ptr CppExecutableCode::createExecutionContext(Thread *thread) const +{ + 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 new file mode 100644 index 000000000..97ce1f0a0 --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutablecode.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "test_export.h" + +namespace libscratchcpp +{ + +class Target; +class List; +class CppCompilerContext; +class CppExecutionContext; + +class LIBSCRATCHCPP_TEST_EXPORT CppExecutableCode : public ExecutableCode +{ + public: + CppExecutableCode(CppCompilerContext *ctx); + + 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; + + virtual std::shared_ptr createExecutionContext(Thread *thread) const override final; + + 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; +}; + +} // 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..3ed4b96de --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.cpp @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include "cppexecutioncontext.h" + +using namespace libscratchcpp; + +CppExecutionContext::CppExecutionContext(CppCompilerContext *ctx, Thread *thread) : + ExecutionContext(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 new file mode 100644 index 000000000..60886061d --- /dev/null +++ b/src/engine/internal/codegen/cpp/cppexecutioncontext.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +#include "test_export.h" + +namespace libscratchcpp +{ + +class CppCompilerContext; + +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 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 diff --git a/src/engine/internal/codegen/llvm/instructions/control.cpp b/src/engine/internal/codegen/llvm/instructions/control.cpp index 100f1875e..a4bb3ed7b 100644 --- a/src/engine/internal/codegen/llvm/instructions/control.cpp +++ b/src/engine/internal/codegen/llvm/instructions/control.cpp @@ -3,6 +3,7 @@ #include "control.h" #include "../llvminstruction.h" #include "../llvmbuildutils.h" +#include "../../typeutils.h" using namespace libscratchcpp; using namespace libscratchcpp::llvmins; @@ -92,7 +93,7 @@ LLVMInstruction *Control::buildSelect(LLVMInstruction *ins) llvm::Value *trueValue; llvm::Value *falseValue; - if (m_utils.isSingleType(type)) { + if (TypeUtils::isSingleType(type)) { trueValue = m_utils.castValue(arg2.second, type); falseValue = m_utils.castValue(arg3.second, type); } else { diff --git a/src/engine/internal/codegen/llvm/instructions/functions.cpp b/src/engine/internal/codegen/llvm/instructions/functions.cpp index b05623430..b35417e5c 100644 --- a/src/engine/internal/codegen/llvm/instructions/functions.cpp +++ b/src/engine/internal/codegen/llvm/instructions/functions.cpp @@ -3,6 +3,7 @@ #include "functions.h" #include "../llvminstruction.h" #include "../llvmbuildutils.h" +#include "../../typeutils.h" using namespace libscratchcpp; using namespace libscratchcpp::llvmins; @@ -67,7 +68,7 @@ LLVMInstruction *Functions::buildFunctionCall(LLVMInstruction *ins) if (ins->getFunctionReturnReg()) { if (ins->getFunctionReturnReg()->type() == Compiler::StaticType::String) ins->getFunctionReturnReg()->value = stringRet; - else if (m_utils.isSingleType(ins->getFunctionReturnReg()->type())) + else if (TypeUtils::isSingleType(ins->getFunctionReturnReg()->type())) ins->getFunctionReturnReg()->value = ret; else { ins->getFunctionReturnReg()->value = m_utils.addAlloca(retType); diff --git a/src/engine/internal/codegen/llvm/instructions/lists.cpp b/src/engine/internal/codegen/llvm/instructions/lists.cpp index e7ad0cf92..312bd4317 100644 --- a/src/engine/internal/codegen/llvm/instructions/lists.cpp +++ b/src/engine/internal/codegen/llvm/instructions/lists.cpp @@ -6,6 +6,7 @@ #include "../llvmconstantregister.h" #include "../llvmcompilercontext.h" #include "../../optimizationutils.h" +#include "../../typeutils.h" using namespace libscratchcpp; using namespace libscratchcpp::llvmins; @@ -400,7 +401,7 @@ void Lists::createListTypeUpdate(const LLVMListPtr &listPtr, const LLVMRegister llvm::Value *newType; if (newValue->isRawValue) - newType = m_builder.getInt32(static_cast(m_utils.mapType(newValueType))); + newType = m_builder.getInt32(static_cast(TypeUtils::mapType(newValueType))); else { llvm::Value *typeField = m_builder.CreateStructGEP(m_utils.compilerCtx()->valueDataType(), newValue->value, 1); newType = m_builder.CreateLoad(m_builder.getInt32Ty(), typeField); diff --git a/src/engine/internal/codegen/llvm/instructions/procedures.cpp b/src/engine/internal/codegen/llvm/instructions/procedures.cpp index d6d522834..3a26e2e52 100644 --- a/src/engine/internal/codegen/llvm/instructions/procedures.cpp +++ b/src/engine/internal/codegen/llvm/instructions/procedures.cpp @@ -6,6 +6,7 @@ #include "../llvminstruction.h" #include "../llvmbuildutils.h" #include "../llvmcompilercontext.h" +#include "../../typeutils.h" using namespace libscratchcpp; using namespace libscratchcpp::llvmins; @@ -62,7 +63,7 @@ LLVMInstruction *Procedures::buildCallProcedure(LLVMInstruction *ins) const auto &insArgs = ins->getArgs(); for (const auto &arg : insArgs) { - if (m_utils.isSingleType(arg.first)) + if (TypeUtils::isSingleType(arg.first)) args.push_back(m_utils.castValue(arg.second, arg.first)); else args.push_back(m_utils.createValue(arg.second)); diff --git a/src/engine/internal/codegen/llvm/instructions/variables.cpp b/src/engine/internal/codegen/llvm/instructions/variables.cpp index 04382ac3b..245509960 100644 --- a/src/engine/internal/codegen/llvm/instructions/variables.cpp +++ b/src/engine/internal/codegen/llvm/instructions/variables.cpp @@ -5,6 +5,7 @@ #include "../llvmbuildutils.h" #include "../llvmconstantregister.h" #include "../../optimizationutils.h" +#include "../../typeutils.h" using namespace libscratchcpp; using namespace libscratchcpp::llvmins; @@ -65,7 +66,7 @@ LLVMInstruction *Variables::buildWriteLocalVariable(LLVMInstruction *ins) const auto &arg2 = args[1]; LLVMLocalVariableInfo *info = ins->localVarInfo; llvm::Value *typeVar = m_utils.addAlloca(m_builder.getInt32Ty()); - m_builder.CreateStore(m_builder.getInt32(static_cast(m_utils.mapType(arg2.first))), typeVar); + m_builder.CreateStore(m_builder.getInt32(static_cast(TypeUtils::mapType(arg2.first))), typeVar); m_utils.createValueStore(arg1.second->value, typeVar, info->isInt, info->intValue, arg2.second, arg2.first, arg2.first); return ins->getNext(); diff --git a/src/engine/internal/codegen/llvm/llvmbuildutils.cpp b/src/engine/internal/codegen/llvm/llvmbuildutils.cpp index 64a63b734..7eeb36683 100644 --- a/src/engine/internal/codegen/llvm/llvmbuildutils.cpp +++ b/src/engine/internal/codegen/llvm/llvmbuildutils.cpp @@ -14,6 +14,7 @@ #include "llvmregister.h" #include "llvminstruction.h" #include "../optimizationutils.h" +#include "../typeutils.h" using namespace libscratchcpp; @@ -484,24 +485,6 @@ std::vector &LLVMBuildUtils::loops() return m_loops; } -Compiler::StaticType LLVMBuildUtils::mapType(ValueType type) -{ - assert(TYPE_MAP.find(type) != TYPE_MAP.cend()); - return TYPE_MAP[type]; -} - -ValueType LLVMBuildUtils::mapType(Compiler::StaticType type) -{ - assert(REVERSE_TYPE_MAP.find(type) != REVERSE_TYPE_MAP.cend()); - return REVERSE_TYPE_MAP[type]; -} - -bool LLVMBuildUtils::isSingleType(Compiler::StaticType type) -{ - // Check if the type is a power of 2 (only one bit set) - return (type & (static_cast(static_cast(type) - 1))) == static_cast(0); -} - llvm::Value *LLVMBuildUtils::addAlloca(llvm::Type *type) { // Add an alloca to the entry block because allocas must be there (to avoid stack overflow) @@ -529,7 +512,7 @@ llvm::Value *LLVMBuildUtils::addStringAlloca() llvm::Value *LLVMBuildUtils::castValue(LLVMRegister *reg, Compiler::StaticType targetType, NumberType targetNumType) { if (reg->isConst()) { - if (!isSingleType(targetType)) + if (!TypeUtils::isSingleType(targetType)) return createValue(reg); else return castConstValue(reg->constValue(), targetType, targetNumType); @@ -547,7 +530,7 @@ llvm::Value *LLVMBuildUtils::castValue(LLVMRegister *reg, Compiler::StaticType t llvm::SwitchInst *sw = nullptr; std::vector> results; - if (isSingleType(targetType)) { + if (TypeUtils::isSingleType(targetType)) { // Handle multiple source type cases with runtime switch typePtr = getValueTypePtr(reg); loadedType = m_builder.CreateLoad(m_builder.getInt32Ty(), typePtr); @@ -1516,7 +1499,7 @@ void LLVMBuildUtils::createListMap() llvm::Value *LLVMBuildUtils::loadRegisterType(LLVMRegister *reg, Compiler::StaticType type) { if (reg->isRawValue) - return m_builder.getInt32(static_cast(mapType(type))); + return m_builder.getInt32(static_cast(TypeUtils::mapType(type))); else { assert(!reg->isConst()); llvm::Value *typePtr = getValueTypePtr(reg); diff --git a/src/engine/internal/codegen/llvm/llvmbuildutils.h b/src/engine/internal/codegen/llvm/llvmbuildutils.h index 2b2546cee..2dd8b2df9 100644 --- a/src/engine/internal/codegen/llvm/llvmbuildutils.h +++ b/src/engine/internal/codegen/llvm/llvmbuildutils.h @@ -87,10 +87,6 @@ class LIBSCRATCHCPP_TEST_EXPORT LLVMBuildUtils std::vector &ifStatements(); std::vector &loops(); - static Compiler::StaticType mapType(ValueType type); - static ValueType mapType(Compiler::StaticType type); - static bool isSingleType(Compiler::StaticType type); - llvm::Value *addAlloca(llvm::Type *type); llvm::Value *addStringAlloca(); diff --git a/src/engine/internal/codegen/llvm/llvmcodebuilder.cpp b/src/engine/internal/codegen/llvm/llvmcodebuilder.cpp index 3570020e6..d2f6fd7f4 100644 --- a/src/engine/internal/codegen/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/codegen/llvm/llvmcodebuilder.cpp @@ -15,6 +15,7 @@ #include "llvmconstantregister.h" #include "llvmifstatement.h" #include "llvmloop.h" +#include "../typeutils.h" using namespace libscratchcpp; @@ -111,7 +112,7 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, if (returnType != Compiler::StaticType::Void) { auto reg = std::make_shared(returnType); - if (m_utils.isSingleType(returnType)) + if (TypeUtils::isSingleType(returnType)) reg->isRawValue = true; ins->setFunctionReturnReg(reg.get()); @@ -137,7 +138,7 @@ CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functi CompilerConstant *LLVMCodeBuilder::addConstValue(const Value &value) { - auto constReg = std::make_shared(m_utils.mapType(value.type()), value); + auto constReg = std::make_shared(TypeUtils::mapType(value.type()), value); auto reg = std::static_pointer_cast(constReg); m_lastConstValue = reg.get(); return static_cast(static_cast(addReg(reg, nullptr))); @@ -419,7 +420,7 @@ CompilerValue *LLVMCodeBuilder::createStringConcat(CompilerValue *string1, Compi CompilerValue *LLVMCodeBuilder::createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType) { LLVMRegister *ret = createOp(LLVMInstruction::Type::Select, valueType, { Compiler::StaticType::Bool, valueType, valueType }, { cond, trueValue, falseValue }); - ret->isRawValue = m_utils.isSingleType(valueType); + ret->isRawValue = TypeUtils::isSingleType(valueType); return ret; } diff --git a/src/engine/internal/codegen/typeutils.cpp b/src/engine/internal/codegen/typeutils.cpp new file mode 100644 index 000000000..c49d42c03 --- /dev/null +++ b/src/engine/internal/codegen/typeutils.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include + +#include "typeutils.h" + +using namespace libscratchcpp; + +static std::unordered_map TYPE_MAP = { + { ValueType::Number, Compiler::StaticType::Number }, + { ValueType::Bool, Compiler::StaticType::Bool }, + { ValueType::String, Compiler::StaticType::String }, + { ValueType::Pointer, Compiler::StaticType::Pointer } +}; + +static std::unordered_map REVERSE_TYPE_MAP = { + { Compiler::StaticType::Number, ValueType::Number }, + { Compiler::StaticType::Bool, ValueType::Bool }, + { Compiler::StaticType::String, ValueType::String }, + { Compiler::StaticType::Pointer, ValueType::Pointer } +}; + +Compiler::StaticType TypeUtils::mapType(ValueType type) +{ + assert(TYPE_MAP.find(type) != TYPE_MAP.cend()); + return TYPE_MAP[type]; +} + +ValueType TypeUtils::mapType(Compiler::StaticType type) +{ + assert(REVERSE_TYPE_MAP.find(type) != REVERSE_TYPE_MAP.cend()); + return REVERSE_TYPE_MAP[type]; +} + +bool TypeUtils::isSingleType(Compiler::StaticType type) +{ + // Check if the type is a power of 2 (only one bit set) + return (type & (static_cast(static_cast(type) - 1))) == static_cast(0); +} diff --git a/src/engine/internal/codegen/typeutils.h b/src/engine/internal/codegen/typeutils.h new file mode 100644 index 000000000..8c6f5a98b --- /dev/null +++ b/src/engine/internal/codegen/typeutils.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include + +namespace libscratchcpp +{ + +class TypeUtils +{ + public: + static Compiler::StaticType mapType(ValueType type); + static ValueType mapType(Compiler::StaticType type); + static bool isSingleType(Compiler::StaticType type); +}; + +} // namespace libscratchcpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f6cf9531d..44b15bf65 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) @@ -27,7 +29,9 @@ add_subdirectory(assets) add_subdirectory(script) add_subdirectory(extensions) add_subdirectory(codegen) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") add_subdirectory(engine) +endif() add_subdirectory(clock) add_subdirectory(timer) add_subdirectory(randomgenerator) @@ -35,8 +39,11 @@ 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(llvm) add_subdirectory(promise) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") add_subdirectory(test_api) +endif() diff --git a/test/codegen/CMakeLists.txt b/test/codegen/CMakeLists.txt index 3b90abbbc..26ddb465c 100644 --- a/test/codegen/CMakeLists.txt +++ b/test/codegen/CMakeLists.txt @@ -16,48 +16,54 @@ target_link_libraries( add_executable( codegen_test main.cpp - codebuilder_test.cpp codegentestutils.cpp codegentestutils.h instructionlist_test.cpp code_analyzer/variable_type_analysis.cpp code_analyzer/list_type_analysis.cpp code_analyzer/mixed_type_analysis.cpp - operators/equal_comparison_test.cpp - operators/greater_than_test.cpp - operators/less_than_test.cpp - operators/math/add_test.cpp - operators/math/subtract_test.cpp - operators/math/multiply_test.cpp - operators/math/divide_test.cpp - operators/math/random_test.cpp - operators/math/random_int_test.cpp - operators/math/mod_test.cpp - operators/math/abs_test.cpp - operators/math/round_test.cpp - operators/math/floor_test.cpp - operators/math/ceil_test.cpp - operators/math/sqrt_test.cpp - operators/math/sin_test.cpp - operators/math/cos_test.cpp - operators/math/tan_test.cpp - operators/math/asin_test.cpp - operators/math/acos_test.cpp - operators/math/atan_test.cpp - operators/math/ln_test.cpp - operators/math/log10_test.cpp - operators/math/exp_test.cpp - operators/math/exp10_test.cpp - operators/logic/and_test.cpp - operators/logic/or_test.cpp - operators/logic/not_test.cpp - operators/string/string_equal_case_sensitive_test.cpp - operators/string/string_equal_case_insensitive_test.cpp - operators/string/string_concat_test.cpp - operators/string/string_char_test.cpp - operators/string/string_length_test.cpp ) +if (NOT LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") + # TODO: Move this to the executable sources + target_sources(codegen_test PUBLIC + codebuilder_test.cpp + operators/equal_comparison_test.cpp + operators/greater_than_test.cpp + operators/less_than_test.cpp + operators/math/add_test.cpp + operators/math/subtract_test.cpp + operators/math/multiply_test.cpp + operators/math/divide_test.cpp + operators/math/random_test.cpp + operators/math/random_int_test.cpp + operators/math/mod_test.cpp + operators/math/abs_test.cpp + operators/math/round_test.cpp + operators/math/floor_test.cpp + operators/math/ceil_test.cpp + operators/math/sqrt_test.cpp + operators/math/sin_test.cpp + operators/math/cos_test.cpp + operators/math/tan_test.cpp + operators/math/asin_test.cpp + operators/math/acos_test.cpp + operators/math/atan_test.cpp + operators/math/ln_test.cpp + operators/math/log10_test.cpp + operators/math/exp_test.cpp + operators/math/exp10_test.cpp + operators/logic/and_test.cpp + operators/logic/or_test.cpp + operators/logic/not_test.cpp + operators/string/string_equal_case_sensitive_test.cpp + operators/string/string_equal_case_insensitive_test.cpp + operators/string/string_concat_test.cpp + operators/string/string_char_test.cpp + operators/string/string_length_test.cpp + ) +endif() + target_link_libraries( codegen_test GTest::gtest_main @@ -68,3 +74,9 @@ target_link_libraries( ) gtest_discover_tests(codegen_test) + +if (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "llvm") + add_subdirectory(llvm) +elseif (LIBSCRATCHCPP_CODEGEN_BACKEND STREQUAL "cpp") + add_subdirectory(cpp) +endif() diff --git a/test/codegen/cpp/CMakeLists.txt b/test/codegen/cpp/CMakeLists.txt new file mode 100644 index 000000000..04f3e1897 --- /dev/null +++ b/test/codegen/cpp/CMakeLists.txt @@ -0,0 +1,17 @@ +add_executable( + cpp_test + main.cpp + cppexecutioncontext_test.cpp + cppexecutablecode_test.cpp + cppexecutablecodemock.h +) + +target_link_libraries( + cpp_test + GTest::gtest_main + GTest::gmock_main + scratchcpp + scratchcpp_mocks +) + +gtest_discover_tests(cpp_test) diff --git a/test/codegen/cpp/cppexecutablecode_test.cpp b/test/codegen/cpp/cppexecutablecode_test.cpp new file mode 100644 index 000000000..170ad438b --- /dev/null +++ b/test/codegen/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