22
33#pragma once
44
5+ #include " ../engine/engine.h"
56#include " ../scratch/target.h"
67#include " block.h"
78#include < map>
9+ #include < iostream>
810
911namespace libscratchcpp
1012{
@@ -15,21 +17,134 @@ class LIBSCRATCHCPP_EXPORT RunningScript
1517 public:
1618 RunningScript (std::shared_ptr<Block> block, std::shared_ptr<Target> target, Engine *engine);
1719
18- std::shared_ptr<Block> currentBlock () const ;
19- void moveToNextBlock ();
20+ /* ! Returns the current block. */
21+ std::shared_ptr<Block> currentBlock () const { return m_currentBlock; }
2022
21- std::shared_ptr<Block> cMouth ();
22- void moveToSubstack (std::shared_ptr<Block> substackBlock);
23- void moveToSubstack (const BlockArgs &args, int inputId);
24- std::shared_ptr<Block> getSubstack (const BlockArgs &args, int inputId) const ;
25- void skipSubstack ();
23+ /* !
24+ * Continues to the next block, cMouth() or to the first block of a C mouth.
25+ * \note Use moveToSubstack() to move to the substack of e. g. a loop, or
26+ * skipSubstack(), if it doesn't have one.
27+ */
28+ void moveToNextBlock ()
29+ {
30+ if (m_currentBlock) {
31+ if (!m_currentBlock->next () && !m_tree.empty ()) {
32+ bool ret = substackEnd ();
33+ if (!ret)
34+ return ;
35+ moveToNextBlock ();
36+ return ;
37+ }
38+ m_currentBlock = m_currentBlock->next ();
39+ }
40+ }
2641
27- std::shared_ptr<Target> target () const ;
42+ /* ! Returns the C mouth block or nullptr if the block isn't in a C mouth. */
43+ std::shared_ptr<Block> cMouth ()
44+ {
45+ if (m_tree.empty ())
46+ return nullptr ;
47+ return m_tree[m_tree.size () - 1 ].first ;
48+ }
2849
29- bool atCMouthEnd () const ;
50+ /* !
51+ * Moves to a substack, e. g. in a loop.
52+ * \note Please use the overloaded function with the list of inputs
53+ * and the index of the substack input because it'll automatically
54+ * check if there's a substack defined.
55+ */
56+ void moveToSubstack (std::shared_ptr<Block> substackBlock)
57+ {
58+ if (!substackBlock) {
59+ std::cout << " warning: moving to null substack block (nothing will happen)" << std::endl;
60+ return ;
61+ }
62+
63+ if (!m_currentBlock)
64+ std::cout << " warning: " << substackBlock->id () << " : moving to substack from a null block" << std::endl;
65+
66+ m_tree.push_back ({ m_currentBlock, substackBlock });
67+ m_currentBlock = substackBlock;
68+ m_engine->stayOnCurrentBlock ();
69+ }
70+
71+ /* !
72+ * Moves to a substack, e. g. in a loop.
73+ * \param[in] args The arguments passed to the block.
74+ * \param[in] inputId The ID of the substack input (registered by the block section).
75+ */
76+ void moveToSubstack (const BlockArgs &args, int inputId)
77+ {
78+ auto substack = getSubstack (args, inputId);
79+ if (substack)
80+ moveToSubstack (substack);
81+ else
82+ skipSubstack ();
83+ }
84+
85+ /* !
86+ * Finds the substack.
87+ * \param[in] args The arguments passed to the block.
88+ * \param[in] inputId The ID of the substack input (registered by the block section).
89+ */
90+ std::shared_ptr<Block> getSubstack (const BlockArgs &args, int inputId) const
91+ {
92+ auto block = args.block ();
93+ auto input = block->findInputById (inputId);
94+ if (input) {
95+ auto ret = input->valueBlock ();
96+ if (ret)
97+ return ret;
98+ }
99+ return nullptr ;
100+ }
101+
102+ /* ! Use this to avoid passing a null block to moveToSubstack(). */
103+ void skipSubstack ()
104+ {
105+ m_tree.push_back ({ m_currentBlock, nullptr });
106+ m_currentBlock = nullptr ;
107+ bool ret = substackEnd ();
108+ if (!ret) {
109+ m_tree.pop_back ();
110+ m_engine->stayOnCurrentBlock ();
111+ }
112+ }
113+
114+ /* ! Returns the Target which started the script. */
115+ std::shared_ptr<Target> target () const { return m_target; }
116+
117+ /* !
118+ * Returns true if a block implementation has been
119+ * called to check whether to break from a C mouth.
120+ */
121+ bool atCMouthEnd () const { return m_atCMouthEnd; }
30122
31123 private:
32- bool substackEnd ();
124+ bool substackEnd ()
125+ {
126+ /*
127+ * Call the C mouth block implementation
128+ * to check whether to break from the C
129+ * mouth or to jump to the beginning of it.
130+ */
131+ auto cMouthBlock = cMouth ();
132+ m_atCMouthEnd = true ;
133+ bool ret = cMouthBlock->run (this , true ).toBool ();
134+ m_atCMouthEnd = false ;
135+ if (!m_engine->isAtomic ())
136+ m_engine->breakFrame ();
137+ if (ret) {
138+ m_currentBlock = cMouthBlock;
139+ m_tree.pop_back ();
140+ } else {
141+ m_currentBlock = m_tree[m_tree.size () - 1 ].second ;
142+ if (!m_currentBlock)
143+ m_currentBlock = cMouthBlock;
144+ }
145+ return ret;
146+ }
147+
33148 std::shared_ptr<Block> m_currentBlock;
34149 // pair<C mouth block, first block of the substack>
35150 std::vector<std::pair<std::shared_ptr<Block>, std::shared_ptr<Block>>> m_tree;
0 commit comments