@gobstones/gobstones-lang
Version:
166 lines • 6.5 kB
JavaScript
/* 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