UNPKG

earley-sgf

Version:

Early algorithm used to parse SGF file

182 lines (181 loc) 4.82 kB
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';