Skip to content

Commit 9da9b7f

Browse files
committed
Compile blocks of missing monitors
1 parent 082f481 commit 9da9b7f

File tree

7 files changed

+79
-69
lines changed

7 files changed

+79
-69
lines changed

include/scratchcpp/iengine.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,10 +361,10 @@ class LIBSCRATCHCPP_EXPORT IEngine
361361
virtual void setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitors) = 0;
362362

363363
/*! Creates a monitor for the given variable if it's missing and returns it. */
364-
virtual Monitor *createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId) = 0;
364+
virtual Monitor *createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId, BlockComp compileFunction) = 0;
365365

366366
/*! Creates a monitor for the given list if it's missing and returns it. */
367-
virtual Monitor *createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId) = 0;
367+
virtual Monitor *createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId, BlockComp compileFunction) = 0;
368368

369369
/*! Emits when a monitor is added. */
370370
virtual sigslot::signal<Monitor *> &monitorAdded() = 0;

src/blocks/listblocks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ void ListBlocks::setListVisible(std::shared_ptr<List> list, bool visible, IEngin
148148
Monitor *monitor = list->monitor();
149149

150150
if (!monitor)
151-
monitor = engine->createListMonitor(list, "data_listcontents", "LIST", LIST);
151+
monitor = engine->createListMonitor(list, "data_listcontents", "LIST", LIST, &compileListContents);
152152

153153
monitor->setVisible(visible);
154154
}

src/blocks/variableblocks.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void VariableBlocks::setVarVisible(std::shared_ptr<Variable> var, bool visible,
9494
Monitor *monitor = var->monitor();
9595

9696
if (!monitor)
97-
monitor = engine->createVariableMonitor(var, "data_variable", "VARIABLE", VARIABLE);
97+
monitor = engine->createVariableMonitor(var, "data_variable", "VARIABLE", VARIABLE, &compileVariable);
9898

9999
monitor->setVisible(visible);
100100
}

src/engine/internal/engine.cpp

Lines changed: 61 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -312,56 +312,8 @@ void Engine::compile()
312312
// Compile monitor blocks to bytecode
313313
std::cout << "Compiling stage monitors..." << std::endl;
314314

315-
for (auto monitor : m_monitors) {
316-
Target *target = monitor->sprite() ? dynamic_cast<Target *>(monitor->sprite()) : stage();
317-
Compiler compiler(this, target);
318-
auto block = monitor->block();
319-
auto section = blockSection(block->opcode());
320-
auto container = blockSectionContainer(block->opcode());
321-
322-
if (container) {
323-
MonitorNameFunc nameFunc = container->resolveMonitorNameFunc(block->opcode());
324-
325-
if (nameFunc)
326-
monitor->setName(nameFunc(block.get()));
327-
328-
MonitorChangeFunc changeFunc = container->resolveMonitorChangeFunc(block->opcode());
329-
monitor->setValueChangeFunction(changeFunc);
330-
}
331-
332-
if (section) {
333-
auto script = std::make_shared<Script>(target, block, this);
334-
monitor->setScript(script);
335-
compiler.init();
336-
compiler.setBlock(block);
337-
338-
if (block->compileFunction())
339-
block->compile(&compiler);
340-
else
341-
std::cout << "warning: monitor block doesn't have a compile function: " << block->opcode() << std::endl;
342-
343-
// Workaround for register leak warning spam: pause the script after getting the monitor value
344-
compiler.addFunctionCall([](VirtualMachine *vm) -> unsigned int {
345-
vm->stop(false, false, false);
346-
return 0;
347-
});
348-
349-
compiler.end();
350-
351-
script->setBytecode(compiler.bytecode());
352-
script->setConstValues(compiler.constValues());
353-
script->setVariables(compiler.variables());
354-
script->setLists(compiler.lists());
355-
} else {
356-
std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl;
357-
m_unsupportedBlocks.insert(block->opcode());
358-
}
359-
360-
const auto &unsupportedBlocks = compiler.unsupportedBlocks();
361-
362-
for (const std::string &opcode : unsupportedBlocks)
363-
m_unsupportedBlocks.insert(opcode);
364-
}
315+
for (auto monitor : m_monitors)
316+
compileMonitor(monitor);
365317
}
366318

367319
void Engine::start()
@@ -1398,7 +1350,7 @@ void Engine::setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitor
13981350
}
13991351
}
14001352

1401-
Monitor *Engine::createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId)
1353+
Monitor *Engine::createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId, BlockComp compileFunction)
14021354
{
14031355
if (var->monitor())
14041356
return var->monitor();
@@ -1407,14 +1359,16 @@ Monitor *Engine::createVariableMonitor(std::shared_ptr<Variable> var, const std:
14071359
auto field = std::make_shared<Field>(varFieldName, var->name(), var);
14081360
field->setFieldId(varFieldId);
14091361
monitor->block()->addField(field);
1362+
monitor->block()->setCompileFunction(compileFunction);
14101363

14111364
addVarOrListMonitor(monitor, var->target());
14121365
var->setMonitor(monitor.get());
1366+
compileMonitor(monitor);
14131367
return monitor.get();
14141368
}
14151369
}
14161370

1417-
Monitor *Engine::createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId)
1371+
Monitor *Engine::createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId, BlockComp compileFunction)
14181372
{
14191373
if (list->monitor())
14201374
return list->monitor();
@@ -1423,9 +1377,11 @@ Monitor *Engine::createListMonitor(std::shared_ptr<List> list, const std::string
14231377
auto field = std::make_shared<Field>(listFieldName, list->name(), list);
14241378
field->setFieldId(listFieldId);
14251379
monitor->block()->addField(field);
1426-
list->setMonitor(monitor.get());
1380+
monitor->block()->setCompileFunction(compileFunction);
14271381

14281382
addVarOrListMonitor(monitor, list->target());
1383+
list->setMonitor(monitor.get());
1384+
compileMonitor(monitor);
14291385
return monitor.get();
14301386
}
14311387
}
@@ -1783,6 +1739,58 @@ const std::unordered_set<std::string> &Engine::unsupportedBlocks() const
17831739
return m_unsupportedBlocks;
17841740
}
17851741

1742+
void Engine::compileMonitor(std::shared_ptr<Monitor> monitor)
1743+
{
1744+
Target *target = monitor->sprite() ? dynamic_cast<Target *>(monitor->sprite()) : stage();
1745+
Compiler compiler(this, target);
1746+
auto block = monitor->block();
1747+
auto section = blockSection(block->opcode());
1748+
auto container = blockSectionContainer(block->opcode());
1749+
1750+
if (container) {
1751+
MonitorNameFunc nameFunc = container->resolveMonitorNameFunc(block->opcode());
1752+
1753+
if (nameFunc)
1754+
monitor->setName(nameFunc(block.get()));
1755+
1756+
MonitorChangeFunc changeFunc = container->resolveMonitorChangeFunc(block->opcode());
1757+
monitor->setValueChangeFunction(changeFunc);
1758+
}
1759+
1760+
if (section) {
1761+
auto script = std::make_shared<Script>(target, block, this);
1762+
monitor->setScript(script);
1763+
compiler.init();
1764+
compiler.setBlock(block);
1765+
1766+
if (block->compileFunction())
1767+
block->compile(&compiler);
1768+
else
1769+
std::cout << "warning: monitor block doesn't have a compile function: " << block->opcode() << std::endl;
1770+
1771+
// Workaround for register leak warning spam: pause the script after getting the monitor value
1772+
compiler.addFunctionCall([](VirtualMachine *vm) -> unsigned int {
1773+
vm->stop(false, false, false);
1774+
return 0;
1775+
});
1776+
1777+
compiler.end();
1778+
1779+
script->setBytecode(compiler.bytecode());
1780+
script->setConstValues(compiler.constValues());
1781+
script->setVariables(compiler.variables());
1782+
script->setLists(compiler.lists());
1783+
} else {
1784+
std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl;
1785+
m_unsupportedBlocks.insert(block->opcode());
1786+
}
1787+
1788+
const auto &unsupportedBlocks = compiler.unsupportedBlocks();
1789+
1790+
for (const std::string &opcode : unsupportedBlocks)
1791+
m_unsupportedBlocks.insert(opcode);
1792+
}
1793+
17861794
void Engine::finalize()
17871795
{
17881796
m_eventLoopMutex.lock();

src/engine/internal/engine.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ class Engine : public IEngine
149149

150150
const std::vector<std::shared_ptr<Monitor>> &monitors() const override;
151151
void setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitors) override;
152-
Monitor *createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId) override;
153-
Monitor *createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId) override;
152+
Monitor *createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId, BlockComp compileFunction) override;
153+
Monitor *createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId, BlockComp compileFunction) override;
154154
sigslot::signal<Monitor *> &monitorAdded() override;
155155
sigslot::signal<Monitor *, IMonitorHandler *> &monitorRemoved() override;
156156

@@ -195,6 +195,8 @@ class Engine : public IEngine
195195
WhenGreaterThanMenu
196196
};
197197

198+
void compileMonitor(std::shared_ptr<Monitor> monitor);
199+
198200
std::vector<std::shared_ptr<Thread>> stepThreads();
199201
void stepThread(std::shared_ptr<Thread> thread);
200202
void eventLoop(bool untilProjectStops = false);

test/engine/engine_test.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,10 +1790,10 @@ TEST(EngineTest, CreateMissingMonitors)
17901790
ASSERT_EQ(monitors[1], m2);
17911791
ASSERT_EQ(monitors[2], m3);
17921792

1793-
engine.createVariableMonitor(var2, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1794-
engine.createListMonitor(list1, LIST_OPCODE, LIST_FIELD_NAME, LIST_FIELD_ID);
1795-
engine.createVariableMonitor(var4, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1796-
engine.createVariableMonitor(var5, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1793+
engine.createVariableMonitor(var2, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID, nullptr);
1794+
engine.createListMonitor(list1, LIST_OPCODE, LIST_FIELD_NAME, LIST_FIELD_ID, nullptr);
1795+
engine.createVariableMonitor(var4, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID, nullptr);
1796+
engine.createVariableMonitor(var5, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID, nullptr);
17971797

17981798
ASSERT_EQ(monitors.size(), 7);
17991799
checkVariableMonitor(monitors[3], var2);
@@ -1821,10 +1821,10 @@ TEST(EngineTest, CreateMissingMonitors)
18211821
Monitor *m4, *m5, *m6, *m7;
18221822
EXPECT_CALL(addMonitorMock, monitorAdded(_)).WillOnce(SaveArg<0>(&m4)).WillOnce(SaveArg<0>(&m5)).WillOnce(SaveArg<0>(&m6)).WillOnce(SaveArg<0>(&m7));
18231823

1824-
engine.createVariableMonitor(var2, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1825-
engine.createListMonitor(list1, LIST_OPCODE, LIST_FIELD_NAME, LIST_FIELD_ID);
1826-
engine.createVariableMonitor(var4, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1827-
engine.createVariableMonitor(var5, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID);
1824+
engine.createVariableMonitor(var2, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID, nullptr);
1825+
engine.createListMonitor(list1, LIST_OPCODE, LIST_FIELD_NAME, LIST_FIELD_ID, nullptr);
1826+
engine.createVariableMonitor(var4, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID, nullptr);
1827+
engine.createVariableMonitor(var5, VARIABLE_OPCODE, VARIABLE_FIELD_NAME, VARIABLE_FIELD_ID, nullptr);
18281828

18291829
const auto &monitors = engine.monitors();
18301830
ASSERT_EQ(monitors.size(), 7);

test/mocks/enginemock.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ class EngineMock : public IEngine
128128

129129
MOCK_METHOD(const std::vector<std::shared_ptr<Monitor>> &, monitors, (), (const, override));
130130
MOCK_METHOD(void, setMonitors, (const std::vector<std::shared_ptr<Monitor>> &), (override));
131-
MOCK_METHOD(Monitor *, createVariableMonitor, (std::shared_ptr<Variable>, const std::string &, const std::string &, int), (override));
132-
MOCK_METHOD(Monitor *, createListMonitor, (std::shared_ptr<List>, const std::string &, const std::string &, int), (override));
131+
MOCK_METHOD(Monitor *, createVariableMonitor, (std::shared_ptr<Variable>, const std::string &, const std::string &, int, BlockComp), (override));
132+
MOCK_METHOD(Monitor *, createListMonitor, (std::shared_ptr<List>, const std::string &, const std::string &, int, BlockComp), (override));
133133
MOCK_METHOD(sigslot::signal<Monitor *> &, monitorAdded, (), (override));
134134
MOCK_METHOD((sigslot::signal<Monitor *, IMonitorHandler *> &), monitorRemoved, (), (override));
135135

0 commit comments

Comments
 (0)