'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * The MIT License (MIT)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      * Copyright (c) 2015-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      */

var _specialSymbols = require('../special-symbols');

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/**
 * Symbols are stored in the registry, and retrieved from it
 * if the symbol was already created.
 */
var registry = {};

/**
 * Class encapsulates operations with one
 * grammar symbol (terminal or non-terminal)
 */

var GrammarSymbol = function () {
  function GrammarSymbol(symbol) {
    _classCallCheck(this, GrammarSymbol);

    this._symbol = symbol;
  }

  /**
   * Terminals in our grammar are quoted,
   * "a", " ", "var", etc.
   */


  _createClass(GrammarSymbol, [{
    key: 'isTerminal',
    value: function isTerminal() {
      var first = this._symbol[0];
      var last = this._symbol[this._symbol.length - 1];

      return first === '"' && last === '"' || first === "'" && last === "'";
    }

    /**
     * Returns original symbol from an extended name. 1X3 => X
     */

  }, {
    key: 'getOrignialSymbol',
    value: function getOrignialSymbol() {
      if (!this._originalSymbol) {
        this._originalSymbol = this._symbol.replace(/^\d+\|/, '').replace(/\|(?:\d+|\$)$/, '');
      }
      return this._originalSymbol;
    }

    /**
     * Returns start context (in extended LALR 1X3 => 1)
     */

  }, {
    key: 'getStartContext',
    value: function getStartContext() {
      if (!this._startContext) {
        this._startContext = Number(this._symbol.match(/^(\d+)\|/)[1]);
      }
      return this._startContext;
    }

    /**
     * Returns start context (in extended LALR 1X3 => 1)
     */

  }, {
    key: 'getEndContext',
    value: function getEndContext() {
      if (!this._endContext) {
        this._endContext = Number(this._symbol.match(/\|(\d+)$/)[1]);
      }
      return this._endContext;
    }

    /**
     * Returns a symbol from the registry, or creates one.
     */

  }, {
    key: 'getTerminalValue',


    /**
     * Returns raw terminal value (between quotes)
     */
    value: function getTerminalValue() {
      this._checkTerminal();
      return this._symbol.slice(1, this._symbol.length - 1);
    }

    /**
     * Returns a terminal quoted into single or double-quotes,
     * depending on which quotes it's already wrapped itself.
     */

  }, {
    key: 'quotedTerminal',
    value: function quotedTerminal() {
      this._checkTerminal();
      var isSingleQuoted = this._symbol[0] === "'";

      var leftQuote = isSingleQuoted ? '"\'' : '\'"';
      var rightQuote = isSingleQuoted ? '\'"' : '"\'';

      return '' + leftQuote + this.getTerminalValue() + rightQuote;
    }

    /**
     * Checks whether a symbol is a non-terminal.
     */

  }, {
    key: 'isNonTerminal',
    value: function isNonTerminal() {
      return !this.isTerminal();
    }

    /**
     * Checks whether a symbol is Epsilon (instance method).
     */

  }, {
    key: 'isEpsilon',
    value: function isEpsilon() {
      return GrammarSymbol.isEpsilon(this._symbol);
    }

    /**
     * Checks whether a symbol is an end of file (instance method).
     */

  }, {
    key: 'isEOF',
    value: function isEOF() {
      return this._symbol === _specialSymbols.EOF;
    }

    /**
     * Checks whether a symbol is Epsilon (static method).
     */

  }, {
    key: 'getSymbol',


    /**
     * Returns raw symbol.
     */
    value: function getSymbol() {
      return this._symbol;
    }

    /**
     * Checks whether the symbol equals to the passed one.
     */

  }, {
    key: 'isSymbol',
    value: function isSymbol(symbol) {
      return this.getSymbol() === symbol;
    }
  }, {
    key: '_checkTerminal',
    value: function _checkTerminal() {
      if (!this.isTerminal()) {
        throw new TypeError('Symbol ' + this._symbol + ' is not terminal.');
      }
    }
  }], [{
    key: 'get',
    value: function get(symbol) {
      if (!registry.hasOwnProperty(symbol)) {
        registry[symbol] = new GrammarSymbol(symbol);
      }
      return registry[symbol];
    }
  }, {
    key: 'isEpsilon',
    value: function isEpsilon(symbol) {
      return symbol.includes(_specialSymbols.EPSILON);
    }

    /**
     * Checks whether a symbol is EOF (static method).
     */

  }, {
    key: 'isEOF',
    value: function isEOF(symbol) {
      return symbol === _specialSymbols.EOF;
    }
  }]);

  return GrammarSymbol;
}();

exports.default = GrammarSymbol;