"use strict";

function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.TokenDefinition = exports.Token = exports.GenLex = void 0;
exports.getMathGenLex = getMathGenLex;
var _response = _interopRequireDefault(require("../parsec/response.js"));
var _index = require("../parsec/index.js");
var _unit = _interopRequireDefault(require("../data/unit.js"));
var _option = _interopRequireDefault(require("../data/option.js"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
var TokenDefinition = exports.TokenDefinition = /*#__PURE__*/_createClass(
// value will be determined at runtime while parsing
function TokenDefinition(parser, name, precedence) {
  _classCallCheck(this, TokenDefinition);
  this.parser = parser;
  this.name = name;
  this.precedence = precedence;
}); // a Token object is instantiated at runtime, with a value given by the parsed text
var Token = exports.Token = /*#__PURE__*/function () {
  function Token(name, value) {
    _classCallCheck(this, Token);
    this.name = name;
    this.value = value;
  }
  return _createClass(Token, [{
    key: "accept",
    value: function accept(name) {
      // TODO logger console.log('accepting', name, this.name===name, this.value);
      return this.name === name ? _option["default"].some(this.value) : _option["default"].none();
    }
  }]);
}();
var GenLex = exports.GenLex = /*#__PURE__*/function () {
  function GenLex() {
    _classCallCheck(this, GenLex);
    this.spaces = defaultSpaces();
    // definitions keep trace of all: parser, precedence and name
    this.definitions = [];
    // get a token, but not directly its precedence
    this.tokensMap = {};
  }
  return _createClass(GenLex, [{
    key: "tokenize",
    value: function tokenize(parser, name) {
      var precedence = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
      if (typeof parser === 'string') {
        if (name === undefined) {
          name = parser;
        }
        return this.tokenize(_index.C.string(parser), name, precedence);
      }
      var definition = new TokenDefinition(parser, name, precedence);
      this.definitions.push(definition);

      // probably a bad name
      var token = literal(function (token) {
        return token.accept(name);
      }, name);
      this.tokensMap[name] = token;
      return token;
    }
  }, {
    key: "keywords",
    value: function keywords(keys) {
      var _this = this;
      var precedence = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1000;
      return keys.reduce(function (acc, key) {
        return acc.concat(_this.tokenize(key, key, precedence));
      }, []);
    }
  }, {
    key: "setSeparators",
    value: function setSeparators(spacesCharacters) {
      if (typeof spacesCharacters !== 'string') {
        throw "setSeparators needs a string as separators, such as ' \r\n\f\t' ;" + " use  setSeparatorsParser to declare a parser";
      }
      this.spaces = _index.C.charIn(spacesCharacters).map(function () {
        return _unit["default"];
      });
    }

    /**
     * Set separator Parser. It's up to the parser to accept or not
     * optional repetition
     * @param spacesParser
     */
  }, {
    key: "setSeparatorsParser",
    value: function setSeparatorsParser(spacesParser) {
      this.spaces = spacesParser.map(function () {
        return _unit["default"];
      });
    }
  }, {
    key: "updatePrecedence",
    value: function updatePrecedence(tokenName, precedence) {
      this.definitions.find(function (def) {
        return def.name === tokenName;
      }).precedence = precedence;
    }
  }, {
    key: "buildTokenizer",
    value: function buildTokenizer() {
      var token = this.findTokenByPrecedence();
      return this.spaces.optrep().drop().then(token).then(this.spaces.optrep().drop()).single();
    }
  }, {
    key: "use",
    value: function use(grammar) {
      return this.buildTokenizer().chain(grammar);
    }
  }, {
    key: "findTokenByPrecedence",
    value: function findTokenByPrecedence() {
      var sortedDefinitions = this.definitions.sort(function (d1, d2) {
        return d2.precedence - d1.precedence;
      });
      return sortedDefinitions.reduce(function (combinator, definition) {
        return _index.F["try"](getTokenParser(definition))
        //    .or (F.error('no match for '+definition.name))
        .or(combinator);
      }, _index.F.error());
    }
  }, {
    key: "remove",
    value: function remove(tokenName) {
      // find definitions
      this.definitions = this.definitions.filter(function (d) {
        return d.name !== tokenName;
      });
      delete this.tokensMap[tokenName];
    }

    // type: { [key: string]: Parser }
  }, {
    key: "tokens",
    value: function tokens() {
      return this.tokensMap;
    }
  }, {
    key: "get",
    value: function get(tokenName) {
      return this.tokensMap[tokenName];
    }
  }]);
}();
function getTokenParser(def) {
  return def.parser.map(function (value) {
    return new Token(def.name, value);
  });
}

// name is for easier debugging
// eslint-disable-next-line
function literal(tokenize, name) {
  return _index.F.parse(function (input, index) {
    // TODO logger console.log('testing ', {name, input:input.get(index), index});
    // console.log('trying ', {index, name});

    return input.get(index)
    // FIXME= value is the token, token is the value
    .map(function (value) {
      /* TODO: keep for logger
      let token = value;
       try {
          console.log('in map', {value, name, index});
          console.log('tokenizing', tokenize(token));
      } catch (e) {
          console.error('failed', e)
      }*/

      return tokenize(value).map(function (token) {
        // TODO logger console.log('accept with ', name, index);
        //console.log('accept:', token,index, input.location(index));
        return _response["default"].accept(token, input, index + 1, true);
      }).orLazyElse(function () {
        // TODO logger console.log('lazyElse failed with ', name, index);
        // console.log('reject:',index, input.source.offsets[index],input,'>>>', value,
        //  input.location(index));
        return _response["default"].reject(input, index, false);
      });
    }).lazyRecoverWith(function () {
      // TODO logger console.log('failed with ', name, index);
      //console.log('lazyRecover with offset:', input.location(index));
      return _response["default"].reject(input, index, false);
    });
  });
}
function defaultSpaces() {
  return _index.C.charIn(' \r\n\f\t').map(function () {
    return _unit["default"];
  });
}
function getMathGenLex() {
  var basicGenlex = new GenLex();

  // We try first to have digits
  basicGenlex.tokenize(_index.N.number(), 'number', 1100);
  basicGenlex.tokenize(_index.C["char"]('+'), 'plus', 1000);
  basicGenlex.tokenize(_index.C["char"]('-'), 'minus', 1000);
  basicGenlex.tokenize(_index.C["char"]('*'), 'mult', 800);
  basicGenlex.tokenize(_index.C["char"]('/'), 'div', 800);
  basicGenlex.tokenize(_index.C["char"]('('), 'open', 1000);
  basicGenlex.tokenize(_index.C["char"](')'), 'close', 1000);
  return basicGenlex;
}
//# sourceMappingURL=genlex.js.map