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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ if (LIBSCRATCHCPP_USE_LLVM)
include/scratchcpp/dev/compilerconstant.h
include/scratchcpp/dev/executablecode.h
include/scratchcpp/dev/executioncontext.h
include/scratchcpp/dev/promise.h
)

if(LIBSCRATCHCPP_PRINT_LLVM_IR)
Expand Down
8 changes: 7 additions & 1 deletion include/scratchcpp/dev/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class LIBSCRATCHCPP_EXPORT Compiler
std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock);

CompilerValue *addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});
CompilerValue *addTargetFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});
CompilerValue *addFunctionCallWithCtx(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});
CompilerConstant *addConstValue(const Value &value);
CompilerValue *addVariableValue(Variable *variable);
CompilerValue *addListContents(List *list);
Expand Down Expand Up @@ -101,12 +103,16 @@ class LIBSCRATCHCPP_EXPORT Compiler
void beginElseBranch();
void endIf();

void beginWhileLoop(CompilerValue *cond);
void beginRepeatUntilLoop(CompilerValue *cond);
void beginLoopCondition();
void endLoop();

void moveToIf(CompilerValue *cond, std::shared_ptr<Block> substack);
void moveToIfElse(CompilerValue *cond, std::shared_ptr<Block> substack1, std::shared_ptr<Block> substack2);
void moveToRepeatLoop(CompilerValue *count, std::shared_ptr<Block> substack);
void moveToWhileLoop(CompilerValue *cond, std::shared_ptr<Block> substack);
void moveToRepeatUntilLoop(CompilerValue *cond, std::shared_ptr<Block> substack);
void beginLoopCondition();
void warp();

Input *input(const std::string &name) const;
Expand Down
6 changes: 0 additions & 6 deletions include/scratchcpp/dev/executablecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ class LIBSCRATCHCPP_EXPORT ExecutableCode
/*! Returns true if the code is stopped or finished. */
virtual bool isFinished(ExecutionContext *context) const = 0;

/*! Pauses the script (when it's executed using run() again) until resolvePromise() is called. */
virtual void promise() = 0;

/*! Resolves the promise and resumes the script. */
virtual void resolvePromise() = 0;

/*! Creates an execution context for the given Target. */
virtual std::shared_ptr<ExecutionContext> createExecutionContext(Target *target) const = 0;
};
Expand Down
4 changes: 4 additions & 0 deletions include/scratchcpp/dev/executioncontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace libscratchcpp
{

class Target;
class Promise;
class ExecutionContextPrivate;

/*! \brief The ExecutionContext represents the execution context of a target (can be a clone) with variables, lists, etc. */
Expand All @@ -21,6 +22,9 @@ class LIBSCRATCHCPP_EXPORT ExecutionContext

Target *target() const;

std::shared_ptr<Promise> promise() const;
void setPromise(std::shared_ptr<Promise> promise);

private:
spimpl::unique_impl_ptr<ExecutionContextPrivate> impl;
};
Expand Down
27 changes: 27 additions & 0 deletions include/scratchcpp/dev/promise.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "../global.h"
#include "../spimpl.h"

namespace libscratchcpp
{

class PromisePrivate;

/*! \brief The Promise class represents the eventual completion of an asynchronous operation. */
class LIBSCRATCHCPP_EXPORT Promise
{
public:
Promise();
Promise(const Promise &) = delete;

bool isResolved() const;
void resolve();

private:
spimpl::unique_impl_ptr<PromisePrivate> impl;
};

} // namespace libscratchcpp
8 changes: 8 additions & 0 deletions include/scratchcpp/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ namespace libscratchcpp

class VirtualMachine;
class Target;
#ifdef USE_LLVM
class Promise;
#endif
class IEngine;
class Script;
class ThreadPrivate;
Expand All @@ -32,8 +35,13 @@ class LIBSCRATCHCPP_EXPORT Thread

bool isFinished() const;

#ifdef USE_LLVM
std::shared_ptr<Promise> promise() const;
void setPromise(std::shared_ptr<Promise> promise);
#else
void promise();
void resolvePromise();
#endif

private:
spimpl::unique_impl_ptr<ThreadPrivate> impl;
Expand Down
3 changes: 3 additions & 0 deletions src/dev/engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ target_sources(scratchcpp
executioncontext.cpp
executioncontext_p.cpp
executioncontext_p.h
promise.cpp
promise_p.cpp
promise_p.h
internal/icodebuilder.h
internal/icodebuilderfactory.h
internal/codebuilderfactory.cpp
Expand Down
72 changes: 65 additions & 7 deletions src/dev/engine/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBl
std::cerr << "error: if statement created by block '" << impl->block->opcode() << "' not terminated" << std::endl;
assert(false);
}

if (impl->customLoopCount > 0) {
std::cerr << "error: loop created by block '" << impl->block->opcode() << "' not terminated" << std::endl;
assert(false);
}
} else {
std::cout << "warning: unsupported block: " << impl->block->opcode() << std::endl;
impl->unsupportedBlocks.insert(impl->block->opcode());
Expand All @@ -76,14 +81,34 @@ std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBl

/*!
* Adds a call to the given function.\n
* For example: extern "C" bool some_block(Target *target, double arg1, const char *arg2)
* For example: extern "C" bool some_block(double arg1, const char *arg2)
*/
CompilerValue *Compiler::addFunctionCall(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args)
{
assert(argTypes.size() == args.size());
return impl->builder->addFunctionCall(functionName, returnType, argTypes, args);
}

/*!
* Adds a call to the given function with a target parameter.\n
* For example: extern "C" bool some_block(Target *target, double arg1, const char *arg2)
*/
CompilerValue *Compiler::addTargetFunctionCall(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args)
{
assert(argTypes.size() == args.size());
return impl->builder->addTargetFunctionCall(functionName, returnType, argTypes, args);
}

/*!
* Adds a call to the given function with an execution context parameter.\n
* For example: extern "C" bool some_block(ExecutionContext *ctx, double arg1, const char *arg2)
*/
CompilerValue *Compiler::addFunctionCallWithCtx(const std::string &functionName, StaticType returnType, const ArgTypes &argTypes, const Args &args)
{
assert(argTypes.size() == args.size());
return impl->builder->addFunctionCallWithCtx(functionName, returnType, argTypes, args);
}

/*! Adds the given constant to the compiled code. */
CompilerConstant *Compiler::addConstValue(const Value &value)
{
Expand Down Expand Up @@ -362,6 +387,45 @@ void Compiler::endIf()
impl->customIfStatementCount--;
}

/*!
* Begins a custom while loop.
* \note The loop must be terminated with endLoop() after compiling your block.
*/
void Compiler::beginWhileLoop(CompilerValue *cond)
{
impl->builder->beginWhileLoop(cond);
impl->customLoopCount++;
}

/*!
* Begins a custom repeat until loop.
* \note The loop must be terminated with endLoop() after compiling your block.
*/
void Compiler::beginRepeatUntilLoop(CompilerValue *cond)
{
impl->builder->beginRepeatUntilLoop(cond);
impl->customLoopCount++;
}

/*! Begins a while/until loop condition. */
void Compiler::beginLoopCondition()
{
impl->builder->beginLoopCondition();
}

/*! Ends custom loop. */
void Compiler::endLoop()
{
if (impl->customLoopCount == 0) {
std::cerr << "error: called Compiler::endLoop() without a loop";
assert(false);
return;
}

impl->builder->endLoop();
impl->customLoopCount--;
}

/*! Jumps to the given if substack. */
void Compiler::moveToIf(CompilerValue *cond, std::shared_ptr<Block> substack)
{
Expand Down Expand Up @@ -425,12 +489,6 @@ void Compiler::moveToRepeatUntilLoop(CompilerValue *cond, std::shared_ptr<Block>
impl->substackEnd();
}

/*! Begins a while/until loop condition. */
void Compiler::beginLoopCondition()
{
impl->builder->beginLoopCondition();
}

/*! Makes current script run without screen refresh. */
void Compiler::warp()
{
Expand Down
1 change: 1 addition & 0 deletions src/dev/engine/compiler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct CompilerPrivate

std::shared_ptr<Block> block;
int customIfStatementCount = 0;
int customLoopCount = 0;
std::vector<std::pair<std::pair<std::shared_ptr<Block>, std::shared_ptr<Block>>, SubstackType>> substackTree;
bool substackHit = false;
bool warp = false;
Expand Down
12 changes: 12 additions & 0 deletions src/dev/engine/executioncontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,15 @@ Target *ExecutionContext::target() const
{
return impl->target;
}

/*! Returns the script promise. */
std::shared_ptr<Promise> ExecutionContext::promise() const
{
return impl->promise;
}

/*! Sets the script promise (yields until the promise is resolved). */
void ExecutionContext::setPromise(std::shared_ptr<Promise> promise)
{
impl->promise = promise;
}
4 changes: 4 additions & 0 deletions src/dev/engine/executioncontext_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

#pragma once

#include <memory>

namespace libscratchcpp
{

class Target;
class Promise;

struct ExecutionContextPrivate
{
ExecutionContextPrivate(Target *target);

Target *target = nullptr;
std::shared_ptr<Promise> promise;
};

} // namespace libscratchcpp
2 changes: 2 additions & 0 deletions src/dev/engine/internal/icodebuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class ICodeBuilder
virtual std::shared_ptr<ExecutableCode> finalize() = 0;

virtual CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
virtual CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
virtual CompilerValue *addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) = 0;
virtual CompilerConstant *addConstValue(const Value &value) = 0;
virtual CompilerValue *addVariableValue(Variable *variable) = 0;
virtual CompilerValue *addListContents(List *list) = 0;
Expand Down
37 changes: 30 additions & 7 deletions src/dev/engine/internal/llvm/llvmcodebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
m_builder.setFastMathFlags(fmf);

// Create function
// void *f(Target *, ValueData **, List **)
// void *f(ExecutionContext *, Target *, ValueData **, List **)
llvm::PointerType *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_ctx), 0);
llvm::FunctionType *funcType = llvm::FunctionType::get(pointerType, { pointerType, pointerType, pointerType }, false);
llvm::FunctionType *funcType = llvm::FunctionType::get(pointerType, { pointerType, pointerType, pointerType, pointerType }, false);
llvm::Function *func = llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, "f", m_module.get());
llvm::Value *targetPtr = func->getArg(0);
llvm::Value *targetVariables = func->getArg(1);
llvm::Value *targetLists = func->getArg(2);
llvm::Value *executionContextPtr = func->getArg(0);
llvm::Value *targetPtr = func->getArg(1);
llvm::Value *targetVariables = func->getArg(2);
llvm::Value *targetLists = func->getArg(3);

llvm::BasicBlock *entry = llvm::BasicBlock::Create(m_ctx, "entry", func);
m_builder.SetInsertPoint(entry);
Expand Down Expand Up @@ -117,9 +118,17 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
std::vector<llvm::Type *> types;
std::vector<llvm::Value *> args;

// Add execution context arg
if (step.functionCtxArg) {
types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_ctx), 0));
args.push_back(executionContextPtr);
}

// Add target pointer arg
types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_ctx), 0));
args.push_back(targetPtr);
if (step.functionTargetArg) {
types.push_back(llvm::PointerType::get(llvm::Type::getInt8Ty(m_ctx), 0));
args.push_back(targetPtr);
}

// Args
for (auto &arg : step.args) {
Expand Down Expand Up @@ -950,6 +959,20 @@ CompilerValue *LLVMCodeBuilder::addFunctionCall(const std::string &functionName,
return nullptr;
}

CompilerValue *LLVMCodeBuilder::addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
{
CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args);
m_instructions.back().functionTargetArg = true;
return ret;
}

CompilerValue *LLVMCodeBuilder::addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args)
{
CompilerValue *ret = addFunctionCall(functionName, returnType, argTypes, args);
m_instructions.back().functionCtxArg = true;
return ret;
}

CompilerConstant *LLVMCodeBuilder::addConstValue(const Value &value)
{
auto constReg = std::make_shared<LLVMConstantRegister>(TYPE_MAP[value.type()], value);
Expand Down
2 changes: 2 additions & 0 deletions src/dev/engine/internal/llvm/llvmcodebuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class LLVMCodeBuilder : public ICodeBuilder
std::shared_ptr<ExecutableCode> finalize() override;

CompilerValue *addFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
CompilerValue *addTargetFunctionCall(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
CompilerValue *addFunctionCallWithCtx(const std::string &functionName, Compiler::StaticType returnType, const Compiler::ArgTypes &argTypes, const Compiler::Args &args) override;
CompilerConstant *addConstValue(const Value &value) override;
CompilerValue *addVariableValue(Variable *variable) override;
CompilerValue *addListContents(List *list) override;
Expand Down
Loading
Loading