Skip to content

Commit 7f4a461

Browse files
committed
Add API for compiling blocks without using Compiler::compile()
1 parent 3cf001f commit 7f4a461

File tree

4 files changed

+86
-2
lines changed

4 files changed

+86
-2
lines changed

include/scratchcpp/compiler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ class LIBSCRATCHCPP_EXPORT Compiler
3737
Compiler(IEngine *engine);
3838
Compiler(const Compiler &) = delete;
3939

40+
void init();
4041
void compile(std::shared_ptr<Block> topLevelBlock);
42+
void end();
4143

4244
const std::vector<unsigned int> &bytecode() const;
4345

@@ -73,6 +75,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
7375
const std::vector<std::string> &procedures() const;
7476

7577
const std::shared_ptr<Block> &block() const;
78+
void setBlock(std::shared_ptr<Block> block);
7679

7780
BlockPrototype *procedurePrototype() const;
7881
void setProcedurePrototype(BlockPrototype *prototype);

src/engine/compiler.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ Compiler::Compiler(IEngine *engine) :
2020
{
2121
}
2222

23-
/*! Compiles the script. Use bytecode() to read the generated bytecode. */
24-
void Compiler::compile(std::shared_ptr<Block> topLevelBlock)
23+
/*! Initializes the Compiler. Useful if you don't use compile(). */
24+
void Compiler::init()
2525
{
26+
if (impl->initialized)
27+
return;
28+
2629
impl->bytecode.clear();
2730
impl->procedurePrototype = nullptr;
2831
impl->atomic = true;
@@ -31,6 +34,14 @@ void Compiler::compile(std::shared_ptr<Block> topLevelBlock)
3134
// Add start instruction
3235
addInstruction(OP_START);
3336

37+
impl->initialized = true;
38+
}
39+
40+
/*! Compiles the script. Use bytecode() to read the generated bytecode. */
41+
void Compiler::compile(std::shared_ptr<Block> topLevelBlock)
42+
{
43+
init();
44+
3445
impl->block = topLevelBlock;
3546
while (impl->block) {
3647
size_t substacks = impl->substackTree.size();
@@ -50,8 +61,19 @@ void Compiler::compile(std::shared_ptr<Block> topLevelBlock)
5061
impl->substackEnd();
5162
}
5263

64+
end();
65+
}
66+
67+
/*! Finalizes the bytecode. Useful if you don't use compile(). */
68+
void Compiler::end()
69+
{
70+
if (!impl->initialized)
71+
return;
72+
5373
// Add end instruction (halt)
5474
addInstruction(OP_HALT);
75+
76+
impl->initialized = false;
5577
}
5678

5779
/*! Returns the generated bytecode. */
@@ -308,3 +330,9 @@ const std::shared_ptr<Block> &Compiler::block() const
308330
{
309331
return impl->block;
310332
}
333+
334+
/*! Sets the current block. Useful if you don't use compile(). */
335+
void Compiler::setBlock(std::shared_ptr<Block> block)
336+
{
337+
impl->block = block;
338+
}

src/engine/compiler_p.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ struct CompilerPrivate
1919
std::shared_ptr<Block> block;
2020
std::vector<std::pair<std::pair<std::shared_ptr<Block>, std::shared_ptr<Block>>, Compiler::SubstackType>> substackTree;
2121

22+
bool initialized = false;
23+
2224
std::vector<unsigned int> bytecode;
2325
std::vector<InputValue *> constValues;
2426
std::vector<Variable *> variables;

test/compiler/compiler_test.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,57 @@ TEST_F(CompilerTest, Constructors)
4848
ASSERT_EQ(compiler.engine(), &engine);
4949
}
5050

51+
TEST_F(CompilerTest, Block)
52+
{
53+
Engine engine;
54+
Compiler compiler(&engine);
55+
ASSERT_EQ(compiler.block(), nullptr);
56+
auto block = std::make_shared<Block>("", "");
57+
compiler.setBlock(block);
58+
ASSERT_EQ(compiler.block(), block);
59+
}
60+
61+
TEST_F(CompilerTest, Init)
62+
{
63+
Engine engine;
64+
Compiler compiler(&engine);
65+
ASSERT_TRUE(compiler.bytecode().empty());
66+
67+
BlockPrototype prototype;
68+
compiler.setProcedurePrototype(&prototype);
69+
compiler.init();
70+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START }));
71+
ASSERT_EQ(compiler.procedurePrototype(), nullptr);
72+
73+
compiler.setProcedurePrototype(&prototype);
74+
compiler.init();
75+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START }));
76+
ASSERT_EQ(compiler.procedurePrototype(), &prototype);
77+
}
78+
79+
TEST_F(CompilerTest, End)
80+
{
81+
Engine engine;
82+
Compiler compiler(&engine);
83+
ASSERT_TRUE(compiler.bytecode().empty());
84+
85+
compiler.end();
86+
ASSERT_TRUE(compiler.bytecode().empty());
87+
88+
compiler.init();
89+
compiler.end();
90+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
91+
compiler.end();
92+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
93+
94+
compiler.init();
95+
compiler.init();
96+
compiler.end();
97+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
98+
99+
compiler.init();
100+
}
101+
51102
TEST_F(CompilerTest, ConstValues)
52103
{
53104
InputValue v1;

0 commit comments

Comments
 (0)