"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;
var _genlex = require("../../lib/genlex/genlex");
var _index = require("../../lib/parsec/index");
var _index2 = _interopRequireDefault(require("../../lib/stream/index"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
/*
 Implementing general solution :
 E -> T E'
 E' -> + TE'  |  eps
 T -> F T'
 T' -> * FT'  |  eps
 F -> NUMBER | ( E )   (https://en.wikipedia.org/wiki/Operator-precedence_parser)



 * Expr -> SubExpr then OptYieldExpr
 * OptYieldExpr -> YieldExpr.opt()
 * YieldExpr ->  + then SubExpr then YieldExpr
 * PriorExpr -> Terminal then OptPriorExpr
 * OptPriorExpr -> PriorExpr.opt()
 * PriorExpr ->  * then Terminal then OptPriorExpr
 * Terminal -> (Expr)| Number | -Terminal | Expr  // care of priority !

 */

// tokens
var genlex = (0, _genlex.getMathGenLex)();
var _genlex$tokens = genlex.tokens(),
  number = _genlex$tokens.number,
  plus = _genlex$tokens.plus,
  minus = _genlex$tokens.minus,
  mult = _genlex$tokens.mult,
  div = _genlex$tokens.div,
  open = _genlex$tokens.open,
  close = _genlex$tokens.close;
var priorToken = function priorToken() {
  return mult.or(div);
};
var yieldToken = function yieldToken() {
  return plus.or(minus);
};
function terminal() {
  return parenthesis().or(number).or(negative()).or(_index.F.lazy(expression));
}
function negative() {
  return minus.drop().then(_index.F.lazy(terminal)).single().map(function (x) {
    return -x;
  });
}
function parenthesis() {
  return open.drop().then(_index.F.lazy(expression)).then(close.drop()).single();
}
function expression() {
  return priorExpr().flatMap(optYieldExpr);
}
function optYieldExpr(left) {
  return yieldExpr(left).opt().map(function (opt) {
    return opt.isPresent() ? opt.get() : left;
  });
}
function yieldExpr(left) {
  return yieldToken().then(priorExpr()).array().map(function (_ref) {
    var _ref2 = _slicedToArray(_ref, 2),
      token = _ref2[0],
      right = _ref2[1];
    return token === '+' ? left + right : left - right;
  }).flatMap(optYieldExpr);
}
function priorExpr() {
  return terminal().flatMap(optSubPriorExp);
}
function optSubPriorExp(priorValue) {
  return subPriorExpr(priorValue).opt().map(function (opt) {
    return opt.isPresent() ? opt.get() : priorValue;
  });
}
function subPriorExpr(priorValue) {
  return priorToken().then(terminal()).array().map(function (_ref3) {
    var _ref4 = _slicedToArray(_ref3, 2),
      token = _ref4[0],
      left = _ref4[1];
    return token === '*' ? priorValue * left : priorValue / left;
  }).flatMap(optSubPriorExp);
}
function multParser() {
  var parser = expression();
  return genlex.use(parser.then(_index.F.eos().drop()).single());
}
var _default = exports["default"] = {
  setUp: function setUp(done) {
    done();
  },
  'expect multExpr to make mults': function expect_multExpr_to_make_mults(test) {
    var parsing = multParser().parse(_index2["default"].ofString('3 * 4'));
    test.equal(parsing.value, 12, 'simple multiplication');
    parsing = multParser().parse(_index2["default"].ofString('14 / 4'));
    test.equal(parsing.value, 3.5, 'simple division');
    parsing = multParser().parse(_index2["default"].ofString('14 / 4*3 '));
    test.equal(parsing.value, 10.5, 'combine mult and div');
    parsing = multParser().parse(_index2["default"].ofString('14 / 4*3 /2*  2 '));
    test.equal(parsing.value, 10.5, 'combine more mult and div');
    test.done();
  },
  'expect multExpr to make negative priorities': function expect_multExpr_to_make_negative_priorities(test) {
    var parsing = multParser().parse(_index2["default"].ofString('3 * -4'));
    test.equal(parsing.value, -12, 'negative multiplication');
    test.done();
  },
  'expect Expr to be inside parenthesis': function expect_Expr_to_be_inside_parenthesis(test) {
    var parsing = multParser().parse(_index2["default"].ofString('3 * (4)'));
    test.equal(parsing.value, 12, 'simple parenthesis expr');
    parsing = multParser().parse(_index2["default"].ofString('3 * (2*4)'));
    test.equal(parsing.value, 24, 'more complexe parenthesis expr');
    parsing = multParser().parse(_index2["default"].ofString('3 * (2*(4))'));
    test.equal(parsing.value, 24, 'deep parenthesis expr');
    test.done();
  },
  'expect + and * to respect priorities': function expect__and__to_respect_priorities(test) {
    var parsing = multParser().parse(_index2["default"].ofString('3 +2*4 '));
    test.equal(parsing.value, 11, 'simple multiplication');
    test.done();
  },
  'expect - and / to respect priorities': function expect__and___to_respect_priorities(test) {
    var parsing = multParser().parse(_index2["default"].ofString('3 + -4/2*5 '));
    test.equal(parsing.value, -7, 'bad priorities');
    test.done();
  }
};
//# sourceMappingURL=genlex-operation.js.map