diff --git a/include/scratchcpp/compiler.h b/include/scratchcpp/compiler.h index 36515007..f316ac25 100644 --- a/include/scratchcpp/compiler.h +++ b/include/scratchcpp/compiler.h @@ -56,6 +56,7 @@ class LIBSCRATCHCPP_EXPORT Compiler void addInstruction(vm::Opcode opcode, const std::initializer_list &args = {}); void addInput(Input *input); void addInput(int id); + void addConstValue(const Value &value); void addFunctionCall(BlockFunc f); void addProcedureArg(const std::string &procCode, const std::string &argName); void moveToSubstack(std::shared_ptr substack1, std::shared_ptr substack2, SubstackType type); diff --git a/src/blocks/eventblocks.cpp b/src/blocks/eventblocks.cpp index 3bc65702..f06192f2 100644 --- a/src/blocks/eventblocks.cpp +++ b/src/blocks/eventblocks.cpp @@ -34,24 +34,28 @@ void EventBlocks::registerBlocks(IEngine *engine) void EventBlocks::compileBroadcast(Compiler *compiler) { auto input = compiler->input(BROADCAST_INPUT); - compiler->addInput(input); + if (input->type() != Input::Type::ObscuredShadow) { - input->primaryValue()->setValue(compiler->engine()->findBroadcast(input->primaryValue()->value().toString())); + compiler->addConstValue(compiler->engine()->findBroadcast(input->primaryValue()->value().toString())); compiler->addFunctionCall(&broadcastByIndex); - } else + } else { + compiler->addInput(input); compiler->addFunctionCall(&broadcast); + } } void EventBlocks::compileBroadcastAndWait(Compiler *compiler) { auto input = compiler->input(BROADCAST_INPUT); - compiler->addInput(input); + if (input->type() != Input::Type::ObscuredShadow) { - input->primaryValue()->setValue(compiler->engine()->findBroadcast(input->primaryValue()->value().toString())); + int index = compiler->engine()->findBroadcast(input->primaryValue()->value().toString()); + compiler->addConstValue(index); compiler->addFunctionCall(&broadcastByIndexAndWait); - compiler->addInput(input); + compiler->addConstValue(index); compiler->addFunctionCall(&checkBroadcastByIndex); } else { + compiler->addInput(input); compiler->addFunctionCall(&broadcastAndWait); compiler->addInput(input); compiler->addFunctionCall(&checkBroadcast); diff --git a/src/engine/compiler.cpp b/src/engine/compiler.cpp index 037fb9a9..f3901e9e 100644 --- a/src/engine/compiler.cpp +++ b/src/engine/compiler.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -189,6 +188,14 @@ void Compiler::addInput(int id) addInput(input(id)); } +/*! Adds a constant value and an instruction to load it. Useful if you don't have an input for the addInput() method. */ +void libscratchcpp::Compiler::addConstValue(const Value &value) +{ + impl->customConstValues.push_back(std::make_unique()); + impl->customConstValues.back()->setValue(value); + addInstruction(OP_CONST, { impl->constIndex(impl->customConstValues.back().get()) }); +} + /*! Adds a function call to the bytecode (the OP_EXEC instruction). */ void Compiler::addFunctionCall(BlockFunc f) { diff --git a/src/engine/compiler_p.h b/src/engine/compiler_p.h index 819b074a..2b99935b 100644 --- a/src/engine/compiler_p.h +++ b/src/engine/compiler_p.h @@ -3,6 +3,7 @@ #pragma once #include +#include namespace libscratchcpp { @@ -10,6 +11,7 @@ namespace libscratchcpp struct CompilerPrivate { CompilerPrivate(IEngine *engine); + CompilerPrivate(const CompilerPrivate &) = delete; void addInstruction(vm::Opcode opcode, std::initializer_list args = {}); @@ -25,6 +27,7 @@ struct CompilerPrivate std::vector bytecode; std::vector constValues; + std::vector> customConstValues; std::unordered_map> constValueMenuInfo; // input value, std::vector variables; std::vector lists; diff --git a/test/blocks/event_blocks_test.cpp b/test/blocks/event_blocks_test.cpp index 0c1930f2..20ed514c 100644 --- a/test/blocks/event_blocks_test.cpp +++ b/test/blocks/event_blocks_test.cpp @@ -180,9 +180,8 @@ TEST_F(EventBlocksTest, BroadcastAndWait) ASSERT_EQ( compiler.bytecode(), std::vector( - { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 0, vm::OP_EXEC, 1, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 3, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 0); + { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_NOT, vm::OP_EXEC, 3, vm::OP_HALT })); + ASSERT_EQ(compiler.constValues(), std::vector({ 0, 0 })); ASSERT_TRUE(compiler.variables().empty()); ASSERT_TRUE(compiler.lists().empty()); } diff --git a/test/compiler/compiler_test.cpp b/test/compiler/compiler_test.cpp index f4622c50..572b5069 100644 --- a/test/compiler/compiler_test.cpp +++ b/test/compiler/compiler_test.cpp @@ -365,6 +365,27 @@ TEST_F(CompilerTest, ResolveDropdownMenuInput) ASSERT_EQ(compiler.constValues(), std::vector({ "test" })); } +TEST_F(CompilerTest, AddConstValue) +{ + INIT_COMPILER(engine, compiler); + compiler.addInstruction(vm::OP_START); + + compiler.addConstValue(50); + compiler.addInstruction(vm::OP_PRINT); + compiler.addConstValue(50); + compiler.addInstruction(vm::OP_PRINT); + compiler.addConstValue("hello"); + compiler.addInstruction(vm::OP_PRINT); + compiler.addConstValue("world"); + compiler.addInstruction(vm::OP_PRINT); + + compiler.addInstruction(vm::OP_HALT); + ASSERT_EQ( + compiler.bytecode(), + std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_PRINT, vm::OP_CONST, 1, vm::OP_PRINT, vm::OP_CONST, 2, vm::OP_PRINT, vm::OP_CONST, 3, vm::OP_PRINT, vm::OP_HALT })); + ASSERT_EQ(compiler.constValues(), std::vector({ 50, 50, "hello", "world" })); +} + TEST_F(CompilerTest, ResolveField) { INIT_COMPILER(engine, compiler);