@gobstones/gobstones-lang
Version:
145 lines (128 loc) • 4.54 kB
text/typescript
/* eslint-disable no-console */
/* eslint-disable quote-props */
/* Command-line interface */
import { RuntimeState } from './runtime';
import { Runner } from './runner';
import { readJboardFromFile, writeJboardToFile } from './board_formats';
import fs from 'fs';
import { GbsInterpreterException } from '@gobstones/gobstones-parser';
const startsWith = (string: string, prefix: string): boolean =>
string.substring(0, prefix.length) === prefix;
export interface Options {
arguments: string[];
'initial-board'?: string;
'output-board'?: string;
'print-ast': boolean;
'print-code': boolean;
help: boolean;
}
function readOptions(argv: string[]): Options {
const options = {
arguments: [],
'initial-board': undefined,
'output-board': undefined,
'print-ast': false,
'print-code': false,
help: false
};
let i = 2;
while (i < argv.length) {
if (argv[i] === '-h' || argv[i] === '--help') {
options['help'] = true;
} else if (argv[i] === '-a' || argv[i] === '--ast') {
options['print-ast'] = true;
} else if (argv[i] === '-c' || argv[i] === '--code') {
options['print-code'] = true;
} else if (argv[i] === '-i' && i + 1 < argv.length) {
options['initial-board'] = argv[i + 1];
i++;
} else if (startsWith(argv[i], '--initial-board=')) {
options['initial-board'] = argv[i].substring('--initial-board='.length);
} else if (argv[i] === '-o' && i + 1 < argv.length) {
options['output-board'] = argv[i + 1];
i++;
} else if (startsWith(argv[i], '--output-board=')) {
options['output-board'] = argv[i].substring('--output-board='.length);
} else {
options['arguments'].push(argv[i]);
}
i++;
}
return options;
}
function help(): void {
const helpMessage = [
'Usage:',
'gobstones-lang input.gbs',
'',
' -a, --ast Print AST (do not run).',
' -c, --code Print virtual machine code (do not run).',
' -i, --initial-board=<file> Load initial board. Default: empty 9x9.',
' -o, --output-board=<file> Save final board.',
' -h, --help Display this help message.'
];
console.log(helpMessage.join('\n'));
}
function printGbsException(exception: GbsInterpreterException): void {
console.log(exception.message);
const startPos = [
exception.startPos.filename,
exception.startPos.line,
exception.startPos.column
].join(':');
const endPos = [exception.endPos.line, exception.endPos.column].join(':');
console.log('At: ' + startPos + '--' + endPos);
}
function runProgram(options: Options, filename: string): void {
const contents = fs.readFileSync(filename, 'utf8');
try {
const inputs = {};
inputs[filename] = contents;
const runner = new Runner();
if (options['print-ast']) {
runner.parse(inputs);
runner.lint();
console.log(runner.abstractSyntaxTree.toString());
return;
}
if (options['print-code']) {
runner.parse(inputs);
runner.lint();
runner.compile();
console.log(runner.virtualMachineCode.toString());
return;
}
const initialState = new RuntimeState();
if (options['initial-board'] !== undefined) {
initialState.load(readJboardFromFile(options['initial-board']));
}
const output = runner.runState(inputs, initialState);
const finalState = output.state.dump();
console.log(JSON.stringify(finalState));
if (options['output-board'] !== undefined) {
writeJboardToFile(options['output-board'], finalState);
}
if (output.result !== undefined) {
/* The program has a return value */
console.log(output.result.toString());
}
} catch (exception) {
if (exception.isGobstonesException === undefined) {
throw exception;
}
printGbsException(exception);
}
}
function main(): void {
const options = readOptions(process.argv);
if (options['help']) {
help();
return;
}
if (options['arguments'].length === 1) {
runProgram(options, options['arguments'][0]);
} else {
help();
}
}
main();