@mattwca/little-parser-lib 1.0.2 → 1.0.4
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/package.json +1 -1
- package/src/parsers/parsers.ts +19 -6
package/package.json
CHANGED
package/src/parsers/parsers.ts
CHANGED
|
@@ -6,8 +6,11 @@ import { FailedParserResult, isFailedResult, isSuccessfulResult, ParseFn, Parser
|
|
|
6
6
|
/**
|
|
7
7
|
* Combines multiple parsers in sequence, returning an array of their results.
|
|
8
8
|
* If one of the parsers fails, the entire sequence fails.
|
|
9
|
+
* @param parsers The parsers to run in sequence.
|
|
9
10
|
*/
|
|
10
|
-
export function and
|
|
11
|
+
export function and<Parsers extends ParseFn<any>[]>(
|
|
12
|
+
...parsers: Parsers
|
|
13
|
+
): ParseFn<{ [K in keyof Parsers]: Parsers[K] extends ParseFn<infer R> ? R : never }> {
|
|
11
14
|
return (tokenStream: TokenStream) => {
|
|
12
15
|
const results: any[] = [];
|
|
13
16
|
|
|
@@ -21,7 +24,7 @@ export function and(...parsers: ParseFn<any>[]): ParseFn<any[]> {
|
|
|
21
24
|
results.push(parseResult.result);
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
return { result: results };
|
|
27
|
+
return { result: results } as any;
|
|
25
28
|
};
|
|
26
29
|
}
|
|
27
30
|
|
|
@@ -92,20 +95,30 @@ export function or<T>(...parsers: ParseFn<T>[]): ParseFn<T> {
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
/**
|
|
95
|
-
* Applies a parser repeatedly until it fails
|
|
96
|
-
* If the parser fails on the first attempt, returns a failure.
|
|
98
|
+
* Applies a parser repeatedly until it fails or doesn't make progress (move the position), collecting
|
|
99
|
+
* all successful results into an array. If the parser fails on the first attempt, returns a failure.
|
|
97
100
|
*/
|
|
98
|
-
export function many(parser: ParseFn<
|
|
101
|
+
export function many<T>(parser: ParseFn<T>): ParseFn<T[]> {
|
|
99
102
|
return (tokenStream: TokenStream) => {
|
|
100
|
-
const results:
|
|
103
|
+
const results: T[] = [];
|
|
101
104
|
|
|
102
105
|
let parseFailure = null;
|
|
103
106
|
|
|
104
107
|
while (true) {
|
|
108
|
+
const positionBefore = tokenStream.position;
|
|
105
109
|
tokenStream.storePosition();
|
|
106
110
|
|
|
107
111
|
const result = parser(tokenStream);
|
|
112
|
+
|
|
108
113
|
if (isSuccessfulResult(result)) {
|
|
114
|
+
const positionAfter = tokenStream.position;
|
|
115
|
+
|
|
116
|
+
// Check if the parser made any progress - if it didn't, we break out to avoid infinite loops.
|
|
117
|
+
if (positionAfter === positionBefore) {
|
|
118
|
+
tokenStream.restorePosition();
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
|
|
109
122
|
results.push(result.result);
|
|
110
123
|
tokenStream.clearPosition();
|
|
111
124
|
} else {
|