@@ -213,6 +213,18 @@ fn bind_run<'a, F: FilterT, T: Clone + 'a>(
213213 }
214214}
215215
216+ fn label_run < ' a , V , T : ' a > (
217+ cv : Cv < ' a , V , T > ,
218+ run : impl Fn ( Cv < ' a , V , T > ) -> Results < ' a , T , V > ,
219+ ) -> Results < ' a , T , V > {
220+ let ctx = cv. 0 . cons_label ( ) ;
221+ let labels = ctx. labels ;
222+ Box :: new ( run ( ( ctx, cv. 1 ) ) . map_while ( move |y| match y {
223+ Err ( Exn ( exn:: Inner :: Break ( b) ) ) if b == labels => None ,
224+ y => Some ( y) ,
225+ } ) )
226+ }
227+
216228fn fold_run < ' a , V : Clone , T : Clone + ' a > (
217229 xs : impl Iterator < Item = Result < Ctx < ' a , V > , Exn < ' a , V > > > + Clone + ' a ,
218230 cv : Cv < ' a , V , T > ,
@@ -293,11 +305,15 @@ fn lazy_is_lazy() {
293305
294306/// Combination of context and input value.
295307pub type Cv < ' c , V , T = V > = ( Ctx < ' c , V > , T ) ;
308+ /// Combination of context and input value with a path.
309+ type Cvp < ' a , V > = Cv < ' a , V , ( V , RcList < V > ) > ;
310+ type ValPathXs < ' a , V > = Results < ' a , ( V , RcList < V > ) , V > ;
296311
297312/// A filter which is implemented using function pointers.
298313#[ derive( Clone ) ]
299314pub struct Native < V > {
300315 run : RunPtr < V > ,
316+ paths : PathsPtr < V > ,
301317 update : UpdatePtr < V > ,
302318}
303319
@@ -308,6 +324,8 @@ pub struct Native<V> {
308324/// That would also allow to eliminate `F` from `FilterT`.
309325pub type RunPtr < V , F = Native < V > > = for <' a > fn ( & ' a Lut < F > , Cv < ' a , V > ) -> ValXs < ' a , V > ;
310326/// Update function pointer.
327+ pub type PathsPtr < V , F = Native < V > > = for <' a > fn ( & ' a Lut < F > , Cvp < ' a , V > ) -> ValPathXs < ' a , V > ;
328+ /// Update function pointer.
311329pub type UpdatePtr < V , F = Native < V > > =
312330 for <' a > fn ( & ' a Lut < F > , Cv < ' a , V > , BoxUpdate < ' a , V > ) -> ValXs < ' a , V > ;
313331
@@ -316,6 +334,7 @@ impl<V> Native<V> {
316334 pub const fn new ( run : RunPtr < V , Self > ) -> Self {
317335 Self {
318336 run,
337+ paths : |_, _| box_once ( Err ( Exn :: from ( Error :: path_expr ( ) ) ) ) ,
319338 update : |_, _, _| box_once ( Err ( Exn :: from ( Error :: path_expr ( ) ) ) ) ,
320339 }
321340 }
@@ -333,6 +352,10 @@ impl<V: ValT> FilterT for Native<V> {
333352 ( self . run ) ( lut, cv)
334353 }
335354
355+ fn paths < ' a > ( & ' a self , lut : & ' a Lut < Self > , cv : Cvp < ' a , V > ) -> ValPathXs < ' a , V > {
356+ ( self . paths ) ( lut, cv)
357+ }
358+
336359 fn update < ' a > (
337360 & ' a self ,
338361 lut : & ' a Lut < Self > ,
@@ -343,121 +366,6 @@ impl<V: ValT> FilterT for Native<V> {
343366 }
344367}
345368
346- type Cp < ' a , V > = Cv < ' a , V , ( V , RcList < V > ) > ;
347- use crate :: box_iter:: BoxIter ;
348- pub type ValPXs < ' a , V > = BoxIter < ' a , Result < ( V , RcList < V > ) , crate :: Exn < ' a , V > > > ;
349-
350- impl Id {
351- fn paths < ' a , F : FilterT < F > > ( & ' a self , lut : & ' a Lut < F > , cv : Cp < ' a , F :: V > ) -> ValPXs < ' a , F :: V > {
352- // TODO: capture value in path_expr?
353- let err = box_once ( Err ( Exn :: from ( Error :: path_expr ( ) ) ) ) ;
354- let proj = |cv : & Cp < ' a , F :: V > | ( cv. 0 . clone ( ) , cv. 1 . 0 . clone ( ) ) ;
355- match & lut. terms [ self . 0 ] {
356- Ast :: ToString => err,
357- Ast :: Int ( _) | Ast :: Num ( _) | Ast :: Str ( _) => err,
358- Ast :: Arr ( _) | Ast :: ObjEmpty | Ast :: ObjSingle ( ..) => err,
359- Ast :: Neg ( _) | Ast :: Logic ( ..) | Ast :: Math ( ..) | Ast :: Cmp ( ..) => err,
360- Ast :: Update ( ..) | Ast :: UpdateMath ( ..) | Ast :: UpdateAlt ( ..) | Ast :: Assign ( ..) => err,
361- Ast :: Id => box_once ( Ok ( cv. 1 ) ) ,
362- Ast :: Pipe ( l, None , r) => {
363- flat_map_then_with ( l. paths ( lut, ( cv. 0 . clone ( ) , cv. 1 ) ) , cv. 0 , move |y, ctx| {
364- r. paths ( lut, ( ctx, y) )
365- } )
366- }
367- Ast :: Pipe ( l, Some ( pat) , r) => {
368- flat_map_then_with ( l. run ( lut, proj ( & cv) ) , cv, move |y, cv| {
369- bind_run ( pat, r, lut, cv, y, |f, lut, cv| f. paths ( lut, cv) )
370- } )
371- }
372- Ast :: Comma ( l, r) => Box :: new ( l. paths ( lut, cv. clone ( ) ) . chain ( lazy ( || r. paths ( lut, cv) ) ) ) ,
373- Ast :: Alt ( l, r) => {
374- let any_true = l
375- . run ( lut, proj ( & cv) )
376- . any ( |v| v. as_ref ( ) . map_or ( true , ValT :: as_bool) ) ;
377- if any_true { l } else { r } . paths ( lut, cv)
378- }
379- Ast :: Ite ( if_, then_, else_) => {
380- flat_map_then_with ( if_. run ( lut, proj ( & cv) ) , cv, move |v, cv| {
381- if v. as_bool ( ) { then_ } else { else_ } . paths ( lut, cv)
382- } )
383- }
384- Ast :: TryCatch ( f, c) => {
385- Box :: new ( f. paths ( lut, ( cv. 0 . clone ( ) , cv. 1 ) ) . flat_map ( move |y| {
386- match y {
387- Err ( Exn ( exn:: Inner :: Err ( e) ) ) => Box :: new (
388- c. run ( lut, ( cv. 0 . clone ( ) , e. into_val ( ) ) )
389- . map ( |_| Err ( Exn :: from ( Error :: path_expr ( ) ) ) ) ,
390- ) ,
391- y => box_once ( y) ,
392- }
393- } ) )
394- }
395- Ast :: Path ( f, path) => {
396- let path = path. map_ref ( |i| {
397- let cv = ( cv. 0 . clone ( ) , cv. 1 . 0 . clone ( ) ) ;
398- crate :: into_iter:: collect_if_once ( move || i. run ( lut, cv) )
399- } ) ;
400- flat_map_then_with ( f. paths ( lut, cv) , path, |y, path| {
401- flat_map_then_with ( path. explode ( ) , y, |path, y| {
402- Box :: new ( path. paths ( y) . map ( |r| r. map_err ( Exn :: from) ) )
403- } )
404- } )
405- }
406- Ast :: Var ( v) => match cv. 0 . vars . get ( * v) . unwrap ( ) {
407- Bind :: Var ( _) => err,
408- Bind :: Fun ( l) => l. 0 . paths ( lut, ( cv. 0 . with_vars ( l. 1 . clone ( ) ) , cv. 1 ) ) ,
409- Bind :: Label ( l) => box_once ( Err ( Exn ( exn:: Inner :: Break ( * l) ) ) ) ,
410- } ,
411- Ast :: Fold ( xs, pat, init, update, fold_type) => {
412- let xs = rc_lazy_list:: List :: from_iter ( run_and_bind ( xs, lut, proj ( & cv) , pat) ) ;
413- fold_run ( xs, cv, init, update, fold_type, |f, cv| f. paths ( lut, cv) )
414- }
415- Ast :: CallDef ( id, args, skip, tailrec) => {
416- use core:: ops:: ControlFlow ;
417- let with_vars = move |vars| Ctx {
418- vars,
419- labels : cv. 0 . labels ,
420- inputs : cv. 0 . inputs ,
421- } ;
422- let cvs = bind_vars ( args, lut, cv. 0 . clone ( ) . skip_vars ( * skip) , cv, |vp| {
423- vp. 0 . clone ( )
424- } ) ;
425- match tailrec {
426- None => flat_map_then ( cvs, |cv| id. paths ( lut, cv) ) ,
427- Some ( Tailrec :: Catch ) => Box :: new ( crate :: Stack :: new (
428- [ flat_map_then ( cvs, |cv| id. paths ( lut, cv) ) ] . into ( ) ,
429- move |r| match r {
430- Err ( Exn ( exn:: Inner :: TailCall ( id_, vars, v, Some ( p) ) ) ) if id == id_ => {
431- ControlFlow :: Continue ( id. paths ( lut, ( with_vars ( vars) , ( v, p) ) ) )
432- }
433- Ok ( _) | Err ( _) => ControlFlow :: Break ( r) ,
434- } ,
435- ) ) ,
436- Some ( Tailrec :: Throw ) => Box :: new ( cvs. map ( move |cv| {
437- cv. and_then ( |cv| {
438- Err ( Exn ( exn:: Inner :: TailCall (
439- id,
440- cv. 0 . vars ,
441- cv. 1 . 0 ,
442- Some ( cv. 1 . 1 ) ,
443- ) ) )
444- } )
445- } ) ) ,
446- }
447- }
448- Ast :: Label ( id) => {
449- let ctx = cv. 0 . cons_label ( ) ;
450- let labels = ctx. labels ;
451- Box :: new ( id. paths ( lut, ( ctx, cv. 1 ) ) . map_while ( move |y| match y {
452- Err ( Exn ( exn:: Inner :: Break ( b) ) ) if b == labels => None ,
453- y => Some ( y) ,
454- } ) )
455- }
456- _ => todo ! ( ) ,
457- }
458- }
459- }
460-
461369impl < F : FilterT < F > > FilterT < F > for Id {
462370 type V = F :: V ;
463371
@@ -529,18 +437,12 @@ impl<F: FilterT<F>> FilterT<F> for Id {
529437 Box :: new ( move |v| f. run ( lut, ( cv. 0 . clone ( ) , v) ) ) ,
530438 ) ,
531439 Ast :: UpdateMath ( path, op, f) => f. pipe ( lut, cv, move |cv, y| {
532- path. update (
533- lut,
534- cv,
535- Box :: new ( move |x| box_once ( op. run ( x, y. clone ( ) ) . map_err ( Exn :: from) ) ) ,
536- )
440+ let u = move |x : F :: V | box_once ( op. run ( x, y. clone ( ) ) . map_err ( Exn :: from) ) ;
441+ path. update ( lut, cv, Box :: new ( u) )
537442 } ) ,
538443 Ast :: UpdateAlt ( path, f) => f. pipe ( lut, cv, move |cv, y| {
539- path. update (
540- lut,
541- cv,
542- Box :: new ( move |x| box_once ( Ok ( if x. as_bool ( ) { x } else { y. clone ( ) } ) ) ) ,
543- )
444+ let u = move |x : F :: V | box_once ( Ok ( if x. as_bool ( ) { x } else { y. clone ( ) } ) ) ;
445+ path. update ( lut, cv, Box :: new ( u) )
544446 } ) ,
545447 Ast :: Assign ( path, f) => f. pipe ( lut, cv, move |cv, y| {
546448 path. update ( lut, cv, Box :: new ( move |_| box_once ( Ok ( y. clone ( ) ) ) ) )
@@ -598,14 +500,108 @@ impl<F: FilterT<F>> FilterT<F> for Id {
598500 let cvs = bind_vars ( args, lut, Ctx :: new ( [ ] , cv. 0 . inputs ) , cv, Clone :: clone) ;
599501 flat_map_then ( cvs, |cv| lut. funs [ * id] . run ( lut, cv) )
600502 }
601- Ast :: Label ( id) => {
602- let ctx = cv. 0 . cons_label ( ) ;
603- let labels = ctx. labels ;
604- Box :: new ( id. run ( lut, ( ctx, cv. 1 ) ) . map_while ( move |y| match y {
605- Err ( Exn ( exn:: Inner :: Break ( b) ) ) if b == labels => None ,
606- y => Some ( y) ,
503+ Ast :: Label ( id) => label_run ( cv, |cv| id. run ( lut, cv) ) ,
504+ }
505+ }
506+
507+ fn paths < ' a > ( & ' a self , lut : & ' a Lut < F > , cv : Cvp < ' a , F :: V > ) -> ValPathXs < ' a , F :: V > {
508+ // TODO: capture value in path_expr?
509+ let err = box_once ( Err ( Exn :: from ( Error :: path_expr ( ) ) ) ) ;
510+ let proj_cv = |cv : & Cvp < ' a , F :: V > | ( cv. 0 . clone ( ) , cv. 1 . 0 . clone ( ) ) ;
511+ let proj_val = |( val, _path) : & ( F :: V , _ ) | val. clone ( ) ;
512+ match & lut. terms [ self . 0 ] {
513+ Ast :: ToString => err,
514+ Ast :: Int ( _) | Ast :: Num ( _) | Ast :: Str ( _) => err,
515+ Ast :: Arr ( _) | Ast :: ObjEmpty | Ast :: ObjSingle ( ..) => err,
516+ Ast :: Neg ( _) | Ast :: Logic ( ..) | Ast :: Math ( ..) | Ast :: Cmp ( ..) => err,
517+ Ast :: Update ( ..) | Ast :: UpdateMath ( ..) | Ast :: UpdateAlt ( ..) | Ast :: Assign ( ..) => err,
518+ Ast :: Id => box_once ( Ok ( cv. 1 ) ) ,
519+ Ast :: Pipe ( l, None , r) => {
520+ flat_map_then_with ( l. paths ( lut, ( cv. 0 . clone ( ) , cv. 1 ) ) , cv. 0 , move |y, ctx| {
521+ r. paths ( lut, ( ctx, y) )
522+ } )
523+ }
524+ Ast :: Pipe ( l, Some ( pat) , r) => {
525+ flat_map_then_with ( l. run ( lut, proj_cv ( & cv) ) , cv, move |y, cv| {
526+ bind_run ( pat, r, lut, cv, y, |f, lut, cv| f. paths ( lut, cv) )
527+ } )
528+ }
529+ Ast :: Comma ( l, r) => Box :: new ( l. paths ( lut, cv. clone ( ) ) . chain ( lazy ( || r. paths ( lut, cv) ) ) ) ,
530+ Ast :: Alt ( l, r) => {
531+ let any_true = l
532+ . run ( lut, proj_cv ( & cv) )
533+ . any ( |v| v. as_ref ( ) . map_or ( true , ValT :: as_bool) ) ;
534+ if any_true { l } else { r } . paths ( lut, cv)
535+ }
536+ Ast :: Ite ( if_, then_, else_) => {
537+ flat_map_then_with ( if_. run ( lut, proj_cv ( & cv) ) , cv, move |v, cv| {
538+ if v. as_bool ( ) { then_ } else { else_ } . paths ( lut, cv)
539+ } )
540+ }
541+ Ast :: TryCatch ( f, c) => {
542+ Box :: new ( f. paths ( lut, ( cv. 0 . clone ( ) , cv. 1 ) ) . flat_map ( move |y| {
543+ match y {
544+ Err ( Exn ( exn:: Inner :: Err ( e) ) ) => Box :: new (
545+ c. run ( lut, ( cv. 0 . clone ( ) , e. into_val ( ) ) )
546+ . map ( |_| Err ( Exn :: from ( Error :: path_expr ( ) ) ) ) ,
547+ ) ,
548+ y => box_once ( y) ,
549+ }
607550 } ) )
608551 }
552+ Ast :: Path ( f, path) => {
553+ let path = path. map_ref ( |i| {
554+ let cv = ( cv. 0 . clone ( ) , cv. 1 . 0 . clone ( ) ) ;
555+ crate :: into_iter:: collect_if_once ( move || i. run ( lut, cv) )
556+ } ) ;
557+ flat_map_then_with ( f. paths ( lut, cv) , path, |y, path| {
558+ flat_map_then_with ( path. explode ( ) , y, |path, y| {
559+ Box :: new ( path. paths ( y) . map ( |r| r. map_err ( Exn :: from) ) )
560+ } )
561+ } )
562+ }
563+ Ast :: Var ( v) => match cv. 0 . vars . get ( * v) . unwrap ( ) {
564+ Bind :: Var ( _) => err,
565+ Bind :: Fun ( l) => l. 0 . paths ( lut, ( cv. 0 . with_vars ( l. 1 . clone ( ) ) , cv. 1 ) ) ,
566+ Bind :: Label ( l) => box_once ( Err ( Exn ( exn:: Inner :: Break ( * l) ) ) ) ,
567+ } ,
568+ Ast :: Fold ( xs, pat, init, update, fold_type) => {
569+ let xs = rc_lazy_list:: List :: from_iter ( run_and_bind ( xs, lut, proj_cv ( & cv) , pat) ) ;
570+ fold_run ( xs, cv, init, update, fold_type, |f, cv| f. paths ( lut, cv) )
571+ }
572+ Ast :: CallDef ( id, args, skip, tailrec) => {
573+ use core:: ops:: ControlFlow ;
574+ let with_vars = move |vars| Ctx {
575+ vars,
576+ labels : cv. 0 . labels ,
577+ inputs : cv. 0 . inputs ,
578+ } ;
579+ let cvs = bind_vars ( args, lut, cv. 0 . clone ( ) . skip_vars ( * skip) , cv, proj_val) ;
580+ match tailrec {
581+ None => flat_map_then ( cvs, |cv| id. paths ( lut, cv) ) ,
582+ Some ( Tailrec :: Catch ) => Box :: new ( crate :: Stack :: new (
583+ [ flat_map_then ( cvs, |cv| id. paths ( lut, cv) ) ] . into ( ) ,
584+ move |r| match r {
585+ Err ( Exn ( exn:: Inner :: TailCall ( id_, vars, v, Some ( p) ) ) ) if id == id_ => {
586+ ControlFlow :: Continue ( id. paths ( lut, ( with_vars ( vars) , ( v, p) ) ) )
587+ }
588+ Ok ( _) | Err ( _) => ControlFlow :: Break ( r) ,
589+ } ,
590+ ) ) ,
591+ Some ( Tailrec :: Throw ) => Box :: new ( cvs. map ( move |cv| {
592+ cv. and_then ( |cv| {
593+ let val = cv. 1 . 0 ;
594+ let path = Some ( cv. 1 . 1 ) ;
595+ Err ( Exn ( exn:: Inner :: TailCall ( id, cv. 0 . vars , val, path) ) )
596+ } )
597+ } ) ) ,
598+ }
599+ }
600+ Ast :: Label ( id) => label_run ( cv, |cv| id. paths ( lut, cv) ) ,
601+ Ast :: Native ( id, args) => {
602+ let cvs = bind_vars ( args, lut, Ctx :: new ( [ ] , cv. 0 . inputs ) , cv, proj_val) ;
603+ flat_map_then ( cvs, |cv| lut. funs [ * id] . paths ( lut, cv) )
604+ }
609605 }
610606 }
611607
@@ -697,10 +693,17 @@ pub trait FilterT<F: FilterT<F, V = Self::V> = Self> {
697693 /// This is an associated type because it is strictly determined by `F`.
698694 type V : ValT ;
699695
700- /// `f.run((c, v))` returns the output of `v | f` in the context `c`.
696+ /// `f.run(lut, (c, v))` returns the output of `v | f` in the context `c`.
701697 fn run < ' a > ( & ' a self , lut : & ' a Lut < F > , cv : Cv < ' a , Self :: V > ) -> ValXs < ' a , Self :: V > ;
702698
703- /// `p.update((c, v), f)` returns the output of `v | p |= f` in the context `c`.
699+ /// `f.paths(lut, (c, (v, p)))` returns the outputs and paths of `v | f` in the context `c`,
700+ /// where `v` is assumed to be at path `p`.
701+ ///
702+ /// In particular, `v | path(f)` in context `c` yields the same paths as
703+ /// `f.paths(lut, (c, (v, Default::default())))`.
704+ fn paths < ' a > ( & ' a self , lut : & ' a Lut < F > , cv : Cvp < ' a , Self :: V > ) -> ValPathXs < ' a , Self :: V > ;
705+
706+ /// `p.update(lut, (c, v), f)` returns the output of `v | p |= f` in the context `c`.
704707 fn update < ' a > (
705708 & ' a self ,
706709 lut : & ' a Lut < F > ,
0 commit comments