Skip to content

Commit 39aba5d

Browse files
committed
Implement data_itemoflist
1 parent 33f519c commit 39aba5d

File tree

5 files changed

+103
-0
lines changed

5 files changed

+103
-0
lines changed

src/dev/blocks/listblocks.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void ListBlocks::registerBlocks(IEngine *engine)
2727
engine->addCompileFunction(this, "data_deletealloflist", &compileDeleteAllOfList);
2828
engine->addCompileFunction(this, "data_insertatlist", &compileInsertAtList);
2929
engine->addCompileFunction(this, "data_replaceitemoflist", &compileReplaceItemOfList);
30+
engine->addCompileFunction(this, "data_itemoflist", &compileItemOfList);
3031
}
3132

3233
CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
@@ -150,3 +151,22 @@ CompilerValue *ListBlocks::compileReplaceItemOfList(Compiler *compiler)
150151

151152
return nullptr;
152153
}
154+
155+
CompilerValue *ListBlocks::compileItemOfList(Compiler *compiler)
156+
{
157+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
158+
assert(list);
159+
160+
if (list) {
161+
CompilerValue *index = compiler->addInput("INDEX");
162+
CompilerValue *min = compiler->addConstValue(-1);
163+
CompilerValue *max = compiler->addListSize(list);
164+
index = getListIndex(compiler, index, list, max);
165+
index = compiler->createSub(index, compiler->addConstValue(1));
166+
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
167+
CompilerValue *item = compiler->addListItem(list, index);
168+
return compiler->createSelect(cond, item, compiler->addConstValue(Value()), Compiler::StaticType::Unknown);
169+
}
170+
171+
return nullptr;
172+
}

src/dev/blocks/listblocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ListBlocks : public IExtension
2424
static CompilerValue *compileDeleteAllOfList(Compiler *compiler);
2525
static CompilerValue *compileInsertAtList(Compiler *compiler);
2626
static CompilerValue *compileReplaceItemOfList(Compiler *compiler);
27+
static CompilerValue *compileItemOfList(Compiler *compiler);
2728
};
2829

2930
} // namespace libscratchcpp

test/dev/blocks/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ if (LIBSCRATCHCPP_ENABLE_LIST_BLOCKS)
169169
GTest::gmock_main
170170
scratchcpp
171171
scratchcpp_mocks
172+
block_test_deps
172173
)
173174

174175
gtest_discover_tests(list_blocks_test)

test/dev/blocks/list_blocks_test.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
#include <scratchcpp/dev/test/scriptbuilder.h>
66
#include <scratchcpp/script.h>
77
#include <scratchcpp/thread.h>
8+
#include <scratchcpp/block.h>
9+
#include <scratchcpp/input.h>
10+
#include <scratchcpp/field.h>
811
#include <scratchcpp/dev/executioncontext.h>
912
#include <scratchcpp/dev/executablecode.h>
1013
#include <enginemock.h>
1114
#include <randomgeneratormock.h>
1215

1316
#include "../common.h"
17+
#include "util.h"
1418
#include "dev/blocks/listblocks.h"
1519

1620
using namespace libscratchcpp;
@@ -26,6 +30,7 @@ class ListBlocksTest : public testing::Test
2630
m_extension = std::make_unique<ListBlocks>();
2731
m_engine = m_project.engine().get();
2832
m_extension->registerBlocks(m_engine);
33+
registerBlocks(m_engine, m_extension.get());
2934
}
3035

3136
std::unique_ptr<IExtension> m_extension;
@@ -267,3 +272,67 @@ TEST_F(ListBlocksTest, ReplaceItemOfList)
267272
ASSERT_EQ(list1->toString(), "Lorem ipsum dolor sit -53.18");
268273
ASSERT_EQ(list2->toString(), "dolor world false ipsum abc lorem");
269274
}
275+
276+
TEST_F(ListBlocksTest, ItemOfList)
277+
{
278+
auto target = std::make_shared<Sprite>();
279+
280+
auto list = std::make_shared<List>("list", "");
281+
list->append("Lorem");
282+
list->append("ipsum");
283+
list->append("dolor");
284+
list->append(123);
285+
list->append(true);
286+
target->addList(list);
287+
288+
ScriptBuilder builder(m_extension.get(), m_engine, target);
289+
290+
auto addTest = [&builder](const Value &index, std::shared_ptr<List> list) {
291+
builder.addBlock("test_const_string");
292+
builder.addValueInput("STRING", index);
293+
auto valueBlock = builder.takeBlock();
294+
295+
builder.addBlock("data_itemoflist");
296+
builder.addObscuredInput("INDEX", valueBlock);
297+
builder.addEntityField("LIST", list);
298+
auto block = builder.takeBlock();
299+
300+
builder.addBlock("test_print");
301+
builder.addObscuredInput("STRING", block);
302+
return builder.currentBlock();
303+
};
304+
305+
auto block = addTest(3, list);
306+
addTest(5, list);
307+
addTest(0, list);
308+
addTest(6, list);
309+
310+
addTest("last", list);
311+
addTest("random", list);
312+
addTest("any", list);
313+
314+
builder.build();
315+
316+
Compiler compiler(&m_engineMock, target.get());
317+
auto code = compiler.compile(block);
318+
Script script(target.get(), block, &m_engineMock);
319+
script.setCode(code);
320+
Thread thread(target.get(), &m_engineMock, &script);
321+
auto ctx = code->createExecutionContext(&thread);
322+
ctx->setRng(&m_rng);
323+
324+
static const std::string expected =
325+
"dolor\n"
326+
"true\n"
327+
"0\n"
328+
"0\n"
329+
"true\n"
330+
"123\n"
331+
"Lorem\n";
332+
333+
EXPECT_CALL(m_rng, randint(1, 5)).WillOnce(Return(4)).WillOnce(Return(1));
334+
testing::internal::CaptureStdout();
335+
code->run(ctx.get());
336+
ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
337+
ASSERT_EQ(list->toString(), "Lorem ipsum dolor 123 true");
338+
}

test/dev/blocks/util.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ void registerBlocks(IEngine *engine, IExtension *extension)
3535

3636
engine->addCompileFunction(extension, "test_input", [](Compiler *compiler) -> CompilerValue * { return compiler->addInput("INPUT"); });
3737

38+
engine->addCompileFunction(extension, "test_const_string", [](Compiler *compiler) -> CompilerValue * {
39+
auto input = compiler->addInput("STRING");
40+
return compiler->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { input });
41+
});
42+
3843
engine->addCompileFunction(extension, "test_set_var", [](Compiler *compiler) -> CompilerValue * {
3944
Variable *var = static_cast<Variable *>(compiler->field("VARIABLE")->valuePtr().get());
4045
compiler->createVariableWrite(var, compiler->addInput("VALUE"));
@@ -52,4 +57,11 @@ extern "C" bool test_condition()
5257
return conditionReturnValue;
5358
}
5459

60+
extern "C" char *test_const_string(const char *str)
61+
{
62+
char *ret = (char *)malloc((strlen(str) + 1) * sizeof(char));
63+
strcpy(ret, str);
64+
return ret;
65+
}
66+
5567
} // namespace libscratchcpp

0 commit comments

Comments
 (0)