"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();
};