blob: 14e0da8694f1bcd49e59adb723174ebf009872e0 [file] [log] [blame]
/**
* The MIT License (MIT)
* Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
*/
'use strict';
var _require = require('../../transform/utils'),
increaseQuantifierByOne = _require.increaseQuantifierByOne;
/**
* A regexp-tree plugin to merge quantifiers
*
* a+a+ -> a{2,}
* a{2}a{3} -> a{5}
* a{1,2}a{2,3} -> a{3,5}
*/
module.exports = {
Repetition: function Repetition(path) {
var node = path.node,
parent = path.parent;
if (parent.type !== 'Alternative' || !path.index) {
return;
}
var previousSibling = path.getPreviousSibling();
if (!previousSibling) {
return;
}
if (previousSibling.node.type === 'Repetition') {
if (!previousSibling.getChild().hasEqualSource(path.getChild())) {
return;
}
var _extractFromTo = extractFromTo(previousSibling.node.quantifier),
previousSiblingFrom = _extractFromTo.from,
previousSiblingTo = _extractFromTo.to;
var _extractFromTo2 = extractFromTo(node.quantifier),
nodeFrom = _extractFromTo2.from,
nodeTo = _extractFromTo2.to;
// It's does not seem reliable to merge quantifiers with different greediness
// when none of both is a greedy open range
if (previousSibling.node.quantifier.greedy !== node.quantifier.greedy && !isGreedyOpenRange(previousSibling.node.quantifier) && !isGreedyOpenRange(node.quantifier)) {
return;
}
// a*a* -> a*
// a*a+ -> a+
// a+a+ -> a{2,}
// a{2}a{4} -> a{6}
// a{1,2}a{2,3} -> a{3,5}
// a{1,}a{2,} -> a{3,}
// a+a{2,} -> a{3,}
// a??a{2,} -> a{2,}
// a*?a{2,} -> a{2,}
// a+?a{2,} -> a{3,}
node.quantifier.kind = 'Range';
node.quantifier.from = previousSiblingFrom + nodeFrom;
if (previousSiblingTo && nodeTo) {
node.quantifier.to = previousSiblingTo + nodeTo;
} else {
delete node.quantifier.to;
}
if (isGreedyOpenRange(previousSibling.node.quantifier) || isGreedyOpenRange(node.quantifier)) {
node.quantifier.greedy = true;
}
previousSibling.remove();
} else {
if (!previousSibling.hasEqualSource(path.getChild())) {
return;
}
increaseQuantifierByOne(node.quantifier);
previousSibling.remove();
}
}
};
function isGreedyOpenRange(quantifier) {
return quantifier.greedy && (quantifier.kind === '+' || quantifier.kind === '*' || quantifier.kind === 'Range' && !quantifier.to);
}
function extractFromTo(quantifier) {
var from = void 0,
to = void 0;
if (quantifier.kind === '*') {
from = 0;
} else if (quantifier.kind === '+') {
from = 1;
} else if (quantifier.kind === '?') {
from = 0;
to = 1;
} else {
from = quantifier.from;
if (quantifier.to) {
to = quantifier.to;
}
}
return { from: from, to: to };
}