pegisland
Version:
General PEG-based parser supporting island grammars with lake symbols
198 lines • 6.44 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PikaParser = exports.PikaParsingEnv = void 0;
// Copyright (C) 2022- Katsumi Okuda. All rights reserved.
const heap_1 = __importDefault(require("heap"));
const BeginningCalculator_1 = require("./set/BeginningCalculator");
const DepthFirstTraverser_1 = require("./DepthFirstTraverser");
const Indexer_1 = require("./Indexer");
const IParsingEnv_1 = require("./IParsingEnv");
const Position_1 = require("./Position");
const SetCalculator_1 = require("./set/SetCalculator");
const BottomUpParser_1 = require("./BottomUpParser");
class PikaParsingEnv extends IParsingEnv_1.BaseParsingEnv {
constructor(s, peg) {
super(s);
this.peg = peg;
this.parentsMap = createParentsMap(this.peg);
this.createHeap = getHeapCreator(this.peg);
}
parseString(s, start) {
this.fillMemoTable(s);
const startRule = this.peg.rules.get(start);
if (!startRule) {
return Error(`${start} is not a valid nonterminal symbol.`);
}
const result = startRule.parse(this, new Position_1.Position(0, 1, 1));
if (result === null) {
return Error(`Failed to recognize ${start}`);
}
return result;
}
parse(pe, pos) {
// console.log('offset: ' + pos.offset);
if (!this.memo[pos.offset].has(pe)) {
this.memo[pos.offset].set(pe, null);
// const result = pe.parse(this, pos);
// assert(result == null, `${show(pe)} should be null`);
// this.memo[pos.offset].set(pe, result);
}
return this.memo[pos.offset].get(pe);
}
grow(pe, pos) {
const isFirstEval = !this.memo[pos.offset].has(pe);
// console.log('grow ' + show(pe));
if (isFirstEval) {
this.memo[pos.offset].set(pe, null);
}
const result = pe.accept(this.recognizer, pos);
const oldResult = this.memo[pos.offset].get(pe);
if (isFirstEval || (0, BottomUpParser_1.isGrowing)(result, oldResult)) {
this.memo[pos.offset].set(pe, result);
// console.log(result);
return true;
}
return false;
}
fillMemoTable(s) {
for (let pos = s.length; pos >= 0; pos--) {
this.fillMemoEntry(pos);
}
}
fillMemoEntry(pos) {
const [heap] = this.createHeap();
const set = new Set(heap.toArray());
// console.log('heap was created for ' + pos, heap.size());
while (!heap.empty()) {
const pe = heap.pop();
set.delete(pe);
const isGrowing = this.grow(pe, new Position_1.Position(pos, -1, -1)); // XXX
/*
console.log(
pos,
heap.size(),
show(pe) + indexMap.get(pe) + ' was poped!' + isGrowing
);
*/
if (!isGrowing)
continue;
const parents = this.parentsMap.get(pe);
if (!parents)
continue;
parents
.filter((parent) => !set.has(parent))
.forEach((parent) => {
// console.log(show(parent) + ' was pushed!');
heap.push(parent);
set.add(parent);
});
}
}
}
exports.PikaParsingEnv = PikaParsingEnv;
class ParentsBuilder {
constructor(beginning) {
this.beginning = beginning;
this.parents = new Map();
}
build(peg) {
const traverser = new DepthFirstTraverser_1.DepthFirstTraverser(this, (0, BottomUpParser_1.getTopLevelExpressions)(peg));
traverser.traverse();
return this.parents;
}
addParent(pe, parent) {
if (!this.parents.has(pe)) {
this.parents.set(pe, []);
}
const parents = this.parents.get(pe);
parents.push(parent);
}
visitNonterminal(pe) {
this.addParent(pe.rule.rhs, pe);
}
visitTerminal(_pe) {
// Nothing to be done
}
visitZeroOrMore(pe) {
this.addParent(pe.operand, pe);
}
visitOneOrMore(pe) {
this.addParent(pe.operand, pe);
}
visitOptional(pe) {
this.addParent(pe.operand, pe);
}
visitAnd(pe) {
this.addParent(pe.operand, pe);
}
visitNot(pe) {
this.addParent(pe.operand, pe);
}
visitSequence(pe) {
for (const operand of pe.operands) {
this.addParent(operand, pe);
const beginningSet = this.beginning.get(operand);
if (!beginningSet.has(SetCalculator_1.EPSILON)) {
break;
}
}
}
visitOrderedChoice(pe) {
pe.operands.forEach((operand) => {
this.addParent(operand, pe);
});
}
visitGrouping(pe) {
this.addParent(pe.operand, pe);
}
visitRewriting(pe) {
this.addParent(pe.operand, pe);
}
visitColon(pe) {
this.visitBinaryOperator(pe);
}
visitColonNot(pe) {
this.visitBinaryOperator(pe);
}
visitLake(pe) {
this.addParent(pe.operand, pe);
}
visitBinaryOperator(pe) {
this.addParent(pe.lhs, pe);
this.addParent(pe.rhs, pe);
}
}
function getHeapCreator(peg) {
const indexer = new Indexer_1.Indexer();
const [indexMap, terminals] = indexer.build(peg);
/*
console.log(
'terminals: ' + terminals.map((terminal) => (terminal as Terminal).source)
);
*/
const cmp = (a, b) => indexMap.get(a) - indexMap.get(b);
return () => {
const heap = new heap_1.default(cmp);
terminals.forEach((terminal) => {
heap.push(terminal);
});
return [heap, indexMap];
};
}
class PikaParser extends BottomUpParser_1.BottomUpParserBase {
constructor(peg) {
super(peg, PikaParsingEnv);
}
}
exports.PikaParser = PikaParser;
function createParentsMap(peg) {
const beginningCalculator = new BeginningCalculator_1.BeginningCalculator(peg.rules);
const beginningSets = beginningCalculator.calculate();
const parentsBuilder = new ParentsBuilder(beginningSets);
const parentsMap = parentsBuilder.build(peg);
return parentsMap;
}
//# sourceMappingURL=PikaParser.js.map