Skip to content

Commit f29fbc0

Browse files
committed
Compiler: Add API for procedures
1 parent aec52a0 commit f29fbc0

File tree

3 files changed

+99
-4
lines changed

3 files changed

+99
-4
lines changed

include/scratchcpp/dev/compiler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Variable;
2222
class List;
2323
class Input;
2424
class Field;
25+
class BlockPrototype;
2526
class CompilerPrivate;
2627

2728
/*! \brief The Compiler class provides API for compiling Scratch scripts. */
@@ -62,6 +63,8 @@ class LIBSCRATCHCPP_EXPORT Compiler
6263
CompilerValue *addListItemIndex(List *list, CompilerValue *item);
6364
CompilerValue *addListContains(List *list, CompilerValue *item);
6465
CompilerValue *addListSize(List *list);
66+
CompilerValue *addProcedureArgument(const std::string &name);
67+
6568
CompilerValue *addInput(const std::string &name);
6669
CompilerValue *addInput(Input *input);
6770

@@ -130,6 +133,8 @@ class LIBSCRATCHCPP_EXPORT Compiler
130133
void createYield();
131134
void createStop();
132135

136+
void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args);
137+
133138
Input *input(const std::string &name) const;
134139
Field *field(const std::string &name) const;
135140

src/dev/engine/compiler.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,21 @@ std::shared_ptr<libscratchcpp::Block> Compiler::block() const
4646
/*! Compiles the script starting with the given block. */
4747
std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBlock)
4848
{
49-
impl->builder = impl->builderFactory->create(impl->ctx, nullptr);
49+
BlockPrototype *procedurePrototype = nullptr;
50+
51+
if (startBlock) {
52+
// TODO: Move procedure definition logic to the custom blocks extension
53+
auto input = startBlock->inputAt(0);
54+
55+
if (input && input->valueBlock()) {
56+
procedurePrototype = input->valueBlock()->mutationPrototype();
57+
58+
if (procedurePrototype && procedurePrototype->procCode().empty())
59+
procedurePrototype = nullptr;
60+
}
61+
}
62+
63+
impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype);
5064
impl->substackTree.clear();
5165
impl->substackHit = false;
5266
impl->emptySubstack = false;
@@ -176,6 +190,12 @@ CompilerValue *Compiler::addListSize(List *list)
176190
return impl->builder->addListSize(list);
177191
}
178192

193+
/*! Adds the procedure argument with the given name to the code. */
194+
CompilerValue *Compiler::addProcedureArgument(const std::string &name)
195+
{
196+
return impl->builder->addProcedureArgument(name);
197+
}
198+
179199
/*! Compiles the given input (resolved by name) and adds it to the compiled code. */
180200
CompilerValue *Compiler::addInput(const std::string &name)
181201
{
@@ -615,6 +635,12 @@ void Compiler::createStop()
615635
impl->builder->createStop();
616636
}
617637

638+
/*! Creates a call to the procedure with the given prototype. */
639+
void Compiler::createProcedureCall(BlockPrototype *prototype, const libscratchcpp::Compiler::Args &args)
640+
{
641+
impl->builder->createProcedureCall(prototype, args);
642+
}
643+
618644
/*! Convenience method which returns the field with the given name. */
619645
Input *Compiler::input(const std::string &name) const
620646
{

test/dev/compiler/compiler_test.cpp

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,10 @@ class CompilerTest : public testing::Test
4545
m_testVar.reset();
4646
}
4747

48-
void compile(Compiler *compiler, std::shared_ptr<Block> block)
48+
void compile(Compiler *compiler, std::shared_ptr<Block> block, BlockPrototype *procedurePrototype = nullptr)
4949
{
5050
ASSERT_EQ(compiler->block(), nullptr);
51-
// TODO: Test procedures
52-
EXPECT_CALL(m_builderFactory, create(m_ctx.get(), nullptr)).WillOnce(Return(m_builder));
51+
EXPECT_CALL(m_builderFactory, create(m_ctx.get(), procedurePrototype)).WillOnce(Return(m_builder));
5352
EXPECT_CALL(*m_builder, finalize()).WillOnce(Return(m_code));
5453
ASSERT_EQ(compiler->compile(block), m_code);
5554
ASSERT_EQ(compiler->block(), nullptr);
@@ -338,6 +337,25 @@ TEST_F(CompilerTest, AddListContains)
338337
compile(m_compiler.get(), block);
339338
}
340339

340+
TEST_F(CompilerTest, AddProcedureArgument)
341+
{
342+
343+
auto block = std::make_shared<Block>("a", "");
344+
block->setCompileFunction([](Compiler *compiler) -> CompilerValue * {
345+
CompilerValue ret(Compiler::StaticType::Unknown);
346+
347+
EXPECT_CALL(*m_builder, addProcedureArgument("arg 1")).WillOnce(Return(&ret));
348+
EXPECT_EQ(compiler->addProcedureArgument("arg 1"), &ret);
349+
350+
EXPECT_CALL(*m_builder, addProcedureArgument("arg 2")).WillOnce(Return(nullptr));
351+
EXPECT_EQ(compiler->addProcedureArgument("arg 2"), nullptr);
352+
353+
return nullptr;
354+
});
355+
356+
compile(m_compiler.get(), block);
357+
}
358+
341359
TEST_F(CompilerTest, AddInput)
342360
{
343361

@@ -1572,6 +1590,25 @@ TEST_F(CompilerTest, CreateStop)
15721590
compile(m_compiler.get(), block);
15731591
}
15741592

1593+
TEST_F(CompilerTest, CreateProcedureCall)
1594+
{
1595+
1596+
auto block = std::make_shared<Block>("", "");
1597+
1598+
block->setCompileFunction([](Compiler *compiler) -> CompilerValue * {
1599+
BlockPrototype prototype;
1600+
CompilerValue arg1(Compiler::StaticType::Unknown);
1601+
CompilerValue arg2(Compiler::StaticType::Unknown);
1602+
Compiler::Args args = { &arg1, &arg2 };
1603+
1604+
EXPECT_CALL(*m_builder, createProcedureCall(&prototype, args));
1605+
compiler->createProcedureCall(&prototype, args);
1606+
return nullptr;
1607+
});
1608+
1609+
compile(m_compiler.get(), block);
1610+
}
1611+
15751612
TEST_F(CompilerTest, Input)
15761613
{
15771614

@@ -1660,3 +1697,30 @@ TEST_F(CompilerTest, UnsupportedBlocks)
16601697

16611698
ASSERT_EQ(m_compiler->unsupportedBlocks(), std::unordered_set<std::string>({ "block1", "block2", "value_block1", "value_block3", "value_block5", "block4" }));
16621699
}
1700+
1701+
TEST_F(CompilerTest, Procedure)
1702+
{
1703+
{
1704+
auto block = std::make_shared<Block>("", "");
1705+
auto customBlock = std::make_shared<Block>("", "");
1706+
customBlock->mutationPrototype()->setProcCode("");
1707+
1708+
auto input = std::make_shared<Input>("custom_block", Input::Type::ObscuredShadow);
1709+
input->setValueBlock(customBlock);
1710+
block->addInput(input);
1711+
1712+
compile(m_compiler.get(), block, nullptr);
1713+
}
1714+
1715+
{
1716+
auto block = std::make_shared<Block>("", "");
1717+
auto customBlock = std::make_shared<Block>("", "");
1718+
customBlock->mutationPrototype()->setProcCode("test");
1719+
1720+
auto input = std::make_shared<Input>("custom_block", Input::Type::ObscuredShadow);
1721+
input->setValueBlock(customBlock);
1722+
block->addInput(input);
1723+
1724+
compile(m_compiler.get(), block, customBlock->mutationPrototype());
1725+
}
1726+
}

0 commit comments

Comments
 (0)