Skip to content

Commit 545df0c

Browse files
committed
Implement data_deleteoflist
1 parent 8fbb31c commit 545df0c

File tree

3 files changed

+135
-0
lines changed

3 files changed

+135
-0
lines changed

src/dev/blocks/listblocks.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ std::string ListBlocks::description() const
2323
void ListBlocks::registerBlocks(IEngine *engine)
2424
{
2525
engine->addCompileFunction(this, "data_addtolist", &compileAddToList);
26+
engine->addCompileFunction(this, "data_deleteoflist", &compileDeleteOfList);
2627
}
2728

2829
CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
@@ -35,3 +36,58 @@ CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
3536

3637
return nullptr;
3738
}
39+
40+
CompilerValue *ListBlocks::getListIndex(Compiler *compiler, CompilerValue *input, List *list)
41+
{
42+
CompilerLocalVariable *ret = compiler->createLocalVariable(Compiler::StaticType::Number);
43+
CompilerValue *size = compiler->addListSize(list);
44+
45+
CompilerValue *isRandom1 = compiler->createCmpEQ(input, compiler->addConstValue("random"));
46+
CompilerValue *isRandom2 = compiler->createCmpEQ(input, compiler->addConstValue("any"));
47+
CompilerValue *isRandom = compiler->createOr(isRandom1, isRandom2);
48+
49+
compiler->beginIfStatement(isRandom);
50+
{
51+
CompilerValue *random = compiler->createRandomInt(compiler->addConstValue(1), size);
52+
compiler->createLocalVariableWrite(ret, random);
53+
}
54+
compiler->beginElseBranch();
55+
{
56+
CompilerValue *isLast = compiler->createCmpEQ(input, compiler->addConstValue("last"));
57+
compiler->createLocalVariableWrite(ret, compiler->createSelect(isLast, size, input, Compiler::StaticType::Number));
58+
}
59+
compiler->endIf();
60+
61+
return compiler->addLocalVariableValue(ret);
62+
}
63+
64+
CompilerValue *ListBlocks::compileDeleteOfList(Compiler *compiler)
65+
{
66+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
67+
assert(list);
68+
69+
if (list) {
70+
CompilerValue *index = compiler->addInput("INDEX");
71+
CompilerValue *cond = compiler->createCmpEQ(index, compiler->addConstValue("all"));
72+
compiler->beginIfStatement(cond);
73+
{
74+
compiler->createListClear(list);
75+
}
76+
compiler->beginElseBranch();
77+
{
78+
index = getListIndex(compiler, index, list);
79+
index = compiler->createSub(index, compiler->addConstValue(1));
80+
CompilerValue *min = compiler->addConstValue(-1);
81+
CompilerValue *max = compiler->addListSize(list);
82+
cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
83+
compiler->beginIfStatement(cond);
84+
{
85+
compiler->createListRemove(list, index);
86+
}
87+
compiler->endIf();
88+
}
89+
compiler->endIf();
90+
}
91+
92+
return nullptr;
93+
}

src/dev/blocks/listblocks.h

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

10+
class List;
11+
1012
class ListBlocks : public IExtension
1113
{
1214
public:
@@ -17,6 +19,9 @@ class ListBlocks : public IExtension
1719

1820
private:
1921
static CompilerValue *compileAddToList(Compiler *compiler);
22+
static CompilerValue *getListIndex(Compiler *compiler, CompilerValue *input, List *list);
23+
static CompilerValue *compileDeleteOfList(Compiler *compiler);
24+
static CompilerValue *compileDeleteAllOfList(Compiler *compiler);
2025
};
2126

2227
} // namespace libscratchcpp

test/dev/blocks/list_blocks_test.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@
33
#include <scratchcpp/list.h>
44
#include <scratchcpp/dev/compiler.h>
55
#include <scratchcpp/dev/test/scriptbuilder.h>
6+
#include <scratchcpp/script.h>
7+
#include <scratchcpp/thread.h>
8+
#include <scratchcpp/dev/executioncontext.h>
9+
#include <scratchcpp/dev/executablecode.h>
610
#include <enginemock.h>
11+
#include <randomgeneratormock.h>
712

813
#include "../common.h"
914
#include "dev/blocks/listblocks.h"
1015

1116
using namespace libscratchcpp;
1217
using namespace libscratchcpp::test;
1318

19+
using ::testing::Return;
20+
1421
class ListBlocksTest : public testing::Test
1522
{
1623
public:
@@ -25,6 +32,7 @@ class ListBlocksTest : public testing::Test
2532
Project m_project;
2633
IEngine *m_engine = nullptr;
2734
EngineMock m_engineMock;
35+
RandomGeneratorMock m_rng;
2836
};
2937

3038
TEST_F(ListBlocksTest, AddToList)
@@ -59,3 +67,69 @@ TEST_F(ListBlocksTest, AddToList)
5967
ASSERT_EQ(list1->toString(), "test true");
6068
ASSERT_EQ(list2->toString(), "123 Hello world");
6169
}
70+
71+
TEST_F(ListBlocksTest, DeleteOfList)
72+
{
73+
auto target = std::make_shared<Sprite>();
74+
75+
auto list1 = std::make_shared<List>("", "");
76+
list1->append("Lorem");
77+
list1->append("ipsum");
78+
list1->append("dolor");
79+
list1->append(123);
80+
list1->append(true);
81+
target->addList(list1);
82+
83+
auto list2 = std::make_shared<List>("", "");
84+
list2->append("Hello");
85+
list2->append("world");
86+
list2->append(false);
87+
list2->append(-543.5);
88+
list2->append("abc");
89+
list2->append(52.4);
90+
target->addList(list2);
91+
92+
auto list3 = std::make_shared<List>("", "");
93+
list3->append(1);
94+
list3->append(2);
95+
list3->append(3);
96+
target->addList(list3);
97+
98+
ScriptBuilder builder(m_extension.get(), m_engine, target);
99+
100+
auto addTest = [&builder](const Value &index, std::shared_ptr<List> list) {
101+
builder.addBlock("data_deleteoflist");
102+
builder.addValueInput("INDEX", index);
103+
builder.addEntityField("LIST", list);
104+
return builder.currentBlock();
105+
};
106+
107+
auto block = addTest(1, list1);
108+
addTest(3, list1);
109+
addTest(2, list1);
110+
addTest(0, list1);
111+
addTest(3, list1);
112+
113+
addTest("last", list2);
114+
addTest("random", list2);
115+
addTest("any", list2);
116+
117+
addTest("all", list3);
118+
119+
builder.build();
120+
121+
Compiler compiler(&m_engineMock, target.get());
122+
auto code = compiler.compile(block);
123+
Script script(target.get(), block, &m_engineMock);
124+
script.setCode(code);
125+
Thread thread(target.get(), &m_engineMock, &script);
126+
auto ctx = code->createExecutionContext(&thread);
127+
ctx->setRng(&m_rng);
128+
129+
EXPECT_CALL(m_rng, randint(1, 5)).WillOnce(Return(2));
130+
EXPECT_CALL(m_rng, randint(1, 4)).WillOnce(Return(3));
131+
code->run(ctx.get());
132+
ASSERT_EQ(list1->toString(), "ipsum true");
133+
ASSERT_EQ(list2->toString(), "Hello false abc");
134+
ASSERT_TRUE(list3->empty());
135+
}

0 commit comments

Comments
 (0)