Skip to content

Commit c25935a

Browse files
committed
Add Script class for compiled scripts
1 parent 32524a9 commit c25935a

File tree

7 files changed

+194
-72
lines changed

7 files changed

+194
-72
lines changed

src/engine/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ target_sources(scratchcpp
33
engine.cpp
44
virtualmachine.cpp
55
compiler.cpp
6+
script.cpp
67
PUBLIC
78
engine.h
89
global.h
910
virtualmachine.h
1011
compiler.h
12+
script.h
1113
iblocksection.h
1214
iextension.h
1315
)

src/engine/engine.cpp

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../scratchconfiguration.h"
66
#include "iblocksection.h"
77
#include "compiler.h"
8+
#include "script.h"
89
#include <cassert>
910
#include <iostream>
1011
#include <thread>
@@ -76,16 +77,16 @@ void Engine::compile()
7677
if (block->topLevel()) {
7778
auto section = blockSection(block->opcode());
7879
if (section) {
79-
auto vm = std::make_shared<VirtualMachine>(target.get(), this);
80-
m_scripts[block] = vm;
80+
auto script = std::make_shared<Script>(target.get(), this);
81+
m_scripts[block] = script;
8182

8283
compiler.compile(block);
8384

84-
vm->setFunctions(m_functions);
85-
vm->setBytecode(compiler.bytecode());
85+
script->setFunctions(m_functions);
86+
script->setBytecode(compiler.bytecode());
8687
if (block->opcode() == "procedures_definition") {
8788
auto b = block->inputAt(block->findInput("custom_block"))->valueBlock();
88-
procedureBytecodeMap[b->mutationPrototype()->procCode()] = vm->bytecode();
89+
procedureBytecodeMap[b->mutationPrototype()->procCode()] = script->bytecode();
8990
}
9091
} else
9192
std::cout << "warning: unsupported top level block: " << block->opcode() << std::endl;
@@ -122,25 +123,26 @@ void Engine::frame()
122123
m_breakFrame = false;
123124

124125
do {
125-
std::string opcode;
126-
for (auto const &[key, value] : m_scripts) {
127-
if (value.get() == script)
128-
opcode = key->opcode();
129-
}
130126
auto ret = script->run(m_scriptPositions[i]);
131127
if (script->savePos())
132128
m_scriptPositions[i] = ret;
133129
if (script->atEnd()) {
134130
for (auto &[key, value] : m_broadcastMap)
135-
value.erase(std::remove(value.begin(), value.end(), script), value.end());
136-
m_scriptsToRemove.push_back(script);
131+
value.erase(std::remove(value.begin(), value.end(), script->script()), value.end());
132+
m_scriptsToRemove.push_back(script.get());
137133
}
138134
} while (!script->atEnd() && !m_breakFrame);
139135
}
140136

141137
for (auto script : m_scriptsToRemove) {
142-
auto it = std::find(m_runningScripts.begin(), m_runningScripts.end(), script);
143-
auto index = it - m_runningScripts.begin();
138+
size_t index = -1;
139+
for (size_t i = 0; i < m_runningScripts.size(); i++) {
140+
if (m_runningScripts[i].get() == script) {
141+
index = i;
142+
break;
143+
}
144+
}
145+
assert(index != -1);
144146
m_runningScripts.erase(m_runningScripts.begin() + index);
145147
m_scriptPositions.erase(m_scriptPositions.begin() + index);
146148
}
@@ -182,27 +184,32 @@ void Engine::startScript(std::shared_ptr<Block> topLevelBlock, std::shared_ptr<T
182184
}
183185

184186
if (topLevelBlock->next()) {
185-
auto vm = m_scripts[topLevelBlock].get();
186-
m_runningScripts.push_back(vm);
187-
m_scriptPositions.push_back(vm->bytecode());
187+
auto script = m_scripts[topLevelBlock];
188+
m_runningScripts.push_back(script->start());
189+
m_scriptPositions.push_back(script->bytecode());
188190
}
189191
}
190192

191193
/*! Starts the script of the broadcast with the given index. */
192194
void libscratchcpp::Engine::broadcast(unsigned int index, VirtualMachine *sourceScript)
193195
{
194-
const std::vector<VirtualMachine *> &scripts = m_broadcastMap[index];
195-
for (auto vm : scripts) {
196-
auto it = std::find(m_runningScripts.begin(), m_runningScripts.end(), vm);
197-
if (it != m_runningScripts.end()) {
196+
const std::vector<Script *> &scripts = m_broadcastMap[index];
197+
for (auto script : scripts) {
198+
size_t index = -1;
199+
for (size_t i = 0; i < m_runningScripts.size(); i++) {
200+
if (m_runningScripts[i]->script() == script) {
201+
index = i;
202+
break;
203+
}
204+
}
205+
if (index != -1) {
198206
// Reset the script if it's already running
199-
auto i = it - m_runningScripts.begin();
200-
m_scriptPositions[i] = m_runningScripts[i]->bytecode();
201-
if (vm == sourceScript)
202-
vm->stop(false, true);
207+
m_scriptPositions[index] = m_runningScripts[index]->bytecode();
208+
if (script == sourceScript->script())
209+
sourceScript->stop(false, true);
203210
} else {
204-
m_runningScripts.push_back(vm);
205-
m_scriptPositions.push_back(vm->bytecode());
211+
m_runningScripts.push_back(script->start());
212+
m_scriptPositions.push_back(script->bytecode());
206213
}
207214
}
208215
}
@@ -223,8 +230,8 @@ void Engine::stopTarget(Target *target, VirtualMachine *exceptScript)
223230
{
224231
std::vector<VirtualMachine *> scripts;
225232
for (auto script : m_runningScripts) {
226-
if ((script->target() == target) && (script != exceptScript))
227-
scripts.push_back(script);
233+
if ((script->target() == target) && (script.get() != exceptScript))
234+
scripts.push_back(script.get());
228235
}
229236

230237
for (auto script : scripts)
@@ -352,7 +359,7 @@ void libscratchcpp::Engine::addBroadcastScript(std::shared_ptr<Block> whenReceiv
352359
{
353360
auto id = findBroadcast(broadcast->name());
354361
if (m_broadcastMap.count(id) == 1) {
355-
std::vector<VirtualMachine *> &scripts = m_broadcastMap[id];
362+
std::vector<Script *> &scripts = m_broadcastMap[id];
356363
scripts.push_back(m_scripts[whenReceivedBlock].get());
357364
} else
358365
m_broadcastMap[id] = { m_scripts[whenReceivedBlock].get() };

src/engine/engine.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace libscratchcpp
1515
{
1616

1717
class LIBSCRATCHCPP_EXPORT IBlockSection;
18+
class LIBSCRATCHCPP_EXPORT Script;
1819

1920
/*!
2021
* \brief The Engine class provides an API for running Scratch projects.
@@ -73,12 +74,12 @@ class LIBSCRATCHCPP_EXPORT Engine
7374
std::vector<std::shared_ptr<IBlockSection>> m_sections;
7475
std::vector<std::shared_ptr<Target>> m_targets;
7576
std::vector<std::shared_ptr<Broadcast>> m_broadcasts;
76-
std::unordered_map<unsigned int, std::vector<VirtualMachine *>> m_broadcastMap;
77+
std::unordered_map<unsigned int, std::vector<Script *>> m_broadcastMap;
7778
std::vector<std::string> m_extensions;
78-
std::vector<VirtualMachine *> m_runningScripts;
79+
std::vector<std::shared_ptr<VirtualMachine>> m_runningScripts;
7980
std::vector<unsigned int *> m_scriptPositions;
8081
std::vector<VirtualMachine *> m_scriptsToRemove;
81-
std::unordered_map<std::shared_ptr<Block>, std::shared_ptr<VirtualMachine>> m_scripts;
82+
std::unordered_map<std::shared_ptr<Block>, std::shared_ptr<Script>> m_scripts;
8283
std::vector<BlockFunc> m_functions;
8384

8485
bool m_breakFrame = false;

src/engine/script.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include "script.h"
4+
5+
using namespace libscratchcpp;
6+
7+
/*! Constructs Script. */
8+
Script::Script(Target *target, Engine *engine) :
9+
m_target(target),
10+
m_engine(engine)
11+
{
12+
}
13+
14+
/*! Returns the bytecode array. */
15+
unsigned int *Script::bytecode()
16+
{
17+
return m_bytecode;
18+
}
19+
20+
/*! Sets the bytecode of the script. */
21+
void Script::setBytecode(const std::vector<unsigned int> &code)
22+
{
23+
m_bytecodeVector = code;
24+
m_bytecode = m_bytecodeVector.data();
25+
}
26+
27+
/*! Starts the script (creates a virtual machine). */
28+
std::shared_ptr<VirtualMachine> Script::start()
29+
{
30+
auto vm = std::make_shared<VirtualMachine>(m_target, m_engine, this);
31+
vm->setProcedures(m_procedures);
32+
vm->setFunctions(m_functions);
33+
vm->setConstValues(m_constValues);
34+
vm->setVariables(m_variables);
35+
vm->setLists(m_lists);
36+
return vm;
37+
}
38+
39+
/*! Sets the list of procedures (custom blocks). */
40+
void Script::setProcedures(const std::vector<unsigned int *> &procedures)
41+
{
42+
m_proceduresVector = procedures;
43+
m_procedures = m_proceduresVector.data();
44+
}
45+
46+
/*! Sets the list of functions. */
47+
void Script::setFunctions(const std::vector<BlockFunc> &functions)
48+
{
49+
m_functionsVector = functions;
50+
m_functions = m_functionsVector.data();
51+
}
52+
53+
/*! Sets the list of constant values. */
54+
void Script::setConstValues(const std::vector<Value> &values)
55+
{
56+
m_constValuesVector = values;
57+
m_constValues = m_constValuesVector.data();
58+
}
59+
60+
/*! Sets the list of variables. */
61+
void Script::setVariables(const std::vector<Value *> &variables)
62+
{
63+
m_variablesVector = variables;
64+
m_variables = m_variablesVector.data();
65+
}
66+
67+
/*! Sets the list of lists. */
68+
void Script::setLists(const std::vector<List *> &lists)
69+
{
70+
m_listsVector = lists;
71+
m_lists = m_listsVector.data();
72+
}

src/engine/script.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include "virtualmachine.h"
6+
7+
namespace libscratchcpp
8+
{
9+
10+
/*! \brief The Script class represents a compiled Scratch script. */
11+
class LIBSCRATCHCPP_EXPORT Script
12+
{
13+
public:
14+
Script(Target *target, Engine *engine);
15+
Script(const Script &) = delete;
16+
17+
unsigned int *bytecode();
18+
void setBytecode(const std::vector<unsigned int> &code);
19+
20+
void setProcedures(const std::vector<unsigned int *> &procedures);
21+
void setFunctions(const std::vector<BlockFunc> &functions);
22+
void setConstValues(const std::vector<Value> &values);
23+
void setVariables(const std::vector<Value *> &variables);
24+
void setLists(const std::vector<List *> &lists);
25+
26+
std::shared_ptr<VirtualMachine> start();
27+
28+
private:
29+
unsigned int *m_bytecode;
30+
std::vector<unsigned int> m_bytecodeVector;
31+
32+
Target *m_target;
33+
Engine *m_engine;
34+
35+
unsigned int **m_procedures = nullptr;
36+
std::vector<unsigned int *> m_proceduresVector;
37+
38+
BlockFunc *m_functions;
39+
std::vector<BlockFunc> m_functionsVector;
40+
41+
const Value *m_constValues = nullptr;
42+
std::vector<Value> m_constValuesVector;
43+
44+
Value **m_variables = nullptr;
45+
std::vector<Value *> m_variablesVector;
46+
47+
List **m_lists = nullptr;
48+
std::vector<List *> m_listsVector;
49+
};
50+
51+
} // namespace libscratchcpp

src/engine/virtualmachine.cpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,10 @@ VirtualMachine::VirtualMachine()
9494
}
9595

9696
/*! \copydoc VirtualMachine() */
97-
VirtualMachine::VirtualMachine(Target *target, Engine *engine) :
97+
VirtualMachine::VirtualMachine(Target *target, Engine *engine, Script *script) :
9898
m_target(target),
99-
m_engine(engine)
99+
m_engine(engine),
100+
m_script(script)
100101
{
101102
m_regs = new Value *[MAX_REG_COUNT];
102103
for (int i = 0; i < MAX_REG_COUNT; i++)
@@ -113,46 +114,40 @@ VirtualMachine::~VirtualMachine()
113114
delete m_regs;
114115
}
115116

116-
/*! Sets the list of procedures (custom blocks). */
117-
void VirtualMachine::setProcedures(const std::vector<unsigned int *> &procedures)
117+
/*! Sets the array of procedures (custom blocks). */
118+
void VirtualMachine::setProcedures(unsigned int **procedures)
118119
{
119-
m_proceduresVector = procedures;
120-
m_procedures = m_proceduresVector.data();
120+
m_procedures = procedures;
121121
}
122122

123123
/*! Sets the list of functions. */
124-
void VirtualMachine::setFunctions(const std::vector<BlockFunc> &functions)
124+
void VirtualMachine::setFunctions(BlockFunc *functions)
125125
{
126-
m_functionsVector = functions;
127-
m_functions = m_functionsVector.data();
126+
m_functions = functions;
128127
}
129128

130129
/*! Sets the list of constant values. */
131-
void VirtualMachine::setConstValues(const std::vector<Value> &values)
130+
void VirtualMachine::setConstValues(const Value *values)
132131
{
133-
m_constValuesVector = values;
134-
m_constValues = m_constValuesVector.data();
132+
m_constValues = values;
135133
}
136134

137135
/*! Sets the list of variables. */
138-
void VirtualMachine::setVariables(const std::vector<Value *> &variables)
136+
void VirtualMachine::setVariables(Value **variables)
139137
{
140-
m_variablesVector = variables;
141-
m_variables = m_variablesVector.data();
138+
m_variables = variables;
142139
}
143140

144141
/*! Sets the list of lists. */
145-
void VirtualMachine::setLists(const std::vector<List *> &lists)
142+
void VirtualMachine::setLists(List **lists)
146143
{
147-
m_listsVector = lists;
148-
m_lists = m_listsVector.data();
144+
m_lists = lists;
149145
}
150146

151147
/*! Sets the bytecode of the script. */
152-
void VirtualMachine::setBytecode(const std::vector<unsigned int> &code)
148+
void VirtualMachine::setBytecode(unsigned int *code)
153149
{
154-
m_bytecodeVector = code;
155-
m_bytecode = m_bytecodeVector.data();
150+
m_bytecode = code;
156151
}
157152

158153
/*! Runs the script. */

0 commit comments

Comments
 (0)