From 36f78982e616e88a6c867d45c7ea601a34010d19 Mon Sep 17 00:00:00 2001 From: Tangent Wantwight Date: Sat, 29 Jul 2023 16:26:41 -0400 Subject: [PATCH] Make pattern mapping chained --- notcl.js | 52 +++++++++++++++++++--------------------------------- peg.js | 39 +++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/notcl.js b/notcl.js index be89430..726b71c 100644 --- a/notcl.js +++ b/notcl.js @@ -6,7 +6,7 @@ */ var Notcl = (() => { - const { AtLeast, Choose, End, Map, Regex, Sequence, Use } = Peg; + const { AtLeast, Choose, End, Regex, Sequence, Use } = Peg; const InterCommandWhitespace = Regex(/\s+/y); @@ -16,52 +16,38 @@ var Notcl = (() => { const PreWordWhitespace = Regex(/[^\S\n;]*/y); - const BasicWord = Map(Regex(/[^\s;]+/y), ([word]) => ({ - text: word, - })); + const BasicWord = Regex(/[^\s;]+/y).map(([word]) => ({ text: word })); // WIP, need to be able to escape braces correctly // WIP, error if anything after closing brace /** @type {Peg.Pattern} */ - const Brace = Map( - Sequence( - Regex(/\{/y), - AtLeast( - 0, - Choose( - Map( - Use(() => Brace), - (text) => `{${text}}` - ), - Map(Regex(/[^{}]+/y), ([text]) => text) - ) - ), - Regex(/\}/y) - ), - ([_left, fragments, _right]) => fragments.join("") - ); - - const Word = Map( - Sequence( - PreWordWhitespace, + const Brace = Sequence( + Regex(/\{/y), + AtLeast( + 0, Choose( - Map(Brace, (text) => ({ - text, - })), - BasicWord + Use(() => Brace).map((text) => `{${text}}`), + Regex(/[^{}]+/y).map(([text]) => text) ) ), - ([_, word]) => word - ); + Regex(/\}/y) + ).map(([_left, fragments, _right]) => fragments.join("")); + + const Word = Sequence( + PreWordWhitespace, + Choose( + Brace.map((text) => ({ text })), + BasicWord + ) + ).map(([_, word]) => word); const CommandTerminator = Sequence( PreWordWhitespace, Choose(/** @type {Peg.Pattern} */ (Regex(/[\n;]/y)), End) ); - const Command = Map( - Sequence(PreCommand, AtLeast(0, Word), CommandTerminator), + const Command = Sequence(PreCommand, AtLeast(0, Word), CommandTerminator).map( ([_padding, words, _end]) => words ); diff --git a/peg.js b/peg.js index 2c81c0e..38a206c 100644 --- a/peg.js +++ b/peg.js @@ -4,9 +4,19 @@ * If it matches successfully, it returns some captured value, and the index following the match. * * @template T - * @typedef {{ - * (source: string, index: number): ([T, number] | null) - * }} Peg.Pattern + * @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. + */ +/** + * @template T + * @typedef {object} Peg.PatternExt + * @property {(map: (value: T) => U) => Peg.Pattern} map Creates a pattern that wraps another pattern, transforming the returned value on a match + */ +/** + * @template T + * @typedef {Peg.PatternCall & Peg.PatternExt} Peg.Pattern */ var Peg = window.Peg ?? {}; @@ -18,6 +28,13 @@ var Peg = window.Peg ?? {}; * @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 /** @type {Peg.Pattern} */ (pattern); }; @@ -36,20 +53,6 @@ Peg.Use = function (getPattern) { }); }; -/** - * Creates a pattern that wraps another pattern, transforming the returned value on a match - * @template T, U - * @param {Peg.Pattern} pattern - * @param {(value: T)=> U} map - * @return {Peg.Pattern} - */ -Peg.Map = function (pattern, map) { - return Peg.WrapPattern(function (source, index) { - const match = pattern(source, index); - return match ? [map(match[0]), match[1]] : null; - }); -}; - /** * Creates a pattern matching a regex & returning any captures. The regex needs to be sticky (using the //y modifier) * @param {RegExp} regex @@ -108,7 +111,7 @@ Peg.Sequence = function (...patterns) { /** * Creates a pattern that matches consecutive runs of the given pattern, returning an array of all captures. * - * The match only succeeds if the run is at least {min} instances long. + * The match only succeeds if the run is at least {@link min} instances long. * * If the given pattern does not consume input, the matching will be terminated to prevent an eternal loop. *