Skip to content

Commit c25b80f

Browse files
committed
Add edge-activated hat support to Compiler
1 parent a57075c commit c25b80f

File tree

4 files changed

+49
-0
lines changed

4 files changed

+49
-0
lines changed

include/scratchcpp/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
4242
void end();
4343

4444
const std::vector<unsigned int> &bytecode() const;
45+
const std::vector<unsigned int> &hatPredicateBytecode() const;
4546

4647
IEngine *engine() const;
4748
Target *target() const;

src/engine/compiler.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,26 @@ void Compiler::compile(std::shared_ptr<Block> topLevelBlock)
4141
init();
4242

4343
impl->block = topLevelBlock;
44+
45+
// If this is a top-level block, it might be an edge-activated hat block with a predicate compile function
46+
if (impl->block->topLevel()) {
47+
HatPredicateCompileFunc f = impl->block->hatPredicateCompileFunction();
48+
49+
if (f) {
50+
f(this);
51+
52+
// Workaround for register leak warning spam: pause the script after getting the reported value
53+
addFunctionCall([](VirtualMachine *vm) -> unsigned int {
54+
vm->stop(false, false, false);
55+
return 0;
56+
});
57+
58+
end(); // finished with the predicate
59+
impl->hatPredicateBytecode = impl->bytecode;
60+
init(); // now start the real compilation
61+
}
62+
}
63+
4464
while (impl->block) {
4565
size_t substacks = impl->substackTree.size();
4666

@@ -80,6 +100,12 @@ const std::vector<unsigned int> &Compiler::bytecode() const
80100
return impl->bytecode;
81101
}
82102

103+
/*! Returns the generated hat predicate bytecode (if this is an edge-activated hat). */
104+
const std::vector<unsigned int> &Compiler::hatPredicateBytecode() const
105+
{
106+
return impl->hatPredicateBytecode;
107+
}
108+
83109
/*! Returns the Engine. */
84110
IEngine *Compiler::engine() const
85111
{

src/engine/compiler_p.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct CompilerPrivate
2828
bool initialized = false;
2929

3030
std::vector<unsigned int> bytecode;
31+
std::vector<unsigned int> hatPredicateBytecode;
3132
std::vector<InputValue *> constValues;
3233
std::vector<std::unique_ptr<InputValue>> customConstValues;
3334
std::unordered_map<InputValue *, std::pair<bool, std::string>> constValueMenuInfo; // input value, <whether the input points to a dropdown menu, selected menu item>

test/compiler/compiler_test.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,3 +816,24 @@ TEST_F(CompilerTest, MultipleTargets)
816816
ASSERT_EQ(vm->engine(), &engine);
817817
ASSERT_EQ(vm->script(), script.get());
818818
}
819+
820+
TEST_F(CompilerTest, EdgeActivatedHatPredicate)
821+
{
822+
auto hat = std::make_shared<Block>("", "");
823+
hat->setCompileFunction([](Compiler *) {});
824+
hat->setHatPredicateCompileFunction([](Compiler *compiler) { compiler->addConstValue(true); });
825+
826+
auto block = std::make_shared<Block>("", "");
827+
block->setCompileFunction([](Compiler *compiler) {
828+
compiler->addConstValue("test");
829+
compiler->addInstruction(vm::OP_PRINT);
830+
});
831+
block->setParent(hat);
832+
hat->setNext(block);
833+
834+
INIT_COMPILER(engine, compiler);
835+
compiler.compile(hat);
836+
ASSERT_EQ(compiler.hatPredicateBytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }));
837+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 1, vm::OP_PRINT, vm::OP_HALT }));
838+
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ true, "test" }));
839+
}

0 commit comments

Comments
 (0)