pegisland
Version:
General PEG-based parser supporting island grammars with lake symbols
192 lines • 6.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Recognizer = void 0;
// Copyright (C) 2022- Katsumi Okuda. All rights reserved.
const assert_1 = require("assert");
const ParseTree_1 = require("./ParseTree");
const Position_1 = require("./Position");
class Recognizer {
constructor(env) {
this.env = env;
}
visitNonterminal(pe, pos) {
const result = this.env.parseRule(pe.rule, pos);
if (result === null || pe.name === '') {
return result;
}
const [, end] = result;
const value = this.env.s.substring(pos.offset, end.offset).trim();
if (!this.env.has(pe.name)) {
this.env.register(pe.name, value);
}
else if (value !== this.env.lookup(pe.name)) {
return null;
}
return result;
}
visitTerminal(pe, pos) {
pe.regex.lastIndex = pos.offset;
const m = this.env.s.match(pe.regex);
if (m === null) {
return null;
}
const [text] = m;
const { length } = text;
const nextOffset = pos.offset + length;
const lines = text.split('\n');
const baseCol = lines.length === 1 ? pos.column : 1;
const nextPos = new Position_1.Position(nextOffset, pos.line + lines.length - 1, baseCol + lines[lines.length - 1].length);
return [new ParseTree_1.NodeTerminal(new ParseTree_1.Range(pos, nextPos), pe.regex, text), nextPos];
}
visitZeroOrMore(pe, pos) {
const values = [];
let prevPos = null;
let nextPos = pos;
while (nextPos !== prevPos) {
prevPos = nextPos;
const result = this.env.parse(pe.operand, nextPos);
if (!result) {
break;
}
const [value] = result;
[, nextPos] = result;
values.push(value);
}
return [new ParseTree_1.NodeZeroOrMore(new ParseTree_1.Range(pos, nextPos), values), nextPos];
}
visitOneOrMore(pe, pos) {
let prevPos = pos;
const result = this.env.parse(pe.operand, pos);
if (!result) {
return null;
}
let [value, nextPos] = result;
const values = [value];
while (nextPos !== prevPos) {
prevPos = nextPos;
const result = this.env.parse(pe.operand, nextPos);
if (!result) {
break;
}
[value, nextPos] = result;
values.push(value);
}
return [new ParseTree_1.NodeOneOrMore(new ParseTree_1.Range(pos, nextPos), values), nextPos];
}
visitOptional(pe, pos) {
const values = [];
let nextPos = pos;
const result = this.env.parse(pe.operand, nextPos);
if (result) {
const [value] = result;
[, nextPos] = result;
values.push(value);
}
return [new ParseTree_1.NodeOptional(new ParseTree_1.Range(pos, nextPos), values), nextPos];
}
visitAnd(pe, pos) {
const result = this.env.parse(pe.operand, pos);
if (result === null) {
return null;
}
const [value, nextPos] = result;
return [new ParseTree_1.NodeAnd(new ParseTree_1.Range(pos, nextPos), value), pos];
}
visitNot(pe, pos) {
const result = this.env.parse(pe.operand, pos);
if (result !== null) {
return null;
}
return [new ParseTree_1.NodeNot(new ParseTree_1.Range(pos, pos)), pos];
}
visitSequence(pe, pos) {
const values = [];
let nextPos = pos;
for (const operand of pe.operands) {
const result = this.env.parse(operand, nextPos);
if (result === null) {
return null;
}
const [value] = result;
[, nextPos] = result;
values.push(value);
}
return [new ParseTree_1.NodeSequence(new ParseTree_1.Range(pos, nextPos), values), nextPos];
}
visitOrderedChoice(pe, pos) {
for (let i = 0; i < pe.operands.length; i++) {
const result = this.env.parse(pe.operands[i], pos);
if (result !== null) {
const [value, nextPos] = result;
return [
new ParseTree_1.NodeOrderedChoice(new ParseTree_1.Range(pos, nextPos), value, i),
nextPos,
];
}
}
return null;
}
visitGrouping(pe, pos) {
const result = this.env.parse(pe.operand, pos);
if (result === null) {
return null;
}
const [childNode, nextPos] = result;
return [new ParseTree_1.NodeGrouping(new ParseTree_1.Range(pos, nextPos), childNode), nextPos];
}
visitRewriting(pe, pos) {
const result = this.env.parse(pe.operand, pos);
if (result === null) {
return null;
}
const [childNode, nextPos] = result;
return [
new ParseTree_1.NodeRewriting(new ParseTree_1.Range(pos, nextPos), childNode, this),
nextPos,
];
}
visitColon(pe, pos) {
const lhsResult = this.env.parse(pe.lhs, pos);
if (lhsResult === null) {
return null;
}
const [, lhsNextPos] = lhsResult;
const rhsResult = this.env.parse(pe.rhs, pos);
if (rhsResult === null) {
return null;
}
const [, rhsNextPos] = rhsResult;
if (lhsNextPos.offset !== rhsNextPos.offset) {
return null;
}
return rhsResult;
}
visitColonNot(pe, pos) {
const lhsResult = this.env.parse(pe.lhs, pos);
if (lhsResult === null) {
return null;
}
const rhsResult = this.env.parse(pe.rhs, pos);
if (rhsResult !== null) {
const [, lhsNextPos] = lhsResult;
const [, rhsNextPos] = rhsResult;
if (lhsNextPos.offset === rhsNextPos.offset) {
return null;
}
}
return lhsResult;
}
visitLake(pe, pos) {
const result = this.env.parse(pe.operand, pos);
(0, assert_1.strict)(result !== null, 'Lake should not fail since it accepts an empty string');
const [childNode, nextPos] = result;
const zeroOrMore = childNode;
const islands = zeroOrMore.childNodes
.map((group) => group.childNodes[0])
.filter((childNode) => childNode.index === 0)
.map((childNode) => childNode.childNodes[0]);
return [new ParseTree_1.NodeLake(new ParseTree_1.Range(pos, nextPos), islands, pe), nextPos];
}
}
exports.Recognizer = Recognizer;
//# sourceMappingURL=Recognizer.js.map