Skip to content

Commit afd3d0d

Browse files
authored
Merge pull request #566 from scratchcpp/unsupported_blocks_api
Add API for unsupported blocks
2 parents a62a07c + 6037520 commit afd3d0d

File tree

10 files changed

+92
-4
lines changed

10 files changed

+92
-4
lines changed

include/scratchcpp/compiler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <vector>
66
#include <memory>
7+
#include <unordered_set>
78

89
#include "global.h"
910
#include "spimpl.h"
@@ -82,6 +83,8 @@ class LIBSCRATCHCPP_EXPORT Compiler
8283
BlockPrototype *procedurePrototype() const;
8384
void setProcedurePrototype(BlockPrototype *prototype);
8485

86+
const std::unordered_set<std::string> &unsupportedBlocks() const;
87+
8588
private:
8689
spimpl::unique_impl_ptr<CompilerPrivate> impl;
8790
};

include/scratchcpp/iengine.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <memory>
66
#include <vector>
77
#include <unordered_map>
8+
#include <unordered_set>
89
#include <functional>
910

1011
#include "global.h"
@@ -390,6 +391,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
390391

391392
/*! Sets the user agent of the last person to edit the project. */
392393
virtual void setUserAgent(const std::string &agent) = 0;
394+
395+
/*! Returns the unsupported block opcodes which were found when compiling. */
396+
virtual const std::unordered_set<std::string> &unsupportedBlocks() const = 0;
393397
};
394398

395399
} // namespace libscratchcpp

src/engine/compiler.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@ void Compiler::compile(std::shared_ptr<Block> topLevelBlock)
6666

6767
if (impl->block->compileFunction())
6868
impl->block->compile(this);
69-
else
69+
else {
7070
std::cout << "warning: unsupported block: " << impl->block->opcode() << std::endl;
71+
impl->unsupportedBlocks.insert(impl->block->opcode());
72+
}
7173

7274
if (substacks != impl->substackTree.size())
7375
continue;
@@ -186,6 +188,7 @@ void Compiler::addInput(Input *input)
186188
impl->block->compile(this);
187189
else {
188190
std::cout << "warning: unsupported reporter block: " << impl->block->opcode() << std::endl;
191+
impl->unsupportedBlocks.insert(impl->block->opcode());
189192
addInstruction(OP_NULL);
190193
}
191194
} else
@@ -205,6 +208,7 @@ void Compiler::addInput(Input *input)
205208
impl->block->compile(this);
206209
else {
207210
std::cout << "warning: unsupported reporter block: " << impl->block->opcode() << std::endl;
211+
impl->unsupportedBlocks.insert(impl->block->opcode());
208212
addInstruction(OP_NULL);
209213
}
210214
} else
@@ -356,6 +360,12 @@ void Compiler::setProcedurePrototype(BlockPrototype *prototype)
356360
impl->procedurePrototype = prototype;
357361
}
358362

363+
/*! Returns unsupported block opcodes which were found when compiling. */
364+
const std::unordered_set<std::string> &libscratchcpp::Compiler::unsupportedBlocks() const
365+
{
366+
return impl->unsupportedBlocks;
367+
}
368+
359369
/*! Returns the list of custom block prototypes. */
360370
const std::vector<std::string> &Compiler::procedures() const
361371
{

src/engine/compiler_p.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#pragma once
44

55
#include <unordered_map>
6+
#include <unordered_set>
67
#include <scratchcpp/compiler.h>
78
#include <scratchcpp/inputvalue.h>
89

@@ -38,6 +39,8 @@ struct CompilerPrivate
3839
std::unordered_map<std::string, std::vector<std::string>> procedureArgs;
3940
BlockPrototype *procedurePrototype = nullptr;
4041
bool warp = false;
42+
43+
std::unordered_set<std::string> unsupportedBlocks;
4144
};
4245

4346
} // namespace libscratchcpp

src/engine/internal/engine.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ void Engine::clear()
9595
m_edgeActivatedHatValues.clear();
9696

9797
m_running = false;
98+
99+
m_unsupportedBlocks.clear();
98100
}
99101

100102
// Resolves ID references and sets pointers of entities.
@@ -265,7 +267,7 @@ void Engine::compile()
265267
Compiler compiler(this, target.get());
266268
const auto &blocks = target->blocks();
267269
for (auto block : blocks) {
268-
if (block->topLevel() && !block->shadow()) {
270+
if (block->topLevel() && !block->isTopLevelReporter() && !block->shadow()) {
269271
auto section = blockSection(block->opcode());
270272
if (section) {
271273
auto script = std::make_shared<Script>(target.get(), block, this);
@@ -280,8 +282,10 @@ void Engine::compile()
280282
auto b = block->inputAt(block->findInput("custom_block"))->valueBlock();
281283
procedureBytecodeMap[b->mutationPrototype()->procCode()] = script->bytecode();
282284
}
283-
} else
285+
} else {
284286
std::cout << "warning: unsupported top level block: " << block->opcode() << std::endl;
287+
m_unsupportedBlocks.insert(block->opcode());
288+
}
285289
}
286290
}
287291

@@ -298,6 +302,11 @@ void Engine::compile()
298302
m_scripts[block]->setLists(compiler.lists());
299303
}
300304
}
305+
306+
const auto &unsupportedBlocks = compiler.unsupportedBlocks();
307+
308+
for (const std::string &opcode : unsupportedBlocks)
309+
m_unsupportedBlocks.insert(opcode);
301310
}
302311

303312
// Compile monitor blocks to bytecode
@@ -343,8 +352,15 @@ void Engine::compile()
343352
script->setConstValues(compiler.constValues());
344353
script->setVariables(compiler.variables());
345354
script->setLists(compiler.lists());
346-
} else
355+
} else {
347356
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);
348364
}
349365
}
350366

@@ -1622,6 +1638,11 @@ void Engine::setUserAgent(const std::string &agent)
16221638
m_userAgent = agent;
16231639
}
16241640

1641+
const std::unordered_set<std::string> &Engine::unsupportedBlocks() const
1642+
{
1643+
return m_unsupportedBlocks;
1644+
}
1645+
16251646
void Engine::finalize()
16261647
{
16271648
m_eventLoopMutex.lock();

src/engine/internal/engine.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ class Engine : public IEngine
168168
const std::string &userAgent() const override;
169169
void setUserAgent(const std::string &agent) override;
170170

171+
const std::unordered_set<std::string> &unsupportedBlocks() const override;
172+
171173
IClock *m_clock = nullptr;
172174
IAudioEngine *m_audioEngine = nullptr;
173175

@@ -287,6 +289,8 @@ class Engine : public IEngine
287289
sigslot::signal<const std::string &> m_questionAsked;
288290
sigslot::signal<> m_questionAborted;
289291
sigslot::signal<const std::string &> m_questionAnswered;
292+
293+
std::unordered_set<std::string> m_unsupportedBlocks;
290294
};
291295

292296
} // namespace libscratchcpp

test/compiler/compiler_test.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ TEST_F(CompilerTest, AddObscuredInput)
300300

301301
compiler.addInstruction(vm::OP_HALT);
302302
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CHECKPOINT, vm::OP_NULL, vm::OP_PRINT, vm::OP_CONST, 0, vm::OP_PRINT, vm::OP_NULL, vm::OP_PRINT, vm::OP_HALT }));
303+
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "test_block2" }));
303304
}
304305

305306
TEST_F(CompilerTest, AddNoShadowInput)
@@ -328,6 +329,14 @@ TEST_F(CompilerTest, AddNoShadowInput)
328329
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CHECKPOINT, vm::OP_NULL, vm::OP_PRINT, vm::OP_CONST, 0, vm::OP_NULL, vm::OP_PRINT, vm::OP_HALT }));
329330
ASSERT_EQ(compiler.constValues().size(), 1);
330331
ASSERT_EQ(compiler.constValues()[0], "test");
332+
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "test_block2" }));
333+
334+
Input input4("TEST_INPUT4", Input::Type::NoShadow);
335+
std::shared_ptr<Block> block3 = std::make_shared<Block>("", "test_block3");
336+
input4.setValueBlock(block3);
337+
compiler.addInput(&input4);
338+
compiler.addInstruction(vm::OP_PRINT);
339+
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "test_block2", "test_block3" }));
331340
}
332341

333342
TEST_F(CompilerTest, ResolveInput)
@@ -841,3 +850,26 @@ TEST_F(CompilerTest, EdgeActivatedHatPredicate)
841850
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 1, vm::OP_PRINT, vm::OP_HALT }));
842851
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ true, "test" }));
843852
}
853+
854+
TEST_F(CompilerTest, UnsupportedBlocks)
855+
{
856+
auto block1 = std::make_shared<Block>("b1", "block1");
857+
858+
auto block2 = std::make_shared<Block>("b2", "block2");
859+
block2->setParent(block1);
860+
block1->setNext(block2);
861+
862+
auto block3 = std::make_shared<Block>("b3", "block3");
863+
block3->setCompileFunction([](Compiler *) {});
864+
block3->setParent(block2);
865+
block2->setNext(block3);
866+
867+
auto block4 = std::make_shared<Block>("b4", "block4");
868+
block4->setParent(block3);
869+
block3->setNext(block4);
870+
871+
INIT_COMPILER(engine, compiler);
872+
compiler.compile(block1);
873+
874+
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "block1", "block2", "block4" }));
875+
}

test/engine/engine_test.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,15 @@ TEST(EngineTest, UserAgent)
21332133
ASSERT_EQ(engine.userAgent(), "test");
21342134
}
21352135

2136+
TEST(EngineTest, UnsupportedBlocks)
2137+
{
2138+
Project p("unsupported_blocks.sb3");
2139+
ASSERT_TRUE(p.load());
2140+
ASSERT_EQ(
2141+
p.engine()->unsupportedBlocks(),
2142+
std::unordered_set<std::string>({ "ev3_motorTurnClockwise", "ev3_motorSetPower", "ev3_getMotorPosition", "ev3_whenButtonPressed", "ev3_getBrightness", "ev3_getDistance" }));
2143+
}
2144+
21362145
TEST(EngineTest, NoCrashAfterStop)
21372146
{
21382147
// Regtest for #186

test/mocks/enginemock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ class EngineMock : public IEngine
144144

145145
MOCK_METHOD(const std::string &, userAgent, (), (const, override));
146146
MOCK_METHOD(void, setUserAgent, (const std::string &), (override));
147+
148+
MOCK_METHOD(const std::unordered_set<std::string> &, unsupportedBlocks, (), (const, override));
147149
};
148150

149151
} // namespace libscratchcpp

test/unsupported_blocks.sb3

2.06 KB
Binary file not shown.

0 commit comments

Comments
 (0)