/src/script/index.ts
import gs from '../gamestate'; import { Label } from './label'; import * as nearley from 'nearley'; import parserGrammar from './parser'; export enum InstructionStatus { OK, Finish, Goto, } export interface InstructionResult { status: InstructionStatus label?: string } export type InstructionPromise = Promise<InstructionResult> export const InstructionPromise = Promise; export interface ScriptInstruction { execute(): InstructionPromise } // TODO: integrate this into script execution state? export async function executeInstructions(l: ScriptInstruction[]): InstructionPromise { for (const i of l) { const r = await i.execute(); if (r.status != InstructionStatus.OK) { return r; } } return { status: InstructionStatus.OK } } export class Script { instructions: ScriptInstruction[] labels: Map<string, number> pc: number constructor(text?: string) { if (text) { this.parse(text); } else { this.reset(); } } reset() { this.instructions = []; this.labels = new Map(); this.pc = 0; } parse(text: string) { this.reset(); // parse script source (TODO: keep parsed script objects?) const parser = new nearley.Parser(nearley.Grammar.fromCompiled(parserGrammar)); parser.feed(text); // Feed in an extra space because our grammar requires whitespace at the end of a statement parser.feed(' '); const instructions = parser.results[0] // scan for labels for (let i = 0; i < instructions.length; i++) { const instr = instructions[i]; if (instr instanceof Label) { this.labels.set(instr.name, i); instructions.splice(i, 1); i--; } } this.instructions = instructions; } step(): InstructionPromise { let r = this.instructions[this.pc].execute(); this.pc++; return r; } async execute() { this.pc = 0; while (this.pc < this.instructions.length) { const r = await this.step(); if (r.status == InstructionStatus.Finish) { break; } else if (r.status == InstructionStatus.Goto) { if (this.labels.has(r.label)) { this.pc = this.labels.get(r.label); } else { throw new Error('Invalid label: ' + r.label); } } } } dump() { console.log(this.instructions); } }