"use strict"; /** @fileOverview Implements `class page.EBNF.Lst`. * @author Axel T. Schreiner <ats@cs.rit.edu> * @version 1.5.0 */ /** Creates a new representation of a delimited iteration for EBNF. * @class Represents a delimited iteration for EBNF. * * @example * some: item +/ delimiter; * many: item ⭑/ delimiter; * * @private * * @param {eNode} _node body; null if called during unmarshalling. * @param {eNode} _delim delimiter; null if called during unmarshalling. * @param {number} _min minimum number of occurences, 0 or 1. * * @property {eNode} node body. * @property {eNode} delim delimiter. * @property {number} min minimum number of occurences, 0 or 1. * @property {page.BNF.NT} nt corresponding non-terminal for BNF. * @property {boolean} empty true if no input can be accepted. * @property {Map} first terminals at front, maps ord to {@link page.BNF.T}. * @property {Map} follow terminals following, maps ord to {@link page.BNF.T}. */ page.EBNF.Lst = function (_node, _delim, _min) { this.min = _min; this.node = _node; this.delim = _delim; this.nt = undefined; this.empty = undefined; this.first = undefined; this.follow = undefined; }; page.baseclass(page.EBNF.Lst, 'page.EBNF.Lst'); /** Displays delimited iteration in EBNF notation. * @returns {string} */ page.EBNF.Lst.prototype.toString = function () { var result, d; if (this.node instanceof page.EBNF.Alt || this.node instanceof page.EBNF.Seq) result = '(' + this.node + ')'; else result = this.node.toString(); if (this.delim instanceof page.EBNF.Alt || this.delim instanceof page.EBNF.Seq) d = '(' + this.delim + ')'; else d = this.delim.toString(); return result + (this.min == 1 ? ' +/ ' : ' */ ') + d; }; /** Called once by {@link page.EBNF#init} to recursively translate into BNF. * * a +/ b * a ⭑/ b * * where `.min` is 1 or 0, respectively, are translated to * * $#: ; # for min == 0 * $#: a $##; # factored out * $##: ; * $##: b a $##; * * @private * * @param {page.EBNF} _grammar object to which the construct belongs. * @param {page.EBNF.NT} [_nt] left-hand side, if known; avoids the need for a fresh non-terminal. * * @returns {page.BNF.NT} non-terminal representing the translated construct. */ page.EBNF.Lst.prototype.toBNF = function (_grammar, _nt) { _grammar.assert('__WHERE__', !this.nt); var result = this.nt = _nt ? _nt : _grammar.bnf.nt('$'); // $# var nt1 = _grammar.bnf.nt('$'); // $## var at = _grammar.bnf.rules.length; // placeholder if (this.min == 0) _grammar.bnf.rules.push(null); _grammar.bnf.rules.push(null, null, null); var node = this.node instanceof page.BNF.T ? this.node : this.node.toBNF(_grammar); var delim = this.delim instanceof page.BNF.T ? this.delim : this.delim.toBNF(_grammar); if (this.min == 0) _grammar.bnf.rules[at++] = _grammar.bnf.rule(result, [ ]); // $#: _grammar.bnf.rules[at++] = _grammar.bnf.rule(result, [ node, nt1 ]); // $#: node $## _grammar.bnf.rules[at++] = _grammar.bnf.rule(nt1, [ ]); // $##: _grammar.bnf.rules[at] = _grammar.bnf.rule(nt1, [ delim, node, nt1 ]); // $##: delim node $## return result; }; /** Called once by {@link page.EBNF#init} to complete EBNF grammar initialization. * Imports {@link page.BNF.NT}`.empty`, {@link page.BNF.NT}`.first`, and * {@link page.BNF.NT}`.follow` from {@link page.EBNF.Lst#nt} * and then delegates to the descendants. * @private */ page.EBNF.Lst.prototype.init = function () { this.assert('__WHERE__', !this.first); this.empty = this.nt.empty; this.first = this.nt.first; this.follow = this.nt.follow; if (this.node.init) this.node.init(); if (this.delim.init) this.delim.init(); };