@@ -11,53 +11,39 @@ import { parseWithEOF } from "./eof.ts";
11
11
import { cons } from "../cons.ts" ;
12
12
import { type SKITerminalSymbol , term } from "../ski/terminal.ts" ;
13
13
14
- /**
15
- * Parses a chain of SKI atomic terms (term { term }).
16
- * For example, the input "SII" will be parsed as:
17
- * mkApp(mkApp(S, I), I)
18
- *
19
- * Returns a tuple of the literal parsed, the SKI expression, and the updated state.
20
- */
21
- function parseSKIChain ( rdb : ParserState ) : [ string , SKIExpression , ParserState ] {
22
- let [ lit , expr , state ] = parseAtomicSKI ( rdb ) ;
23
- for ( ; ; ) {
24
- const [ next , newState ] = peek ( state ) ;
25
- if (
26
- next === null ||
27
- ( next !== "(" && ! [ "S" , "K" , "I" ] . includes ( next . toUpperCase ( ) ) )
28
- ) {
29
- return [ lit , expr , newState ] ;
30
- }
31
- const [ nextLit , nextExpr , updatedState ] = parseAtomicSKI ( newState ) ;
14
+ const TERMINALS = new Set ( [ "S" , "K" , "I" ] ) ;
15
+
16
+ function isSymbol ( tok : string | null ) : tok is SKITerminalSymbol {
17
+ return tok !== null && TERMINALS . has ( tok . toUpperCase ( ) ) ;
18
+ }
19
+
20
+ function isAtomStart ( tok : string | null ) : boolean {
21
+ return tok === "(" || isSymbol ( tok ) ;
22
+ }
23
+
24
+ function parseSeq ( rdb : ParserState ) : [ string , SKIExpression , ParserState ] {
25
+ let [ lit , expr , state ] = parseAtomicOrParens ( rdb ) ;
26
+ let [ next , newState ] = peek ( state ) ;
27
+
28
+ while ( isAtomStart ( next ) ) {
29
+ const [ nextLit , nextExpr , updatedState ] = parseAtomicOrParens ( newState ) ;
32
30
lit = `${ lit } ${ nextLit } ` ;
33
31
expr = cons ( expr , nextExpr ) ;
34
32
state = updatedState ;
33
+ [ next , newState ] = peek ( state ) ;
35
34
}
35
+
36
+ return [ lit , expr , newState ] ;
36
37
}
37
38
38
- /**
39
- * Parses an atomic SKI term.
40
- * This is either one of the terminals S, K, I or a parenthesized SKI expression.
41
- *
42
- * Returns a tuple of the literal parsed, the SKI expression, and the updated state.
43
- */
44
- export function parseAtomicSKI (
39
+ function parseAtomicOrParens (
45
40
rdb : ParserState ,
46
41
) : [ string , SKIExpression , ParserState ] {
47
42
const [ peeked , state ] = peek ( rdb ) ;
43
+
48
44
if ( peeked === "(" ) {
49
- // Parse a parenthesized expression.
50
- const stateAfterLP = matchLP ( state ) ;
51
- // Inside parentheses we parse a whole chain.
52
- const [ innerLit , innerExpr , stateAfterChain ] = parseSKIChain ( stateAfterLP ) ;
53
- const stateAfterRP = matchRP ( stateAfterChain ) ;
54
- return [ `(${ innerLit } )` , innerExpr , stateAfterRP ] ;
55
- } else if (
56
- peeked &&
57
- ( peeked . toUpperCase ( ) === "S" ||
58
- peeked . toUpperCase ( ) === "K" ||
59
- peeked . toUpperCase ( ) === "I" )
60
- ) {
45
+ return parseParens ( state ) ;
46
+ } else if ( isSymbol ( peeked ) ) {
61
47
const token = peeked . toUpperCase ( ) ;
62
48
const stateAfterConsume = consume ( state ) ;
63
49
return [ peeked , term ( token as SKITerminalSymbol ) , stateAfterConsume ] ;
@@ -69,22 +55,20 @@ export function parseAtomicSKI(
69
55
}
70
56
}
71
57
72
- /**
73
- * Parses a full SKI expression.
74
- * (This is just a wrapper around parseSKIChain, which implements the left‐associative application.)
75
- *
76
- * Returns a tuple of the literal parsed, the SKI expression, and the updated state.
77
- */
78
- export function parseSKIInternal (
79
- rdb : ParserState ,
58
+ function parseParens (
59
+ state : ParserState ,
80
60
) : [ string , SKIExpression , ParserState ] {
81
- return parseSKIChain ( rdb ) ;
61
+ const stateAfterLP = matchLP ( state ) ;
62
+ const [ innerLit , innerExpr , stateAfterChain ] = parseSeq ( stateAfterLP ) ;
63
+ const stateAfterRP = matchRP ( stateAfterChain ) ;
64
+ return [ `(${ innerLit } )` , innerExpr , stateAfterRP ] ;
82
65
}
83
66
84
- /**
85
- * Parses an input string into an SKI expression.
86
- */
67
+ export const parseSKIDelimited = (
68
+ rdb : ParserState ,
69
+ ) : [ string , SKIExpression , ParserState ] => parseSeq ( rdb ) ;
70
+
87
71
export function parseSKI ( input : string ) : SKIExpression {
88
- const [ , expr ] = parseWithEOF ( input , parseSKIInternal ) ;
72
+ const [ , expr ] = parseWithEOF ( input , parseSKIDelimited ) ;
89
73
return expr ;
90
74
}
0 commit comments