Skip to content

Add API for unsupported blocks #566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/scratchcpp/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <vector>
#include <memory>
#include <unordered_set>

#include "global.h"
#include "spimpl.h"
Expand Down Expand Up @@ -82,6 +83,8 @@ class LIBSCRATCHCPP_EXPORT Compiler
BlockPrototype *procedurePrototype() const;
void setProcedurePrototype(BlockPrototype *prototype);

const std::unordered_set<std::string> &unsupportedBlocks() const;

private:
spimpl::unique_impl_ptr<CompilerPrivate> impl;
};
Expand Down
4 changes: 4 additions & 0 deletions include/scratchcpp/iengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <memory>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <functional>

#include "global.h"
Expand Down Expand Up @@ -390,6 +391,9 @@ class LIBSCRATCHCPP_EXPORT IEngine

/*! Sets the user agent of the last person to edit the project. */
virtual void setUserAgent(const std::string &agent) = 0;

/*! Returns the unsupported block opcodes which were found when compiling. */
virtual const std::unordered_set<std::string> &unsupportedBlocks() const = 0;
};

} // namespace libscratchcpp
12 changes: 11 additions & 1 deletion src/engine/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ void Compiler::compile(std::shared_ptr<Block> topLevelBlock)

if (impl->block->compileFunction())
impl->block->compile(this);
else
else {
std::cout << "warning: unsupported block: " << impl->block->opcode() << std::endl;
impl->unsupportedBlocks.insert(impl->block->opcode());
}

if (substacks != impl->substackTree.size())
continue;
Expand Down Expand Up @@ -186,6 +188,7 @@ void Compiler::addInput(Input *input)
impl->block->compile(this);
else {
std::cout << "warning: unsupported reporter block: " << impl->block->opcode() << std::endl;
impl->unsupportedBlocks.insert(impl->block->opcode());
addInstruction(OP_NULL);
}
} else
Expand All @@ -205,6 +208,7 @@ void Compiler::addInput(Input *input)
impl->block->compile(this);
else {
std::cout << "warning: unsupported reporter block: " << impl->block->opcode() << std::endl;
impl->unsupportedBlocks.insert(impl->block->opcode());
addInstruction(OP_NULL);
}
} else
Expand Down Expand Up @@ -356,6 +360,12 @@ void Compiler::setProcedurePrototype(BlockPrototype *prototype)
impl->procedurePrototype = prototype;
}

/*! Returns unsupported block opcodes which were found when compiling. */
const std::unordered_set<std::string> &libscratchcpp::Compiler::unsupportedBlocks() const
{
return impl->unsupportedBlocks;
}

/*! Returns the list of custom block prototypes. */
const std::vector<std::string> &Compiler::procedures() const
{
Expand Down
3 changes: 3 additions & 0 deletions src/engine/compiler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include <unordered_map>
#include <unordered_set>
#include <scratchcpp/compiler.h>
#include <scratchcpp/inputvalue.h>

Expand Down Expand Up @@ -38,6 +39,8 @@ struct CompilerPrivate
std::unordered_map<std::string, std::vector<std::string>> procedureArgs;
BlockPrototype *procedurePrototype = nullptr;
bool warp = false;

std::unordered_set<std::string> unsupportedBlocks;
};

} // namespace libscratchcpp
27 changes: 24 additions & 3 deletions src/engine/internal/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ void Engine::clear()
m_edgeActivatedHatValues.clear();

m_running = false;

m_unsupportedBlocks.clear();
}

// Resolves ID references and sets pointers of entities.
Expand Down Expand Up @@ -265,7 +267,7 @@ void Engine::compile()
Compiler compiler(this, target.get());
const auto &blocks = target->blocks();
for (auto block : blocks) {
if (block->topLevel() && !block->shadow()) {
if (block->topLevel() && !block->isTopLevelReporter() && !block->shadow()) {
auto section = blockSection(block->opcode());
if (section) {
auto script = std::make_shared<Script>(target.get(), block, this);
Expand All @@ -280,8 +282,10 @@ void Engine::compile()
auto b = block->inputAt(block->findInput("custom_block"))->valueBlock();
procedureBytecodeMap[b->mutationPrototype()->procCode()] = script->bytecode();
}
} else
} else {
std::cout << "warning: unsupported top level block: " << block->opcode() << std::endl;
m_unsupportedBlocks.insert(block->opcode());
}
}
}

Expand All @@ -298,6 +302,11 @@ void Engine::compile()
m_scripts[block]->setLists(compiler.lists());
}
}

const auto &unsupportedBlocks = compiler.unsupportedBlocks();

for (const std::string &opcode : unsupportedBlocks)
m_unsupportedBlocks.insert(opcode);
}

// Compile monitor blocks to bytecode
Expand Down Expand Up @@ -343,8 +352,15 @@ void Engine::compile()
script->setConstValues(compiler.constValues());
script->setVariables(compiler.variables());
script->setLists(compiler.lists());
} else
} else {
std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl;
m_unsupportedBlocks.insert(block->opcode());
}

const auto &unsupportedBlocks = compiler.unsupportedBlocks();

for (const std::string &opcode : unsupportedBlocks)
m_unsupportedBlocks.insert(opcode);
}
}

Expand Down Expand Up @@ -1622,6 +1638,11 @@ void Engine::setUserAgent(const std::string &agent)
m_userAgent = agent;
}

const std::unordered_set<std::string> &Engine::unsupportedBlocks() const
{
return m_unsupportedBlocks;
}

void Engine::finalize()
{
m_eventLoopMutex.lock();
Expand Down
4 changes: 4 additions & 0 deletions src/engine/internal/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class Engine : public IEngine
const std::string &userAgent() const override;
void setUserAgent(const std::string &agent) override;

const std::unordered_set<std::string> &unsupportedBlocks() const override;

IClock *m_clock = nullptr;
IAudioEngine *m_audioEngine = nullptr;

Expand Down Expand Up @@ -287,6 +289,8 @@ class Engine : public IEngine
sigslot::signal<const std::string &> m_questionAsked;
sigslot::signal<> m_questionAborted;
sigslot::signal<const std::string &> m_questionAnswered;

std::unordered_set<std::string> m_unsupportedBlocks;
};

} // namespace libscratchcpp
32 changes: 32 additions & 0 deletions test/compiler/compiler_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ TEST_F(CompilerTest, AddObscuredInput)

compiler.addInstruction(vm::OP_HALT);
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 }));
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "test_block2" }));
}

TEST_F(CompilerTest, AddNoShadowInput)
Expand Down Expand Up @@ -328,6 +329,14 @@ TEST_F(CompilerTest, AddNoShadowInput)
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 }));
ASSERT_EQ(compiler.constValues().size(), 1);
ASSERT_EQ(compiler.constValues()[0], "test");
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "test_block2" }));

Input input4("TEST_INPUT4", Input::Type::NoShadow);
std::shared_ptr<Block> block3 = std::make_shared<Block>("", "test_block3");
input4.setValueBlock(block3);
compiler.addInput(&input4);
compiler.addInstruction(vm::OP_PRINT);
ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "test_block2", "test_block3" }));
}

TEST_F(CompilerTest, ResolveInput)
Expand Down Expand Up @@ -841,3 +850,26 @@ TEST_F(CompilerTest, EdgeActivatedHatPredicate)
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_CONST, 1, vm::OP_PRINT, vm::OP_HALT }));
ASSERT_EQ(compiler.constValues(), std::vector<Value>({ true, "test" }));
}

TEST_F(CompilerTest, UnsupportedBlocks)
{
auto block1 = std::make_shared<Block>("b1", "block1");

auto block2 = std::make_shared<Block>("b2", "block2");
block2->setParent(block1);
block1->setNext(block2);

auto block3 = std::make_shared<Block>("b3", "block3");
block3->setCompileFunction([](Compiler *) {});
block3->setParent(block2);
block2->setNext(block3);

auto block4 = std::make_shared<Block>("b4", "block4");
block4->setParent(block3);
block3->setNext(block4);

INIT_COMPILER(engine, compiler);
compiler.compile(block1);

ASSERT_EQ(compiler.unsupportedBlocks(), std::unordered_set<std::string>({ "block1", "block2", "block4" }));
}
9 changes: 9 additions & 0 deletions test/engine/engine_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2133,6 +2133,15 @@ TEST(EngineTest, UserAgent)
ASSERT_EQ(engine.userAgent(), "test");
}

TEST(EngineTest, UnsupportedBlocks)
{
Project p("unsupported_blocks.sb3");
ASSERT_TRUE(p.load());
ASSERT_EQ(
p.engine()->unsupportedBlocks(),
std::unordered_set<std::string>({ "ev3_motorTurnClockwise", "ev3_motorSetPower", "ev3_getMotorPosition", "ev3_whenButtonPressed", "ev3_getBrightness", "ev3_getDistance" }));
}

TEST(EngineTest, NoCrashAfterStop)
{
// Regtest for #186
Expand Down
2 changes: 2 additions & 0 deletions test/mocks/enginemock.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ class EngineMock : public IEngine

MOCK_METHOD(const std::string &, userAgent, (), (const, override));
MOCK_METHOD(void, setUserAgent, (const std::string &), (override));

MOCK_METHOD(const std::unordered_set<std::string> &, unsupportedBlocks, (), (const, override));
};

} // namespace libscratchcpp
Binary file added test/unsupported_blocks.sb3
Binary file not shown.
Loading