UNPKG

@gobstones/gobstones-lang

Version:
166 lines 6.5 kB
/* eslint-disable no-underscore-dangle */ import { Parser } from '@gobstones/gobstones-parser'; import { Linter } from '@gobstones/gobstones-parser'; import { SymbolTable } from '@gobstones/gobstones-parser'; import { Compiler } from './compiler'; import { RuntimePrimitives, RuntimeState } from './runtime'; import { VirtualMachine } from './vm'; import { UnknownPosition } from '@gobstones/gobstones-parser'; import { T_UPPERID, T_LOWERID, Token } from '@gobstones/gobstones-parser'; import { ASTDefProcedure, ASTDefFunction, ASTDefType, ASTStmtBlock, ASTConstructorDeclaration } from '@gobstones/gobstones-parser'; /* This module is a façade for all the combined functionality of the * parser/compiler/vm */ const tok = (tag, value) => new Token(tag, value, UnknownPosition, UnknownPosition); export class Runner { constructor() { this.initialize(); } initialize() { this._ast = undefined; this._primitives = new RuntimePrimitives(); this._symtable = this._newSymtableWithPrimitives(); this._linter = new Linter(this._symtable); this._code = undefined; this._vm = undefined; this._result = undefined; } /* Parse, compile, and run a program in the default global state * (typically an empty 9x9 board in Gobstones). * Return the return value of the program, ignoring the final state. * A GbsInterpreterException may be thrown. */ run(input) { return this.runState(input, new RuntimeState()).result; } /* Parse, compile, and run a program in the given initial state. * Return an object of the form * {'result': r, 'state': s] * where r is the result of the program and s is the final state. * A GbsInterpreterException may be thrown. */ runState(input, initialState) { this.parse(input); this.lint(); this.compile(); this.execute(initialState); return { result: this._result, state: this._vm.globalState() }; } parse(input) { const parser = new Parser(input); this._ast = parser.parse(); for (const option of parser.getLanguageOptions()) { this._setLanguageOption(option); } } enableLintCheck(linterCheckId, enabled) { this._linter.enableCheck(linterCheckId, enabled); } lint() { this._symtable = this._linter.lint(this._ast); } compile() { this._code = new Compiler(this._symtable).compile(this._ast); } initializeVirtualMachine(initialState) { this._vm = new VirtualMachine(this._code, initialState); } execute(initialState) { this.executeWithTimeout(initialState, 0); } executeWithTimeout(initialState, millisecs) { this.executeWithTimeoutTakingSnapshots(initialState, millisecs, undefined); } executeWithTimeoutTakingSnapshots(initialState, millisecs, // eslint-disable-next-line @typescript-eslint/ban-types snapshotCallback) { this.initializeVirtualMachine(initialState); this._result = this._vm.runWithTimeoutTakingSnapshots(millisecs, snapshotCallback); } executeEventWithTimeout(eventValue, millisecs) { this._result = this._vm.runEventWithTimeout(eventValue, millisecs); } get abstractSyntaxTree() { return this._ast; } get primitives() { return this._primitives; } get symbolTable() { return this._symtable; } get virtualMachineCode() { return this._code; } get result() { return this._result; } get globalState() { return this._vm.globalState(); } /* Evaluate language options set by the LANGUAGE pragma */ _setLanguageOption(option) { if (option === 'DestructuringForeach') { this.enableLintCheck('forbidden-extension-destructuring-foreach', false); } else if (option === 'AllowRecursion') { this.enableLintCheck('forbidden-extension-allow-recursion', false); } else { throw Error('Unknown language option: ' + option); } } /* Dynamic stack of regions */ regionStack() { return this._vm.regionStack(); } /* Create a new symbol table, including definitions for all the primitive * types and operations (which come from RuntimePrimitives) */ _newSymtableWithPrimitives() { const symtable = new SymbolTable(); /* Populate symbol table with primitive types */ for (const type of this._primitives.types()) { symtable.defType(this._astDefType(type)); } /* Populate symbol table with primitive procedures */ for (const procedureName of this._primitives.procedures()) { symtable.defProcedure(this._astDefProcedure(procedureName)); } /* Populate symbol table with primitive functions */ for (const functionName of this._primitives.functions()) { symtable.defFunction(this._astDefFunction(functionName)); } return symtable; } _astDefType(type) { const constructorDeclarations = []; for (const constructor of this._primitives.typeConstructors(type)) { constructorDeclarations.push(this._astConstructorDeclaration(type, constructor)); } return new ASTDefType(tok(T_UPPERID, type), constructorDeclarations); } _astDefProcedure(procedureName) { const nargs = this._primitives.getOperation(procedureName).nargs(); const parameters = []; for (let i = 1; i <= nargs; i++) { parameters.push(tok(T_LOWERID, 'x' + i.toString())); } return new ASTDefProcedure(tok(T_LOWERID, procedureName), parameters, new ASTStmtBlock([])); } _astDefFunction(functionName) { const nargs = this._primitives.getOperation(functionName).nargs(); const parameters = []; for (let i = 1; i <= nargs; i++) { parameters.push(tok(T_LOWERID, 'x' + i.toString())); } return new ASTDefFunction(tok(T_LOWERID, functionName), parameters, new ASTStmtBlock([])); } _astConstructorDeclaration(type, constructor) { const fields = []; for (const field of this._primitives.constructorFields(type, constructor)) { fields.push(tok(T_LOWERID, field)); } return new ASTConstructorDeclaration(tok(T_UPPERID, constructor), fields); } } //# sourceMappingURL=runner.js.map