tarsec 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,34 +33,15 @@ parser("hello world"); // success
33
33
  parser("hello there"); // failure
34
34
  ```
35
35
 
36
- ## A longer example
37
-
38
- ```ts
39
- // define a parser to parse "hello, <name>!"
40
- const parser = seq([
41
- str("hello"),
42
- space,
43
-
44
- /*
45
-
46
- Capture group to capture the name.
47
-
48
- `many1(noneOf("!"))` parses one or more characters
49
- that are not an exclamation mark.
50
- `many1` returns an array of characters,
51
- `many1WithJoin` joins them into a string.
52
-
53
- This capture group is then given the name "person".
54
-
55
- */
56
- capture(many1WithJoin(noneOf("!")), "person"),
57
- char("!"),
58
- ], getCaptures);
59
-
60
- // parse
61
- const parsed = parser("hello adit!");
62
-
63
- console.log(parsed.success); // true
64
- console.log(parsed.result); // { person: "adit" }
65
- ```
66
-
36
+ ## Learning tarsec
37
+ - [A five minute introduction](/tutorials/5-minute-intro.md)
38
+ - [The three building blocks in tarsec](/tutorials/three-building-blocks.md)
39
+ - [API reference](https://egonschiele.github.io/tarsec/)
40
+
41
+ ## Features
42
+ - tarsec is entirely TypeScript. There's nothing to compile.
43
+ - [Debug mode](/tutorials/debugging.md) that prints what's happening step-by-step
44
+ - Derived types: tarsec will generate TypeScript types for your parser
45
+ - Partial [backtracking](/tutorials/backtracking.md) support
46
+
47
+ Read more about [use cases for tarsec](/tutorials/use-case.md).
@@ -0,0 +1,2 @@
1
+ import { GeneralParser, MergedResults, MergedCaptures, Parser } from "@/lib/types";
2
+ export declare function seq<const T extends readonly GeneralParser<any, any>[], U>(parsers: T, transform: (results: MergedResults<T>[], captures: MergedCaptures<T>) => U, debugName?: string): Parser<U>;
@@ -0,0 +1,123 @@
1
+ (function (factory) {
2
+ if (typeof module === "object" && typeof module.exports === "object") {
3
+ var v = factory(require, exports);
4
+ if (v !== undefined) module.exports = v;
5
+ }
6
+ else if (typeof define === "function" && define.amd) {
7
+ define(["require", "exports", "@/lib/trace", "@/lib/types", "@/lib/utils"], factory);
8
+ }
9
+ })(function (require, exports) {
10
+ "use strict";
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.seq = void 0;
13
+ const trace_1 = require("@/lib/trace");
14
+ const types_1 = require("@/lib/types");
15
+ const utils_1 = require("@/lib/utils");
16
+ /*
17
+ To add backtracking support requires a fairly big change. Here's an example that needs backtracking.
18
+
19
+ ```ts
20
+ const parser = seq([
21
+ str("hello "),
22
+ or([str("world"), str("world!")]),
23
+ optional("?")
24
+ ], getResults);
25
+ ```
26
+
27
+ If we try to parse `"hello world!"`, the first parser in the OR will succeed, but then we'll get stuck at the `optional`. Instead, we need to go back up the tree and try the second parser in the OR. A few things need to happen.
28
+
29
+ 1. instead of just processing these parsers sequentially in a for loop, we need to model them as a tree
30
+ 2. the OR parser needs to let us know that there are other branches to try.
31
+
32
+ For #2, there's an optional `nextParser` key on a parser success. The or parser can use this to say "a parser succeeded and here's the result, but there are other parsers that could be tried". `nextParser` is a parser that runs the remaining branches. So in this example, the OR would return a success with `nextParser = or([str("world")])`.
33
+
34
+ Next, we need to model this as a tree. Each node in the tree has a parent and child and the parser for that node.
35
+
36
+ ```ts
37
+ parent: Node;
38
+ parser: GeneralParser<any, any> | null;
39
+ child: Node;
40
+ ```
41
+
42
+ Hopefully that is self-explanatory. We start at the root of the tree, try the parser there, then use `.child` to go to the next node and so on. We don't model multiple paths as multiple children. To keep the code simple, we do something else.
43
+
44
+ Each node also has a `closed` key. Once we've run the parser for a node, we mark it `closed`. Closed means there are no more branches here. UNLESS, the parser returns a `nextParser`. In that case, we *don't* mark it closed because there are still other options to try. In that case, we also *replace* the parser on that node with nextParser.
45
+
46
+ So, going back to the hello world example, let's say we're stuck at the `optional`:
47
+
48
+ ```ts
49
+ const parser = seq([
50
+ str("hello "),
51
+ or([str("world"), str("world!")]),
52
+ optional("?")
53
+ ], getResults);
54
+ ```
55
+
56
+ We use `.parent` to go back up the tree. We're looking for a node that isn't closed. If we find one, we start again from there. In this case, we'd find an open node at the or with parser `or([str("world")])`. We can restart from there, but there's a bunch of state to reset.
57
+
58
+ 1. From the new `or` parser, we need to go to the optional parser. We're doing it all again in the same order. This is one reason why it's easier to model this without multiple children. Otherwise, all the children would have to point to the next level, the next level would have to point to all the children in the previous level, and you'd have multiple parents, which is awful to deal with.
59
+
60
+ 2. We have consumed input and added to the results. We need to undo that. At this point, the input is `!`, because we've consumed `hello world`. And the results array is `["hello ", "world"]`. We need to rewind both of those.
61
+
62
+ To do that, I count how many levels up we've gone to find another branch, and just pop that many elements off the results array. So results is now `["hello "]`. The input is trickier. How would I keep track of what the input was when we were at the OR the last time?
63
+
64
+ This is where the final key on a tree node comes in. Nodes also have an optional `input` key.
65
+
66
+ IF a parser succeeds, and
67
+ IF there's a nextParser,
68
+ We know we may come back to this node. So we save the current input as `.input` on the node.
69
+
70
+ This approach has some issues. Notably, it doesn't work if you need to backtrack at multiple points in the tree. The test `backtracking-deep.test.ts` shows this.
71
+
72
+ The code is also complex and it would be easy to have bugs in this logic. I wish there was a cleaner solution for rewinding state.
73
+ */
74
+ function seq(parsers, transform, debugName = "") {
75
+ return (0, trace_1.trace)(`seq(${debugName})`, (input) => {
76
+ const results = [];
77
+ let rest = input;
78
+ const captures = {};
79
+ const rootNode = (0, types_1.createTree)(parsers);
80
+ let current = rootNode;
81
+ while (current) {
82
+ const parser = current.parser;
83
+ if (!parser) {
84
+ console.log({ current, parser, results, captures });
85
+ throw new Error("parser is null");
86
+ }
87
+ const parsed = parser(rest);
88
+ current.closed = true;
89
+ /* console.log({ parsed }); */
90
+ if (!parsed.success) {
91
+ const [ancestor, count] = (0, utils_1.findAncestorWithNextParser)(current);
92
+ if (ancestor) {
93
+ current = ancestor;
94
+ rest = ancestor.input;
95
+ (0, utils_1.popMany)(results, count);
96
+ continue;
97
+ }
98
+ else {
99
+ // don't consume input if we're failing
100
+ return Object.assign(Object.assign({}, parsed), { rest: input });
101
+ }
102
+ }
103
+ results.push(parsed.result);
104
+ if (parsed.nextParser) {
105
+ /* console.log("setting next parser", parsed.nextParser); */
106
+ current.parser = parsed.nextParser;
107
+ current.input = rest;
108
+ current.closed = false;
109
+ }
110
+ rest = parsed.rest;
111
+ if ((0, types_1.isCaptureResult)(parsed)) {
112
+ for (const key in parsed.captures) {
113
+ captures[key] = parsed.captures[key];
114
+ }
115
+ }
116
+ current = current.child;
117
+ }
118
+ const result = transform(results, captures);
119
+ return (0, types_1.success)(result, rest);
120
+ });
121
+ }
122
+ exports.seq = seq;
123
+ });
@@ -1,7 +1,15 @@
1
- import { CaptureParser, GeneralParser, MergedCaptures, MergedResults, Parser, Prettify } from "./types";
1
+ export { seq } from "./combinators/seq";
2
+ import { CaptureParser, MergedResults, Parser, Prettify } from "./types";
2
3
  export declare function many<T>(parser: Parser<T>): Parser<T[]>;
3
4
  export declare function many1<T>(parser: Parser<T>): Parser<T[]>;
4
- export declare function count<T>(parser: Parser<T>): Parser<number>;
5
+ /**
6
+ * Takes a parser, runs it n times, and returns the results as an array.
7
+ * If it cannot run the parser n times, it fails without consuming input.
8
+ * @param num - number of times to run the parser
9
+ * @param parser - parser to run
10
+ * @returns - parser that runs the given parser `num` times and returns an array of the results
11
+ */
12
+ export declare function count<T>(num: number, parser: Parser<T>): Parser<T[]>;
5
13
  export declare function manyWithJoin(parser: Parser<string>): Parser<string>;
6
14
  export declare function many1WithJoin(parser: Parser<string>): Parser<string>;
7
15
  export declare function or<const T extends readonly Parser<any>[]>(parsers: T, name?: string): Parser<MergedResults<T>>;
@@ -11,7 +19,6 @@ export declare function between<O, C, P>(open: Parser<O>, close: Parser<C>, pars
11
19
  export declare function sepBy<S, P>(separator: Parser<S>, parser: Parser<P>): Parser<P[]>;
12
20
  export declare function getResults<R, C>(results: R, captures: C): R;
13
21
  export declare function getCaptures<R, C>(results: R, captures: C): C;
14
- export declare function seq<const T extends readonly GeneralParser<any, any>[], U>(parsers: T, transform: (results: MergedResults<T>[], captures: MergedCaptures<T>) => U, debugName?: string): Parser<U>;
15
22
  export declare function capture<T, const S extends string>(parser: Parser<T>, name: S): CaptureParser<T, Record<S, T>>;
16
23
  export declare function wrap<T, const S extends string>(parser: Parser<T>, name: S): Parser<Prettify<Record<S, T>>>;
17
24
  export declare function transform<T, X>(parser: Parser<T>, transformerFunc: (x: T) => X): Parser<X>;
@@ -4,12 +4,14 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "./trace", "./types", "./utils"], factory);
7
+ define(["require", "exports", "./combinators/seq", "./trace", "./types", "./utils"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.transform = exports.wrap = exports.capture = exports.seq = exports.getCaptures = exports.getResults = exports.sepBy = exports.between = exports.not = exports.optional = exports.or = exports.many1WithJoin = exports.manyWithJoin = exports.count = exports.many1 = exports.many = void 0;
12
+ exports.transform = exports.wrap = exports.capture = exports.getCaptures = exports.getResults = exports.sepBy = exports.between = exports.not = exports.optional = exports.or = exports.many1WithJoin = exports.manyWithJoin = exports.count = exports.many1 = exports.many = exports.seq = void 0;
13
+ var seq_1 = require("./combinators/seq");
14
+ Object.defineProperty(exports, "seq", { enumerable: true, get: function () { return seq_1.seq; } });
13
15
  const trace_1 = require("./trace");
14
16
  const types_1 = require("./types");
15
17
  const utils_1 = require("./utils");
@@ -43,13 +45,26 @@
43
45
  });
44
46
  }
45
47
  exports.many1 = many1;
46
- function count(parser) {
48
+ /**
49
+ * Takes a parser, runs it n times, and returns the results as an array.
50
+ * If it cannot run the parser n times, it fails without consuming input.
51
+ * @param num - number of times to run the parser
52
+ * @param parser - parser to run
53
+ * @returns - parser that runs the given parser `num` times and returns an array of the results
54
+ */
55
+ function count(num, parser) {
47
56
  return (0, trace_1.trace)("count", (input) => {
48
- const result = many(parser)(input);
49
- if (result.success) {
50
- return (0, types_1.success)(result.result.length, result.rest);
57
+ let results = [];
58
+ let rest = input;
59
+ for (let i = 0; i < num; i++) {
60
+ let parsed = parser(rest);
61
+ if (!parsed.success) {
62
+ return (0, types_1.failure)(`expected ${num} matches, got ${i}`, input);
63
+ }
64
+ results.push(parsed.result);
65
+ rest = parsed.rest;
51
66
  }
52
- return result;
67
+ return (0, types_1.success)(results, rest);
53
68
  });
54
69
  }
55
70
  exports.count = count;
@@ -67,10 +82,14 @@
67
82
  */
68
83
  function or(parsers, name = "") {
69
84
  return (0, trace_1.trace)(`or(${name})`, (input) => {
70
- for (let parser of parsers) {
71
- let result = parser(input);
85
+ for (let i = 0; i < parsers.length; i++) {
86
+ let result = parsers[i](input);
72
87
  if (result.success) {
73
- return result;
88
+ if (i === parsers.length - 1)
89
+ return result;
90
+ const nextParser = or(parsers.slice(i + 1), name);
91
+ /* console.log({ nextParser }, parsers.slice(i + 1)); */
92
+ return Object.assign(Object.assign({}, result), { nextParser });
74
93
  }
75
94
  }
76
95
  return (0, types_1.failure)(`all parsers failed`, input);
@@ -147,29 +166,6 @@
147
166
  return captures;
148
167
  }
149
168
  exports.getCaptures = getCaptures;
150
- function seq(parsers, transform, debugName = "") {
151
- return (0, trace_1.trace)(`seq(${debugName})`, (input) => {
152
- const results = [];
153
- let rest = input;
154
- const captures = {};
155
- for (let parser of parsers) {
156
- let parsed = parser(rest);
157
- if (!parsed.success) {
158
- return parsed;
159
- }
160
- results.push(parsed.result);
161
- rest = parsed.rest;
162
- if ((0, types_1.isCaptureResult)(parsed)) {
163
- for (const key in parsed.captures) {
164
- captures[key] = parsed.captures[key];
165
- }
166
- }
167
- }
168
- const result = transform(results, captures);
169
- return (0, types_1.success)(result, rest);
170
- });
171
- }
172
- exports.seq = seq;
173
169
  function capture(parser, name) {
174
170
  return (0, trace_1.trace)(`capture(${(0, utils_1.escape)(name)})`, (input) => {
175
171
  let result = parser(input);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./parsers";
2
2
  export * from "./combinators";
3
3
  export * from "./trace";
4
+ export * from "./types";
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
18
  if (v !== undefined) module.exports = v;
19
19
  }
20
20
  else if (typeof define === "function" && define.amd) {
21
- define(["require", "exports", "./parsers", "./combinators", "./trace"], factory);
21
+ define(["require", "exports", "./parsers", "./combinators", "./trace", "./types"], factory);
22
22
  }
23
23
  })(function (require, exports) {
24
24
  "use strict";
@@ -26,4 +26,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
26
  __exportStar(require("./parsers"), exports);
27
27
  __exportStar(require("./combinators"), exports);
28
28
  __exportStar(require("./trace"), exports);
29
+ __exportStar(require("./types"), exports);
29
30
  });
@@ -0,0 +1,2 @@
1
+ import { BetweenWithinResult, Parser } from "../types";
2
+ export declare function betweenWithin(parser: Parser<string>): Parser<BetweenWithinResult[]>;
@@ -0,0 +1,68 @@
1
+ (function (factory) {
2
+ if (typeof module === "object" && typeof module.exports === "object") {
3
+ var v = factory(require, exports);
4
+ if (v !== undefined) module.exports = v;
5
+ }
6
+ else if (typeof define === "function" && define.amd) {
7
+ define(["require", "exports", "../trace", "../types"], factory);
8
+ }
9
+ })(function (require, exports) {
10
+ "use strict";
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.betweenWithin = void 0;
13
+ const trace_1 = require("../trace");
14
+ const types_1 = require("../types");
15
+ function betweenWithin(parser) {
16
+ return (0, trace_1.trace)("betweenWithin", (input) => {
17
+ let start = 0;
18
+ let current = 0;
19
+ let currentlyMatching = false;
20
+ const results = [];
21
+ while (current < input.length) {
22
+ const parsed = parser(input.slice(current));
23
+ if (parsed.success) {
24
+ if (currentlyMatching) {
25
+ const value = input.slice(start, current + parsed.result.length);
26
+ if (value.length > 0) {
27
+ results.push({
28
+ type: "matched",
29
+ value,
30
+ });
31
+ }
32
+ current += parsed.result.length;
33
+ start = current;
34
+ currentlyMatching = false;
35
+ }
36
+ else {
37
+ const value = input.slice(start, current);
38
+ if (value.length > 0) {
39
+ results.push({
40
+ type: "unmatched",
41
+ value,
42
+ });
43
+ }
44
+ currentlyMatching = true;
45
+ start = current;
46
+ current += parsed.result.length;
47
+ }
48
+ }
49
+ else {
50
+ current += 1;
51
+ }
52
+ }
53
+ if (start < current) {
54
+ if (currentlyMatching) {
55
+ return (0, types_1.failure)("unexpected end of input", "");
56
+ }
57
+ else {
58
+ results.push({
59
+ type: "unmatched",
60
+ value: input.slice(start, current),
61
+ });
62
+ }
63
+ }
64
+ return (0, types_1.success)(results, "");
65
+ });
66
+ }
67
+ exports.betweenWithin = betweenWithin;
68
+ });
package/dist/parsers.d.ts CHANGED
@@ -1,9 +1,43 @@
1
1
  import { Parser } from "./types";
2
- export declare function char(c: string): Parser<string>;
3
- export declare function str(s: string): Parser<string>;
2
+ export { betweenWithin } from "./parsers/betweenWithin";
3
+ /**
4
+ * Takes a character. Returns a parser that parses that character.
5
+ *
6
+ * @param c - character to parse
7
+ * @returns - parser that parses the given character
8
+ */
9
+ export declare function char<const S extends string>(c: S): Parser<S>;
10
+ /**
11
+ * Takes a string. Returns a parser that parses that string.
12
+ *
13
+ * @param s - string to parse
14
+ * @returns - parser that parses the given string
15
+ */
16
+ export declare function str<const S extends string>(s: S): Parser<S>;
17
+ /**
18
+ * Takes a string. Returns a parser that parses
19
+ * one of the characters in that string.
20
+ *
21
+ * @param chars - string of possible characters
22
+ * @returns - parser that parses one of the given characters
23
+ */
4
24
  export declare function oneOf(chars: string): Parser<string>;
25
+ /**
26
+ * Takes a string. Returns a parser that parses one character
27
+ * that's not any of the characters in the given string
28
+ *
29
+ * @param chars - string of characters to avoid
30
+ * @returns - parser that parses a character that is not in the given string
31
+ */
5
32
  export declare function noneOf(chars: string): Parser<string>;
6
- export declare function anyChar(input: string): Parser<string>;
33
+ /**
34
+ * A parser that parses any one character.
35
+ * Fails on empty strings, succeeds otherwise.
36
+ *
37
+ * @param input - input string
38
+ * @returns - ParserResult
39
+ */
40
+ export declare const anyChar: any;
7
41
  export declare const space: Parser<string>;
8
42
  export declare const spaces: Parser<string>;
9
43
  export declare const digit: Parser<string>;
@@ -14,4 +48,5 @@ export declare const num: Parser<string>;
14
48
  export declare const quote: Parser<string>;
15
49
  export declare const tab: Parser<string>;
16
50
  export declare const newline: Parser<string>;
51
+ export declare const eof: Parser<null>;
17
52
  export declare const quotedString: Parser<string>;
package/dist/parsers.js CHANGED
@@ -4,16 +4,24 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "./combinators", "./trace", "./types", "./utils"], factory);
7
+ define(["require", "exports", "./combinators", "./trace", "./types", "./utils", "./parsers/betweenWithin"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.quotedString = exports.newline = exports.tab = exports.quote = exports.num = exports.word = exports.alphanum = exports.letter = exports.digit = exports.spaces = exports.space = exports.anyChar = exports.noneOf = exports.oneOf = exports.str = exports.char = void 0;
12
+ exports.quotedString = exports.eof = exports.newline = exports.tab = exports.quote = exports.num = exports.word = exports.alphanum = exports.letter = exports.digit = exports.spaces = exports.space = exports.anyChar = exports.noneOf = exports.oneOf = exports.str = exports.char = exports.betweenWithin = void 0;
13
13
  const combinators_1 = require("./combinators");
14
14
  const trace_1 = require("./trace");
15
15
  const types_1 = require("./types");
16
16
  const utils_1 = require("./utils");
17
+ var betweenWithin_1 = require("./parsers/betweenWithin");
18
+ Object.defineProperty(exports, "betweenWithin", { enumerable: true, get: function () { return betweenWithin_1.betweenWithin; } });
19
+ /**
20
+ * Takes a character. Returns a parser that parses that character.
21
+ *
22
+ * @param c - character to parse
23
+ * @returns - parser that parses the given character
24
+ */
17
25
  function char(c) {
18
26
  return (0, trace_1.trace)(`char(${(0, utils_1.escape)(c)})`, (input) => {
19
27
  if (input.length === 0) {
@@ -26,10 +34,16 @@
26
34
  if (input[0] === c) {
27
35
  return (0, types_1.success)(c, input.slice(1));
28
36
  }
29
- return (0, types_1.failure)(`expected ${c}, got ${input[0]}`, input);
37
+ return (0, types_1.failure)(`expected ${(0, utils_1.escape)(c)}, got ${(0, utils_1.escape)(input[0])}`, input);
30
38
  });
31
39
  }
32
40
  exports.char = char;
41
+ /**
42
+ * Takes a string. Returns a parser that parses that string.
43
+ *
44
+ * @param s - string to parse
45
+ * @returns - parser that parses the given string
46
+ */
33
47
  function str(s) {
34
48
  return (0, trace_1.trace)(`str(${(0, utils_1.escape)(s)})`, (input) => {
35
49
  if (input.substring(0, s.length) === s) {
@@ -39,6 +53,13 @@
39
53
  });
40
54
  }
41
55
  exports.str = str;
56
+ /**
57
+ * Takes a string. Returns a parser that parses
58
+ * one of the characters in that string.
59
+ *
60
+ * @param chars - string of possible characters
61
+ * @returns - parser that parses one of the given characters
62
+ */
42
63
  function oneOf(chars) {
43
64
  return (0, trace_1.trace)(`oneOf(${(0, utils_1.escape)(chars)})`, (input) => {
44
65
  if (input.length === 0) {
@@ -52,6 +73,13 @@
52
73
  });
53
74
  }
54
75
  exports.oneOf = oneOf;
76
+ /**
77
+ * Takes a string. Returns a parser that parses one character
78
+ * that's not any of the characters in the given string
79
+ *
80
+ * @param chars - string of characters to avoid
81
+ * @returns - parser that parses a character that is not in the given string
82
+ */
55
83
  function noneOf(chars) {
56
84
  return (0, trace_1.trace)(`noneOf(${(0, utils_1.escape)(chars)})`, (input) => {
57
85
  if (input.length === 0) {
@@ -64,15 +92,19 @@
64
92
  });
65
93
  }
66
94
  exports.noneOf = noneOf;
67
- function anyChar(input) {
68
- return (0, trace_1.trace)("anyChar", (input) => {
69
- if (input.length === 0) {
70
- return (0, types_1.failure)("unexpected end of input", input);
71
- }
72
- return { success: true, match: input[0], rest: input.slice(1) };
73
- });
74
- }
75
- exports.anyChar = anyChar;
95
+ /**
96
+ * A parser that parses any one character.
97
+ * Fails on empty strings, succeeds otherwise.
98
+ *
99
+ * @param input - input string
100
+ * @returns - ParserResult
101
+ */
102
+ exports.anyChar = (0, trace_1.trace)("anyChar", (input) => {
103
+ if (input.length === 0) {
104
+ return (0, types_1.failure)("unexpected end of input", input);
105
+ }
106
+ return (0, types_1.success)(input[0], input.slice(1));
107
+ });
76
108
  exports.space = oneOf(" \t\n\r");
77
109
  exports.spaces = (0, combinators_1.many1WithJoin)(exports.space);
78
110
  exports.digit = oneOf("0123456789");
@@ -83,5 +115,12 @@
83
115
  exports.quote = oneOf(`'"`);
84
116
  exports.tab = char("\t");
85
117
  exports.newline = char("\n");
86
- exports.quotedString = (0, combinators_1.transform)((0, combinators_1.seq)([exports.quote, exports.word, exports.quote], combinators_1.getResults), (x) => x.join(""));
118
+ const eof = (input) => {
119
+ if (input === "") {
120
+ return (0, types_1.success)(null, input);
121
+ }
122
+ return (0, types_1.failure)("expected end of input", input);
123
+ };
124
+ exports.eof = eof;
125
+ exports.quotedString = (0, combinators_1.seq)([exports.quote, exports.word, exports.quote], (results) => results.join(""));
87
126
  });
package/dist/types.d.ts CHANGED
@@ -3,6 +3,7 @@ export type ParserSuccess<T> = {
3
3
  success: true;
4
4
  result: T;
5
5
  rest: string;
6
+ nextParser?: GeneralParser<any, any>;
6
7
  };
7
8
  export type CaptureParserSuccess<T, C extends PlainObject> = ParserSuccess<T> & {
8
9
  captures: C;
@@ -30,4 +31,24 @@ type ExtractCaptures<T> = T extends CaptureParser<any, infer U> ? U : never;
30
31
  type ExtractCaptureParsers<T extends readonly GeneralParser<any, any>[]> = Extract<T[number], CaptureParser<any, any>>;
31
32
  export type MergedCaptures<T extends readonly GeneralParser<any, any>[]> = Prettify<UnionToIntersection<ExtractCaptures<ExtractCaptureParsers<T>>>>;
32
33
  export type MergedResults<T extends readonly GeneralParser<any, any>[]> = ExtractResults<T[number]>;
34
+ export type Node = ParserNode | EmptyNode;
35
+ export type ParserNode = {
36
+ parent: Node;
37
+ parser: GeneralParser<any, any> | null;
38
+ input?: string;
39
+ child: Node;
40
+ closed: boolean;
41
+ };
42
+ export type EmptyNode = null;
43
+ export declare function createNode(parent: Node | null, parser: GeneralParser<any, any>): ParserNode;
44
+ export declare function createTree(parsers: readonly GeneralParser<any, any>[]): Node;
45
+ export type Matched = {
46
+ type: "matched";
47
+ value: string;
48
+ };
49
+ export type Unmatched = {
50
+ type: "unmatched";
51
+ value: string;
52
+ };
53
+ export type BetweenWithinResult = Matched | Unmatched;
33
54
  export {};
package/dist/types.js CHANGED
@@ -9,7 +9,7 @@
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.failure = exports.captureSuccess = exports.success = exports.isCaptureResult = void 0;
12
+ exports.createTree = exports.createNode = exports.failure = exports.captureSuccess = exports.success = exports.isCaptureResult = void 0;
13
13
  function isCaptureResult(result) {
14
14
  return "captures" in result;
15
15
  }
@@ -26,24 +26,26 @@
26
26
  return { success: false, message, rest };
27
27
  }
28
28
  exports.failure = failure;
29
+ function createNode(parent, parser) {
30
+ return {
31
+ parent,
32
+ parser,
33
+ child: null,
34
+ closed: false,
35
+ };
36
+ }
37
+ exports.createNode = createNode;
38
+ function createTree(parsers) {
39
+ if (parsers.length === 0) {
40
+ return null;
41
+ }
42
+ const rootNode = createNode(null, parsers[0]);
43
+ let currentNode = rootNode;
44
+ for (let i = 1; i < parsers.length; i++) {
45
+ currentNode.child = createNode(currentNode, parsers[i]);
46
+ currentNode = currentNode.child;
47
+ }
48
+ return rootNode;
49
+ }
50
+ exports.createTree = createTree;
29
51
  });
30
- /* export type Merge2<O extends Array<T>, T = any> = Prettify<
31
- UnionToIntersection<O[number]>
32
- >;
33
-
34
- export type NonNullObject<T> = {
35
- [K in keyof T]: T[K] extends null | undefined ? never : T[K];
36
- }; */
37
- /* export type NonNullableUnionOfObjects<T> = T extends object
38
- ? RemoveNeverKeys<DeepNonNullable<T>>
39
- : T;
40
-
41
- export type DeepNonNullable<T> = {
42
- [P in keyof T]-?: NonNullable<T[P]>;
43
- }; */
44
- /* export type FilterNeverKeys<T> = {
45
- [K in keyof T]: T[K] extends never ? never : K;
46
- };
47
- */
48
- /* type ValueOf<T> = T[keyof T]; */
49
- /* type RemoveNeverKeys<T> = Pick<T, ValueOf<FilterNeverKeys<T>>>; */
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { Node } from "./types";
1
2
  export declare function escape(str: any): string;
2
3
  export declare function merge(a: any | any[], b: any | any[]): any[];
3
4
  export declare function mergeCaptures(a: Record<string, any>, b: Record<string, any>): Record<string, any>;
5
+ export declare function findAncestorWithNextParser(node: Node, count?: number): [Node, number];
6
+ export declare function popMany(arr: any[], count: number): void;