diff --git a/jsconfig.json b/jsconfig.json index 5ebfc59..f6bcfc4 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "checkJs": true, - "strict": true + "strict": true, + "lib": ["ES6", "DOM"] } } diff --git a/notcl.js b/notcl.js index c1f2308..fc43a8f 100644 --- a/notcl.js +++ b/notcl.js @@ -57,6 +57,8 @@ var Notcl = (() => { ([commands, _eof]) => commands ); + const ERROR_CONTEXT = /(?<=([^\n]{0,50}))([^\n]{0,50})/y; + return { /** * Parse out a Notcl script into an easier-to-interpret representation. @@ -73,7 +75,21 @@ var Notcl = (() => { /* Parse */ const commands = Script(code, 0); - return commands?.[0] ?? []; + if (commands[0]) { + return [true, commands[1]]; + } else { + const errorPos = commands[1]; + ERROR_CONTEXT.lastIndex = errorPos; + const [, before, after] = /** @type {RegExpExecArray} */ ( + ERROR_CONTEXT.exec(code) + ); + return [ + false, + `Error at position ${commands[1]} +${before}${after} +${"-".repeat(before.length)}^`, + ]; + } }, }; })(); diff --git a/peg.js b/peg.js index 38a206c..e5677c0 100644 --- a/peg.js +++ b/peg.js @@ -7,7 +7,7 @@ * @callback Peg.PatternCall * @param {string} source - the string being parsed * @param {number} index - the index in the string to begin matching from - * @returns {[T, number] | null} - if successful, the captured value & the index to start parsing following symbols from. Else, null. + * @returns {[true, T, number] | [false, number]} - if successful, true, the captured value, and the index to start parsing following symbols from. Else, false, and the furthest index that could be understood. */ /** * @template T @@ -24,14 +24,14 @@ var Peg = window.Peg ?? {}; * Makes a pattern from a function, adding helper methods. * * @template T - * @param {(source: string, index: number) => ([T, number] | null)} pattern + * @param {(source: string, index: number) => ([true, T, number] | [false, number])} pattern * @returns {Peg.Pattern} */ Peg.WrapPattern = function (pattern) { /** @type {Peg.Pattern} */ (pattern).map = function (map) { return Peg.WrapPattern(function (source, index) { const match = pattern(source, index); - return match ? [map(match[0]), match[1]] : null; + return match[0] ? [true, map(match[1]), match[2]] : [false, match[1]]; }); }; @@ -62,7 +62,7 @@ Peg.Regex = function (regex) { return Peg.WrapPattern(function (source, index) { regex.lastIndex = index; const matches = regex.exec(source); - return matches ? [matches, regex.lastIndex] : null; + return matches ? [true, matches, regex.lastIndex] : [false, index]; }); }; @@ -74,13 +74,16 @@ Peg.Regex = function (regex) { */ Peg.Choose = function (...patterns) { return Peg.WrapPattern(function (source, index) { + let furthest = index; for (const pattern of patterns) { const match = pattern(source, index); - if (match) { + if (match[0]) { return match; + } else if (match[1] > furthest) { + furthest = match[1]; } } - return null; + return [false, furthest]; }); }; @@ -98,13 +101,13 @@ Peg.Sequence = function (...patterns) { const values = /** @type {T} */ (/** @type {unknown} */ ([])); for (const pattern of patterns) { const match = pattern(source, index); - if (match == null) { - return null; + if (match[0] == false) { + return match; } - values.push(match[0]); - index = match[1]; + values.push(match[1]); + index = match[2]; } - return [values, index]; + return [true, values, index]; }); }; @@ -124,17 +127,24 @@ Peg.Sequence = function (...patterns) { Peg.AtLeast = function (min, pattern) { return Peg.WrapPattern(function (source, index) { const values = /** @type {T[]} */ ([]); + let furthest = index; do { const match = pattern(source, index); - if (match == null) break; - values.push(match[0]); - if (index == match[1]) break; - index = match[1]; + if (match[0] == false) { + furthest = match[1]; + break; + } + values.push(match[1]); + if (index == match[2]) { + furthest = match[2]; + break; + } + index = match[2]; } while (true); if (values.length >= min) { - return [values, index]; + return [true, values, index]; } else { - return null; + return [false, furthest]; } }); }; @@ -145,8 +155,8 @@ Peg.AtLeast = function (min, pattern) { */ Peg.End = Peg.WrapPattern(function End(source, index) { if (source.length == index) { - return [true, index]; + return [true, true, index]; } else { - return null; + return [false, index]; } });