import '../../../assert/js/assert.js';
import '../../../globals.js';
import { alpenglow, RenderExecutionStack, RenderInstructionLocation } from '../imports.js';
// Should be kept empty
const scratchInstructions = [];
export default class RenderExecutor {
    constructor() {
        this.stack = new RenderExecutionStack();
        this.indexStack = [];
        this.instructions = [];
        this.instructionIndex = 0;
        this.isDone = false;
        this.evaluator = this.execute.bind(this);
    }
    loadRenderProgram(renderProgram) {
        renderProgram.writeInstructions(scratchInstructions);
        this.loadInstructions(scratchInstructions);
        scratchInstructions.length = 0;
    }
    loadInstructions(instructions) {
        this.instructions.length = 0;
        for (let i = 0; i < instructions.length; i++) {
            const instruction = instructions[i];
            // Don't actually insert locations. Just store the index for now.
            if (instruction instanceof RenderInstructionLocation) {
                instruction.index = this.instructions.length;
            }
            else {
                this.instructions.push(instruction);
            }
        }
        this.updateIndices();
    }
    reset() {
        this.stack.reset();
        this.indexStack.length = 0;
        this.instructionIndex = 0;
        this.isDone = false;
    }
    execute(context, output) {
        const stack = this.stack;
        const instructions = this.instructions;
        this.stack.reset();
        this.indexStack.length = 0;
        this.instructionIndex = 0;
        this.isDone = false;
        // NOTE: Implicit "exit" at the end of any sequence
        while (!this.isDone && this.instructionIndex < instructions.length) {
            instructions[this.instructionIndex++].execute(stack, context, this);
        }
        assert && assert(this.stack.getLength() === 1);
        stack.popInto(output);
        return output;
    }
    jump(location) {
        this.instructionIndex = location.index;
    }
    call(location) {
        this.indexStack.push(this.instructionIndex);
        this.instructionIndex = location.index;
    }
    return() {
        assert && assert(this.indexStack.length > 0);
        this.instructionIndex = this.indexStack.pop();
    }
    exit() {
        this.isDone = true;
    }
    updateIndices() {
        for (let i = 0; i < this.instructions.length; i++) {
            const instruction = this.instructions[i];
            if (instruction instanceof RenderInstructionLocation) {
                instruction.index = i;
            }
        }
    }
}
alpenglow.register('RenderExecutor', RenderExecutor);
//# sourceMappingURL=RenderExecutor.js.map