Skip to content

Commit 3b84a15

Browse files
committed
Compiler: Add support for substacks
1 parent ccdb80d commit 3b84a15

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

src/engine/compiler.cpp

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,21 @@ void Compiler::compile()
2424

2525
m_block = m_block->next();
2626
while (m_block) {
27+
size_t substacks = m_substackTree.size();
28+
2729
if (m_block->compileFunction())
2830
m_block->compile(this);
2931
else
3032
std::cout << "warning: unsupported block: " << m_block->opcode() << std::endl;
31-
m_block = m_block->next();
33+
34+
if (substacks != m_substackTree.size())
35+
continue;
36+
37+
if (m_block)
38+
m_block = m_block->next();
39+
40+
if (!m_block && !m_substackTree.empty())
41+
substackEnd();
3242
}
3343

3444
// Add end instruction (halt)
@@ -107,6 +117,10 @@ void Compiler::addInstruction(Opcode opcode, std::initializer_list<unsigned int>
107117
void Compiler::addInput(int id)
108118
{
109119
auto in = input(id);
120+
if (!in) {
121+
addInstruction(OP_NULL);
122+
return;
123+
}
110124
switch (in->type()) {
111125
case Input::Type::Shadow:
112126
addInstruction(OP_CONST, { constIndex(in->primaryValue()) });
@@ -128,6 +142,21 @@ void Compiler::addFunctionCall(BlockFunc f)
128142
addInstruction(OP_EXEC, { m_engine->functionIndex(f) });
129143
}
130144

145+
/*! Jumps to the given substack. The second substack is used for example for the if/else block. */
146+
void Compiler::moveToSubstack(std::shared_ptr<Block> substack1, std::shared_ptr<Block> substack2, SubstackType type)
147+
{
148+
m_substackTree.push_back({ { m_block, substack2 }, type });
149+
m_block = substack1;
150+
if (!m_block)
151+
substackEnd();
152+
}
153+
154+
/*! Jumps to the given substack. */
155+
void Compiler::moveToSubstack(std::shared_ptr<Block> substack, SubstackType type)
156+
{
157+
moveToSubstack(substack, nullptr, type);
158+
}
159+
131160
/*! Returns the input with the given ID. */
132161
Input *Compiler::input(int id) const
133162
{
@@ -140,6 +169,13 @@ Field *Compiler::field(int id) const
140169
return m_block->findFieldById(id);
141170
}
142171

172+
/*! Returns the block in the given input. Same as input(id)->valueBlock(), but with a null pointer check. */
173+
std::shared_ptr<Block> Compiler::inputBlock(int id) const
174+
{
175+
auto in = input(id);
176+
return in ? in->valueBlock() : nullptr;
177+
}
178+
143179
/*! Returns the index of the given variable. */
144180
unsigned int Compiler::variableIndex(std::shared_ptr<IEntity> varEntity)
145181
{
@@ -170,3 +206,26 @@ unsigned int Compiler::constIndex(InputValue *value)
170206
m_constValues.push_back(value);
171207
return m_constValues.size() - 1;
172208
}
209+
210+
void Compiler::substackEnd()
211+
{
212+
auto parent = m_substackTree.back();
213+
switch (parent.second) {
214+
case SubstackType::Loop:
215+
addInstruction(OP_LOOP_END);
216+
break;
217+
case SubstackType::IfStatement:
218+
if (parent.first.second) {
219+
addInstruction(OP_ELSE);
220+
m_block = parent.first.second;
221+
m_substackTree[m_substackTree.size() - 1].first.second = nullptr;
222+
return;
223+
} else
224+
addInstruction(OP_ENDIF);
225+
break;
226+
}
227+
m_block = parent.first.first->next();
228+
m_substackTree.pop_back();
229+
if (!m_block && !m_substackTree.empty())
230+
substackEnd();
231+
}

src/engine/compiler.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ namespace libscratchcpp
1212
class LIBSCRATCHCPP_EXPORT Compiler
1313
{
1414
public:
15+
enum class SubstackType
16+
{
17+
Loop,
18+
IfStatement
19+
};
20+
1521
Compiler(Engine *engine, std::shared_ptr<Block> topLevelBlock);
1622
Compiler(const Compiler &) = delete;
1723

@@ -33,17 +39,22 @@ class LIBSCRATCHCPP_EXPORT Compiler
3339
void addInstruction(vm::Opcode opcode, std::initializer_list<unsigned int> args = {});
3440
void addInput(int id);
3541
void addFunctionCall(BlockFunc f);
42+
void moveToSubstack(std::shared_ptr<Block> substack1, std::shared_ptr<Block> substack2, SubstackType type);
43+
void moveToSubstack(std::shared_ptr<Block> substack, SubstackType type);
3644

3745
Input *input(int id) const;
3846
Field *field(int id) const;
47+
std::shared_ptr<Block> inputBlock(int id) const;
3948
unsigned int variableIndex(std::shared_ptr<IEntity> varEntity);
4049
unsigned int listIndex(std::shared_ptr<IEntity> listEntity);
4150

4251
private:
4352
unsigned int constIndex(InputValue *value);
53+
void substackEnd();
4454

4555
Engine *m_engine;
4656
std::shared_ptr<Block>(m_block);
57+
std::vector<std::pair<std::pair<std::shared_ptr<Block>, std::shared_ptr<Block>>, SubstackType>> m_substackTree;
4758

4859
std::vector<unsigned int> m_bytecode;
4960
std::vector<InputValue *> m_constValues;

0 commit comments

Comments
 (0)