-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchain.ts
More file actions
70 lines (61 loc) · 2.09 KB
/
Copy pathchain.ts
File metadata and controls
70 lines (61 loc) · 2.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* Parser chain utilities for expression parsing.
*
* This module provides utilities for parsing chains of expressions
* (applications) by repeatedly consuming atomic terms until termination
* conditions are met.
*
* @module
*/
import { ParseError } from "./parseError.ts";
import {
isAtDefinitionKeywordLine,
type ParserState,
peek,
remaining,
skipWhitespace,
withParserState,
} from "./parserState.ts";
/**
* Parses a chain of expressions (applications) by repeatedly
* consuming atomic terms until either the input is exhausted,
* a termination token (')') is encountered, or a newline is found
* that's not part of whitespace within a term.
*
* @param state the current parser state.
* @param parseAtomic a function that parses an atomic term from the state,
* returning a triple: [literal, term, updatedState].
* @param createApplication a function that creates an application of two terms.
* @returns a triple: [concatenated literal, chained term, updated parser state].
* @throws ParseError if no term is parsed.
*/
export function parseChain<T>(
state: ParserState,
parseAtomic: (state: ParserState) => [string, T, ParserState],
createApplication: (left: T, right: T) => T,
): [string, T, ParserState] {
const literals: string[] = [];
let resultTerm: T | undefined = undefined;
let currentState = skipWhitespace(state);
for (let chainLength = 0; ; chainLength = chainLength + 1) {
const [hasRemaining] = remaining(currentState);
if (!hasRemaining) break;
const [peeked] = peek(currentState);
if (peeked === ")") break;
if (isAtDefinitionKeywordLine(currentState)) {
break;
}
const [atomLit, atomTerm, newState] = parseAtomic(currentState);
literals.push(atomLit);
if (resultTerm === undefined) {
resultTerm = atomTerm;
} else {
resultTerm = createApplication(resultTerm, atomTerm);
}
currentState = skipWhitespace(newState);
}
if (resultTerm === undefined) {
throw new ParseError(withParserState(currentState, "expected a term"));
}
return [literals.join(" "), resultTerm, currentState];
}