Source: EBNFP/Lst.js

"use strict";

/** @fileOverview Implements `class page.EBNFP.Lst extends page.EBNF.Lst`.
  * @author Axel T. Schreiner <ats@cs.rit.edu>
  * @version 1.5.1
  */

/** Creates a new representation of a delimited iteration for EBNFP.
  * @class Represents a delimited iteration for EBNFP.
  * @extends page.EBNF.Lst
  *
  * @example
  * some: item +/ delimiter;
  * many: item ⭑/ delimiter;
  *
  * @private
  *
  * @param {epNode} _node body.
  * @param {epNode} _delim delimiter.
  * @param {number} _min minimum number of occurences, 0 or 1.
  *
  * @property {epNode} node body.
  * @property {epNode} 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.EBNFP.Lst = function (_node, _delim, _min) {
  page.EBNF.Lst.call(this, _node, _delim, _min);
};

page.subclass(page.EBNFP.Lst, 'page.EBNFP.Lst', page.EBNF.Lst);

/** Called once by {@link page.EBNFP#init} to recursively translate into BNF.
  *
  *     a +/ b
  *     a ⭑/ b
  *
  * where `.min` is 1 or 0, respectively, are translated to
  *
  *     $#:  %prec error;         # for min == 0
  *     $#:  a $## %prec error;   # factored out
  *     $#:  error $##;
  *     $##: %prec error;
  *     $##: $## b a;
  *     $##: $# error a;
  *     $##: $# b error;
  *     $##: $# error;
  *
  * `error` depends on `_grammar.recover`
  * and `%prec error` is inserted if the grammar specifies `%right error`.
  *
  * @private
  * @override
  * @variation EBNFP
  *
  * @param {page.EBNFP} _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.EBNFP.Lst.prototype.toBNF = function (_grammar, _nt) {
  _grammar.assert('__WHERE__', !this.nt);

  // insert error?
  var error = _grammar.bnf.token();
  var prec = 'prec' in error && error.prec.assoc == 'right';
  if (!_grammar.recover && !prec) error = null;

  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);
  if (error) _grammar.bnf.rules.push(null, 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++] =                                                 // $#: [%prec error]
      prec ? _grammar.bnf.rule(result, [ ], error) : _grammar.bnf.rule(result, [ ]);
  _grammar.bnf.rules[at++] =                                                   // $#: node $## [%prec error]
    prec ? _grammar.bnf.rule(result, [ node, nt1 ], error) : _grammar.bnf.rule(result, [ node, nt1 ]);
  if (error)
    _grammar.bnf.rules[at++] = _grammar.bnf.rule(result, [ error, nt1 ]);      // $#: error $##
  _grammar.bnf.rules[at++] =                                                   // $##: [%prec error]
    prec ? _grammar.bnf.rule(nt1, [ ], error) : _grammar.bnf.rule(nt1, [ ]);
  _grammar.bnf.rules[at++] = _grammar.bnf.rule(nt1, [ nt1, delim, node ]);     // $##: $## delim node
  if (error) {
    _grammar.bnf.rules[at++] = _grammar.bnf.rule(nt1, [ nt1, error, node ]);   // $##: $## error node
    _grammar.bnf.rules[at++] = _grammar.bnf.rule(nt1, [ nt1, delim, error ]);  // $##: $## delim error
    _grammar.bnf.rules[at] = _grammar.bnf.rule(nt1, [ nt1, error ]);           // $##: $## error
  }
  return result;
};