@masala/parser
Version:
180 lines (129 loc) • 5.76 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _genlex = require('../../lib/genlex/genlex');
var _index = require('../../lib/parsec/index');
var _index2 = require('../../lib/stream/index');
var _index3 = _interopRequireDefault(_index2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*
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());
}
exports.default = {
setUp: function setUp(done) {
done();
},
'expect multExpr to make mults': function expectMultExprToMakeMults(test) {
var parsing = multParser().parse(_index3.default.ofString('3 * 4'));
test.equal(parsing.value, 12, 'simple multiplication');
parsing = multParser().parse(_index3.default.ofString('14 / 4'));
test.equal(parsing.value, 3.5, 'simple division');
parsing = multParser().parse(_index3.default.ofString('14 / 4*3 '));
test.equal(parsing.value, 10.5, 'combine mult and div');
parsing = multParser().parse(_index3.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 expectMultExprToMakeNegativePriorities(test) {
var parsing = multParser().parse(_index3.default.ofString('3 * -4'));
test.equal(parsing.value, -12, 'negative multiplication');
test.done();
},
'expect Expr to be inside parenthesis': function expectExprToBeInsideParenthesis(test) {
var parsing = multParser().parse(_index3.default.ofString('3 * (4)'));
test.equal(parsing.value, 12, 'simple parenthesis expr');
parsing = multParser().parse(_index3.default.ofString('3 * (2*4)'));
test.equal(parsing.value, 24, 'more complexe parenthesis expr');
parsing = multParser().parse(_index3.default.ofString('3 * (2*(4))'));
test.equal(parsing.value, 24, 'deep parenthesis expr');
test.done();
},
'expect + and * to respect priorities': function expectAndToRespectPriorities(test) {
var parsing = multParser().parse(_index3.default.ofString('3 +2*4 '));
test.equal(parsing.value, 11, 'simple multiplication');
test.done();
},
'expect - and / to respect priorities': function expectAndToRespectPriorities(test) {
var parsing = multParser().parse(_index3.default.ofString('3 + -4/2*5 '));
test.equal(parsing.value, -7, 'bad priorities');
test.done();
}
};
//# sourceMappingURL=genlex-operation.js.map