earley-sgf
Version:
Early algorithm used to parse SGF file
182 lines (181 loc) • 4.82 kB
JavaScript
import { sgfTree } from './sgfTree.js';
/*
* Asserts the type is Parent and the token value.
*/
function atn(obj, token) {
if (!('children' in obj)) {
throw new TypeError('Not a Parent');
}
if (obj.token !== token) {
throw new TypeError('token is ' + obj.token);
}
return obj;
}
/*
* Asserts the type is Terminal
*/
function getText(obj) {
if (!('text' in obj)) {
throw new TypeError('Not a Terminal');
}
return obj.text;
}
function sgfGame(sgfFileContents) {
const _collection = sgfTree(sgfFileContents);
if (_collection === null) {
throw new TypeError('Parsing of SGF failed');
}
/*
* Only interested in the first game in the collection
*/
const _tree = atn(_collection.children[0], 'tree');
return createTree(_tree);
}
/**
* tree -> ( nodes trees )
* nodes -> node
* nodes -> node nodes
*/
function createTree(_tree) {
let _nodes = atn(_tree.children[1], 'nodes');
let nodes = [];
while (true) {
const _node = atn(_nodes.children[0], 'node');
nodes.push(createNode(_node));
if (_nodes.children.length === 1)
break;
_nodes = atn(_nodes.children[1], 'nodes');
}
const _trees = atn(_tree.children[2], 'trees');
const children = createTrees(_trees);
return { nodes, children };
}
/**
* trees -> tree trees
* trees ->
*/
function createTrees(_trees) {
let trees = [];
while (_trees.children.length === 2) {
const _tree = atn(_trees.children[0], 'tree');
trees.push(createTree(_tree));
_trees = atn(_trees.children[1], 'trees');
}
return trees;
}
/**
* node -> ; props
* props ->
* props -> prop props
*/
function createNode(_node) {
let _props = atn(_node.children[1], 'props');
let props = [];
while (_props.children.length === 2) {
const _prop = atn(_props.children[0], 'prop');
const prop = createProp(_prop);
if (prop != null)
props.push(prop);
_props = atn(_props.children[1], 'props');
}
return { props };
}
/**
* prop -> setup values
* prop -> komi [ text ]
*/
function createProp(_prop) {
const type = _prop.children[0];
switch (type.token) {
case 'move':
return createMove(_prop);
case 'setup':
return createStone(_prop);
case 'territory':
return createScore(_prop);
case 'player':
return createPlayer(_prop);
case 'komi':
const komi = getText(_prop.children[2]);
return { komi };
case 'date':
const date = getText(_prop.children[2]);
return { date };
case 'size':
const size = getText(_prop.children[2]);
return { size };
case 'result':
const result = getText(_prop.children[2]);
return { result };
case 'malformed':
case 'ignored':
return null;
default:
throw new TypeError('Not a property ' + type.token);
}
}
/*
* prop -> move [ text ]
* prop -> move [ ]
* move -> B
* move -> W
*/
function createMove(_prop) {
let _move = atn(_prop.children[0], 'move');
const move = getText(_move.children[0]);
if (_prop.children.length === 4) {
const position = getText(_prop.children[2]);
return { move, position };
}
else {
return { move };
}
}
/*
* prop -> setup values
* setup -> AB | AW | AE
*/
function createStone(_prop) {
const _setup = atn(_prop.children[0], 'setup');
const stone = getText(_setup.children[0]).substring(1);
const _values = atn(_prop.children[1], 'values');
const positions = createPositions(_values);
return { stone, positions };
}
/*
* prop -> territory values
* territory -> TB | TW | TE
*/
function createScore(_prop) {
const _territory = atn(_prop.children[0], 'territory');
const score = getText(_territory.children[0]).substring(1);
const _values = atn(_prop.children[1], 'values');
const positions = createPositions(_values);
return { score, positions };
}
/*
* values -> [ text ]
* values -> [ text ] values
*/
function createPositions(_values) {
let strings = [];
while (true) {
strings.push(getText(_values.children[1]));
if (_values.children.length !== 4)
break;
_values = atn(_values.children[3], 'values');
}
return strings;
}
/**
* prop -> player [ text ]
* player -> PB | PW
*/
function createPlayer(_prop) {
const _player = atn(_prop.children[0], 'player');
const player = getText(_player.children[0]).substring(1);
const name = getText(_prop.children[2]);
return { player, name };
}
export { sgfGame };
export { sgfHead } from './sgfTree.js';