@@ -2,14 +2,27 @@ import type { Param } from "./param.ts";
22import type { Symbol } from "./read.ts" ;
33import type { Result } from "./result.ts" ;
44import type { Flag , Setter , Word } from "./tokenize.ts" ;
5- import type { Tokenizer } from "./tokenizer.ts" ;
6- import type { Issue } from "./types.ts" ;
5+ import { Tokenizer } from "./tokenizer.ts" ;
6+ import type { AnyPhase , Issue } from "./types.ts" ;
77
88export interface Binding < T > {
99 rest : Tokenizer < Symbol > ;
1010 result : Result < T > ;
1111}
1212
13+ export interface PhaseBinding {
14+ rest : Tokenizer < Symbol > ;
15+ model : Record < string , unknown > ;
16+ issues : Issue [ ] ;
17+ valid : boolean ;
18+ cursor ?: number ;
19+ }
20+
21+ export interface PhaseSegment {
22+ readonly tokens : Iterable < Symbol > ;
23+ readonly cursor ?: number ;
24+ }
25+
1326export function bind < T , P extends Param < string , T > > ( options : {
1427 param : P ;
1528 tokens : Tokenizer < Flag | Setter | Word > ;
@@ -68,6 +81,79 @@ export function bind<T, P extends Param<string, T>>(options: {
6881 } ;
6982}
7083
84+ export function bindPhase ( options : {
85+ phase : AnyPhase ;
86+ segment : PhaseSegment ;
87+ tokens : Tokenizer < Symbol > ;
88+ } ) : PhaseBinding {
89+ let { phase, segment } = options ;
90+ let tokens = options . tokens ;
91+ let params = Object . values ( phase . params ) as Param < string , unknown > [ ] ;
92+ let members = new Set ( Array . from ( segment . tokens , ( token ) => token . index ) ) ;
93+ let cursor = segment . cursor ;
94+ let results = new Map < string , Result < unknown > > ( ) ;
95+ let settled = new Set < string > ( ) ;
96+
97+ while ( true ) {
98+ for ( let param of params ) {
99+ if ( settled . has ( param . name ) ) {
100+ continue ;
101+ }
102+
103+ let visible = Array . from ( tokens ) . filter ( ( token ) => {
104+ return members . has ( token . index ) &&
105+ ( cursor === undefined || token . index <= cursor ) ;
106+ } ) ;
107+ let binding = bind ( {
108+ param,
109+ tokens : new Tokenizer ( visible ) ,
110+ } ) ;
111+ let remaining = new Set (
112+ Array . from ( binding . rest , ( token ) => token . index ) ,
113+ ) ;
114+ let claimed = new Set (
115+ visible
116+ . filter ( ( token ) => ! remaining . has ( token . index ) )
117+ . map ( ( token ) => token . index ) ,
118+ ) ;
119+
120+ results . set ( param . name , binding . result ) ;
121+
122+ if ( claimed . size > 0 ) {
123+ tokens = tokens . claimAll ( ( token ) => claimed . has ( token . index ) ) . rest ;
124+ settled . add ( param . name ) ;
125+ }
126+ }
127+
128+ if ( cursor === undefined || has ( tokens , members , cursor ) ) {
129+ break ;
130+ }
131+
132+ cursor = next ( tokens , members , cursor ) ;
133+ }
134+
135+ let model : Record < string , unknown > = { } ;
136+ let issues : Issue [ ] = [ ] ;
137+ let valid = true ;
138+
139+ for ( let param of params ) {
140+ let result = results . get ( param . name ) ;
141+ if ( ! result ) {
142+ continue ;
143+ }
144+
145+ issues . push ( ...result . issues ?? [ ] ) ;
146+
147+ if ( result . ok ) {
148+ model [ param . name ] = result . value ;
149+ } else {
150+ valid = false ;
151+ }
152+ }
153+
154+ return { rest : tokens , model, issues, valid, cursor } ;
155+ }
156+
71157function validate < T , P extends Param < string , T > > (
72158 param : P ,
73159 value : unknown ,
@@ -87,7 +173,11 @@ function validate<T, P extends Param<string, T>>(
87173 if ( validated . issues ) {
88174 return {
89175 ok : false ,
90- issues : validated . issues . map ( ( i ) => ( { ...i , path } ) ) ,
176+ issues : validated . issues . map ( ( issue ) => ( {
177+ ...issue ,
178+ message : issue . message ,
179+ path,
180+ } ) ) ,
91181 } ;
92182 } else {
93183 return {
@@ -97,3 +187,30 @@ function validate<T, P extends Param<string, T>>(
97187 } ;
98188 }
99189}
190+
191+ function has (
192+ tokens : Tokenizer < Symbol > ,
193+ members : Set < number > ,
194+ index : number ,
195+ ) : boolean {
196+ for ( let token of tokens ) {
197+ if ( members . has ( token . index ) && token . index === index ) {
198+ return true ;
199+ }
200+ }
201+ return false ;
202+ }
203+
204+ function next (
205+ tokens : Tokenizer < Symbol > ,
206+ members : Set < number > ,
207+ index : number ,
208+ ) : number | undefined {
209+ for ( let token of tokens ) {
210+ if (
211+ members . has ( token . index ) && token . index > index && token . type === "word"
212+ ) {
213+ return token . index ;
214+ }
215+ }
216+ }
0 commit comments