From 657f9b3ad68810d792363d4a02e2bed9c2169235 Mon Sep 17 00:00:00 2001 From: GregRos Date: Wed, 6 Sep 2023 14:35:58 +0300 Subject: [PATCH] Made manySepBy push the separators into a key. --- package.json | 2 +- src/lib/combinators.ts | 1 + src/lib/internal/combinators/combinator.ts | 2 +- src/lib/internal/combinators/index.ts | 2 +- src/lib/internal/combinators/many-sep-by.ts | 36 +++++++++++++------- src/publish.ts | 23 ------------- src/test/unit/combinators/sequential.spec.ts | 12 ++++--- 7 files changed, 35 insertions(+), 43 deletions(-) delete mode 100644 src/publish.ts diff --git a/package.json b/package.json index ecea023..1b8e090 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parjs", - "version": "0.15.2", + "version": "0.16.0", "repository": "https://github.com/GregRos/parjs", "homepage": "https://github.com/GregRos/parjs", "exports": { diff --git a/src/lib/combinators.ts b/src/lib/combinators.ts index 871bf23..5596b5b 100644 --- a/src/lib/combinators.ts +++ b/src/lib/combinators.ts @@ -16,6 +16,7 @@ export { map, manyTill, manySepBy, + ArrayWithSeparators, reason, many, later, diff --git a/src/lib/internal/combinators/combinator.ts b/src/lib/internal/combinators/combinator.ts index 0472ed4..2d50ba2 100644 --- a/src/lib/internal/combinators/combinator.ts +++ b/src/lib/internal/combinators/combinator.ts @@ -8,7 +8,7 @@ import { ScalarConverter } from "../scalar-converter"; * Represents the given function as a Parjs combinator. * @param f The combinator function. */ -export function defineCombinator(f: (act: ParjserBase) => Parjser) { +export function defineCombinator(f: (act: ParjserBase & Parjser) => Parjser) { return (x: ImplicitParjser) => { const resolved = ScalarConverter.convert(x); return f(resolved as ParjserBase); diff --git a/src/lib/internal/combinators/index.ts b/src/lib/internal/combinators/index.ts index 92927f6..42fe729 100644 --- a/src/lib/internal/combinators/index.ts +++ b/src/lib/internal/combinators/index.ts @@ -8,7 +8,7 @@ export { backtrack } from "./backtrack"; export { exactly } from "./exactly"; export { later, DelayedParjser } from "./later"; export { many } from "./many"; -export { manySepBy } from "./many-sep-by"; +export { manySepBy, ArrayWithSeparators } from "./many-sep-by"; export { manyTill, manyBetween } from "./many-till"; export { map, mapConst } from "./map"; export { must } from "./must"; diff --git a/src/lib/internal/combinators/many-sep-by.ts b/src/lib/internal/combinators/many-sep-by.ts index ac24e98..069d017 100644 --- a/src/lib/internal/combinators/many-sep-by.ts +++ b/src/lib/internal/combinators/many-sep-by.ts @@ -6,11 +6,20 @@ import { Issues } from "../issues"; import { ResultKind } from "../result"; import { ParsingState } from "../state"; -import { ImplicitParjser, ParjsCombinator } from "../../index"; +import { ImplicitParjser, ParjsCombinator, Parjser } from "../../index"; import { ScalarConverter } from "../scalar-converter"; import { ParjserBase } from "../parser"; import { defineCombinator } from "./combinator"; +export type ArrayWithSeparators = Normal[] & { + separators: Separator[]; +}; + +export function getArrayWithSeparators(arr: T[], separators: S[]): ArrayWithSeparators { + (arr as any).separators = separators; + return arr as any; +} + /** * Applies the source parser repeatedly until it fails softly, with each pair of * applications separated by applying `delimeter`. Also terminates if `delimeter` @@ -19,30 +28,31 @@ import { defineCombinator } from "./combinator"; * @param max Optionally, then maximum number of times to apply the source * parser. Defaults to `Infinity`. */ -export function manySepBy( - delimeter: ImplicitParjser, +export function manySepBy( + delimeter: ImplicitParjser, max?: number -): ParjsCombinator; +): ParjsCombinator>; -export function manySepBy(implDelimeter: ImplicitParjser, max = Infinity) { - const delimeter = ScalarConverter.convert(implDelimeter) as any as ParjserBase; - return defineCombinator(source => { +export function manySepBy(implDelimeter: ImplicitParjser, max = Infinity) { + const delimeter = ScalarConverter.convert(implDelimeter) as ParjserBase & Parjser; + return defineCombinator(source => { return new (class extends ParjserBase { type = "manySepBy"; expecting = source.expecting; _apply(ps: ParsingState): void { - const arr = [] as any[]; + const results = getArrayWithSeparators([], []); + source.apply(ps); if (ps.atLeast(ResultKind.HardFail)) { return; } else if (ps.isSoft) { - ps.value = []; + ps.value = results; ps.kind = ResultKind.Ok; return; } let { position } = ps; - arr.push(ps.value); + results.push(ps.value); let i = 1; for (;;) { if (i >= max) break; @@ -52,7 +62,7 @@ export function manySepBy(implDelimeter: ImplicitParjser, max = Infinity) { } else if (ps.atLeast(ResultKind.HardFail)) { return; } - + results.separators.push(ps.value); source.apply(ps); if (ps.isSoft) { break; @@ -62,13 +72,13 @@ export function manySepBy(implDelimeter: ImplicitParjser, max = Infinity) { if (max >= Infinity && ps.position === position) { Issues.guardAgainstInfiniteLoop("many"); } - arr.push(ps.value); + results.push(ps.value); position = ps.position; i++; } ps.kind = ResultKind.Ok; ps.position = position; - ps.value = arr; + ps.value = results; } })(); }); diff --git a/src/publish.ts b/src/publish.ts deleted file mode 100644 index ec155d4..0000000 --- a/src/publish.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { retargetSourcemaps } from "retarget-sourcemaps-after-move"; -import { rm, mkdir, cp } from "shelljs"; -function run() { - const pub = ".tmp/publish"; - const srcRoot = "src/lib"; - rm("-rf", pub); - mkdir("-p", pub); - cp("-r", ["package.json", "LICENSE.md", "README.md"], pub); - cp("-r", "dist/lib/.", pub); - cp("-r", "src/lib/.", `${pub}/src`); - retargetSourcemaps({ - srcRoot: { - old: srcRoot, - new: `${pub}/src` - }, - distRoot: { - old: "dist/lib", - new: ".tmp/publish" - }, - distGlob: "**/*.js" - }); -} -run(); diff --git a/src/test/unit/combinators/sequential.spec.ts b/src/test/unit/combinators/sequential.spec.ts index b8807a1..3f5f9c5 100644 --- a/src/test/unit/combinators/sequential.spec.ts +++ b/src/test/unit/combinators/sequential.spec.ts @@ -17,6 +17,7 @@ import { thenPick, manyBetween } from "../../../lib/combinators"; +import { getArrayWithSeparators } from "../../../lib/internal/combinators/many-sep-by"; const goodInput = "abcd"; const softBadInput = "a"; @@ -198,7 +199,7 @@ describe("sequential combinators", () => { }); it("succeeds with empty input", () => { - expectSuccess(parser.parse(""), []); + expectSuccess(parser.parse(""), getArrayWithSeparators([], [])); }); it("many fails hard on 1st application", () => { @@ -218,7 +219,7 @@ describe("sequential combinators", () => { it("sep+many that don't consume succeed with max iterations", () => { const parser2 = string("").pipe(manySepBy("", 2)); - expectSuccess(parser2.parse(""), ["", ""]); + expectSuccess(parser2.parse(""), getArrayWithSeparators(["", ""], [""])); }); it("many that fails hard on 2nd iteration", () => { @@ -227,12 +228,15 @@ describe("sequential combinators", () => { }); it("succeeds with non-empty input", () => { - expectSuccess(parser.parse("ab, ab"), ["ab", "ab"]); + expectSuccess(parser.parse("ab, ab"), getArrayWithSeparators(["ab", "ab"], [", "])); }); it("chains into terminating separator", () => { const parser2 = parser.pipe(thenq(", ")); - expectSuccess(parser2.parse("ab, ab, "), ["ab", "ab"]); + expectSuccess( + parser2.parse("ab, ab, "), + getArrayWithSeparators(["ab", "ab"], [", ", ", "]) + ); }); it("fails soft if first many fails", () => { expectFailure(parser.parse("xa"), ResultKind.SoftFail);