Skip to content

Commit 77f687e

Browse files
committed
Implement control_stop
1 parent 5b37719 commit 77f687e

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

src/dev/blocks/controlblocks.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include <scratchcpp/dev/compilerconstant.h>
66
#include <scratchcpp/value.h>
77
#include <scratchcpp/input.h>
8+
#include <scratchcpp/field.h>
9+
#include <scratchcpp/dev/executioncontext.h>
10+
#include <scratchcpp/thread.h>
811

912
#include "controlblocks.h"
1013

@@ -26,6 +29,7 @@ void ControlBlocks::registerBlocks(IEngine *engine)
2629
engine->addCompileFunction(this, "control_repeat", &compileRepeat);
2730
engine->addCompileFunction(this, "control_if", &compileIf);
2831
engine->addCompileFunction(this, "control_if_else", &compileIfElse);
32+
engine->addCompileFunction(this, "control_stop", &compileStop);
2933
}
3034

3135
CompilerValue *ControlBlocks::compileForever(Compiler *compiler)
@@ -57,3 +61,32 @@ CompilerValue *ControlBlocks::compileIfElse(Compiler *compiler)
5761
compiler->moveToIfElse(compiler->addInput("CONDITION"), substack ? substack->valueBlock() : nullptr, substack2 ? substack2->valueBlock() : nullptr);
5862
return nullptr;
5963
}
64+
65+
CompilerValue *ControlBlocks::compileStop(Compiler *compiler)
66+
{
67+
Field *option = compiler->field("STOP_OPTION");
68+
69+
if (option) {
70+
std::string str = option->value().toString();
71+
72+
if (str == "all")
73+
compiler->addFunctionCallWithCtx("control_stop_all", Compiler::StaticType::Void);
74+
else if (str == "this script")
75+
compiler->createStop();
76+
else if (str == "other scripts in sprite" || str == "other scripts in stage")
77+
compiler->addFunctionCallWithCtx("control_stop_other_scripts_in_target", Compiler::StaticType::Void);
78+
}
79+
80+
return nullptr;
81+
}
82+
83+
extern "C" void control_stop_all(ExecutionContext *ctx)
84+
{
85+
ctx->engine()->stop();
86+
}
87+
88+
extern "C" void control_stop_other_scripts_in_target(ExecutionContext *ctx)
89+
{
90+
Thread *thread = ctx->thread();
91+
ctx->engine()->stopTarget(thread->target(), thread);
92+
}

src/dev/blocks/controlblocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class ControlBlocks : public IExtension
2020
static CompilerValue *compileRepeat(Compiler *compiler);
2121
static CompilerValue *compileIf(Compiler *compiler);
2222
static CompilerValue *compileIfElse(Compiler *compiler);
23+
static CompilerValue *compileStop(Compiler *compiler);
2324
};
2425

2526
} // namespace libscratchcpp

test/dev/blocks/control_blocks_test.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include <scratchcpp/sprite.h>
55
#include <scratchcpp/block.h>
66
#include <scratchcpp/input.h>
7+
#include <scratchcpp/script.h>
8+
#include <scratchcpp/thread.h>
79
#include <enginemock.h>
810

911
#include "../common.h"
@@ -250,3 +252,83 @@ TEST_F(ControlBlocksTest, IfElse)
250252
builder.run();
251253
}
252254
}
255+
256+
TEST_F(ControlBlocksTest, Stop)
257+
{
258+
auto target = std::make_shared<Sprite>();
259+
260+
// Stop all
261+
{
262+
ScriptBuilder builder(m_extension.get(), m_engine, target);
263+
264+
builder.addBlock("control_stop");
265+
builder.addDropdownField("STOP_OPTION", "all");
266+
auto block = builder.currentBlock();
267+
268+
Compiler compiler(&m_engineMock, target.get());
269+
auto code = compiler.compile(block);
270+
Script script(target.get(), block, &m_engineMock);
271+
script.setCode(code);
272+
Thread thread(target.get(), &m_engineMock, &script);
273+
274+
EXPECT_CALL(m_engineMock, stop());
275+
thread.run();
276+
}
277+
278+
m_engine->clear();
279+
target = std::make_shared<Sprite>();
280+
281+
// Stop this script
282+
{
283+
ScriptBuilder builder(m_extension.get(), m_engine, target);
284+
285+
builder.addBlock("control_stop");
286+
builder.addDropdownField("STOP_OPTION", "this script");
287+
builder.addBlock("test_print_test");
288+
289+
builder.build();
290+
291+
testing::internal::CaptureStdout();
292+
builder.run();
293+
ASSERT_TRUE(testing::internal::GetCapturedStdout().empty());
294+
}
295+
296+
m_engine->clear();
297+
target = std::make_shared<Sprite>();
298+
299+
// Stop other scripts in sprite
300+
{
301+
ScriptBuilder builder(m_extension.get(), m_engine, target);
302+
303+
builder.addBlock("control_stop");
304+
builder.addDropdownField("STOP_OPTION", "other scripts in sprite");
305+
auto block = builder.currentBlock();
306+
307+
Compiler compiler(&m_engineMock, target.get());
308+
auto code = compiler.compile(block);
309+
Script script(target.get(), block, &m_engineMock);
310+
script.setCode(code);
311+
Thread thread(target.get(), &m_engineMock, &script);
312+
313+
EXPECT_CALL(m_engineMock, stopTarget(target.get(), &thread));
314+
thread.run();
315+
}
316+
317+
// Stop other scripts in stage
318+
{
319+
ScriptBuilder builder(m_extension.get(), m_engine, target);
320+
321+
builder.addBlock("control_stop");
322+
builder.addDropdownField("STOP_OPTION", "other scripts in stage");
323+
auto block = builder.currentBlock();
324+
325+
Compiler compiler(&m_engineMock, target.get());
326+
auto code = compiler.compile(block);
327+
Script script(target.get(), block, &m_engineMock);
328+
script.setCode(code);
329+
Thread thread(target.get(), &m_engineMock, &script);
330+
331+
EXPECT_CALL(m_engineMock, stopTarget(target.get(), &thread));
332+
thread.run();
333+
}
334+
}

0 commit comments

Comments
 (0)