Skip to content

Commit d1a45d1

Browse files
committed
Add hat predicate support to Script
1 parent c25b80f commit d1a45d1

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

include/scratchcpp/script.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class LIBSCRATCHCPP_EXPORT Script
3434
const std::vector<unsigned int> &bytecodeVector() const;
3535
void setBytecode(const std::vector<unsigned int> &code);
3636

37+
void setHatPredicateBytecode(const std::vector<unsigned int> &code);
38+
bool runHatPredicate();
39+
3740
void setProcedures(const std::vector<unsigned int *> &procedures);
3841
void setFunctions(const std::vector<BlockFunc> &functions);
3942
void setConstValues(const std::vector<Value> &values);

src/engine/script.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <scratchcpp/list.h>
77
#include <scratchcpp/sprite.h>
88
#include <scratchcpp/iengine.h>
9+
#include <scratchcpp/stage.h>
910
#include <iostream>
1011

1112
#include "script_p.h"
@@ -48,6 +49,37 @@ void Script::setBytecode(const std::vector<unsigned int> &code)
4849
impl->bytecode = impl->bytecodeVector.data();
4950
}
5051

52+
/*! Sets the edge-activated hat predicate bytecode. */
53+
void Script::setHatPredicateBytecode(const std::vector<unsigned int> &code)
54+
{
55+
impl->hatPredicateBytecodeVector = code;
56+
57+
if (impl->engine && !code.empty()) {
58+
impl->hatPredicateVm = std::make_shared<VirtualMachine>(impl->engine->stage(), impl->engine, this);
59+
impl->hatPredicateVm->setBytecode(impl->hatPredicateBytecodeVector.data());
60+
impl->hatPredicateVm->setFunctions(impl->functions);
61+
impl->hatPredicateVm->setConstValues(impl->constValues);
62+
}
63+
}
64+
65+
/*!
66+
* Runs the edge-activated hat predicate and returns the reported value.
67+
* \note If there isn't any predicate, nothing will happen and the returned value will be false.
68+
*/
69+
bool Script::runHatPredicate()
70+
{
71+
if (impl->hatPredicateVm && impl->hatPredicateVm->bytecode()) {
72+
impl->hatPredicateVm->reset();
73+
impl->hatPredicateVm->run();
74+
assert(impl->hatPredicateVm->registerCount() == 1);
75+
76+
if (impl->hatPredicateVm->registerCount() == 1)
77+
return impl->hatPredicateVm->getInput(0, 1)->toBool();
78+
}
79+
80+
return false;
81+
}
82+
5183
/*! Starts the script (creates a virtual machine). */
5284
std::shared_ptr<VirtualMachine> Script::start()
5385
{
@@ -129,13 +161,19 @@ void Script::setFunctions(const std::vector<BlockFunc> &functions)
129161
{
130162
impl->functionsVector = functions;
131163
impl->functions = impl->functionsVector.data();
164+
165+
if (impl->hatPredicateVm)
166+
impl->hatPredicateVm->setFunctions(impl->functions);
132167
}
133168

134169
/*! Sets the list of constant values. */
135170
void Script::setConstValues(const std::vector<Value> &values)
136171
{
137172
impl->constValuesVector = values;
138173
impl->constValues = impl->constValuesVector.data();
174+
175+
if (impl->hatPredicateVm)
176+
impl->hatPredicateVm->setConstValues(impl->constValues);
139177
}
140178

141179
/*! Sets the list of variables. */

src/engine/script_p.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ struct ScriptPrivate
2323
unsigned int *bytecode = nullptr;
2424
std::vector<unsigned int> bytecodeVector;
2525

26+
std::vector<unsigned int> hatPredicateBytecodeVector;
27+
std::shared_ptr<VirtualMachine> hatPredicateVm;
28+
2629
Target *target = nullptr;
2730
std::shared_ptr<Block> topBlock;
2831
IEngine *engine = nullptr;

test/script/script_test.cpp

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include <scratchcpp/script.h>
22
#include <scratchcpp/block.h>
33
#include <scratchcpp/virtualmachine.h>
4-
#include <scratchcpp/target.h>
54
#include <scratchcpp/sprite.h>
5+
#include <scratchcpp/stage.h>
66
#include <scratchcpp/variable.h>
77
#include <scratchcpp/list.h>
88
#include <enginemock.h>
@@ -41,6 +41,74 @@ TEST_F(ScriptTest, Bytecode)
4141
ASSERT_EQ(script.bytecodeVector(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
4242
}
4343

44+
static Target *stageTest = nullptr;
45+
static IEngine *engineTest = nullptr;
46+
static Script *scriptTest = nullptr;
47+
48+
TEST_F(ScriptTest, HatPredicate)
49+
{
50+
Script script(&m_target, nullptr, &m_engine);
51+
ASSERT_FALSE(script.runHatPredicate());
52+
53+
Stage stage;
54+
EXPECT_CALL(m_engine, stage()).Times(3).WillRepeatedly(Return(&stage));
55+
56+
BlockFunc f1 = [](VirtualMachine *vm) -> unsigned int {
57+
vm->addReturnValue(true);
58+
vm->stop(false, false, false);
59+
stageTest = vm->target();
60+
engineTest = vm->engine();
61+
scriptTest = vm->script();
62+
return 0;
63+
};
64+
65+
BlockFunc f2 = f1;
66+
67+
BlockFunc f3 = [](VirtualMachine *vm) -> unsigned int {
68+
vm->addReturnValue(false);
69+
vm->stop(false, false, false);
70+
stageTest = vm->target();
71+
engineTest = vm->engine();
72+
scriptTest = vm->script();
73+
return 0;
74+
};
75+
76+
stageTest = nullptr;
77+
engineTest = nullptr;
78+
scriptTest = nullptr;
79+
script.setFunctions({ f1 });
80+
script.setConstValues({ "test" });
81+
script.setHatPredicateBytecode({ vm::OP_START, vm::OP_CONST, 0, vm::OP_PRINT, vm::OP_EXEC, 0, vm::OP_HALT });
82+
testing::internal::CaptureStdout();
83+
ASSERT_TRUE(script.runHatPredicate());
84+
ASSERT_EQ(testing::internal::GetCapturedStdout(), "test\n");
85+
ASSERT_EQ(stageTest, &stage);
86+
ASSERT_EQ(engineTest, &m_engine);
87+
ASSERT_EQ(scriptTest, &script);
88+
89+
stageTest = nullptr;
90+
engineTest = nullptr;
91+
scriptTest = nullptr;
92+
script.setHatPredicateBytecode({ vm::OP_START, vm::OP_CONST, 0, vm::OP_PRINT, vm::OP_EXEC, 1, vm::OP_HALT });
93+
script.setFunctions({ f1, f2, f3 });
94+
script.setConstValues({ 5 });
95+
testing::internal::CaptureStdout();
96+
ASSERT_TRUE(script.runHatPredicate());
97+
ASSERT_EQ(testing::internal::GetCapturedStdout(), "5\n");
98+
ASSERT_EQ(stageTest, &stage);
99+
ASSERT_EQ(engineTest, &m_engine);
100+
ASSERT_EQ(scriptTest, &script);
101+
102+
stageTest = nullptr;
103+
engineTest = nullptr;
104+
scriptTest = nullptr;
105+
script.setHatPredicateBytecode({ vm::OP_START, vm::OP_EXEC, 2, vm::OP_HALT });
106+
ASSERT_FALSE(script.runHatPredicate());
107+
ASSERT_EQ(stageTest, &stage);
108+
ASSERT_EQ(engineTest, &m_engine);
109+
ASSERT_EQ(scriptTest, &script);
110+
}
111+
44112
unsigned int testFunction(VirtualMachine *)
45113
{
46114
return 0;

0 commit comments

Comments
 (0)