Skip to content

Commit 1da38a7

Browse files
authored
Merge pull request #612 from scratchcpp/llvm_list_blocks
LLVM: Implement list blocks
2 parents e4944e1 + 0d91530 commit 1da38a7

29 files changed

+1357
-64
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ if (LIBSCRATCHCPP_USE_LLVM)
7676
include/scratchcpp/dev/compiler.h
7777
include/scratchcpp/dev/compilervalue.h
7878
include/scratchcpp/dev/compilerconstant.h
79+
include/scratchcpp/dev/compilerlocalvariable.h
7980
include/scratchcpp/dev/executablecode.h
8081
include/scratchcpp/dev/executioncontext.h
8182
include/scratchcpp/dev/promise.h

include/scratchcpp/dev/compiler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Target;
1616
class ExecutableCode;
1717
class CompilerValue;
1818
class CompilerConstant;
19+
class CompilerLocalVariable;
1920
class Variable;
2021
class List;
2122
class Input;
@@ -52,6 +53,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
5253
CompilerValue *addFunctionCallWithCtx(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});
5354
CompilerConstant *addConstValue(const Value &value);
5455
CompilerValue *addLoopIndex();
56+
CompilerValue *addLocalVariableValue(CompilerLocalVariable *variable);
5557
CompilerValue *addVariableValue(Variable *variable);
5658
CompilerValue *addListContents(List *list);
5759
CompilerValue *addListItem(List *list, CompilerValue *index);
@@ -66,6 +68,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
6668
CompilerValue *createDiv(CompilerValue *operand1, CompilerValue *operand2);
6769

6870
CompilerValue *createRandom(CompilerValue *from, CompilerValue *to);
71+
CompilerValue *createRandomInt(CompilerValue *from, CompilerValue *to);
6972

7073
CompilerValue *createCmpEQ(CompilerValue *operand1, CompilerValue *operand2);
7174
CompilerValue *createCmpGT(CompilerValue *operand1, CompilerValue *operand2);
@@ -94,6 +97,9 @@ class LIBSCRATCHCPP_EXPORT Compiler
9497

9598
CompilerValue *createSelect(CompilerValue *cond, CompilerValue *trueValue, CompilerValue *falseValue, Compiler::StaticType valueType);
9699

100+
CompilerLocalVariable *createLocalVariable(Compiler::StaticType type);
101+
void createLocalVariableWrite(CompilerLocalVariable *variable, CompilerValue *value);
102+
97103
void createVariableWrite(Variable *variable, CompilerValue *value);
98104

99105
void createListClear(List *list);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include "compiler.h"
6+
7+
namespace libscratchcpp
8+
{
9+
10+
class CompilerLocalVariablePrivate;
11+
12+
/*! \brief The CompilerLocalVariable class represents a statically typed local variable in compiled code. */
13+
class LIBSCRATCHCPP_EXPORT CompilerLocalVariable
14+
{
15+
public:
16+
CompilerLocalVariable(CompilerValue *ptr);
17+
CompilerLocalVariable(const CompilerLocalVariable &) = delete;
18+
19+
CompilerValue *ptr() const;
20+
Compiler::StaticType type() const;
21+
22+
private:
23+
spimpl::unique_impl_ptr<CompilerLocalVariablePrivate> impl;
24+
};
25+
26+
} // namespace libscratchcpp

include/scratchcpp/dev/test/scriptbuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ class LIBSCRATCHCPP_EXPORT ScriptBuilder
3131
~ScriptBuilder();
3232

3333
void addBlock(const std::string &opcode);
34-
void addReporterBlock(const std::string &opcode);
3534
void captureBlockReturnValue();
3635

3736
void addValueInput(const std::string &name, const Value &value);
@@ -47,6 +46,7 @@ class LIBSCRATCHCPP_EXPORT ScriptBuilder
4746
void addEntityField(const std::string &name, std::shared_ptr<Entity> entity);
4847

4948
std::shared_ptr<Block> currentBlock();
49+
std::shared_ptr<Block> takeBlock();
5050

5151
void build();
5252
void run();

src/dev/blocks/listblocks.cpp

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3+
#include <scratchcpp/iengine.h>
4+
#include <scratchcpp/dev/compiler.h>
5+
#include <scratchcpp/dev/compilerconstant.h>
6+
#include <scratchcpp/field.h>
7+
#include <scratchcpp/list.h>
8+
39
#include "listblocks.h"
410

511
using namespace libscratchcpp;
@@ -16,4 +22,191 @@ std::string ListBlocks::description() const
1622

1723
void ListBlocks::registerBlocks(IEngine *engine)
1824
{
25+
engine->addCompileFunction(this, "data_addtolist", &compileAddToList);
26+
engine->addCompileFunction(this, "data_deleteoflist", &compileDeleteOfList);
27+
engine->addCompileFunction(this, "data_deletealloflist", &compileDeleteAllOfList);
28+
engine->addCompileFunction(this, "data_insertatlist", &compileInsertAtList);
29+
engine->addCompileFunction(this, "data_replaceitemoflist", &compileReplaceItemOfList);
30+
engine->addCompileFunction(this, "data_itemoflist", &compileItemOfList);
31+
engine->addCompileFunction(this, "data_itemnumoflist", &compileItemNumOfList);
32+
engine->addCompileFunction(this, "data_lengthoflist", &compileLengthOfList);
33+
engine->addCompileFunction(this, "data_listcontainsitem", &compileListContainsItem);
34+
}
35+
36+
CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
37+
{
38+
auto list = compiler->field("LIST")->valuePtr();
39+
assert(list);
40+
41+
if (list)
42+
compiler->createListAppend(static_cast<List *>(list.get()), compiler->addInput("ITEM"));
43+
44+
return nullptr;
45+
}
46+
47+
CompilerValue *ListBlocks::getListIndex(Compiler *compiler, CompilerValue *input, List *list, CompilerValue *listSize)
48+
{
49+
CompilerLocalVariable *ret = compiler->createLocalVariable(Compiler::StaticType::Number);
50+
51+
CompilerValue *isRandom1 = compiler->createCmpEQ(input, compiler->addConstValue("random"));
52+
CompilerValue *isRandom2 = compiler->createCmpEQ(input, compiler->addConstValue("any"));
53+
CompilerValue *isRandom = compiler->createOr(isRandom1, isRandom2);
54+
55+
compiler->beginIfStatement(isRandom);
56+
{
57+
CompilerValue *random = compiler->createRandomInt(compiler->addConstValue(1), listSize);
58+
compiler->createLocalVariableWrite(ret, random);
59+
}
60+
compiler->beginElseBranch();
61+
{
62+
CompilerValue *isLast = compiler->createCmpEQ(input, compiler->addConstValue("last"));
63+
compiler->createLocalVariableWrite(ret, compiler->createSelect(isLast, listSize, input, Compiler::StaticType::Number));
64+
}
65+
compiler->endIf();
66+
67+
return compiler->addLocalVariableValue(ret);
68+
}
69+
70+
CompilerValue *ListBlocks::compileDeleteOfList(Compiler *compiler)
71+
{
72+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
73+
assert(list);
74+
75+
if (list) {
76+
CompilerValue *index = compiler->addInput("INDEX");
77+
CompilerValue *cond = compiler->createCmpEQ(index, compiler->addConstValue("all"));
78+
compiler->beginIfStatement(cond);
79+
{
80+
compiler->createListClear(list);
81+
}
82+
compiler->beginElseBranch();
83+
{
84+
CompilerValue *min = compiler->addConstValue(-1);
85+
CompilerValue *max = compiler->addListSize(list);
86+
index = getListIndex(compiler, index, list, max);
87+
index = compiler->createSub(index, compiler->addConstValue(1));
88+
cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
89+
compiler->beginIfStatement(cond);
90+
{
91+
compiler->createListRemove(list, index);
92+
}
93+
compiler->endIf();
94+
}
95+
compiler->endIf();
96+
}
97+
98+
return nullptr;
99+
}
100+
101+
CompilerValue *ListBlocks::compileDeleteAllOfList(Compiler *compiler)
102+
{
103+
auto list = compiler->field("LIST")->valuePtr();
104+
assert(list);
105+
106+
if (list)
107+
compiler->createListClear(static_cast<List *>(list.get()));
108+
109+
return nullptr;
110+
}
111+
112+
CompilerValue *ListBlocks::compileInsertAtList(Compiler *compiler)
113+
{
114+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
115+
assert(list);
116+
117+
if (list) {
118+
CompilerValue *index = compiler->addInput("INDEX");
119+
CompilerValue *min = compiler->addConstValue(-1);
120+
CompilerValue *max = compiler->createAdd(compiler->addListSize(list), compiler->addConstValue(1));
121+
index = getListIndex(compiler, index, list, max);
122+
index = compiler->createSub(index, compiler->addConstValue(1));
123+
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
124+
compiler->beginIfStatement(cond);
125+
{
126+
CompilerValue *item = compiler->addInput("ITEM");
127+
compiler->createListInsert(list, index, item);
128+
}
129+
compiler->endIf();
130+
}
131+
132+
return nullptr;
133+
}
134+
135+
CompilerValue *ListBlocks::compileReplaceItemOfList(Compiler *compiler)
136+
{
137+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
138+
assert(list);
139+
140+
if (list) {
141+
CompilerValue *index = compiler->addInput("INDEX");
142+
CompilerValue *min = compiler->addConstValue(-1);
143+
CompilerValue *max = compiler->addListSize(list);
144+
index = getListIndex(compiler, index, list, max);
145+
index = compiler->createSub(index, compiler->addConstValue(1));
146+
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
147+
compiler->beginIfStatement(cond);
148+
{
149+
CompilerValue *item = compiler->addInput("ITEM");
150+
compiler->createListReplace(list, index, item);
151+
}
152+
compiler->endIf();
153+
}
154+
155+
return nullptr;
156+
}
157+
158+
CompilerValue *ListBlocks::compileItemOfList(Compiler *compiler)
159+
{
160+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
161+
assert(list);
162+
163+
if (list) {
164+
CompilerValue *index = compiler->addInput("INDEX");
165+
CompilerValue *min = compiler->addConstValue(-1);
166+
CompilerValue *max = compiler->addListSize(list);
167+
index = getListIndex(compiler, index, list, max);
168+
index = compiler->createSub(index, compiler->addConstValue(1));
169+
CompilerValue *cond = compiler->createAnd(compiler->createCmpGT(index, min), compiler->createCmpLT(index, max));
170+
CompilerValue *item = compiler->addListItem(list, index);
171+
return compiler->createSelect(cond, item, compiler->addConstValue(Value()), Compiler::StaticType::Unknown);
172+
}
173+
174+
return nullptr;
175+
}
176+
177+
CompilerValue *ListBlocks::compileItemNumOfList(Compiler *compiler)
178+
{
179+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
180+
assert(list);
181+
182+
if (list) {
183+
CompilerValue *item = compiler->addInput("ITEM");
184+
return compiler->createAdd(compiler->addListItemIndex(list, item), compiler->addConstValue(1));
185+
}
186+
187+
return nullptr;
188+
}
189+
190+
CompilerValue *ListBlocks::compileLengthOfList(Compiler *compiler)
191+
{
192+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
193+
assert(list);
194+
195+
if (list)
196+
return compiler->addListSize(list);
197+
198+
return nullptr;
199+
}
200+
201+
CompilerValue *ListBlocks::compileListContainsItem(Compiler *compiler)
202+
{
203+
List *list = static_cast<List *>(compiler->field("LIST")->valuePtr().get());
204+
assert(list);
205+
206+
if (list) {
207+
CompilerValue *item = compiler->addInput("ITEM");
208+
return compiler->addListContains(list, item);
209+
}
210+
211+
return nullptr;
19212
}

src/dev/blocks/listblocks.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,27 @@
77
namespace libscratchcpp
88
{
99

10+
class List;
11+
1012
class ListBlocks : public IExtension
1113
{
1214
public:
1315
std::string name() const override;
1416
std::string description() const override;
1517

1618
void registerBlocks(IEngine *engine) override;
19+
20+
private:
21+
static CompilerValue *compileAddToList(Compiler *compiler);
22+
static CompilerValue *getListIndex(Compiler *compiler, CompilerValue *input, List *list, CompilerValue *listSize);
23+
static CompilerValue *compileDeleteOfList(Compiler *compiler);
24+
static CompilerValue *compileDeleteAllOfList(Compiler *compiler);
25+
static CompilerValue *compileInsertAtList(Compiler *compiler);
26+
static CompilerValue *compileReplaceItemOfList(Compiler *compiler);
27+
static CompilerValue *compileItemOfList(Compiler *compiler);
28+
static CompilerValue *compileItemNumOfList(Compiler *compiler);
29+
static CompilerValue *compileLengthOfList(Compiler *compiler);
30+
static CompilerValue *compileListContainsItem(Compiler *compiler);
1731
};
1832

1933
} // namespace libscratchcpp

src/dev/engine/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ target_sources(scratchcpp
99
compilerconstant.cpp
1010
compilerconstant_p.cpp
1111
compilerconstant_p.h
12+
compilerlocalvariable.cpp
13+
compilerlocalvariable_p.cpp
14+
compilerlocalvariable_p.h
1215
executioncontext.cpp
1316
executioncontext_p.cpp
1417
executioncontext_p.h

src/dev/engine/compiler.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ CompilerValue *Compiler::addLoopIndex()
127127
return impl->builder->addLoopIndex();
128128
}
129129

130+
/*! Adds the value of the given local variable to the code. */
131+
CompilerValue *Compiler::addLocalVariableValue(CompilerLocalVariable *variable)
132+
{
133+
return impl->builder->addLocalVariableValue(variable);
134+
}
135+
130136
/*! Adds the value of the given variable to the code. */
131137
CompilerValue *Compiler::addVariableValue(Variable *variable)
132138
{
@@ -199,6 +205,15 @@ CompilerValue *Compiler::createRandom(CompilerValue *from, CompilerValue *to)
199205
return impl->builder->createRandom(from, to);
200206
}
201207

208+
/*!
209+
* Creates a random integer instruction.
210+
* \note Infinity or NaN results in undefined behavior.
211+
*/
212+
CompilerValue *Compiler::createRandomInt(CompilerValue *from, CompilerValue *to)
213+
{
214+
return impl->builder->createRandomInt(from, to);
215+
}
216+
202217
/*! Creates an equality comparison instruction. */
203218
CompilerValue *Compiler::createCmpEQ(CompilerValue *operand1, CompilerValue *operand2)
204219
{
@@ -337,6 +352,18 @@ CompilerValue *Compiler::createSelect(CompilerValue *cond, CompilerValue *trueVa
337352
return impl->builder->createSelect(cond, trueValue, falseValue, valueType);
338353
}
339354

355+
/*! Creates a local variable with the given type. */
356+
CompilerLocalVariable *Compiler::createLocalVariable(StaticType type)
357+
{
358+
return impl->builder->createLocalVariable(type);
359+
}
360+
361+
/*! Creates a local variable write operation. */
362+
void Compiler::createLocalVariableWrite(CompilerLocalVariable *variable, CompilerValue *value)
363+
{
364+
impl->builder->createLocalVariableWrite(variable, value);
365+
}
366+
340367
/*! Creates a variable write operation. */
341368
void Compiler::createVariableWrite(Variable *variable, CompilerValue *value)
342369
{
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include <scratchcpp/dev/compilerlocalvariable.h>
4+
#include <scratchcpp/dev/compilervalue.h>
5+
6+
#include "compilerlocalvariable_p.h"
7+
8+
using namespace libscratchcpp;
9+
10+
CompilerLocalVariable::CompilerLocalVariable(CompilerValue *ptr) :
11+
impl(spimpl::make_unique_impl<CompilerLocalVariablePrivate>(ptr))
12+
{
13+
}
14+
15+
CompilerValue *CompilerLocalVariable::ptr() const
16+
{
17+
return impl->ptr;
18+
}
19+
20+
Compiler::StaticType CompilerLocalVariable::type() const
21+
{
22+
return impl->ptr->type();
23+
}

0 commit comments

Comments
 (0)