Skip to content

Commit 69be16c

Browse files
authored
Merge pull request #630 from scratchcpp/llvm_edge_activated_hats
Implement edge activated hats
2 parents 0da8733 + f3924cc commit 69be16c

30 files changed

+607
-53
lines changed

include/scratchcpp/compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
4949
Target *target() const;
5050
std::shared_ptr<Block> block() const;
5151

52-
std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock);
52+
std::shared_ptr<ExecutableCode> compile(std::shared_ptr<Block> startBlock, bool isHatPredicate = false);
5353
void preoptimize();
5454

5555
CompilerValue *addFunctionCall(const std::string &functionName, StaticType returnType = StaticType::Void, const ArgTypes &argTypes = {}, const Args &args = {});

include/scratchcpp/executablecode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class LIBSCRATCHCPP_EXPORT ExecutableCode
2121
/*! Runs the script until it finishes or yields. */
2222
virtual void run(ExecutionContext *context) = 0;
2323

24+
/*! Runs the hat predicate and returns its return value. */
25+
virtual bool runPredicate(ExecutionContext *context) = 0;
26+
2427
/*! Stops the code. isFinished() will return true. */
2528
virtual void kill(ExecutionContext *context) = 0;
2629

include/scratchcpp/script.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class LIBSCRATCHCPP_EXPORT Script
3131
ExecutableCode *code() const;
3232
void setCode(std::shared_ptr<ExecutableCode> code);
3333

34+
ExecutableCode *hatPredicateCode() const;
35+
void setHatPredicateCode(std::shared_ptr<ExecutableCode> code);
36+
3437
bool runHatPredicate(Target *target);
3538

3639
std::shared_ptr<Thread> start();

include/scratchcpp/thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class LIBSCRATCHCPP_EXPORT Thread
2727
Script *script() const;
2828

2929
void run();
30+
bool runPredicate();
3031
void kill();
3132
void reset();
3233

src/blocks/eventblocks.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@
33
#include <scratchcpp/iengine.h>
44
#include <scratchcpp/compiler.h>
55
#include <scratchcpp/block.h>
6+
#include <scratchcpp/input.h>
67
#include <scratchcpp/field.h>
78
#include <scratchcpp/broadcast.h>
89
#include <scratchcpp/executioncontext.h>
910
#include <scratchcpp/thread.h>
1011
#include <scratchcpp/compilerconstant.h>
1112
#include <scratchcpp/promise.h>
1213
#include <scratchcpp/stringptr.h>
14+
#include <scratchcpp/sprite.h>
15+
#include <scratchcpp/itimer.h>
1316
#include <utf8.h>
1417

1518
#include "eventblocks.h"
19+
#include "audio/audioinput.h"
20+
#include "audio/iaudioloudness.h"
1621

1722
using namespace libscratchcpp;
1823

@@ -33,6 +38,7 @@ Rgb EventBlocks::color() const
3338

3439
void EventBlocks::registerBlocks(IEngine *engine)
3540
{
41+
// Blocks
3642
engine->addCompileFunction(this, "event_whentouchingobject", &compileWhenTouchingObject);
3743
engine->addCompileFunction(this, "event_whenflagclicked", &compileWhenFlagClicked);
3844
engine->addCompileFunction(this, "event_whenthisspriteclicked", &compileWhenThisSpriteClicked);
@@ -43,6 +49,10 @@ void EventBlocks::registerBlocks(IEngine *engine)
4349
engine->addCompileFunction(this, "event_broadcast", &compileBroadcast);
4450
engine->addCompileFunction(this, "event_broadcastandwait", &compileBroadcastAndWait);
4551
engine->addCompileFunction(this, "event_whenkeypressed", &compileWhenKeyPressed);
52+
53+
// Hat predicates
54+
engine->addHatPredicateCompileFunction(this, "event_whentouchingobject", &compileWhenTouchingObjectPredicate);
55+
engine->addHatPredicateCompileFunction(this, "event_whengreaterthan", &compileWhenGreaterThanPredicate);
4656
}
4757

4858
CompilerValue *EventBlocks::compileWhenTouchingObject(Compiler *compiler)
@@ -51,6 +61,21 @@ CompilerValue *EventBlocks::compileWhenTouchingObject(Compiler *compiler)
5161
return nullptr;
5262
}
5363

64+
CompilerValue *EventBlocks::compileWhenTouchingObjectPredicate(Compiler *compiler)
65+
{
66+
Input *input = compiler->input("TOUCHINGOBJECTMENU");
67+
CompilerValue *name = nullptr;
68+
69+
if (input->pointsToDropdownMenu()) {
70+
std::string value = input->selectedMenuItem();
71+
72+
name = compiler->addConstValue(value);
73+
} else
74+
name = compiler->addInput(input);
75+
76+
return compiler->addTargetFunctionCall("event_whentouchingobject_predicate", Compiler::StaticType::Bool, { Compiler::StaticType::String }, { name });
77+
}
78+
5479
CompilerValue *EventBlocks::compileWhenFlagClicked(Compiler *compiler)
5580
{
5681
compiler->engine()->addGreenFlagScript(compiler->block());
@@ -99,6 +124,27 @@ CompilerValue *EventBlocks::compileWhenGreaterThan(Compiler *compiler)
99124
return nullptr;
100125
}
101126

127+
CompilerValue *EventBlocks::compileWhenGreaterThanPredicate(Compiler *compiler)
128+
{
129+
Field *field = compiler->field("WHENGREATERTHANMENU");
130+
std::string predicate;
131+
132+
if (field) {
133+
const std::string option = field->value().toString();
134+
135+
if (option == "LOUDNESS")
136+
predicate = "event_whengreaterthan_loudness_predicate";
137+
else if (option == "TIMER")
138+
predicate = "event_whengreaterthan_timer_predicate";
139+
else
140+
return compiler->addConstValue(false);
141+
} else
142+
return compiler->addConstValue(false);
143+
144+
CompilerValue *value = compiler->addInput("VALUE");
145+
return compiler->addFunctionCallWithCtx(predicate, Compiler::StaticType::Bool, { Compiler::StaticType::Number }, { value });
146+
}
147+
102148
CompilerValue *EventBlocks::compileBroadcast(Compiler *compiler)
103149
{
104150
auto input = compiler->addInput("BROADCAST_INPUT");
@@ -127,6 +173,43 @@ CompilerValue *EventBlocks::compileWhenKeyPressed(Compiler *compiler)
127173
return nullptr;
128174
}
129175

176+
extern "C" bool event_whentouchingobject_predicate(Target *target, const StringPtr *name)
177+
{
178+
static const StringPtr MOUSE_STR = StringPtr("_mouse_");
179+
static const StringPtr EDGE_STR = StringPtr("_edge_");
180+
181+
IEngine *engine = target->engine();
182+
183+
if (string_compare_case_sensitive(name, &MOUSE_STR) == 0)
184+
return target->touchingPoint(engine->mouseX(), engine->mouseY());
185+
else if (string_compare_case_sensitive(name, &EDGE_STR) == 0)
186+
return target->touchingEdge();
187+
else {
188+
// TODO: Use UTF-16 in engine
189+
const std::string u8name = utf8::utf16to8(std::u16string(name->data));
190+
Target *anotherTarget = engine->targetAt(engine->findTarget(u8name));
191+
192+
if (anotherTarget && !anotherTarget->isStage())
193+
return target->touchingSprite(static_cast<Sprite *>(anotherTarget));
194+
else
195+
return false;
196+
}
197+
}
198+
199+
extern "C" bool event_whengreaterthan_loudness_predicate(ExecutionContext *ctx, double value)
200+
{
201+
if (!EventBlocks::audioInput)
202+
EventBlocks::audioInput = AudioInput::instance().get();
203+
204+
auto audioLoudness = EventBlocks::audioInput->audioLoudness();
205+
return (audioLoudness->getLoudness() > value);
206+
}
207+
208+
extern "C" bool event_whengreaterthan_timer_predicate(ExecutionContext *ctx, double value)
209+
{
210+
return ctx->engine()->timer()->value() > value;
211+
}
212+
130213
extern "C" void event_broadcast(ExecutionContext *ctx, const StringPtr *name, bool wait)
131214
{
132215
Thread *thread = ctx->thread();

src/blocks/eventblocks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
namespace libscratchcpp
88
{
99

10+
class IAudioInput;
11+
1012
class EventBlocks : public IExtension
1113
{
1214
public:
@@ -16,14 +18,18 @@ class EventBlocks : public IExtension
1618

1719
void registerBlocks(IEngine *engine) override;
1820

21+
static inline IAudioInput *audioInput = nullptr;
22+
1923
private:
2024
static CompilerValue *compileWhenTouchingObject(Compiler *compiler);
25+
static CompilerValue *compileWhenTouchingObjectPredicate(Compiler *compiler);
2126
static CompilerValue *compileWhenFlagClicked(Compiler *compiler);
2227
static CompilerValue *compileWhenThisSpriteClicked(Compiler *compiler);
2328
static CompilerValue *compileWhenStageClicked(Compiler *compiler);
2429
static CompilerValue *compileWhenBroadcastReceived(Compiler *compiler);
2530
static CompilerValue *compileWhenBackdropSwitchesTo(Compiler *compiler);
2631
static CompilerValue *compileWhenGreaterThan(Compiler *compiler);
32+
static CompilerValue *compileWhenGreaterThanPredicate(Compiler *compiler);
2733
static CompilerValue *compileBroadcast(Compiler *compiler);
2834
static CompilerValue *compileBroadcastAndWait(Compiler *compiler);
2935
static CompilerValue *compileWhenKeyPressed(Compiler *compiler);

src/engine/compiler.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ std::shared_ptr<libscratchcpp::Block> Compiler::block() const
4444
}
4545

4646
/*! Compiles the script starting with the given block. */
47-
std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBlock)
47+
std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBlock, bool isHatPredicate)
4848
{
4949
BlockPrototype *procedurePrototype = nullptr;
5050

@@ -60,13 +60,32 @@ std::shared_ptr<ExecutableCode> Compiler::compile(std::shared_ptr<Block> startBl
6060
}
6161
}
6262

63-
impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype);
63+
impl->builder = impl->builderFactory->create(impl->ctx, procedurePrototype, isHatPredicate);
6464
impl->substackTree.clear();
6565
impl->substackHit = false;
6666
impl->emptySubstack = false;
6767
impl->warp = false;
6868
impl->block = startBlock;
6969

70+
if (impl->block && isHatPredicate) {
71+
auto f = impl->block->hatPredicateCompileFunction();
72+
73+
if (f) {
74+
CompilerValue *ret = f(this);
75+
assert(ret);
76+
77+
if (!ret)
78+
std::cout << "warning: '" << impl->block->opcode() << "' hat predicate compile function doesn't return a valid value" << std::endl;
79+
} else {
80+
std::cout << "warning: unsupported hat predicate: " << impl->block->opcode() << std::endl;
81+
impl->unsupportedBlocks.insert(impl->block->opcode());
82+
addConstValue(false); // return false if unsupported
83+
}
84+
85+
impl->block = nullptr;
86+
return impl->builder->finalize();
87+
}
88+
7089
while (impl->block) {
7190
if (impl->block->compileFunction()) {
7291
assert(impl->customIfStatementCount == 0);

src/engine/internal/codebuilderfactory.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ std::shared_ptr<CodeBuilderFactory> CodeBuilderFactory::instance()
1313
return m_instance;
1414
}
1515

16-
std::shared_ptr<ICodeBuilder> CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype) const
16+
std::shared_ptr<ICodeBuilder> CodeBuilderFactory::create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const
1717
{
1818
assert(dynamic_cast<LLVMCompilerContext *>(ctx));
19-
return std::make_shared<LLVMCodeBuilder>(static_cast<LLVMCompilerContext *>(ctx), procedurePrototype);
19+
return std::make_shared<LLVMCodeBuilder>(static_cast<LLVMCompilerContext *>(ctx), procedurePrototype, isPredicate);
2020
}
2121

2222
std::shared_ptr<CompilerContext> CodeBuilderFactory::createCtx(IEngine *engine, Target *target) const

src/engine/internal/codebuilderfactory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class CodeBuilderFactory : public ICodeBuilderFactory
1111
{
1212
public:
1313
static std::shared_ptr<CodeBuilderFactory> instance();
14-
std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype) const override;
14+
std::shared_ptr<ICodeBuilder> create(CompilerContext *ctx, BlockPrototype *procedurePrototype, bool isPredicate) const override;
1515
std::shared_ptr<CompilerContext> createCtx(IEngine *engine, Target *target) const override;
1616

1717
private:

src/engine/internal/engine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ void Engine::compile()
274274
auto script = std::make_shared<Script>(target.get(), block, this);
275275
m_scripts[block] = script;
276276
script->setCode(compiler.compile(block));
277+
278+
if (block->hatPredicateCompileFunction())
279+
script->setHatPredicateCode(compiler.compile(block, true));
277280
} else {
278281
std::cout << "warning: unsupported top level block: " << block->opcode() << std::endl;
279282
m_unsupportedBlocks.insert(block->opcode());

0 commit comments

Comments
 (0)