Skip to content

Commit ea0c7eb

Browse files
committed
Implement data_showlist block
1 parent 8c22d09 commit ea0c7eb

File tree

3 files changed

+161
-0
lines changed

3 files changed

+161
-0
lines changed

src/blocks/listblocks.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <scratchcpp/field.h>
66
#include <scratchcpp/block.h>
77
#include <scratchcpp/list.h>
8+
#include <scratchcpp/stage.h>
9+
#include <scratchcpp/monitor.h>
810

911
#include "listblocks.h"
1012

@@ -33,6 +35,7 @@ void ListBlocks::registerBlocks(IEngine *engine)
3335
engine->addCompileFunction(this, "data_itemnumoflist", &compileItemNumberInList);
3436
engine->addCompileFunction(this, "data_lengthoflist", &compileLengthOfList);
3537
engine->addCompileFunction(this, "data_listcontainsitem", &compileListContainsItem);
38+
engine->addCompileFunction(this, "data_showlist", &compileShowList);
3639

3740
// Monitor names
3841
engine->addMonitorNameFunction(this, "data_listcontents", &listContentsMonitorName);
@@ -107,6 +110,49 @@ void ListBlocks::compileListContainsItem(Compiler *compiler)
107110
compiler->addInstruction(vm::OP_LIST_CONTAINS, { compiler->listIndex(compiler->field(LIST)->valuePtr()) });
108111
}
109112

113+
void ListBlocks::compileShowList(Compiler *compiler)
114+
{
115+
Field *field = compiler->field(LIST);
116+
assert(field);
117+
List *var = static_cast<List *>(field->valuePtr().get());
118+
assert(var);
119+
120+
compiler->addConstValue(var->id());
121+
122+
if (var->target() == static_cast<Target *>(compiler->engine()->stage()))
123+
compiler->addFunctionCall(&showGlobalList);
124+
else
125+
compiler->addFunctionCall(&showList);
126+
}
127+
128+
void ListBlocks::setListVisible(std::shared_ptr<List> list, bool visible)
129+
{
130+
if (list) {
131+
assert(list->monitor());
132+
list->monitor()->setVisible(visible);
133+
}
134+
}
135+
136+
unsigned int ListBlocks::showGlobalList(VirtualMachine *vm)
137+
{
138+
if (Stage *target = vm->engine()->stage()) {
139+
int index = target->findListById(vm->getInput(0, 1)->toString());
140+
setListVisible(target->listAt(index), true);
141+
}
142+
143+
return 1;
144+
}
145+
146+
unsigned int ListBlocks::showList(VirtualMachine *vm)
147+
{
148+
if (Target *target = vm->target()) {
149+
int index = target->findListById(vm->getInput(0, 1)->toString());
150+
setListVisible(target->listAt(index), true);
151+
}
152+
153+
return 1;
154+
}
155+
110156
const std::string &ListBlocks::listContentsMonitorName(Block *block)
111157
{
112158
List *list = dynamic_cast<List *>(block->findFieldById(LIST)->valuePtr().get());

src/blocks/listblocks.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace libscratchcpp
88
{
99

1010
class Compiler;
11+
class List;
1112

1213
/*! \brief The ListBlocks class contains the implementation of list blocks. */
1314
class ListBlocks : public IBlockSection
@@ -39,6 +40,12 @@ class ListBlocks : public IBlockSection
3940
static void compileItemNumberInList(Compiler *compiler);
4041
static void compileLengthOfList(Compiler *compiler);
4142
static void compileListContainsItem(Compiler *compiler);
43+
static void compileShowList(Compiler *compiler);
44+
45+
static void setListVisible(std::shared_ptr<List> list, bool visible);
46+
47+
static unsigned int showGlobalList(VirtualMachine *vm);
48+
static unsigned int showList(VirtualMachine *vm);
4249

4350
static const std::string &listContentsMonitorName(Block *block);
4451

test/blocks/list_blocks_test.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <scratchcpp/input.h>
44
#include <scratchcpp/field.h>
55
#include <scratchcpp/list.h>
6+
#include <scratchcpp/stage.h>
7+
#include <scratchcpp/monitor.h>
68
#include <enginemock.h>
79

810
#include "../common.h"
@@ -11,6 +13,8 @@
1113

1214
using namespace libscratchcpp;
1315

16+
using ::testing::Return;
17+
1418
class ListBlocksTest : public testing::Test
1519
{
1620
public:
@@ -104,6 +108,7 @@ TEST_F(ListBlocksTest, RegisterBlocks)
104108
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "data_itemnumoflist", &ListBlocks::compileItemNumberInList)).Times(1);
105109
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "data_lengthoflist", &ListBlocks::compileLengthOfList)).Times(1);
106110
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "data_listcontainsitem", &ListBlocks::compileListContainsItem)).Times(1);
111+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "data_showlist", &ListBlocks::compileShowList)).Times(1);
107112

108113
// Monitor names
109114
EXPECT_CALL(m_engineMock, addMonitorNameFunction(m_section.get(), "data_listcontents", &ListBlocks::listContentsMonitorName));
@@ -435,3 +440,106 @@ TEST_F(ListBlocksTest, ListContainsItem)
435440
list2.get(),
436441
}));
437442
}
443+
444+
TEST_F(ListBlocksTest, ShowList)
445+
{
446+
Compiler compiler(&m_engineMock);
447+
Stage stage;
448+
Target target;
449+
450+
// show list [list1]
451+
auto list1 = std::make_shared<List>("b", "list1");
452+
list1->setTarget(&stage);
453+
auto block1 = createListBlock("a", "data_showlist", list1);
454+
455+
// show list [list2]
456+
auto list2 = std::make_shared<List>("d", "list2");
457+
list2->setTarget(&target);
458+
auto block2 = createListBlock("c", "data_showlist", list2);
459+
460+
EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage));
461+
EXPECT_CALL(m_engineMock, functionIndex(&ListBlocks::showGlobalList)).WillOnce(Return(0));
462+
compiler.init();
463+
compiler.setBlock(block1);
464+
ListBlocks::compileShowList(&compiler);
465+
466+
EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage));
467+
EXPECT_CALL(m_engineMock, functionIndex(&ListBlocks::showList)).WillOnce(Return(1));
468+
compiler.setBlock(block2);
469+
ListBlocks::compileShowList(&compiler);
470+
compiler.end();
471+
472+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_HALT }));
473+
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ "b", "d" }));
474+
ASSERT_TRUE(compiler.variables().empty());
475+
ASSERT_TRUE(compiler.lists().empty());
476+
}
477+
478+
TEST_F(ListBlocksTest, ShowListImpl)
479+
{
480+
static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT };
481+
static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT };
482+
static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_EXEC, 1, vm::OP_HALT };
483+
static unsigned int bytecode4[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_EXEC, 1, vm::OP_HALT };
484+
static BlockFunc functions[] = { &ListBlocks::showGlobalList, &ListBlocks::showList };
485+
static Value constValues[] = { "a", "b", "c", "d" };
486+
487+
auto list1 = std::make_shared<List>("b", "");
488+
Monitor monitor1("b", "");
489+
monitor1.setVisible(false);
490+
list1->setMonitor(&monitor1);
491+
492+
auto list2 = std::make_shared<List>("d", "");
493+
Monitor monitor2("d", "");
494+
monitor2.setVisible(false);
495+
list2->setMonitor(&monitor2);
496+
497+
Stage stage;
498+
stage.addList(list1);
499+
500+
Target target;
501+
target.addList(list2);
502+
503+
// Global
504+
VirtualMachine vm1(&stage, &m_engineMock, nullptr);
505+
vm1.setBytecode(bytecode1);
506+
vm1.setFunctions(functions);
507+
vm1.setConstValues(constValues);
508+
509+
EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage));
510+
vm1.run();
511+
512+
ASSERT_EQ(vm1.registerCount(), 0);
513+
ASSERT_FALSE(monitor1.visible());
514+
ASSERT_FALSE(monitor2.visible());
515+
516+
EXPECT_CALL(m_engineMock, stage()).WillOnce(Return(&stage));
517+
vm1.reset();
518+
vm1.setBytecode(bytecode2);
519+
vm1.run();
520+
521+
ASSERT_EQ(vm1.registerCount(), 0);
522+
ASSERT_TRUE(monitor1.visible());
523+
ASSERT_FALSE(monitor2.visible());
524+
525+
monitor1.setVisible(false);
526+
527+
// Local
528+
VirtualMachine vm2(&target, &m_engineMock, nullptr);
529+
vm2.setBytecode(bytecode3);
530+
vm2.setFunctions(functions);
531+
vm2.setConstValues(constValues);
532+
vm2.run();
533+
534+
ASSERT_EQ(vm2.registerCount(), 0);
535+
ASSERT_FALSE(monitor1.visible());
536+
ASSERT_FALSE(monitor2.visible());
537+
538+
vm2.reset();
539+
vm2.setBytecode(bytecode4);
540+
vm2.run();
541+
542+
ASSERT_EQ(vm2.registerCount(), 0);
543+
ASSERT_FALSE(monitor1.visible());
544+
ASSERT_TRUE(monitor2.visible());
545+
}

0 commit comments

Comments
 (0)