Skip to content

Commit 6504cdd

Browse files
authored
Merge pull request #631 from scratchcpp/llvm_monitors
Implement monitors
2 parents fdcede5 + e58c9ee commit 6504cdd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+695
-165
lines changed

include/scratchcpp/block.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity
2323
public:
2424
friend class Engine;
2525

26-
Block(const std::string &id, const std::string &opcode);
26+
Block(const std::string &id, const std::string &opcode, bool isMonitorBlock = false);
2727
Block(const Block &) = delete;
2828

2929
CompilerValue *compile(Compiler *compiler);
@@ -90,6 +90,8 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity
9090

9191
InputValue *topLevelReporterInfo();
9292

93+
bool isMonitorBlock() const;
94+
9395
private:
9496
void updateInputMap();
9597
void updateFieldMap();

include/scratchcpp/compiler.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ class LIBSCRATCHCPP_EXPORT Compiler
3838
Unknown
3939
};
4040

41+
enum class CodeType
42+
{
43+
Script,
44+
Reporter,
45+
HatPredicate
46+
};
47+
4148
using ArgTypes = std::vector<StaticType>;
4249
using Args = std::vector<CompilerValue *>;
4350

@@ -49,7 +56,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
4956
Target *target() const;
5057
std::shared_ptr<Block> block() const;
5158

52-
std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock, bool isHatPredicate = false);
59+
std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock, CodeType codeType = CodeType::Script);
5360
void preoptimize();
5461

5562
CompilerValue *addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});

include/scratchcpp/executablecode.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace libscratchcpp
1111

1212
class ExecutionContext;
1313
class Thread;
14+
struct ValueData;
1415

1516
/*! \brief The ExecutableCode class represents the code of a compiled Scratch script. */
1617
class LIBSCRATCHCPP_EXPORT ExecutableCode
@@ -21,6 +22,12 @@ class LIBSCRATCHCPP_EXPORT ExecutableCode
2122
/*! Runs the script until it finishes or yields. */
2223
virtual void run(ExecutionContext *context) = 0;
2324

25+
/*!
26+
* Runs the reporter and returns its return value.
27+
* \note Make sure to call value_free() to free the value.
28+
*/
29+
virtual ValueData runReporter(ExecutionContext *context) = 0;
30+
2431
/*! Runs the hat predicate and returns its return value. */
2532
virtual bool runPredicate(ExecutionContext *context) = 0;
2633

include/scratchcpp/imonitorhandler.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ class LIBSCRATCHCPP_EXPORT IMonitorHandler
1717

1818
virtual void init(Monitor *monitor) = 0;
1919

20-
// TODO: Add onValueChanged()
21-
// virtual void onValueChanged(const VirtualMachine *vm) = 0;
20+
virtual void onValueChanged(const Value &value) = 0;
2221
virtual void onXChanged(int x) = 0;
2322
virtual void onYChanged(int y) = 0;
2423
virtual void onVisibleChanged(bool visible) = 0;

include/scratchcpp/monitor.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ class LIBSCRATCHCPP_EXPORT Monitor : public Entity
5656

5757
const std::string &opcode() const;
5858

59-
// TODO: Add updateValue()
60-
// void updateValue(const VirtualMachine *vm);
59+
void updateValue(const Value &value);
6160

6261
void setValueChangeFunction(MonitorChangeFunc f);
6362
void changeValue(const Value &newValue);

include/scratchcpp/thread.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#pragma once
44

5-
#include "global.h"
5+
#include "valuedata.h"
66
#include "spimpl.h"
77

88
namespace libscratchcpp
@@ -27,6 +27,7 @@ class LIBSCRATCHCPP_EXPORT Thread
2727
Script *script() const;
2828

2929
void run();
30+
ValueData runReporter();
3031
bool runPredicate();
3132
void kill();
3233
void reset();

src/blocks/listblocks.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <scratchcpp/iengine.h>
44
#include <scratchcpp/compiler.h>
55
#include <scratchcpp/compilerconstant.h>
6+
#include <scratchcpp/block.h>
67
#include <scratchcpp/field.h>
78
#include <scratchcpp/list.h>
89

@@ -27,6 +28,8 @@ Rgb ListBlocks::color() const
2728

2829
void ListBlocks::registerBlocks(IEngine *engine)
2930
{
31+
// Blocks
32+
engine->addCompileFunction(this, "data_listcontents", &compileListContents);
3033
engine->addCompileFunction(this, "data_addtolist", &compileAddToList);
3134
engine->addCompileFunction(this, "data_deleteoflist", &compileDeleteOfList);
3235
engine->addCompileFunction(this, "data_deletealloflist", &compileDeleteAllOfList);
@@ -36,6 +39,24 @@ void ListBlocks::registerBlocks(IEngine *engine)
3639
engine->addCompileFunction(this, "data_itemnumoflist", &compileItemNumOfList);
3740
engine->addCompileFunction(this, "data_lengthoflist", &compileLengthOfList);
3841
engine->addCompileFunction(this, "data_listcontainsitem", &compileListContainsItem);
42+
43+
// Monitor names
44+
engine->addMonitorNameFunction(this, "data_listcontents", &listContentsMonitorName);
45+
}
46+
47+
CompilerValue *ListBlocks::compileListContents(Compiler *compiler)
48+
{
49+
auto list = compiler->field("LIST")->valuePtr();
50+
assert(list);
51+
52+
// If this block is used in a list monitor, return the list pointer
53+
if (compiler->block()->isMonitorBlock()) {
54+
// TODO: Refactor this
55+
// List monitors expect a reference to the list
56+
// We don't have a list reference type, so cast the pointer to number
57+
return compiler->addConstValue((uintptr_t)list.get());
58+
} else
59+
return compiler->addListContents(static_cast<List *>(list.get()));
3960
}
4061

4162
CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
@@ -194,3 +215,19 @@ CompilerValue *ListBlocks::compileListContainsItem(Compiler *compiler)
194215

195216
return nullptr;
196217
}
218+
219+
const std::string &ListBlocks::listContentsMonitorName(Block *block)
220+
{
221+
static const std::string empty = "";
222+
auto field = block->fieldAt(block->findField("LIST"));
223+
224+
if (!field)
225+
return empty;
226+
227+
List *list = dynamic_cast<List *>(field->valuePtr().get());
228+
229+
if (list)
230+
return list->name();
231+
else
232+
return empty;
233+
}

src/blocks/listblocks.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class ListBlocks : public IExtension
1919
void registerBlocks(IEngine *engine) override;
2020

2121
private:
22+
static CompilerValue *compileListContents(Compiler *compiler);
2223
static CompilerValue *compileAddToList(Compiler *compiler);
2324
static CompilerValue *getListIndex(Compiler *compiler, CompilerValue *input, List *list, CompilerValue *listSize);
2425
static CompilerValue *compileDeleteOfList(Compiler *compiler);
@@ -29,6 +30,8 @@ class ListBlocks : public IExtension
2930
static CompilerValue *compileItemNumOfList(Compiler *compiler);
3031
static CompilerValue *compileLengthOfList(Compiler *compiler);
3132
static CompilerValue *compileListContainsItem(Compiler *compiler);
33+
34+
static const std::string &listContentsMonitorName(Block *block);
3235
};
3336

3437
} // namespace libscratchcpp

src/blocks/variableblocks.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <scratchcpp/iengine.h>
44
#include <scratchcpp/compiler.h>
55
#include <scratchcpp/compilerconstant.h>
6+
#include <scratchcpp/block.h>
67
#include <scratchcpp/input.h>
78
#include <scratchcpp/field.h>
89
#include <scratchcpp/variable.h>
@@ -28,9 +29,16 @@ Rgb VariableBlocks::color() const
2829

2930
void VariableBlocks::registerBlocks(IEngine *engine)
3031
{
32+
// Blocks
3133
engine->addCompileFunction(this, "data_variable", &compileVariable);
3234
engine->addCompileFunction(this, "data_setvariableto", &compileSetVariableTo);
3335
engine->addCompileFunction(this, "data_changevariableby", &compileChangeVariableBy);
36+
37+
// Monitor names
38+
engine->addMonitorNameFunction(this, "data_variable", &variableMonitorName);
39+
40+
// Monitor change functions
41+
engine->addMonitorChangeFunction(this, "data_variable", &changeVariableMonitorValue);
3442
}
3543

3644
CompilerValue *VariableBlocks::compileVariable(Compiler *compiler)
@@ -70,3 +78,33 @@ CompilerValue *VariableBlocks::compileChangeVariableBy(Compiler *compiler)
7078

7179
return nullptr;
7280
}
81+
82+
const std::string &VariableBlocks::variableMonitorName(Block *block)
83+
{
84+
static const std::string empty = "";
85+
86+
auto field = block->fieldAt(block->findField("VARIABLE"));
87+
88+
if (!field)
89+
return empty;
90+
91+
Variable *var = dynamic_cast<Variable *>(field->valuePtr().get());
92+
93+
if (var)
94+
return var->name();
95+
else
96+
return empty;
97+
}
98+
99+
void VariableBlocks::changeVariableMonitorValue(Block *block, const Value &newValue)
100+
{
101+
auto field = block->fieldAt(block->findField("VARIABLE"));
102+
103+
if (!field)
104+
return;
105+
106+
Variable *var = dynamic_cast<Variable *>(field->valuePtr().get());
107+
108+
if (var)
109+
var->setValue(newValue);
110+
}

src/blocks/variableblocks.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class VariableBlocks : public IExtension
2020
static CompilerValue *compileVariable(Compiler *compiler);
2121
static CompilerValue *compileSetVariableTo(Compiler *compiler);
2222
static CompilerValue *compileChangeVariableBy(Compiler *compiler);
23+
24+
static const std::string &variableMonitorName(Block *block);
25+
static void changeVariableMonitorValue(Block *block, const Value &newValue);
2326
};
2427

2528
} // namespace libscratchcpp

src/engine/compiler.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ std::shared_ptr<libscratchcpp::Block> Compiler::block() const
4444
}
4545

4646
/*! Compiles the script starting with the given block. */
47-
std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBlock, bool isHatPredicate)
47+
std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBlock, CodeType codeType)
4848
{
4949
BlockPrototype *procedurePrototype = nullptr;
5050

@@ -60,14 +60,14 @@ std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBl
6060
}
6161
}
6262

63-
impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, isHatPredicate);
63+
impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, codeType);
6464
impl->substackTree.clear();
6565
impl->substackHit = false;
6666
impl->emptySubstack = false;
6767
impl->warp = false;
6868
impl->block = startBlock;
6969

70-
if (impl->block && isHatPredicate) {
70+
if (impl->block && codeType == CodeType::HatPredicate) {
7171
auto f = impl->block->hatPredicateCompileFunction();
7272

7373
if (f) {

src/engine/internal/codebuilderfactory.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ std::shared_ptr<CodeBuilderFactory> CodeBuilderFactory::instance()
1313
return m_instance;
1414
}
1515

16-
std::shared_ptr<ICodeBuilder> CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const
16+
std::shared_ptr<ICodeBuilder> CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) const
1717
{
1818
assert(dynamic_cast<LLVMCompilerContext *>(ctx));
19-
return std::make_shared<LLVMCodeBuilder>(static_cast<LLVMCompilerContext *>(ctx), procedurePrototype, isPredicate);
19+
return std::make_shared<LLVMCodeBuilder>(static_cast<LLVMCompilerContext *>(ctx), procedurePrototype, codeType);
2020
}
2121

2222
std::shared_ptr<CompilerContext> CodeBuilderFactory::createCtx(IEngine *engine, Target *target) const

src/engine/internal/codebuilderfactory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class CodeBuilderFactory : public ICodeBuilderFactory
1111
{
1212
public:
1313
static std::shared_ptr<CodeBuilderFactory> instance();
14-
std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const override;
14+
std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) const override;
1515
std::shared_ptr<CompilerContext> createCtx(IEngine *engine, Target *target) const override;
1616

1717
private:

src/engine/internal/engine.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ void Engine::compile()
276276
script->setCode(compiler.compile(block));
277277

278278
if (block->hatPredicateCompileFunction())
279-
script->setHatPredicateCode(compiler.compile(block, true));
279+
script->setHatPredicateCode(compiler.compile(block, Compiler::CodeType::HatPredicate));
280280
} else {
281281
std::cout << "warning: unsupported top level block: " << block->opcode() << std::endl;
282282
m_unsupportedBlocks.insert(block->opcode());
@@ -468,10 +468,10 @@ void Engine::updateMonitors()
468468
auto script = monitor->script();
469469

470470
if (script) {
471-
// TODO: Implement this
472-
/*auto thread = script->start();
473-
thread->run();
474-
monitor->updateValue(thread->vm());*/
471+
auto thread = script->start();
472+
ValueData value = thread->runReporter();
473+
monitor->updateValue(Value(value));
474+
value_free(&value);
475475
}
476476
}
477477
}
@@ -1851,7 +1851,35 @@ int Engine::resolveFieldValue(IExtension *extension, const std::string &value) c
18511851

18521852
void Engine::compileMonitor(std::shared_ptr<Monitor> monitor)
18531853
{
1854-
// TODO: Implement this
1854+
Target *target = monitor->sprite() ? static_cast<Target *>(monitor->sprite()) : stage();
1855+
auto block = monitor->block();
1856+
auto ext = blockExtension(block->opcode());
1857+
1858+
if (ext) {
1859+
auto ctx = Compiler::createContext(this, target);
1860+
Compiler compiler(ctx.get());
1861+
MonitorNameFunc nameFunc = resolveMonitorNameFunc(ext, block->opcode());
1862+
1863+
if (nameFunc)
1864+
monitor->setName(nameFunc(block.get()));
1865+
1866+
MonitorChangeFunc changeFunc = resolveMonitorChangeFunc(ext, block->opcode());
1867+
monitor->setValueChangeFunction(changeFunc);
1868+
1869+
auto script = std::make_shared<Script>(target, block, this);
1870+
monitor->setScript(script);
1871+
auto code = compiler.compile(block, Compiler::CodeType::Reporter);
1872+
script->setCode(code);
1873+
m_monitorCompilerContexts[monitor.get()] = ctx;
1874+
1875+
const auto &unsupportedBlocks = compiler.unsupportedBlocks();
1876+
1877+
for (const std::string &opcode : unsupportedBlocks)
1878+
m_unsupportedBlocks.insert(opcode);
1879+
} else {
1880+
std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl;
1881+
m_unsupportedBlocks.insert(block->opcode());
1882+
}
18551883
}
18561884

18571885
void Engine::finalize()

src/engine/internal/engine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ class Engine : public IEngine
237237

238238
std::vector<std::shared_ptr<Target>> m_targets;
239239
std::unordered_map<Target *, std::shared_ptr<CompilerContext>> m_compilerContexts;
240+
std::unordered_map<Monitor *, std::shared_ptr<CompilerContext>> m_monitorCompilerContexts; // TODO: Use shared_ptr in (LLVM)ExecutableCode and remove these maps (might not be a good idea)
240241
std::vector<std::shared_ptr<Broadcast>> m_broadcasts;
241242
std::unordered_map<Broadcast *, std::vector<Script *>> m_broadcastMap;
242243
std::unordered_map<Broadcast *, std::vector<Script *>> m_backdropBroadcastMap;

src/engine/internal/icodebuilderfactory.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,20 @@
22

33
#pragma once
44

5+
#include <scratchcpp/compiler.h>
56
#include <memory>
67

78
namespace libscratchcpp
89
{
910

1011
class ICodeBuilder;
11-
class CompilerContext;
12-
class BlockPrototype;
13-
class Target;
14-
class IEngine;
1512

1613
class ICodeBuilderFactory
1714
{
1815
public:
1916
virtual ~ICodeBuilderFactory() { }
2017

21-
virtual std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, bool isPredicate = false) const = 0;
18+
virtual std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype = nullptr, Compiler::CodeType codeType = Compiler::CodeType::Script) const = 0;
2219
virtual std::shared_ptr<CompilerContext> createCtx(IEngine *engine, Target *target) const = 0;
2320
};
2421

0 commit comments

Comments
 (0)