UNPKG

pegisland

Version:

General PEG-based parser supporting island grammars with lake symbols

259 lines 10.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GeneralPegBuilder = void 0; // Copyright (C) 2021- Katsumi Okuda. All rights reserved. const assert_1 = require("assert"); const ParseTree_1 = require("./ParseTree"); const pe = __importStar(require("./ParsingExpression")); const Rule_1 = require("./Rule"); const Peg_1 = require("./Peg"); const PegParser_1 = require("./PegParser"); const set_operations_1 = require("./set-operations"); class GeneralPegBuilder { constructor() { this.rules = new Map(); this.visitedRules = new Set(); this.errors = []; } build(grammar) { const pegParser = new PegParser_1.PegParser(); const result = pegParser.parse(grammar); if (result instanceof Error) { return result; } this.makeRules(result); const toplevelRules = (0, set_operations_1.difference)(new Set(this.rules.values()), this.visitedRules); if (this.errors.length !== 0) { return Error(this.errors.join('\n')); } return new Peg_1.Peg(this.rules, [...toplevelRules]); } makeRules(tree) { const [seq] = tree.childNodes; const [, plus] = seq.childNodes; plus.childNodes.forEach((node) => { const [seq] = node.childNodes; const [id] = seq.childNodes[1].childNodes[0].childNodes; (0, assert_1.strict)(id instanceof ParseTree_1.NodeTerminal); const rule = this.getRule(id.text); rule.rhs = this.processExpression(seq.childNodes[3]); // check if it has a water annotation const optAnnotations = seq.childNodes[0]; const [annotations] = optAnnotations.childNodes; const hasAnnotation = annotations.childNodes.length > 0; rule.isWater = hasAnnotation; }); } getRule(symbol) { if (!this.rules.has(symbol)) { this.rules.set(symbol, new Rule_1.Rule(symbol, new pe.NullParsingExpression())); } return this.rules.get(symbol); } processExpression(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; (0, assert_1.strict)(seq instanceof ParseTree_1.NodeSequence); const [rewriting, star] = seq.childNodes; const rewritings = [rewriting]; star.childNodes.forEach((seq) => { const [, rewriting] = seq.childNodes; rewritings.push(rewriting); }); const operands = rewritings.map((rewriting) => this.processRewriting(rewriting)); return operands.length === 1 ? operands[0] : new pe.OrderedChoice(operands); } processRewriting(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [sequence, opt] = seq.childNodes; let operand = this.processSequence(sequence); if (opt.childNodes.length === 1) { const [seq] = opt.childNodes; const [, str] = seq.childNodes; const [choice] = str.childNodes[0].childNodes; const [term] = choice.childNodes; (0, assert_1.strict)(term instanceof ParseTree_1.NodeTerminal); const result = eval(term.text); operand = new pe.Rewriting(operand, result); } return operand; } processSequence(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [star] = node.childNodes; const operands = star.childNodes.map((node) => this.processPrefix(node.childNodes[0])); return operands.length === 1 ? operands[0] : new pe.Sequence(operands); } processPrefix(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [opt, suffix] = seq.childNodes; let operand = this.processSuffix(suffix); if (opt.childNodes.length !== 0) { const choice = opt.childNodes[0]; operand = new [pe.And, pe.Not][choice.index](operand); } return operand; } processSuffix(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [primary, opt] = seq.childNodes; let operand = this.processPrimary(primary); if (opt.childNodes.length !== 0) { const choice = opt.childNodes[0]; operand = [ () => this.makeSuffixWithOperand(choice, operand), () => this.makeSuffixWithOperand(choice, operand), () => this.makeSuffixWithOperand(choice, operand), () => this.makeSuffixWithOperand(choice, operand), () => new pe.Optional(operand), () => new pe.ZeroOrMore(operand), () => new pe.OneOrMore(operand), ][choice.index](); } return operand; } makeSuffixWithOperand(choice, operand) { const [choiceOperand] = choice.childNodes; const colonSeq = choiceOperand; const [, rhs] = colonSeq.childNodes; const rhsOperand = this.processPrimary(rhs); return [ () => createStarPlus(operand, rhsOperand), () => createPlusPlus(operand, rhsOperand), () => new pe.ColonNot(operand, rhsOperand), () => new pe.Colon(operand, rhsOperand), ][choice.index](); } processPrimary(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const choice = node.childNodes[0]; (0, assert_1.strict)(choice.index <= 6); return [ this.processRegexp, this.processLake, this.processNamedIdentifier, this.processGrouping, this.processString, this.processClass, this.processDot, ][choice.index].call(this, choice.childNodes[0]); } processOperatorWithOneOperand(node, PeCtor) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeSequence); const operand = this.processExpression(node.childNodes[1]); return new PeCtor(operand); } processGrouping(node) { return this.processOperatorWithOneOperand(node, pe.Grouping); } processLake(node) { return this.processOperatorWithOneOperand(node, pe.Lake); } processRegexp(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [choice] = seq.childNodes; const [term] = choice.childNodes; (0, assert_1.strict)(term instanceof ParseTree_1.NodeTerminal); const { text } = term; const pattern = text.slice(2, text.length - 1); const regex = this.createRegExp(pattern, node); return new pe.Terminal(regex, text); } createRegExp(pattern, node) { try { return new RegExp(pattern); } catch (e) { const { column } = node.range.start; const { line } = node.range.start; this.errors.push(`Invalid regular expression: ${pattern} at ${line}:${column}`); return /./; } } processNamedIdentifier(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [opt] = seq.childNodes; (0, assert_1.strict)(opt instanceof ParseTree_1.NodeOptional); let subname = ''; if (opt.childNodes.length > 0) { const optSeq = opt.childNodes[0]; const term = optSeq.childNodes[0]; subname = term.text; } const id = seq.childNodes[1]; { const [seq] = id.childNodes; const [term] = seq.childNodes; (0, assert_1.strict)(term instanceof ParseTree_1.NodeTerminal); const rule = this.getRule(term.text); this.visitedRules.add(rule); return new pe.Nonterminal(rule, subname); } } processString(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [choice] = seq.childNodes; const [term] = choice.childNodes; (0, assert_1.strict)(term instanceof ParseTree_1.NodeTerminal); const result = eval(term.text); const pattern = result.replace(/([^0-9a-zA-Z])/g, '\\$1'); return new pe.Terminal(this.createRegExp(pattern, node), term.text); } processClass(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); const [seq] = node.childNodes; const [terminal] = seq.childNodes; (0, assert_1.strict)(terminal instanceof ParseTree_1.NodeTerminal); const text = terminal.text[0] === '^' ? `[^${terminal.text.substring(2)}` : terminal.text; return new pe.Terminal(this.createRegExp(text, node), terminal.text); } processDot(node) { (0, assert_1.strict)(node instanceof ParseTree_1.NodeNonterminal); return new pe.Terminal(/./, '.'); } } exports.GeneralPegBuilder = GeneralPegBuilder; function createXPlus(lhs, rhs, PeCtor) { return new pe.Sequence([ new PeCtor(new pe.Grouping(new pe.Sequence([new pe.Not(rhs), lhs]))), rhs, ]); } function createPlusPlus(lhs, rhs) { return createXPlus(lhs, rhs, pe.OneOrMore); } function createStarPlus(lhs, rhs) { return createXPlus(lhs, rhs, pe.ZeroOrMore); } //# sourceMappingURL=GeneralPegBuilder.js.map