UNPKG

pegisland

Version:

General PEG-based parser supporting island grammars with lake symbols

165 lines 6.61 kB
"use strict"; 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