UNPKG

pegjs-util

Version:
194 lines (184 loc) 7.81 kB
/* ** pegjs-util -- Utility Class for Peggy ** Copyright (c) 2014-2024 Dr. Ralf S. Engelschall <rse@engelschall.com> ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the ** "Software"), to deal in the Software without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Universal Module Definition (UMD) for Library */ (function (root, name, factory) { /* global define: false */ /* global module: false */ if (typeof module === "object" && typeof module.exports === "object") /* CommonJS environment */ module.exports = factory(root); else if (typeof define === "function" && typeof define.amd !== "undefined") /* AMD environment */ define(name, function () { return factory(root); }); else /* Browser environment */ root[name] = factory(root); }(/* global global: false */ (typeof global !== "undefined" ? global : /* global window: false */ (typeof window !== "undefined" ? window : this)), "PEGUtil", function (/* root */) { var PEGUtil = {}; /* helper function for generating a function to generate an AST node */ PEGUtil.makeAST = function makeAST (location, options) { return function () { return options.util.__makeAST.call( null, location().start.line, location().start.column, location().start.offset, arguments ); }; }; /* helper function for generating a function to unroll the parse stack */ PEGUtil.makeUnroll = function (location, options) { return function (first, list, take) { if ( typeof list !== "object" || !(list instanceof Array)) throw new options.util.__SyntaxError("unroll: invalid list argument for unrolling", (typeof list), "Array", location()); if (typeof take !== "undefined") { if (typeof take === "number") take = [ take ]; var result = []; if (first !== null) result.push(first); for (var i = 0; i < list.length; i++) { for (var j = 0; j < take.length; j++) result.push(list[i][take[j]]); } return result; } else { if (first !== null) list.unshift(first); return list; } }; }; /* utility function: create a source excerpt */ var excerpt = function (txt, o) { var l = txt.length; var b = o - 20; if (b < 0) b = 0; var e = o + 20; if (e > l) e = l; var hex = function (ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }; var extract = function (txt, pos, len) { return txt.substr(pos, len) .replace(/\\/g, "\\\\") .replace(/\x08/g, "\\b") .replace(/\t/g, "\\t") .replace(/\n/g, "\\n") .replace(/\f/g, "\\f") .replace(/\r/g, "\\r") .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return "\\x0" + hex(ch); }) .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return "\\x" + hex(ch); }) .replace(/[\u0100-\u0FFF]/g, function(ch) { return "\\u0" + hex(ch); }) .replace(/[\u1000-\uFFFF]/g, function(ch) { return "\\u" + hex(ch); }); }; return { prolog: extract(txt, b, o - b), token: extract(txt, o, 1), epilog: extract(txt, o + 1, e - (o + 1)) }; }; /* provide top-level parsing functionality */ PEGUtil.parse = function (parser, txt, options) { if (typeof parser !== "object") throw new Error("invalid parser object (not an object)"); if (typeof parser.parse !== "function") throw new Error("invalid parser object (no \"parse\" function)"); if (typeof txt !== "string") throw new Error("invalid input text (not a string)"); if (typeof options !== "undefined" && typeof options !== "object") throw new Error("invalid options (not an object)"); if (typeof options === "undefined") options = {}; var result = { ast: null, error: null }; try { var makeAST; if (typeof options.makeAST === "function") makeAST = options.makeAST; else { makeAST = function (location, args) { return { line: location().start.line, column: location().start.column, offset: location().start.offset, args: args }; }; } options.util = { makeUnroll: PEGUtil.makeUnroll, makeAST: PEGUtil.makeAST, __makeAST: makeAST, __SyntaxError: parser.SyntaxError }; result.ast = parser.parse(txt, options); result.error = null; } catch (e) { result.ast = null; if (e instanceof parser.SyntaxError) { var definedOrElse = function (value, fallback) { return (typeof value !== "undefined" ? value : fallback); }; result.error = { line: definedOrElse(e.location.start.line, 0), column: definedOrElse(e.location.start.column, 0), message: e.message, found: definedOrElse(e.found, ""), expected: definedOrElse(e.expected, ""), location: excerpt(txt, definedOrElse(e.location.start.offset, 0)) }; } else { result.error = { line: 0, column: 0, message: e.message, found: "", expected: "", location: excerpt("", 0) }; } } return result; }; /* render a useful error message */ PEGUtil.errorMessage = function (e, noFinalNewline) { var l = e.location; var prefix1 = "line " + e.line + " (column " + e.column + "): "; var prefix2 = ""; for (var i = 0; i < prefix1.length + l.prolog.length; i++) prefix2 += "-"; var msg = prefix1 + l.prolog + l.token + l.epilog + "\n" + prefix2 + "^" + "\n" + e.message + (noFinalNewline ? "" : "\n"); return msg; }; return PEGUtil; }));