pegisland
Version:
General PEG-based parser supporting island grammars with lake symbols
165 lines • 6.61 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.processLakes = exports.isLake = void 0;
// Copyright (C) 2021- Katsumi Okuda. All rights reserved.
const assert_1 = require("assert");
const AltCalculator_1 = require("./set/AltCalculator");
const BeginningCalculator_1 = require("./set/BeginningCalculator");
const ParsingExpression_1 = require("./ParsingExpression");
const IParsingExpressionVisitor_1 = require("./IParsingExpressionVisitor");
const PostorderExpressionTraverser_1 = require("./PostorderExpressionTraverser");
const set_operations_1 = require("./set-operations");
const SucceedCalculator_1 = require("./set/SucceedCalculator");
function isLake(symbol) {
return /^<.*?>$/.test(symbol);
}
exports.isLake = isLake;
function isDummy(rhs) {
if (rhs instanceof ParsingExpression_1.Sequence) {
if (rhs.operands.length === 2) {
const [first, second] = rhs.operands;
return (first instanceof ParsingExpression_1.Not &&
first.operand instanceof ParsingExpression_1.Terminal &&
first.operand.regex.source === '.' &&
second instanceof ParsingExpression_1.Terminal &&
second.regex.source === '.');
}
}
return false;
}
function removeDuplications(rules, nonterminals) {
return [
...new Set(nonterminals.map((nonterminal) => nonterminal.rule.symbol)),
].map((name) => new ParsingExpression_1.Nonterminal(rules.get(name)));
}
function removeDup(rules, symbols) {
const terminals = [...symbols].filter((symbol) => symbol instanceof ParsingExpression_1.Terminal);
const nonterminals = [...symbols].filter((symbol) => symbol instanceof ParsingExpression_1.Nonterminal);
return new Set([...terminals, ...removeDuplications(rules, nonterminals)]);
}
function convert(rules, alts) {
const dic = new Map([...rules.entries()].map(([symbol, rule]) => [
symbol,
removeDup(rules, alts.get(rule.rhs)),
]));
return dic;
}
function expandLake(alts, altSymbols) {
return new Set([...alts]
.map((alt) => alt instanceof ParsingExpression_1.Nonterminal && isLake(alt.rule.symbol)
? [
...altSymbols.get(alt.rule.symbol),
]
: alt)
.flat());
}
function expandLakes(altSymbols) {
let isChanging = true;
while (isChanging) {
isChanging = false;
[...altSymbols.keys()].forEach((key) => {
const alts = altSymbols.get(key);
const expandedAlts = expandLake(alts, altSymbols);
altSymbols.set(key, expandedAlts);
isChanging || (isChanging = !(0, set_operations_1.areEqualSets)(alts, expandedAlts));
});
}
}
function removeLakes(altSymbols) {
[...altSymbols.keys()].forEach((key) => {
const alts = altSymbols.get(key);
const altsWithoutLakes = new Set([...alts].filter((alt) => !(alt instanceof ParsingExpression_1.Nonterminal && isLake(alt.rule.symbol))));
altSymbols.set(key, altsWithoutLakes);
});
}
function processLakes(peg, waterSymbols = []) {
createRulesForLakeSymbols(peg);
// console.log(peg.toString());
const alts = calculateAlts(peg);
const altSymbols = convert(peg.rules, alts);
expandLakes(altSymbols);
removeLakes(altSymbols);
[...altSymbols.keys()].forEach((key) => {
const alts = altSymbols.get(key);
altSymbols.set(key, removeDup(peg.rules, alts));
});
updateLakeRules(peg, altSymbols, waterSymbols);
processLakeOperators(peg, alts);
}
exports.processLakes = processLakes;
function updateLakeRules(peg, altSymbols, waterSymbols) {
peg.rules.forEach((rule, symbol) => {
const isLakeSymbol = isLake(symbol);
if (isLakeSymbol) {
const altSet = altSymbols.get(rule.symbol);
updateLakeRule(altSet, waterSymbols, peg, rule);
}
});
}
function updateLakeRule(altSet, waterSymbols, peg, rule) {
let waters = [
new ParsingExpression_1.Sequence([
...[...altSet.values()].map((symbol) => new ParsingExpression_1.Not(symbol)),
new ParsingExpression_1.Terminal(/./, '.'),
]),
];
const waterExps = [
...waterSymbols
.filter((s) => peg.rules.has(s))
.map((s) => new ParsingExpression_1.Nonterminal(peg.rules.get(s))),
];
waters = [...waterExps, ...waters];
(0, assert_1.strict)(!(rule.rhs instanceof ParsingExpression_1.NullParsingExpression));
if (rule.rhs instanceof ParsingExpression_1.OrderedChoice) {
rule.rhs = new ParsingExpression_1.OrderedChoice([...rule.rhs.operands, ...waters]);
}
else if (isDummy(rule.rhs)) {
rule.rhs = createRhs([...waters]);
}
else {
rule.rhs = createRhs([rule.rhs, ...waters]);
}
}
function createRulesForLakeSymbols(peg) {
[...peg.rules.keys()]
.filter((symbol) => isLake(symbol))
.forEach((lakeSymbol) => {
const rule = peg.rules.get(lakeSymbol);
if (rule.rhs instanceof ParsingExpression_1.NullParsingExpression) {
rule.rhs = new ParsingExpression_1.Sequence([
new ParsingExpression_1.Not(new ParsingExpression_1.Terminal(/./, '.')),
new ParsingExpression_1.Terminal(/./, '.'),
]);
}
});
}
function calculateAlts(peg) {
const beginnings = new BeginningCalculator_1.BeginningCalculator(peg.rules).calculate();
const succeeds = new SucceedCalculator_1.SucceedCalculator(peg.rules, beginnings).calculate();
return new AltCalculator_1.AltCalculator(peg.rules, beginnings, succeeds).calculate();
}
function processLakeOperators(peg, alts) {
class AltSetter extends IParsingExpressionVisitor_1.DefaultParsingExpressionVisitor {
constructor(altSets, waterRules) {
super();
this.altSets = altSets;
this.waterRules = waterRules;
}
visitLake(pe) {
pe.makeSemantics(this.altSets.get(pe.operand), this.waterRules);
}
}
const waterRules = [...peg.rules.values()].filter((rule) => rule.isWater);
peg.rules.forEach((rule, _symbol) => {
const traverser = new PostorderExpressionTraverser_1.PostorderExpressionTraverser(new AltSetter(alts, waterRules));
traverser.traverse(rule.rhs);
});
}
function createRhs(expressions) {
(0, assert_1.strict)(expressions.length > 0);
if (expressions.length === 1) {
return expressions[0];
}
return new ParsingExpression_1.OrderedChoice(expressions);
}
//# sourceMappingURL=lake.js.map