Skip to content

Commit

Permalink
clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
GarboMuffin committed Aug 13, 2023
1 parent 2df8c42 commit ad98650
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 41 deletions.
3 changes: 2 additions & 1 deletion src/compiler/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const compile = thread => {

return {
startingFunction: entry,
procedures
procedures,
executableHat: ir.entry.executableHat
};
};

Expand Down
6 changes: 6 additions & 0 deletions src/compiler/intermediate.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ class IntermediateScript {
* @type {Function|null}
*/
this.cachedCompileResult = null;

/**
* Whether the top block of this script is an executable hat.
* @type {boolean}
*/
this.executableHat = false;
}
}

Expand Down
53 changes: 25 additions & 28 deletions src/compiler/irgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -1462,7 +1462,8 @@ class ScriptTreeGenerator {
const hatInfo = this.runtime._hats[opcode];

if (this.thread.stackClick) {
// We still need to run the top block, but the result is ignored.
// We still need to treat the hat as a normal block (so executableHat should be false) for
// interpreter parity, but the reuslt is ignored.
const opcodeFunction = this.runtime.getOpcodeFunction(opcode);
if (opcodeFunction) {
return [
Expand All @@ -1473,39 +1474,35 @@ class ScriptTreeGenerator {
return this.walkStack(nextBlock);
}

// startHats automatically runs the first block in each thread it starts, which makes
// this quite special.

this.script.yields = true;

let hatNode;
if (hatInfo.edgeActivated) {
// Edge-activated HAT
hatNode = {
kind: 'hat.edge',
id: hatBlock.id,
condition: this.descendCompatLayer(hatBlock)
};
} else {
const opcodeFunction = this.runtime.getOpcodeFunction(opcode);
if (opcodeFunction) {
// Non-edge-activated HAT
hatNode = {
this.script.yields = true;
this.script.executableHat = true;
return [
{
kind: 'hat.edge',
id: hatBlock.id,
condition: this.descendCompatLayer(hatBlock)
},
...this.walkStack(nextBlock)
];
}

const opcodeFunction = this.runtime.getOpcodeFunction(opcode);
if (opcodeFunction) {
// Predicate-based HAT
this.script.yields = true;
this.script.executableHat = true;
return [
{
kind: 'hat.predicate',
condition: this.descendCompatLayer(hatBlock)
};
} else {
// Probably an EVENT block.
hatNode = {
kind: 'hat.noop'
};
}
},
...this.walkStack(nextBlock)
];
}

return [
hatNode,
...this.walkStack(nextBlock)
];
return this.walkStack(nextBlock);
}

/**
Expand Down
10 changes: 3 additions & 7 deletions src/compiler/jsgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -850,10 +850,11 @@ class JSGenerator {
this.source += `}\n`;
break;

case 'hat.edge': {
case 'hat.edge':
this.isInHat = true;
this.source += '{\n';
// For exact Scratch parity, evaluate the input before checking old edge state.
// Can matter if the input is not instantly evaluated.
this.source += `const resolvedValue = ${this.descendInput(node.condition).asBoolean()};\n`;
this.source += `const id = "${sanitize(node.id)}";\n`;
this.source += 'const hasOldEdgeValue = target.hasEdgeActivatedValue(id);\n';
Expand All @@ -866,19 +867,14 @@ class JSGenerator {
this.source += '}\n';
this.isInHat = false;
break;
}
case 'hat.noop':
this.source += 'yield; /* hat noop */\n';
break;
case 'hat.predicate': {
case 'hat.predicate':
this.isInHat = true;
this.source += `if (!${this.descendInput(node.condition).asBoolean()}) {\n`;
this.retire();
this.source += '}\n';
this.source += 'yield;\n';
this.isInHat = false;
break;
}

case 'event.broadcast':
this.source += `startHats("event_whenbroadcastreceived", { BROADCAST_OPTION: ${this.descendInput(node.broadcast).asString()} });\n`;
Expand Down
12 changes: 7 additions & 5 deletions src/engine/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -2118,11 +2118,13 @@ class Runtime extends EventEmitter {
// threads are stepped. See ScratchRuntime.as for original implementation
newThreads.forEach(thread => {
if (thread.isCompiled) {
// It is quite likely that we are currently executing a block, so make sure
// that we leave the compiler's state intact at the end.
compilerExecute.saveGlobalState();
compilerExecute(thread);
compilerExecute.restoreGlobalState();
if (thread.executableHat) {
// It is quite likely that we are currently executing a block, so make sure
// that we leave the compiler's state intact at the end.
compilerExecute.saveGlobalState();
compilerExecute(thread);
compilerExecute.restoreGlobalState();
}
} else {
execute(this.sequencer, thread);
thread.goToNextBlock();
Expand Down
3 changes: 3 additions & 0 deletions src/engine/thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class Thread {
* @type {Object.<string, import('../compiler/compile').CompiledScript>}
*/
this.procedures = null;
this.executableHat = false;
}

/**
Expand Down Expand Up @@ -502,6 +503,8 @@ class Thread {

this.generator = result.startingFunction(this)();

this.executableHat = result.executableHat;

if (!this.blockContainer.forceNoGlow) {
this.blockGlowInFrame = this.topBlock;
this.requestScriptGlowInFrame = true;
Expand Down

0 comments on commit ad98650

Please sign in to comment.