Skip to content
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
4 changes: 3 additions & 1 deletion include/scratchcpp/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity
public:
friend class Engine;

Block(const std::string &id, const std::string &opcode);
Block(const std::string &id, const std::string &opcode, bool isMonitorBlock = false);
Block(const Block &) = delete;

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

InputValue *topLevelReporterInfo();

bool isMonitorBlock() const;

private:
void updateInputMap();
void updateFieldMap();
Expand Down
9 changes: 8 additions & 1 deletion include/scratchcpp/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ class LIBSCRATCHCPP_EXPORT Compiler
Unknown
};

enum class CodeType
{
Script,
Reporter,
HatPredicate
};

using ArgTypes = std::vector<StaticType>;
using Args = std::vector<CompilerValue *>;

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

std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock, bool isHatPredicate = false);
std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock, CodeType codeType = CodeType::Script);
void preoptimize();

CompilerValue *addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});
Expand Down
7 changes: 7 additions & 0 deletions include/scratchcpp/executablecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace libscratchcpp

class ExecutionContext;
class Thread;
struct ValueData;

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

/*!
* Runs the reporter and returns its return value.
* \note Make sure to call value_free() to free the value.
*/
virtual ValueData runReporter(ExecutionContext *context) = 0;

/*! Runs the hat predicate and returns its return value. */
virtual bool runPredicate(ExecutionContext *context) = 0;

Expand Down
3 changes: 1 addition & 2 deletions include/scratchcpp/imonitorhandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ class LIBSCRATCHCPP_EXPORT IMonitorHandler

virtual void init(Monitor *monitor) = 0;

// TODO: Add onValueChanged()
// virtual void onValueChanged(const VirtualMachine *vm) = 0;
virtual void onValueChanged(const Value &value) = 0;
virtual void onXChanged(int x) = 0;
virtual void onYChanged(int y) = 0;
virtual void onVisibleChanged(bool visible) = 0;
Expand Down
3 changes: 1 addition & 2 deletions include/scratchcpp/monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ class LIBSCRATCHCPP_EXPORT Monitor : public Entity

const std::string &opcode() const;

// TODO: Add updateValue()
// void updateValue(const VirtualMachine *vm);
void updateValue(const Value &value);

void setValueChangeFunction(MonitorChangeFunc f);
void changeValue(const Value &newValue);
Expand Down
3 changes: 2 additions & 1 deletion include/scratchcpp/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#pragma once

#include "global.h"
#include "valuedata.h"
#include "spimpl.h"

namespace libscratchcpp
Expand All @@ -27,6 +27,7 @@ class LIBSCRATCHCPP_EXPORT Thread
Script *script() const;

void run();
ValueData runReporter();
bool runPredicate();
void kill();
void reset();
Expand Down
37 changes: 37 additions & 0 deletions src/blocks/listblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <scratchcpp/iengine.h>
#include <scratchcpp/compiler.h>
#include <scratchcpp/compilerconstant.h>
#include <scratchcpp/block.h>
#include <scratchcpp/field.h>
#include <scratchcpp/list.h>

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

void ListBlocks::registerBlocks(IEngine *engine)
{
// Blocks
engine->addCompileFunction(this, "data_listcontents", &compileListContents);
engine->addCompileFunction(this, "data_addtolist", &compileAddToList);
engine->addCompileFunction(this, "data_deleteoflist", &compileDeleteOfList);
engine->addCompileFunction(this, "data_deletealloflist", &compileDeleteAllOfList);
Expand All @@ -36,6 +39,24 @@ void ListBlocks::registerBlocks(IEngine *engine)
engine->addCompileFunction(this, "data_itemnumoflist", &compileItemNumOfList);
engine->addCompileFunction(this, "data_lengthoflist", &compileLengthOfList);
engine->addCompileFunction(this, "data_listcontainsitem", &compileListContainsItem);

// Monitor names
engine->addMonitorNameFunction(this, "data_listcontents", &listContentsMonitorName);
}

CompilerValue *ListBlocks::compileListContents(Compiler *compiler)
{
auto list = compiler->field("LIST")->valuePtr();
assert(list);

// If this block is used in a list monitor, return the list pointer
if (compiler->block()->isMonitorBlock()) {
// TODO: Refactor this
// List monitors expect a reference to the list
// We don't have a list reference type, so cast the pointer to number
return compiler->addConstValue((uintptr_t)list.get());
} else
return compiler->addListContents(static_cast<List *>(list.get()));
}

CompilerValue *ListBlocks::compileAddToList(Compiler *compiler)
Expand Down Expand Up @@ -194,3 +215,19 @@ CompilerValue *ListBlocks::compileListContainsItem(Compiler *compiler)

return nullptr;
}

const std::string &ListBlocks::listContentsMonitorName(Block *block)
{
static const std::string empty = "";
auto field = block->fieldAt(block->findField("LIST"));

if (!field)
return empty;

List *list = dynamic_cast<List *>(field->valuePtr().get());

if (list)
return list->name();
else
return empty;
}
3 changes: 3 additions & 0 deletions src/blocks/listblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ListBlocks : public IExtension
void registerBlocks(IEngine *engine) override;

private:
static CompilerValue *compileListContents(Compiler *compiler);
static CompilerValue *compileAddToList(Compiler *compiler);
static CompilerValue *getListIndex(Compiler *compiler, CompilerValue *input, List *list, CompilerValue *listSize);
static CompilerValue *compileDeleteOfList(Compiler *compiler);
Expand All @@ -29,6 +30,8 @@ class ListBlocks : public IExtension
static CompilerValue *compileItemNumOfList(Compiler *compiler);
static CompilerValue *compileLengthOfList(Compiler *compiler);
static CompilerValue *compileListContainsItem(Compiler *compiler);

static const std::string &listContentsMonitorName(Block *block);
};

} // namespace libscratchcpp
38 changes: 38 additions & 0 deletions src/blocks/variableblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <scratchcpp/iengine.h>
#include <scratchcpp/compiler.h>
#include <scratchcpp/compilerconstant.h>
#include <scratchcpp/block.h>
#include <scratchcpp/input.h>
#include <scratchcpp/field.h>
#include <scratchcpp/variable.h>
Expand All @@ -28,9 +29,16 @@ Rgb VariableBlocks::color() const

void VariableBlocks::registerBlocks(IEngine *engine)
{
// Blocks
engine->addCompileFunction(this, "data_variable", &compileVariable);
engine->addCompileFunction(this, "data_setvariableto", &compileSetVariableTo);
engine->addCompileFunction(this, "data_changevariableby", &compileChangeVariableBy);

// Monitor names
engine->addMonitorNameFunction(this, "data_variable", &variableMonitorName);

// Monitor change functions
engine->addMonitorChangeFunction(this, "data_variable", &changeVariableMonitorValue);
}

CompilerValue *VariableBlocks::compileVariable(Compiler *compiler)
Expand Down Expand Up @@ -70,3 +78,33 @@ CompilerValue *VariableBlocks::compileChangeVariableBy(Compiler *compiler)

return nullptr;
}

const std::string &VariableBlocks::variableMonitorName(Block *block)
{
static const std::string empty = "";

auto field = block->fieldAt(block->findField("VARIABLE"));

if (!field)
return empty;

Variable *var = dynamic_cast<Variable *>(field->valuePtr().get());

if (var)
return var->name();
else
return empty;
}

void VariableBlocks::changeVariableMonitorValue(Block *block, const Value &newValue)
{
auto field = block->fieldAt(block->findField("VARIABLE"));

if (!field)
return;

Variable *var = dynamic_cast<Variable *>(field->valuePtr().get());

if (var)
var->setValue(newValue);
}
3 changes: 3 additions & 0 deletions src/blocks/variableblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ class VariableBlocks : public IExtension
static CompilerValue *compileVariable(Compiler *compiler);
static CompilerValue *compileSetVariableTo(Compiler *compiler);
static CompilerValue *compileChangeVariableBy(Compiler *compiler);

static const std::string &variableMonitorName(Block *block);
static void changeVariableMonitorValue(Block *block, const Value &newValue);
};

} // namespace libscratchcpp
6 changes: 3 additions & 3 deletions src/engine/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ std::shared_ptr<libscratchcpp::Block> Compiler::block() const
}

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

Expand All @@ -60,14 +60,14 @@ std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBl
}
}

impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, isHatPredicate);
impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, codeType);
impl->substackTree.clear();
impl->substackHit = false;
impl->emptySubstack = false;
impl->warp = false;
impl->block = startBlock;

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

if (f) {
Expand Down
4 changes: 2 additions & 2 deletions src/engine/internal/codebuilderfactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ std::shared_ptr<CodeBuilderFactory> CodeBuilderFactory::instance()
return m_instance;
}

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

std::shared_ptr<CompilerContext> CodeBuilderFactory::createCtx(IEngine *engine, Target *target) const
Expand Down
2 changes: 1 addition & 1 deletion src/engine/internal/codebuilderfactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class CodeBuilderFactory : public ICodeBuilderFactory
{
public:
static std::shared_ptr<CodeBuilderFactory> instance();
std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const override;
std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype, Compiler::CodeType codeType) const override;
std::shared_ptr<CompilerContext> createCtx(IEngine *engine, Target *target) const override;

private:
Expand Down
40 changes: 34 additions & 6 deletions src/engine/internal/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ void Engine::compile()
script->setCode(compiler.compile(block));

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

if (script) {
// TODO: Implement this
/*auto thread = script->start();
thread->run();
monitor->updateValue(thread->vm());*/
auto thread = script->start();
ValueData value = thread->runReporter();
monitor->updateValue(Value(value));
value_free(&value);
}
}
}
Expand Down Expand Up @@ -1851,7 +1851,35 @@ int Engine::resolveFieldValue(IExtension *extension, const std::string &value) c

void Engine::compileMonitor(std::shared_ptr<Monitor> monitor)
{
// TODO: Implement this
Target *target = monitor->sprite() ? static_cast<Target *>(monitor->sprite()) : stage();
auto block = monitor->block();
auto ext = blockExtension(block->opcode());

if (ext) {
auto ctx = Compiler::createContext(this, target);
Compiler compiler(ctx.get());
MonitorNameFunc nameFunc = resolveMonitorNameFunc(ext, block->opcode());

if (nameFunc)
monitor->setName(nameFunc(block.get()));

MonitorChangeFunc changeFunc = resolveMonitorChangeFunc(ext, block->opcode());
monitor->setValueChangeFunction(changeFunc);

auto script = std::make_shared<Script>(target, block, this);
monitor->setScript(script);
auto code = compiler.compile(block, Compiler::CodeType::Reporter);
script->setCode(code);
m_monitorCompilerContexts[monitor.get()] = ctx;

const auto &unsupportedBlocks = compiler.unsupportedBlocks();

for (const std::string &opcode : unsupportedBlocks)
m_unsupportedBlocks.insert(opcode);
} else {
std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl;
m_unsupportedBlocks.insert(block->opcode());
}
}

void Engine::finalize()
Expand Down
1 change: 1 addition & 0 deletions src/engine/internal/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class Engine : public IEngine

std::vector<std::shared_ptr<Target>> m_targets;
std::unordered_map<Target *, std::shared_ptr<CompilerContext>> m_compilerContexts;
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)
std::vector<std::shared_ptr<Broadcast>> m_broadcasts;
std::unordered_map<Broadcast *, std::vector<Script *>> m_broadcastMap;
std::unordered_map<Broadcast *, std::vector<Script *>> m_backdropBroadcastMap;
Expand Down
7 changes: 2 additions & 5 deletions src/engine/internal/icodebuilderfactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,20 @@

#pragma once

#include <scratchcpp/compiler.h>
#include <memory>

namespace libscratchcpp
{

class ICodeBuilder;
class CompilerContext;
class BlockPrototype;
class Target;
class IEngine;

class ICodeBuilderFactory
{
public:
virtual ~ICodeBuilderFactory() { }

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

Expand Down
Loading