1 import Base 2 import ./execution_effects.bend as Effects 3 import ./chunk_column.bend as C 4 import ./lifecycle.bend as L 5 import ./change_tick.bend as Tick 6 7 type Error<-E:Data> is Data: 8 Error{index:U32,value:E} 9 type Run<-S:Data,-A:Type,-B:Type,-E:Data> is Type: 10 Run{read:C.Column,write:C.Column,errors:List<&2,Error>,aligned:Bool} 11 12 type Selection is Data: 13 All{} 14 Selected{indices:List<&2,U32>} 15 Filtered{indices:List<&2,U32>,filter:L.Filter,cursor:Maybe<&2,Tick.Tick>} 16 def contains(+index:U32,indices:List<&2,U32>) -> Bool: 17 match indices: 18 case []: False{} 19 case current <> rest: U32.is_eq(index,current) || contains(index,rest) 20 def eligible(index:U32,stamp:L.Stamp,tick:Tick.Tick,selection:Selection) -> Bool: 21 match selection: 22 case All{}: True{} 23 case Selected{indices}: contains(index,indices) 24 case Filtered{indices,filter,cursor}:Bool.and(contains(index,indices),L.matches(filter,stamp,cursor,tick)) 25 type Layout is Data: 26 LayoutLeaf{} 27 LayoutBranch{half:U32,left:Layout,right:Layout} 28 def layout_join(~S:Data,~A:Type,+half:U32,left:C.Column & Layout,right:C.Column & Layout) -> C.Column & Layout: 29 match left right: 30 case Tuple{l,ls} Tuple{r,rs}: (C.Branch{half,l,r},LayoutBranch{half,ls,rs}) 31 def layout(~S:Data,~A:Type,column:C.Column) -> C.Column & Layout: 32 match column: 33 case C.Leaf{values,stamps}: (C.Leaf{values,stamps},LayoutLeaf{}) 34 case C.Branch{+half,left,right}: layout_join(~S,~A,half,layout(~S,~A,left),layout(~S,~A,right)) 35 def same(left:Layout,right:Layout) -> Bool: 36 match left right: 37 case LayoutLeaf{} LayoutLeaf{}: True{} 38 case LayoutBranch{lh,ll,lr} LayoutBranch{rh,rl,rr}: U32.is_eq(lh,rh) && same(ll,rl) && same(lr,rr) 39 case _ _: False{} 40 # Sequential row traversal threads its physical columns and affine output owner. 41 # Context is reusable selection data; it cannot contain affine payload owners. 42 type OutputRow<-A:Type,-B:Type,-O:Type,-E:Data> is Type: 43 OutputRow{read:Maybe<&1,A>,write:Maybe<&1,B>,stamp:L.Stamp,output:O,errors:List<&2,Error>} 44 type OutputValues<-A:Type,-B:Type,-O:Type,-E:Data> is Type: 45 OutputValues{read:Array>,write:Array>,stamps:Array,output:O,errors:List<&2,Error>,aligned:Bool} 46 type OutputRun<-S:Data,-A:Type,-B:Type,-O:Type,-E:Data> is Type: 47 OutputRun{read:C.Column,write:C.Column,output:O,errors:List<&2,Error>,aligned:Bool} 48 def output_result(~A:Type,~B:Type,~O:Type,~E:Data,read:A,index:U32,stamp:L.Stamp,result:B & (O & Maybe<&2,E>)) -> OutputRow: 49 match result: 50 case (write,(output,None{})):OutputRow{Some{read},Some{write},stamp,output,[]} 51 case (write,(output,Some{error})):OutputRow{Some{read},Some{write},stamp,output,[Error{index,error}]} 52 def output_values(~A:Type,~B:Type,~O:Type,~E:Data,result:OutputRow) -> OutputValues: 53 match result: 54 case OutputRow{read,write,stamp,output,errors}:OutputValues{ALeaf{read},ALeaf{write},ALeaf{stamp},output,errors,True{}} 55 def output_values_join(~A:Type,~B:Type,~O:Type,~E:Data,leftRead:Array>,leftWrite:Array>,leftStamps:Array,leftErrors:List<&2,Error>,leftAligned:Bool,right:OutputValues) -> OutputValues: 56 match right: 57 case OutputValues{read,write,stamps,output,errors,aligned}:OutputValues{ANode{leftRead,read},ANode{leftWrite,write},ANode{leftStamps,stamps},output,List.append(&2,Error,leftErrors,errors),Bool.and(leftAligned,aligned)} 58 def output_leaf_run(~S:Data,~A:Type,~B:Type,~O:Type,~E:Data,readStamps:Array,result:OutputValues) -> OutputRun: 59 match result: 60 case OutputValues{a,b,stamps,output,errors,aligned}:OutputRun{C.Leaf{a,readStamps},C.Leaf{b,stamps},output,errors,aligned} 61 def output_join(~S:Data,~A:Type,~B:Type,~O:Type,~E:Data,+half:U32,leftRead:C.Column,leftWrite:C.Column,leftErrors:List<&2,Error>,leftAligned:Bool,right:OutputRun) -> OutputRun: 62 match right: 63 case OutputRun{read,write,output,errors,aligned}:OutputRun{C.Branch{half,leftRead,read},C.Branch{half,leftWrite,write},output,List.append(&2,Error,leftErrors,errors),Bool.and(leftAligned,aligned)} 64 def effect_Body(~F:Type -> Type,~K:Data,~V:Data,~B:Type,~O:Type,~E:Data) -> Type: 65 K -> U32 -> V -> B -> O -> F(B & (O & Maybe<&2,E>)) 66 def effect_projected(~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~body:effect_Body(~F,~K,~V,~B,~O,~E),context:K,write:B,output:O,+index:U32,stamp:L.Stamp,tick:Tick.Tick,result:A & V) -> F(OutputRow): 67 match result: 68 case (read,view):Effects.map(~F,(B & (O & Maybe<&2,E>)),OutputRow,effects,body(context,index,view,write,output),result => output_result(~A,~B,~O,~E,read,index,L.written(True{},stamp,tick),result)) 69 def effect_allowed(~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),context:K,read:A,write:B,output:O,index:U32,stamp:L.Stamp,tick:Tick.Tick,selected:Bool) -> F(OutputRow): 70 match selected: 71 case False{}:Effects.pure(~F,OutputRow,effects,OutputRow{Some{read},Some{write},stamp,output,[]}) 72 case True{}:effect_projected(~F,~effects,~A,~B,~O,~V,~K,~E,~body,context,write,output,index,stamp,tick,project(read)) 73 def effect_row(~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),context:K,read:Maybe<&1,A>,write:Maybe<&1,B>,output:O,+index:U32,+stamp:L.Stamp,+tick:Tick.Tick,selection:Selection) -> F(OutputRow): 74 match read write: 75 case None{} write:Effects.pure(~F,OutputRow,effects,OutputRow{None{},write,stamp,output,[]}) 76 case Some{read} None{}:Effects.pure(~F,OutputRow,effects,OutputRow{Some{read},None{},stamp,output,[]}) 77 case Some{read} Some{write}:effect_allowed(~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,read,write,output,index,stamp,tick,eligible(index,stamp,tick,selection)) 78 def effect_leaf_right(~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~E:Data,left:OutputValues,walk:O -> F(OutputValues)) -> F(OutputValues): 79 match left: 80 case OutputValues{read,write,stamps,output,errors,aligned}:Effects.map(~F,OutputValues,OutputValues,effects,walk(output),right => output_values_join(~A,~B,~O,~E,read,write,stamps,errors,aligned,right)) 81 def effect_leaf(~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),+context:K,read:Array>,write:Array>,stamps:Array,output:O,+offset:U32,+size:U32,+tick:Tick.Tick,+selection:Selection) -> F(OutputValues): 82 match read write stamps: 83 case ALeaf{a} ALeaf{b} ALeaf{stamp}:Effects.map(~F,OutputRow,OutputValues,effects,effect_row(~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,a,b,output,offset,stamp,tick,selection),result => output_values(~A,~B,~O,~E,result)) 84 case ANode{al,ar} ANode{bl,br} ANode{sl,sr}:Effects.bind(~F,OutputValues,OutputValues,effects,effect_leaf(~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,al,bl,sl,output,offset,U32.shr(size),tick,selection),left => effect_leaf_right(~F,~effects,~A,~B,~O,~E,left,output => effect_leaf(~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,ar,br,sr,output,U32.add(offset,U32.shr(size)),U32.shr(size),tick,selection))) 85 case a b s:Effects.pure(~F,OutputValues,effects,OutputValues{a,b,s,output,[],False{}}) 86 def effect_branch_right(~S:Data,~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~E:Data,+half:U32,left:OutputRun,walk:O -> F(OutputRun)) -> F(OutputRun): 87 match left: 88 case OutputRun{read,write,output,errors,aligned}:Effects.map(~F,OutputRun,OutputRun,effects,walk(output),right => output_join(~S,~A,~B,~O,~E,half,read,write,errors,aligned,right)) 89 def effect_rows(~S:Data,~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),+context:K,read:C.Column,write:C.Column,output:O,+offset:U32,+tick:Tick.Tick,+selection:Selection) -> F(OutputRun): 90 match read write: 91 case C.Leaf{a,sa} C.Leaf{b,sb}:Effects.map(~F,OutputValues,OutputRun,effects,effect_leaf(~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,a,b,sb,output,offset,8,tick,selection),result => output_leaf_run(~S,~A,~B,~O,~E,sa,result)) 92 case C.Branch{+half,al,ar} C.Branch{_,bl,br}:Effects.bind(~F,OutputRun,OutputRun,effects,effect_rows(~S,~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,al,bl,output,offset,tick,selection),left => effect_branch_right(~S,~F,~effects,~A,~B,~O,~E,half,left,output => effect_rows(~S,~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,ar,br,output,U32.add(offset,half),tick,selection))) 93 case a b:Effects.pure(~F,OutputRun,effects,OutputRun{a,b,output,[],False{}}) 94 def effect_execute(~S:Data,~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),context:K,read:C.Column,write:C.Column,output:O,offset:U32,tick:Tick.Tick,selection:Selection,aligned:Bool) -> F(OutputRun): 95 match aligned: 96 case False{}:Effects.pure(~F,OutputRun,effects,OutputRun{read,write,output,[],False{}}) 97 case True{}:effect_rows(~S,~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,read,write,output,offset,tick,selection) 98 def effect_prepared(~S:Data,~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),context:K,output:O,offset:U32,tick:Tick.Tick,selection:Selection,left:C.Column & Layout,right:C.Column & Layout) -> F(OutputRun): 99 match left right: 100 case Tuple{read,ls} Tuple{write,rs}:effect_execute(~S,~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,read,write,output,offset,tick,selection,same(ls,rs)) 101 def effect_with_output(~S:Data,~F:Type -> Type,~effects:Effects.Effects,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:effect_Body(~F,~K,~V,~B,~O,~E),context:K,read:C.Column,write:C.Column,output:O,offset:U32,tick:Tick.Tick,selection:Selection) -> F(OutputRun): 102 effect_prepared(~S,~F,~effects,~A,~B,~O,~V,~K,~E,~project,~body,context,output,offset,tick,selection,layout(~S,~A,read),layout(~S,~B,write)) 103 104 def with_output(~S:Data,~A:Type,~B:Type,~O:Type,~V:Data,~K:Data,~E:Data,~project:A -> A & V,~body:K -> U32 -> V -> B -> O -> B & (O & Maybe<&2,E>),context:K,read:C.Column,write:C.Column,output:O,offset:U32,tick:Tick.Tick,selection:Selection) -> OutputRun: 105 effect_with_output(~S,~Effects.Identity,~Effects.identity(),~A,~B,~O,~V,~K,~E,~project,~body,context,read,write,output,offset,tick,selection) 106 107 def unit_result(~B:Type,~E:Data,result:B & Maybe<&2,E>) -> B & (Unit & Maybe<&2,E>): 108 match result: 109 case (owner,error):(owner,(Unit{},error)) 110 def unit_body(~B:Type,~V:Data,~E:Data,~body:U32 -> V -> B -> B & Maybe<&2,E>,_:Unit,index:U32,view:V,owner:B,_:Unit) -> B & (Unit & Maybe<&2,E>): 111 unit_result(~B,~E,body(index,view,owner)) 112 def unit_run(~S:Data,~A:Type,~B:Type,~E:Data,result:OutputRun) -> Run: 113 match result: 114 case OutputRun{read,write,_,errors,aligned}:Run{read,write,errors,aligned} 115 def selected(~S:Data,~A:Type,~B:Type,~V:Data,~E:Data,~project:A -> A & V,~body:U32 -> V -> B -> B & Maybe<&2,E>,read:C.Column,write:C.Column,offset:U32,tick:Tick.Tick,selection:Selection) -> Run: 116 unit_run(~S,~A,~B,~E,with_output(~S,~A,~B,~Unit,~V,~Unit,~E,~project,~unit_body(~B,~V,~E,~body),Unit{},read,write,Unit{},offset,tick,selection)) 117 def serial(~S:Data,~A:Type,~B:Type,~V:Data,~E:Data,~project:A -> A & V,~body:U32 -> V -> B -> B & Maybe<&2,E>,read:C.Column,write:C.Column,offset:U32,tick:Tick.Tick) -> Run: 118 selected(~S,~A,~B,~V,~E,~project,~body,read,write,offset,tick,All{}) 119 def serial_selected(~S:Data,~A:Type,~B:Type,~V:Data,~E:Data,~project:A -> A & V,~body:U32 -> V -> B -> B & Maybe<&2,E>,read:C.Column,write:C.Column,offset:U32,tick:Tick.Tick,selection:Selection) -> Run: 120 selected(~S,~A,~B,~V,~E,~project,~body,read,write,offset,tick,selection)