From dc6ef4946c0a43e1838d61c4146b9616d8df4ce4 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:22:49 +0100 Subject: [PATCH 01/15] Add CodeType enum There are 3 types of compiled code: script (void), reporter (any value), hat predicate (bool) --- include/scratchcpp/compiler.h | 9 ++- src/engine/compiler.cpp | 6 +- src/engine/internal/codebuilderfactory.cpp | 4 +- src/engine/internal/codebuilderfactory.h | 2 +- src/engine/internal/engine.cpp | 2 +- src/engine/internal/icodebuilderfactory.h | 7 +-- src/engine/internal/llvm/llvmcodebuilder.cpp | 63 ++++++++++++++----- src/engine/internal/llvm/llvmcodebuilder.h | 4 +- .../internal/llvm/llvmexecutablecode.cpp | 18 ++++-- src/engine/internal/llvm/llvmexecutablecode.h | 5 +- test/blocks/event_blocks_test.cpp | 14 ++--- test/compiler/compiler_test.cpp | 16 ++--- test/llvm/llvmcodebuilder_test.cpp | 6 +- test/llvm/llvmexecutablecode_test.cpp | 10 +-- test/mocks/codebuilderfactorymock.h | 2 +- 15 files changed, 105 insertions(+), 63 deletions(-) diff --git a/include/scratchcpp/compiler.h b/include/scratchcpp/compiler.h index cc7db35a..7930b710 100644 --- a/include/scratchcpp/compiler.h +++ b/include/scratchcpp/compiler.h @@ -38,6 +38,13 @@ class LIBSCRATCHCPP_EXPORT Compiler Unknown }; + enum class CodeType + { + Script, + Reporter, + HatPredicate + }; + using ArgTypes = std::vector; using Args = std::vector; @@ -49,7 +56,7 @@ class LIBSCRATCHCPP_EXPORT Compiler Target *target() const; std::shared_ptr block() const; - std::shared_ptr compile(std::shared_ptr startBlock, bool isHatPredicate = false); + std::shared_ptr compile(std::shared_ptr startBlock, CodeType codeType = CodeType::Script); void preoptimize(); CompilerValue *addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {}); diff --git a/src/engine/compiler.cpp b/src/engine/compiler.cpp index 17ea93ce..9fee9506 100644 --- a/src/engine/compiler.cpp +++ b/src/engine/compiler.cpp @@ -44,7 +44,7 @@ std::shared_ptr Compiler::block() const } /*! Compiles the script starting with the given block. */ -std::shared_ptr Compiler::compile(std::shared_ptr startBlock, bool isHatPredicate) +std::shared_ptr Compiler::compile(std::shared_ptr startBlock, CodeType codeType) { BlockPrototype *procedurePrototype = nullptr; @@ -60,14 +60,14 @@ std::shared_ptr Compiler::compile(std::shared_ptr startBl } } - impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, isHatPredicate); + impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, codeType); impl->substackTree.clear(); impl->substackHit = false; impl->emptySubstack = false; impl->warp = false; impl->block = startBlock; - if (impl->block && isHatPredicate) { + if (impl->block && codeType == CodeType::HatPredicate) { auto f = impl->block->hatPredicateCompileFunction(); if (f) { diff --git a/src/engine/internal/codebuilderfactory.cpp b/src/engine/internal/codebuilderfactory.cpp index 42ea1122..853f283c 100644 --- a/src/engine/internal/codebuilderfactory.cpp +++ b/src/engine/internal/codebuilderfactory.cpp @@ -13,10 +13,10 @@ std::shared_ptr CodeBuilderFactory::instance() return m_instance; } -std::shared_ptr CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const +std::shared_ptr CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) const { assert(dynamic_cast(ctx)); - return std::make_shared(static_cast(ctx), procedurePrototype, isPredicate); + return std::make_shared(static_cast(ctx), procedurePrototype, codeType); } std::shared_ptr CodeBuilderFactory::createCtx(IEngine *engine, Target *target) const diff --git a/src/engine/internal/codebuilderfactory.h b/src/engine/internal/codebuilderfactory.h index c0c29568..4dac2db7 100644 --- a/src/engine/internal/codebuilderfactory.h +++ b/src/engine/internal/codebuilderfactory.h @@ -11,7 +11,7 @@ class CodeBuilderFactory : public ICodeBuilderFactory { public: static std::shared_ptr instance(); - std::shared_ptr create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const override; + std::shared_ptr create(CompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) const override; std::shared_ptr createCtx(IEngine *engine, Target *target) const override; private: diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp index 4c42540a..5ffa9a07 100644 --- a/src/engine/internal/engine.cpp +++ b/src/engine/internal/engine.cpp @@ -276,7 +276,7 @@ void Engine::compile() script->setCode(compiler.compile(block)); if (block->hatPredicateCompileFunction()) - script->setHatPredicateCode(compiler.compile(block, true)); + script->setHatPredicateCode(compiler.compile(block, Compiler::CodeType::HatPredicate)); } else { std::cout << "warning: unsupported top level block: " << block->opcode() << std::endl; m_unsupportedBlocks.insert(block->opcode()); diff --git a/src/engine/internal/icodebuilderfactory.h b/src/engine/internal/icodebuilderfactory.h index eecc3c0a..de0b7b8d 100644 --- a/src/engine/internal/icodebuilderfactory.h +++ b/src/engine/internal/icodebuilderfactory.h @@ -2,23 +2,20 @@ #pragma once +#include #include namespace libscratchcpp { class ICodeBuilder; -class CompilerContext; -class BlockPrototype; -class Target; -class IEngine; class ICodeBuilderFactory { public: virtual ~ICodeBuilderFactory() { } - virtual std::shared_ptr create(CompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, bool isPredicate = false) const = 0; + virtual std::shared_ptr create(CompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType codeType = Compiler::CodeType::Script) const = 0; virtual std::shared_ptr createCtx(IEngine *engine, Target *target) const = 0; }; diff --git a/src/engine/internal/llvm/llvmcodebuilder.cpp b/src/engine/internal/llvm/llvmcodebuilder.cpp index e212b3cf..7af0c422 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.cpp +++ b/src/engine/internal/llvm/llvmcodebuilder.cpp @@ -26,7 +26,7 @@ static std::unordered_map static const std::unordered_set VAR_LIST_READ_INSTRUCTIONS = { LLVMInstruction::Type::ReadVariable, LLVMInstruction::Type::GetListItem, LLVMInstruction::Type::GetListItemIndex, LLVMInstruction::Type::ListContainsItem }; -LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) : +LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) : m_ctx(ctx), m_target(ctx->target()), m_llvmCtx(*ctx->llvmCtx()), @@ -35,7 +35,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce m_procedurePrototype(procedurePrototype), m_defaultWarp(procedurePrototype ? procedurePrototype->warp() : false), m_warp(m_defaultWarp), - m_isPredicate(isPredicate) + m_codeType(codeType) { initTypes(); createVariableMap(); @@ -56,8 +56,8 @@ std::shared_ptr LLVMCodeBuilder::finalize() if (it == m_instructions.end()) m_warp = true; - // Do not create coroutine in hat predicates - if (m_isPredicate) + // Only create coroutines in scripts + if (m_codeType != Compiler::CodeType::Script) m_warp = true; } @@ -1319,15 +1319,20 @@ std::shared_ptr LLVMCodeBuilder::finalize() // End and verify the function llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0); - if (m_isPredicate) { - // Use last instruction return value - assert(!m_instructions.empty()); - m_builder.CreateRet(m_instructions.back()->functionReturnReg->value); - } else { - if (m_warp) - m_builder.CreateRet(llvm::ConstantPointerNull::get(pointerType)); - else - coro->end(); + switch (m_codeType) { + case Compiler::CodeType::Script: + if (m_warp) + m_builder.CreateRet(llvm::ConstantPointerNull::get(pointerType)); + else + coro->end(); + break; + + // TODO: Implement reporter code type + case Compiler::CodeType::HatPredicate: + // Use last instruction return value + assert(!m_instructions.empty()); + m_builder.CreateRet(m_instructions.back()->functionReturnReg->value); + break; } verifyFunction(m_function); @@ -1349,7 +1354,7 @@ std::shared_ptr LLVMCodeBuilder::finalize() verifyFunction(resumeFunc); - return std::make_shared(m_ctx, m_function->getName().str(), resumeFunc->getName().str(), m_isPredicate); + return std::make_shared(m_ctx, m_function->getName().str(), resumeFunc->getName().str(), m_codeType); } CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) @@ -2019,7 +2024,20 @@ void LLVMCodeBuilder::popLoopScope() std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedurePrototype) { - return procedurePrototype ? "proc." + procedurePrototype->procCode() : (m_isPredicate ? "predicate" : "script"); + std::string name; + + switch (m_codeType) { + case Compiler::CodeType::Script: + name = "script"; + break; + + // TODO: Implement reporter code type + case Compiler::CodeType::HatPredicate: + name = "predicate"; + break; + } + + return procedurePrototype ? "proc." + procedurePrototype->procCode() : name; } std::string LLVMCodeBuilder::getResumeFunctionName(BlockPrototype *procedurePrototype) @@ -2046,7 +2064,20 @@ llvm::FunctionType *LLVMCodeBuilder::getMainFunctionType(BlockPrototype *procedu } } - return llvm::FunctionType::get(m_isPredicate ? m_builder.getInt1Ty() : pointerType, argTypes, false); + llvm::Type *retType = nullptr; + + switch (m_codeType) { + case Compiler::CodeType::Script: + retType = pointerType; + break; + + // TODO: Implement reporter code type + case Compiler::CodeType::HatPredicate: + retType = m_builder.getInt1Ty(); + break; + } + + return llvm::FunctionType::get(retType, argTypes, false); } llvm::Function *LLVMCodeBuilder::getOrCreateFunction(const std::string &name, llvm::FunctionType *type) diff --git a/src/engine/internal/llvm/llvmcodebuilder.h b/src/engine/internal/llvm/llvmcodebuilder.h index 5a765270..52cce789 100644 --- a/src/engine/internal/llvm/llvmcodebuilder.h +++ b/src/engine/internal/llvm/llvmcodebuilder.h @@ -25,7 +25,7 @@ class LLVMLoopScope; class LLVMCodeBuilder : public ICodeBuilder { public: - LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, bool isPredicate = false); + LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType codeType = Compiler::CodeType::Script); std::shared_ptr finalize() override; @@ -239,7 +239,7 @@ class LLVMCodeBuilder : public ICodeBuilder bool m_defaultWarp = false; bool m_warp = false; int m_defaultArgCount = 0; - bool m_isPredicate = false; // for hat predicates + Compiler::CodeType m_codeType = Compiler::CodeType::Script; long m_loopScope = -1; // index std::vector> m_loopScopes; diff --git a/src/engine/internal/llvm/llvmexecutablecode.cpp b/src/engine/internal/llvm/llvmexecutablecode.cpp index f41c660b..4ba1cffc 100644 --- a/src/engine/internal/llvm/llvmexecutablecode.cpp +++ b/src/engine/internal/llvm/llvmexecutablecode.cpp @@ -16,11 +16,11 @@ using namespace libscratchcpp; -LLVMExecutableCode::LLVMExecutableCode(LLVMCompilerContext *ctx, const std::string &mainFunctionName, const std::string &resumeFunctionName, bool isPredicate) : +LLVMExecutableCode::LLVMExecutableCode(LLVMCompilerContext *ctx, const std::string &mainFunctionName, const std::string &resumeFunctionName, Compiler::CodeType codeType) : m_ctx(ctx), m_mainFunctionName(mainFunctionName), m_resumeFunctionName(resumeFunctionName), - m_isPredicate(isPredicate) + m_codeType(codeType) { assert(m_ctx); @@ -101,10 +101,16 @@ std::shared_ptr LLVMExecutableCode::createExecutionContext(Thr if (!m_ctx->jitInitialized()) m_ctx->initJit(); - if (m_isPredicate) - m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); - else - m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); + switch (m_codeType) { + case Compiler::CodeType::Script: + m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); + break; + + // TODO: Implement reporter code type + case Compiler::CodeType::HatPredicate: + m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); + break; + } m_resumeFunction = m_ctx->lookupFunction(m_resumeFunctionName); return std::make_shared(thread); diff --git a/src/engine/internal/llvm/llvmexecutablecode.h b/src/engine/internal/llvm/llvmexecutablecode.h index 5526bed5..4ff50ec1 100644 --- a/src/engine/internal/llvm/llvmexecutablecode.h +++ b/src/engine/internal/llvm/llvmexecutablecode.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include #include @@ -16,7 +17,7 @@ class LLVMExecutionContext; class LLVMExecutableCode : public ExecutableCode { public: - LLVMExecutableCode(LLVMCompilerContext *ctx, const std::string &mainFunctionName, const std::string &resumeFunctionName, bool isPredicate); + LLVMExecutableCode(LLVMCompilerContext *ctx, const std::string &mainFunctionName, const std::string &resumeFunctionName, Compiler::CodeType codeType); void run(ExecutionContext *context) override; bool runPredicate(ExecutionContext *context) override; @@ -38,7 +39,7 @@ class LLVMExecutableCode : public ExecutableCode std::string m_mainFunctionName; std::string m_predicateFunctionName; std::string m_resumeFunctionName; - bool m_isPredicate = false; + Compiler::CodeType m_codeType; mutable std::variant m_mainFunction; mutable ResumeFunctionType m_resumeFunction = nullptr; diff --git a/test/blocks/event_blocks_test.cpp b/test/blocks/event_blocks_test.cpp index a01da37e..03a354bd 100644 --- a/test/blocks/event_blocks_test.cpp +++ b/test/blocks/event_blocks_test.cpp @@ -65,7 +65,7 @@ TEST_F(EventBlocksTest, WhenTouchingObjectPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); @@ -89,7 +89,7 @@ TEST_F(EventBlocksTest, WhenTouchingObjectPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); @@ -113,7 +113,7 @@ TEST_F(EventBlocksTest, WhenTouchingObjectPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); @@ -137,7 +137,7 @@ TEST_F(EventBlocksTest, WhenTouchingObjectPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); @@ -155,7 +155,7 @@ TEST_F(EventBlocksTest, WhenTouchingObjectPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); @@ -274,7 +274,7 @@ TEST_F(EventBlocksTest, WhenGreaterThanPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); @@ -297,7 +297,7 @@ TEST_F(EventBlocksTest, WhenGreaterThanPredicate) auto block = builder.currentBlock(); Compiler compiler(&m_engineMock, target.get()); - auto code = compiler.compile(block, true); + auto code = compiler.compile(block, Compiler::CodeType::HatPredicate); Script script(target.get(), block, &m_engineMock); script.setHatPredicateCode(code); Thread thread(target.get(), &m_engineMock, &script); diff --git a/test/compiler/compiler_test.cpp b/test/compiler/compiler_test.cpp index 3b823b7b..540f6634 100644 --- a/test/compiler/compiler_test.cpp +++ b/test/compiler/compiler_test.cpp @@ -46,12 +46,12 @@ class CompilerTest : public testing::Test m_testVar.reset(); } - void compile(Compiler *compiler, std::shared_ptr block, BlockPrototype *procedurePrototype = nullptr, bool isHatPredicate = false) + void compile(Compiler *compiler, std::shared_ptr block, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType codeType = Compiler::CodeType::Script) { ASSERT_EQ(compiler->block(), nullptr); - EXPECT_CALL(m_builderFactory, create(m_ctx.get(), procedurePrototype, isHatPredicate)).WillOnce(Return(m_builder)); + EXPECT_CALL(m_builderFactory, create(m_ctx.get(), procedurePrototype, codeType)).WillOnce(Return(m_builder)); EXPECT_CALL(*m_builder, finalize()).WillOnce(Return(m_code)); - ASSERT_EQ(compiler->compile(block, isHatPredicate), m_code); + ASSERT_EQ(compiler->compile(block, codeType), m_code); ASSERT_EQ(compiler->block(), nullptr); } @@ -1780,18 +1780,18 @@ TEST_F(CompilerTest, UnsupportedBlocks) // Hat predicates auto block5 = std::make_shared("b5", "block5"); - compile(m_compiler.get(), block5, nullptr, true); + compile(m_compiler.get(), block5, nullptr, Compiler::CodeType::HatPredicate); auto block6 = std::make_shared("b6", "block6"); block6->setCompileFunction([](Compiler *) -> CompilerValue * { return nullptr; }); - compile(m_compiler.get(), block6, nullptr, true); + compile(m_compiler.get(), block6, nullptr, Compiler::CodeType::HatPredicate); auto block7 = std::make_shared("b7", "block7"); CompilerConstant ret(Compiler::StaticType::Bool, Value(true)); block7->setCompileFunction([](Compiler *) -> CompilerValue * { return nullptr; }); block7->setHatPredicateCompileFunction([](Compiler *compiler) -> CompilerValue * { return compiler->addConstValue(true); }); EXPECT_CALL(*m_builder, addConstValue(Value(true))).WillOnce(Return(&ret)); - compile(m_compiler.get(), block7, nullptr, true); + compile(m_compiler.get(), block7, nullptr, Compiler::CodeType::HatPredicate); // Check ASSERT_EQ(m_compiler->unsupportedBlocks(), std::unordered_set({ "block1", "block2", "value_block1", "value_block3", "value_block5", "block4", "block5", "block6" })); @@ -1846,9 +1846,9 @@ TEST_F(CompilerTest, HatPredicate) // Script EXPECT_CALL(*m_builder, addConstValue(Value(true))).WillOnce(Return(&ret1)); - compile(m_compiler.get(), block, nullptr, false); + compile(m_compiler.get(), block, nullptr, Compiler::CodeType::Script); // Hat predicate EXPECT_CALL(*m_builder, addConstValue(Value(false))).WillOnce(Return(&ret2)); - compile(m_compiler.get(), block, nullptr, true); + compile(m_compiler.get(), block, nullptr, Compiler::CodeType::HatPredicate); } diff --git a/test/llvm/llvmcodebuilder_test.cpp b/test/llvm/llvmcodebuilder_test.cpp index 86cbfe0b..c2d5c916 100644 --- a/test/llvm/llvmcodebuilder_test.cpp +++ b/test/llvm/llvmcodebuilder_test.cpp @@ -67,12 +67,12 @@ class LLVMCodeBuilderTest : public testing::Test test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency } - void createBuilder(Target *target, BlockPrototype *procedurePrototype, bool isPredicate = false) + void createBuilder(Target *target, BlockPrototype *procedurePrototype, Compiler::CodeType codeType = Compiler::CodeType::Script) { if (m_contexts.find(target) == m_contexts.cend() || !target) m_contexts[target] = std::make_unique(&m_engine, target); - m_builder = std::make_unique(m_contexts[target].get(), procedurePrototype, isPredicate); + m_builder = std::make_unique(m_contexts[target].get(), procedurePrototype, codeType); } void createBuilder(Target *target, bool warp) @@ -82,7 +82,7 @@ class LLVMCodeBuilderTest : public testing::Test createBuilder(target, m_procedurePrototype.get()); } - void createPredicateBuilder(Target *target) { createBuilder(target, nullptr, true); } + void createPredicateBuilder(Target *target) { createBuilder(target, nullptr, Compiler::CodeType::HatPredicate); } void createBuilder(bool warp) { createBuilder(nullptr, warp); } diff --git a/test/llvm/llvmexecutablecode_test.cpp b/test/llvm/llvmexecutablecode_test.cpp index f025831e..fb3a9bd9 100644 --- a/test/llvm/llvmexecutablecode_test.cpp +++ b/test/llvm/llvmexecutablecode_test.cpp @@ -110,7 +110,7 @@ TEST_F(LLVMExecutableCodeTest, CreateExecutionContext) endFunction(m_builder->getInt1(true)); { - auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), false); + auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), Compiler::CodeType::Script); m_script->setCode(code); Thread thread(&m_target, &m_engine, m_script.get()); auto ctx = code->createExecutionContext(&thread); @@ -129,7 +129,7 @@ TEST_F(LLVMExecutableCodeTest, CreatePredicateExecutionContext) endFunction(m_builder->getInt1(true)); { - auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), true); + auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), Compiler::CodeType::HatPredicate); m_script->setCode(code); Thread thread(&m_target, &m_engine, m_script.get()); auto ctx = code->createExecutionContext(&thread); @@ -151,7 +151,7 @@ TEST_F(LLVMExecutableCodeTest, MainFunction) llvm::Function *resumeFunc = beginResumeFunction(); endFunction(m_builder->getInt1(true)); - auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), false); + auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), Compiler::CodeType::Script); m_script->setCode(code); Thread thread(&m_target, &m_engine, m_script.get()); auto ctx = code->createExecutionContext(&thread); @@ -206,7 +206,7 @@ TEST_F(LLVMExecutableCodeTest, PredicateFunction) llvm::Function *resumeFunc = beginResumeFunction(); endFunction(m_builder->getInt1(true)); - auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), true); + auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), Compiler::CodeType::HatPredicate); m_script->setCode(code); Thread thread(&m_target, &m_engine, m_script.get()); auto ctx = code->createExecutionContext(&thread); @@ -233,7 +233,7 @@ TEST_F(LLVMExecutableCodeTest, Promise) llvm::Function *resumeFunc = beginResumeFunction(); endFunction(m_builder->getInt1(true)); - auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), false); + auto code = std::make_shared(m_ctx.get(), mainFunc->getName().str(), resumeFunc->getName().str(), Compiler::CodeType::Script); m_script->setCode(code); Thread thread(&m_target, &m_engine, m_script.get()); auto ctx = code->createExecutionContext(&thread); diff --git a/test/mocks/codebuilderfactorymock.h b/test/mocks/codebuilderfactorymock.h index 3489995d..d1d1d080 100644 --- a/test/mocks/codebuilderfactorymock.h +++ b/test/mocks/codebuilderfactorymock.h @@ -8,6 +8,6 @@ using namespace libscratchcpp; class CodeBuilderFactoryMock : public ICodeBuilderFactory { public: - MOCK_METHOD(std::shared_ptr, create, (CompilerContext *, BlockPrototype *, bool), (const, override)); + MOCK_METHOD(std::shared_ptr, create, (CompilerContext *, BlockPrototype *, Compiler::CodeType), (const, override)); MOCK_METHOD(std::shared_ptr, createCtx, (IEngine *, Target *), (const, override)); }; From 601bd29c713a35fd86f1452b140fb88e12723097 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Fri, 21 Feb 2025 19:54:48 +0100 Subject: [PATCH 02/15] Add runReporter() method to ExecutableCode --- include/scratchcpp/executablecode.h | 7 ++ .../internal/llvm/llvmexecutablecode.cpp | 13 ++- src/engine/internal/llvm/llvmexecutablecode.h | 4 +- test/llvm/llvmexecutablecode_test.cpp | 105 +++++++++++++----- test/llvm/testfunctions.cpp | 10 +- test/llvm/testfunctions.h | 1 + test/llvm/testmock.h | 5 +- test/mocks/executablecodemock.h | 2 + 8 files changed, 117 insertions(+), 30 deletions(-) diff --git a/include/scratchcpp/executablecode.h b/include/scratchcpp/executablecode.h index c55a4983..1c5706ad 100644 --- a/include/scratchcpp/executablecode.h +++ b/include/scratchcpp/executablecode.h @@ -11,6 +11,7 @@ namespace libscratchcpp class ExecutionContext; class Thread; +struct ValueData; /*! \brief The ExecutableCode class represents the code of a compiled Scratch script. */ class LIBSCRATCHCPP_EXPORT ExecutableCode @@ -21,6 +22,12 @@ class LIBSCRATCHCPP_EXPORT ExecutableCode /*! Runs the script until it finishes or yields. */ virtual void run(ExecutionContext *context) = 0; + /*! + * Runs the reporter and returns its return value. + * \note Make sure to call value_free() to free the value. + */ + virtual ValueData runReporter(ExecutionContext *context) = 0; + /*! Runs the hat predicate and returns its return value. */ virtual bool runPredicate(ExecutionContext *context) = 0; diff --git a/src/engine/internal/llvm/llvmexecutablecode.cpp b/src/engine/internal/llvm/llvmexecutablecode.cpp index 4ba1cffc..5b6a70d8 100644 --- a/src/engine/internal/llvm/llvmexecutablecode.cpp +++ b/src/engine/internal/llvm/llvmexecutablecode.cpp @@ -67,6 +67,14 @@ void LLVMExecutableCode::run(ExecutionContext *context) } } +ValueData LLVMExecutableCode::runReporter(ExecutionContext *context) +{ + assert(std::holds_alternative(m_mainFunction)); + Target *target = context->thread()->target(); + ReporterFunctionType f = std::get(m_mainFunction); + return f(context, target, target->variableData(), target->listData()); +} + bool LLVMExecutableCode::runPredicate(ExecutionContext *context) { assert(std::holds_alternative(m_mainFunction)); @@ -106,7 +114,10 @@ std::shared_ptr LLVMExecutableCode::createExecutionContext(Thr m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); break; - // TODO: Implement reporter code type + case Compiler::CodeType::Reporter: + m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); + break; + case Compiler::CodeType::HatPredicate: m_mainFunction = m_ctx->lookupFunction(m_mainFunctionName); break; diff --git a/src/engine/internal/llvm/llvmexecutablecode.h b/src/engine/internal/llvm/llvmexecutablecode.h index 4ff50ec1..a4b150b1 100644 --- a/src/engine/internal/llvm/llvmexecutablecode.h +++ b/src/engine/internal/llvm/llvmexecutablecode.h @@ -20,6 +20,7 @@ class LLVMExecutableCode : public ExecutableCode LLVMExecutableCode(LLVMCompilerContext *ctx, const std::string &mainFunctionName, const std::string &resumeFunctionName, Compiler::CodeType codeType); void run(ExecutionContext *context) override; + ValueData runReporter(ExecutionContext *context) override; bool runPredicate(ExecutionContext *context) override; void kill(libscratchcpp::ExecutionContext *context) override; void reset(ExecutionContext *context) override; @@ -30,6 +31,7 @@ class LLVMExecutableCode : public ExecutableCode private: using MainFunctionType = void *(*)(ExecutionContext *, Target *, ValueData **, List **); + using ReporterFunctionType = ValueData (*)(ExecutionContext *, Target *, ValueData **, List **); using PredicateFunctionType = bool (*)(ExecutionContext *, Target *, ValueData **, List **); using ResumeFunctionType = bool (*)(void *); @@ -41,7 +43,7 @@ class LLVMExecutableCode : public ExecutableCode std::string m_resumeFunctionName; Compiler::CodeType m_codeType; - mutable std::variant m_mainFunction; + mutable std::variant m_mainFunction; mutable ResumeFunctionType m_resumeFunction = nullptr; }; diff --git a/test/llvm/llvmexecutablecode_test.cpp b/test/llvm/llvmexecutablecode_test.cpp index fb3a9bd9..d792cfde 100644 --- a/test/llvm/llvmexecutablecode_test.cpp +++ b/test/llvm/llvmexecutablecode_test.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ class LLVMExecutableCodeTest : public testing::Test m_module = m_ctx->module(); m_llvmCtx = m_ctx->llvmCtx(); m_builder = std::make_unique>(*m_llvmCtx); + m_valueDataType = LLVMTypes::createValueDataType(m_builder.get()); test_function(nullptr, nullptr, nullptr, nullptr, nullptr); // force dependency m_script = std::make_unique