11// SPDX-License-Identifier: Apache-2.0
22
3+ #include < scratchcpp/iengine.h>
4+ #include < scratchcpp/dev/compiler.h>
5+ #include < scratchcpp/dev/compilerconstant.h>
6+ #include < scratchcpp/value.h>
7+ #include < scratchcpp/input.h>
8+ #include < scratchcpp/field.h>
9+ #include < scratchcpp/dev/executioncontext.h>
10+ #include < scratchcpp/thread.h>
11+ #include < scratchcpp/istacktimer.h>
12+ #include < scratchcpp/variable.h>
13+ #include < scratchcpp/sprite.h>
14+
315#include " controlblocks.h"
416
517using namespace libscratchcpp ;
@@ -16,4 +28,206 @@ std::string ControlBlocks::description() const
1628
1729void ControlBlocks::registerBlocks (IEngine *engine)
1830{
31+ engine->addCompileFunction (this , " control_forever" , &compileForever);
32+ engine->addCompileFunction (this , " control_repeat" , &compileRepeat);
33+ engine->addCompileFunction (this , " control_if" , &compileIf);
34+ engine->addCompileFunction (this , " control_if_else" , &compileIfElse);
35+ engine->addCompileFunction (this , " control_stop" , &compileStop);
36+ engine->addCompileFunction (this , " control_wait" , &compileWait);
37+ engine->addCompileFunction (this , " control_wait_until" , &compileWaitUntil);
38+ engine->addCompileFunction (this , " control_repeat_until" , &compileRepeatUntil);
39+ engine->addCompileFunction (this , " control_while" , &compileWhile);
40+ engine->addCompileFunction (this , " control_for_each" , &compileForEach);
41+ engine->addCompileFunction (this , " control_start_as_clone" , &compileStartAsClone);
42+ engine->addCompileFunction (this , " control_create_clone_of" , &compileCreateCloneOf);
43+ engine->addCompileFunction (this , " control_delete_this_clone" , &compileDeleteThisClone);
44+ }
45+
46+ CompilerValue *ControlBlocks::compileForever (Compiler *compiler)
47+ {
48+ auto substack = compiler->input (" SUBSTACK" );
49+ compiler->beginLoopCondition ();
50+ compiler->moveToWhileLoop (compiler->addConstValue (true ), substack ? substack->valueBlock () : nullptr );
51+ return nullptr ;
52+ }
53+
54+ CompilerValue *ControlBlocks::compileRepeat (Compiler *compiler)
55+ {
56+ auto substack = compiler->input (" SUBSTACK" );
57+ compiler->moveToRepeatLoop (compiler->addInput (" TIMES" ), substack ? substack->valueBlock () : nullptr );
58+ return nullptr ;
59+ }
60+
61+ CompilerValue *ControlBlocks::compileIf (Compiler *compiler)
62+ {
63+ auto substack = compiler->input (" SUBSTACK" );
64+ compiler->moveToIf (compiler->addInput (" CONDITION" ), substack ? substack->valueBlock () : nullptr );
65+ return nullptr ;
66+ }
67+
68+ CompilerValue *ControlBlocks::compileIfElse (Compiler *compiler)
69+ {
70+ auto substack = compiler->input (" SUBSTACK" );
71+ auto substack2 = compiler->input (" SUBSTACK2" );
72+ compiler->moveToIfElse (compiler->addInput (" CONDITION" ), substack ? substack->valueBlock () : nullptr , substack2 ? substack2->valueBlock () : nullptr );
73+ return nullptr ;
74+ }
75+
76+ CompilerValue *ControlBlocks::compileStop (Compiler *compiler)
77+ {
78+ Field *option = compiler->field (" STOP_OPTION" );
79+
80+ if (option) {
81+ std::string str = option->value ().toString ();
82+
83+ if (str == " all" )
84+ compiler->addFunctionCallWithCtx (" control_stop_all" , Compiler::StaticType::Void);
85+ else if (str == " this script" )
86+ compiler->createStop ();
87+ else if (str == " other scripts in sprite" || str == " other scripts in stage" )
88+ compiler->addFunctionCallWithCtx (" control_stop_other_scripts_in_target" , Compiler::StaticType::Void);
89+ }
90+
91+ return nullptr ;
92+ }
93+
94+ CompilerValue *ControlBlocks::compileWait (Compiler *compiler)
95+ {
96+ auto duration = compiler->addInput (" DURATION" );
97+ compiler->addFunctionCallWithCtx (" control_start_wait" , Compiler::StaticType::Void, { Compiler::StaticType::Number }, { duration });
98+ compiler->createYield ();
99+
100+ compiler->beginLoopCondition ();
101+ auto elapsed = compiler->addFunctionCallWithCtx (" control_stack_timer_elapsed" , Compiler::StaticType::Bool);
102+ compiler->beginRepeatUntilLoop (elapsed);
103+ compiler->endLoop ();
104+
105+ return nullptr ;
106+ }
107+
108+ CompilerValue *ControlBlocks::compileWaitUntil (Compiler *compiler)
109+ {
110+ compiler->beginLoopCondition ();
111+ compiler->beginRepeatUntilLoop (compiler->addInput (" CONDITION" ));
112+ compiler->endLoop ();
113+ return nullptr ;
114+ }
115+
116+ CompilerValue *ControlBlocks::compileRepeatUntil (Compiler *compiler)
117+ {
118+ auto substack = compiler->input (" SUBSTACK" );
119+ compiler->beginLoopCondition ();
120+ compiler->moveToRepeatUntilLoop (compiler->addInput (" CONDITION" ), substack ? substack->valueBlock () : nullptr );
121+ return nullptr ;
122+ }
123+
124+ CompilerValue *ControlBlocks::compileWhile (Compiler *compiler)
125+ {
126+ auto substack = compiler->input (" SUBSTACK" );
127+ compiler->beginLoopCondition ();
128+ compiler->moveToWhileLoop (compiler->addInput (" CONDITION" ), substack ? substack->valueBlock () : nullptr );
129+ return nullptr ;
130+ }
131+
132+ CompilerValue *ControlBlocks::compileForEach (Compiler *compiler)
133+ {
134+ Variable *var = static_cast <Variable *>(compiler->field (" VARIABLE" )->valuePtr ().get ());
135+ assert (var);
136+ auto substack = compiler->input (" SUBSTACK" );
137+ compiler->moveToRepeatLoop (compiler->addInput (" VALUE" ), substack ? substack->valueBlock () : nullptr );
138+ auto index = compiler->createAdd (compiler->addLoopIndex (), compiler->addConstValue (1 ));
139+ compiler->createVariableWrite (var, index);
140+ return nullptr ;
141+ }
142+
143+ CompilerValue *ControlBlocks::compileStartAsClone (Compiler *compiler)
144+ {
145+ compiler->engine ()->addCloneInitScript (compiler->block ());
146+ return nullptr ;
147+ }
148+
149+ CompilerValue *ControlBlocks::compileCreateCloneOf (Compiler *compiler)
150+ {
151+ Input *input = compiler->input (" CLONE_OPTION" );
152+
153+ if (input->pointsToDropdownMenu ()) {
154+ std::string spriteName = input->selectedMenuItem ();
155+
156+ if (spriteName == " _myself_" )
157+ compiler->addTargetFunctionCall (" control_create_clone_of_myself" );
158+ else {
159+ auto index = compiler->engine ()->findTarget (spriteName);
160+ CompilerValue *arg = compiler->addConstValue (index);
161+ compiler->addFunctionCallWithCtx (" control_create_clone_by_index" , Compiler::StaticType::Void, { Compiler::StaticType::Number }, { arg });
162+ }
163+ } else {
164+ CompilerValue *arg = compiler->addInput (" CLONE_OPTION" );
165+ compiler->addFunctionCallWithCtx (" control_create_clone" , Compiler::StaticType::Void, { Compiler::StaticType::String }, { arg });
166+ }
167+
168+ return nullptr ;
169+ }
170+
171+ CompilerValue *ControlBlocks::compileDeleteThisClone (Compiler *compiler)
172+ {
173+ compiler->addTargetFunctionCall (" control_delete_this_clone" );
174+ return nullptr ;
175+ }
176+
177+ extern " C" void control_stop_all (ExecutionContext *ctx)
178+ {
179+ ctx->engine ()->stop ();
180+ }
181+
182+ extern " C" void control_stop_other_scripts_in_target (ExecutionContext *ctx)
183+ {
184+ Thread *thread = ctx->thread ();
185+ ctx->engine ()->stopTarget (thread->target (), thread);
186+ }
187+
188+ extern " C" void control_start_wait (ExecutionContext *ctx, double seconds)
189+ {
190+ ctx->stackTimer ()->start (seconds);
191+ ctx->engine ()->requestRedraw ();
192+ }
193+
194+ extern " C" bool control_stack_timer_elapsed (ExecutionContext *ctx)
195+ {
196+ return ctx->stackTimer ()->elapsed ();
197+ }
198+
199+ extern " C" void control_create_clone_of_myself (Target *target)
200+ {
201+ if (!target->isStage ())
202+ static_cast <Sprite *>(target)->clone ();
203+ }
204+
205+ extern " C" void control_create_clone_by_index (ExecutionContext *ctx, double index)
206+ {
207+ Target *target = ctx->engine ()->targetAt (index);
208+
209+ if (!target->isStage ())
210+ static_cast <Sprite *>(target)->clone ();
211+ }
212+
213+ extern " C" void control_create_clone (ExecutionContext *ctx, const char *spriteName)
214+ {
215+ if (strcmp (spriteName, " _myself_" ) == 0 )
216+ control_create_clone_of_myself (ctx->thread ()->target ());
217+ else {
218+ IEngine *engine = ctx->engine ();
219+ auto index = engine->findTarget (spriteName);
220+ Target *target = engine->targetAt (index);
221+
222+ if (!target->isStage ())
223+ static_cast <Sprite *>(target)->clone ();
224+ }
225+ }
226+
227+ extern " C" void control_delete_this_clone (Target *target)
228+ {
229+ if (!target->isStage ()) {
230+ target->engine ()->stopTarget (target, nullptr );
231+ static_cast <Sprite *>(target)->deleteClone ();
232+ }
19233}
0 commit comments