Skip to content

Commit 92ad9fa

Browse files
committed
Compiler: Implement while loop
1 parent 9408959 commit 92ad9fa

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

include/scratchcpp/dev/compiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class LIBSCRATCHCPP_EXPORT Compiler
4141
void moveToIf(std::shared_ptr<Block> substack);
4242
void moveToIfElse(std::shared_ptr<Block> substack1, std::shared_ptr<Block> substack2);
4343
void moveToRepeatLoop(std::shared_ptr<Block> substack);
44+
void moveToWhileLoop(std::shared_ptr<Block> substack);
45+
void beginLoopCondition();
4446
void warp();
4547

4648
Input *input(const std::string &name) const;

src/dev/engine/compiler.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,24 @@ void Compiler::moveToRepeatLoop(std::shared_ptr<Block> substack)
141141
impl->substackEnd();
142142
}
143143

144+
/*! Jumps to the given while loop substack. */
145+
void Compiler::moveToWhileLoop(std::shared_ptr<Block> substack)
146+
{
147+
impl->substackHit = true;
148+
impl->substackTree.push_back({ { impl->block, nullptr }, CompilerPrivate::SubstackType::Loop });
149+
impl->block = substack;
150+
impl->builder->beginWhileLoop();
151+
152+
if (!impl->block)
153+
impl->substackEnd();
154+
}
155+
156+
/*! Begins a while/until loop condition. */
157+
void Compiler::beginLoopCondition()
158+
{
159+
impl->builder->beginLoopCondition();
160+
}
161+
144162
/*! Makes current script run without screen refresh. */
145163
void Compiler::warp()
146164
{

test/dev/compiler/compiler_test.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,96 @@ TEST_F(CompilerTest, MoveToRepeatLoop)
479479
compile(compiler, l1);
480480
}
481481

482+
TEST_F(CompilerTest, MoveToWhileLoop)
483+
{
484+
Compiler compiler(&m_engine, &m_target);
485+
486+
auto l1 = std::make_shared<Block>("", "loop");
487+
l1->setCompileFunction([](Compiler *compiler) {
488+
EXPECT_CALL(*m_builder, beginWhileLoop());
489+
EXPECT_CALL(*m_builder, endLoop());
490+
compiler->moveToWhileLoop(nullptr);
491+
});
492+
493+
auto l2 = std::make_shared<Block>("", "loop");
494+
l1->setNext(l2);
495+
l2->setParent(l1);
496+
l2->setCompileFunction([](Compiler *compiler) {
497+
EXPECT_CALL(*m_builder, beginWhileLoop());
498+
EXPECT_CALL(*m_builder, addConstValue(Value(2)));
499+
EXPECT_CALL(*m_builder, endLoop());
500+
compiler->moveToWhileLoop(compiler->input("SUBSTACK")->valueBlock());
501+
});
502+
503+
auto substack = std::make_shared<Block>("", "substack");
504+
substack->setParent(l2);
505+
substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(2); });
506+
507+
auto input = std::make_shared<Input>("SUBSTACK", Input::Type::NoShadow);
508+
input->setValueBlock(substack);
509+
l2->addInput(input);
510+
511+
// Nested
512+
auto l3 = std::make_shared<Block>("", "loop");
513+
l2->setNext(l3);
514+
l3->setParent(l2);
515+
l3->setCompileFunction([](Compiler *compiler) {
516+
EXPECT_CALL(*m_builder, beginWhileLoop()).Times(2);
517+
EXPECT_CALL(*m_builder, endLoop()).Times(2);
518+
EXPECT_CALL(*m_builder, addConstValue(Value(1)));
519+
compiler->moveToWhileLoop(compiler->input("SUBSTACK")->valueBlock());
520+
});
521+
522+
// Begin loop
523+
auto loopSubstack = std::make_shared<Block>("", "loop");
524+
loopSubstack->setParent(l3);
525+
loopSubstack->setCompileFunction([](Compiler *compiler) { compiler->moveToWhileLoop(compiler->input("SUBSTACK")->valueBlock()); });
526+
527+
substack = std::make_shared<Block>("", "substack");
528+
substack->setParent(loopSubstack);
529+
substack->setCompileFunction([](Compiler *compiler) { compiler->addConstValue(1); });
530+
531+
input = std::make_shared<Input>("SUBSTACK", Input::Type::NoShadow);
532+
input->setValueBlock(substack);
533+
loopSubstack->addInput(input);
534+
535+
// End loop
536+
input = std::make_shared<Input>("SUBSTACK", Input::Type::NoShadow);
537+
input->setValueBlock(loopSubstack);
538+
l3->addInput(input);
539+
540+
// Empty loop body
541+
auto l4 = std::make_shared<Block>("", "loop");
542+
l3->setNext(l4);
543+
l4->setParent(l3);
544+
l4->setCompileFunction([](Compiler *compiler) {
545+
EXPECT_CALL(*m_builder, beginWhileLoop());
546+
EXPECT_CALL(*m_builder, endLoop());
547+
compiler->moveToWhileLoop(nullptr);
548+
});
549+
550+
// Code after the loop
551+
auto block = std::make_shared<Block>("", "");
552+
block->setParent(l4);
553+
l4->setNext(block);
554+
block->setCompileFunction([](Compiler *compiler) { compiler->addConstValue("after"); });
555+
556+
EXPECT_CALL(*m_builder, addConstValue(Value("after")));
557+
compile(compiler, l1);
558+
}
559+
560+
TEST_F(CompilerTest, BeginLoopCondition)
561+
{
562+
Compiler compiler(&m_engine, &m_target);
563+
auto block = std::make_shared<Block>("a", "");
564+
block->setCompileFunction([](Compiler *compiler) {
565+
EXPECT_CALL(*m_builder, beginLoopCondition());
566+
compiler->beginLoopCondition();
567+
});
568+
569+
compile(compiler, block);
570+
}
571+
482572
TEST_F(CompilerTest, Input)
483573
{
484574
Compiler compiler(&m_engine, &m_target);

0 commit comments

Comments
 (0)