Skip to content
48 changes: 48 additions & 0 deletions src/engine/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,54 @@ class Runtime extends EventEmitter {
return 'THREAD_FINISHED'
}

/**
* Event name for before the sequencer executes a tick.
* @const {string}
*/
static get BEFORE_TICK () {
return 'BEFORE_TICK'
}

/**
* Event name for after the sequencer executes a tick.
* @const {string}
*/
static get AFTER_TICK () {
return 'AFTER_TICK'
}

/**
* Event name for before the sequencer considers a thread to be stepped.
* @const {string}
*/
static get BEFORE_THREAD_CONSIDERED () {
return 'BEFORE_THREAD_CONSIDERED'
}

/**
* Event name for after the sequencer considers a thread to be stepped.
* @const {string}
*/
static get AFTER_THREAD_CONSIDERED () {
return 'AFTER_THREAD_CONSIDERED'
}

/**
* Event name for before the sequencer steps a thread.
* @const {string}
*/
static get BEFORE_THREAD_STEP () {
return 'BEFORE_THREAD_STEP'
}

/**
* Event name for after the sequencer steps a thread.
* @const {string}
*/
static get AFTER_THREAD_STEP () {
return 'AFTER_THREAD_STEP'
}

/**
* Event name for sprite renaming.
* @const {string}
Expand Down
20 changes: 19 additions & 1 deletion src/engine/sequencer.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,12 @@ class Sequencer {
let stoppedThread = false;
// Attempt to run each thread one time.
const threads = this.runtime.threads;
for (this.activeThreadIndex = 0; this.activeThreadIndex < threads.length; this.activeThreadIndex++) {
this.runtime.emit('BEFORE_TICK', threads);
for (this.activeThreadIndex = 0; this.activeThreadIndex < threads.length; this.activeThreadIndex++,
this.runtime.emit('AFTER_THREAD_CONSIDERED', this.activeThread)) {
const i = this.activeThreadIndex;
const activeThread = this.activeThread = threads[i];
this.runtime.emit('BEFORE_THREAD_CONSIDERED', activeThread);
// Check if the thread is done so it is not executed.
if (activeThread.stack.length === 0 ||
activeThread.status === Thread.STATUS_DONE) {
Expand Down Expand Up @@ -148,6 +151,7 @@ class Sequencer {
stoppedThread = true;
}
}
this.runtime.emit('AFTER_TICK', threads);
// We successfully ticked once. Prevents running STATUS_YIELD_TICK
// threads on the next tick.
ranFirstTick = true;
Expand Down Expand Up @@ -175,6 +179,7 @@ class Sequencer {
}

this.activeThread = null;
this.activeThreadIndex = null;

return doneThreads;
}
Expand All @@ -184,8 +189,11 @@ class Sequencer {
* @param {!Thread} thread Thread object to step.
*/
stepThread (thread) {
this.runtime.emit('BEFORE_THREAD_STEP', thread);

if (thread.isCompiled) {
compilerExecute(thread);
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
}

Expand All @@ -198,6 +206,7 @@ class Sequencer {
if (thread.stack.length === 0) {
thread.status = Thread.STATUS_DONE;
this.runtime.emit('THREAD_FINISHED', thread);
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
}
}
Expand Down Expand Up @@ -239,12 +248,15 @@ class Sequencer {
// A promise was returned by the primitive. Yield the thread
// until the promise resolves. Promise resolution should reset
// thread.status to Thread.STATUS_RUNNING.
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
} else if (thread.status === Thread.STATUS_YIELD_TICK) {
// stepThreads will reset the thread to Thread.STATUS_RUNNING
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
} else if (thread.status === Thread.STATUS_DONE) {
// Nothing more to execute.
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
}
// If no control flow has happened, switch to next block.
Expand All @@ -259,6 +271,7 @@ class Sequencer {
// No more stack to run!
thread.status = Thread.STATUS_DONE;
this.runtime.emit('THREAD_FINISHED', thread);
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
}

Expand All @@ -274,22 +287,27 @@ class Sequencer {
thread.warpTimer.timeElapsed() > Sequencer.WARP_TIME) {
// Don't do anything to the stack, since loops need
// to be re-executed.
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
}
// Don't go to the next block for this level of the stack,
// since loops need to be re-executed.
this.runtime.emit('AFTER_THREAD_STEP', thread);
continue;

} else if (stackFrame.waitingReporter) {
// This level of the stack was waiting for a value.
// This means a reporter has just returned - so don't go
// to the next block for this level of the stack.
this.runtime.emit('AFTER_THREAD_STEP', thread);
return;
}
// Get next block of existing block on the stack.
thread.goToNextBlock();
}
}

this.runtime.emit('AFTER_THREAD_STEP', thread);
}

/**
Expand Down