# Shape and owner preservation for traversals with consumed cursor state. import Base import ../traversal_array.bend as Traversal import ../traversal_loop.bend as Loop import ./storage_witness.bend as Witness import ./traversal_witness.bend as TraversalWitness type Sample<-Reader: Type,-Element: Data,-Context: Data,-reader: Reader,-result: Reader & Traversal.Visited> is Data: Sample{context: Context,-value: Element,equation: {result == (reader,Traversal.Visited{context,value}) : Reader & Traversal.Visited}} def store(~Reader: Type,~Element: Data,~Context: Data,+depth: Nat,-reader: Reader,+position: U32,-output: Array, -result: Reader & Traversal.Visited,output_evidence: Witness.Witness(Element,depth,output),sample: Sample) -> TraversalWitness.StateEvidence: match sample: case Sample{context,value,equation}: %Equal.sym(Reader & Traversal.Visited,result,(reader,Traversal.Visited{context,value}),equation) : TraversalWitness.StateEvidence TraversalWitness.StateEvidence{Array.set(Element,output,position,value),(position + 1 : U32),context,{==},Witness.write(Element,depth,output,position,value,output_evidence)} def step(~Reader: Type,~Element: Data,~Context: Data,~ReaderEvidence: @-reader: Reader -> Data, ~read: Reader -> Context -> Reader & Traversal.Visited, ~read_preserves: @-reader: Reader -> @context: Context -> ReaderEvidence(reader) -> Sample, +depth: Nat,-reader: Reader,-state: Traversal.State<&1,&1,Reader,Array,Context>,reader_evidence: ReaderEvidence(reader), evidence: TraversalWitness.StateEvidence) -> TraversalWitness.StateEvidence: match evidence: case TraversalWitness.StateEvidence{output,position,context,equation,output_evidence}: %Equal.sym(Traversal.State<&1,&1,Reader,Array,Context>,state,Traversal.State{reader,output,position,context},equation) : TraversalWitness.StateEvidence store(~Reader,~Element,~Context,depth,reader,position,output,read(reader,context),output_evidence,read_preserves(reader,context,reader_evidence)) def spread_store(~Element: Data,~Context: Data,+depth: Nat,-input: Array,+position: U32,-output: Array,target: Traversal.Target, -result: Array & Element,output_evidence: Witness.Witness(Element,depth,output),observed: Witness.Read) -> TraversalWitness.StateEvidence,Element,Context,input,depth,Traversal.spread_store(~Element,~Context,position,output,target,result)>: match target observed: case Traversal.Target{context,+address} Witness.Read{value,equation}: %Equal.sym(Array & Element,result,(input,value),equation) : TraversalWitness.StateEvidence,Element,Context,input,depth,Traversal.spread_store(~Element,~Context,position,output,Traversal.Target{context,address},_)> TraversalWitness.StateEvidence{Array.set(Element,output,address,value),(position + 1 : U32),context,{==},Witness.write(Element,depth,output,address,value,output_evidence)} def spread_step(~Element: Data,~Context: Data,~target: Context -> Traversal.Target, +depth: Nat,-input: Array,-state: Traversal.State<&1,&1,Array,Array,Context>,input_evidence: Witness.ArrayWitness, evidence: TraversalWitness.StateEvidence,Element,Context,input,depth,state>) -> TraversalWitness.StateEvidence,Element,Context,input,depth,Traversal.spread_step(~Element,~Context,~target,state)>: match evidence: case TraversalWitness.StateEvidence{output,+position,context,equation,output_evidence}: %Equal.sym(Traversal.State<&1,&1,Array,Array,Context>,state,Traversal.State{input,output,position,context},equation) : TraversalWitness.StateEvidence,Element,Context,input,depth,Traversal.spread_step(~Element,~Context,~target,_)> spread_store(~Element,~Context,depth,input,position,output,target(context),Array.get(Element,input,position),output_evidence, Witness.observed(Element,input,position,input_evidence)) def update_sample(~Reader: Type,~Element: Data,~Context: Data,~combine: Element -> Element -> Element, +depth: Nat,-reader: Reader,+position: U32,-output: Array,-current: Element,-result: Reader & Traversal.Visited, output_evidence: Witness.Witness(Element,depth,output),sample: Sample) -> TraversalWitness.StateEvidence: match sample: case Sample{context,value,equation}: %Equal.sym(Reader & Traversal.Visited,result,(reader,Traversal.Visited{context,value}),equation) : TraversalWitness.StateEvidence TraversalWitness.StateEvidence{Array.set(Element,output,position,combine(current,value)),(position + 1 : U32),context,{==}, Witness.write(Element,depth,output,position,combine(current,value),output_evidence)} def update_current(~Reader: Type,~Element: Data,~Context: Data,~read: Reader -> Context -> Reader & Traversal.Visited, ~combine: Element -> Element -> Element,+depth: Nat,-reader: Reader,position: U32,context: Context,-output: Array,-result: Array & Element, output_evidence: Witness.Witness(Element,depth,output),observed: Witness.Read,sample: Sample) -> TraversalWitness.StateEvidence: match observed: case Witness.Read{value,equation}: %Equal.sym(Array & Element,result,(output,value),equation) : TraversalWitness.StateEvidence update_sample(~Reader,~Element,~Context,~combine,depth,reader,position,output,value,read(reader,context),output_evidence,sample) def update_step(~Reader: Type,~Element: Data,~Context: Data,~ReaderEvidence: @-reader: Reader -> Data, ~read: Reader -> Context -> Reader & Traversal.Visited,~combine: Element -> Element -> Element, ~read_preserves: @-reader: Reader -> @context: Context -> ReaderEvidence(reader) -> Sample, +depth: Nat,-reader: Reader,-state: Traversal.State<&1,&1,Reader,Array,Context>,reader_evidence: ReaderEvidence(reader), evidence: TraversalWitness.StateEvidence) -> TraversalWitness.StateEvidence: match evidence: case TraversalWitness.StateEvidence{output,+position,+context,equation,+output_evidence}: %Equal.sym(Traversal.State<&1,&1,Reader,Array,Context>,state,Traversal.State{reader,output,position,context},equation) : TraversalWitness.StateEvidence update_current(~Reader,~Element,~Context,~read,~combine,depth,reader,position,context,output,Array.get(Element,output,position),output_evidence, Witness.read(Element,depth,output,position,output_evidence),read_preserves(reader,context,reader_evidence)) def update(~Reader: Type,~Element: Data,~Context: Data,~ReaderEvidence: @-reader: Reader -> Data, ~read: Reader -> Context -> Reader & Traversal.Visited,~combine: Element -> Element -> Element, ~read_preserves: @-reader: Reader -> @context: Context -> ReaderEvidence(reader) -> Sample, +depth: Nat,count: Nat,-reader: Reader,-state: Traversal.State<&1,&1,Reader,Array,Context>,+reader_evidence: ReaderEvidence(reader), evidence: TraversalWitness.StateEvidence) -> TraversalWitness.StateEvidence: match count: case 0n: evidence case 1n+rest: update(~Reader,~Element,~Context,~ReaderEvidence,~read,~combine,~read_preserves,depth,rest,reader, Traversal.visit_update_step(~Reader,~Element,~Context,~read,~combine,state),reader_evidence, update_step(~Reader,~Element,~Context,~ReaderEvidence,~read,~combine,~read_preserves,depth,reader,state,reader_evidence,evidence)) def fold_value(~Reader: Type,~Element: Data,~Accumulator: Data,~Context: Data,~combine: Accumulator -> Element -> Accumulator, -reader: Reader,+position: U32,-accumulator: Accumulator,-result: Reader & Traversal.Visited,sample: Sample) -> TraversalWitness.FoldEvidence: match sample: case Sample{context,value,equation}: %Equal.sym(Reader & Traversal.Visited,result,(reader,Traversal.Visited{context,value}),equation) : TraversalWitness.FoldEvidence TraversalWitness.FoldEvidence{combine(accumulator,value),(position + 1 : U32),context,{==}} def fold_step(~Reader: Type,~Element: Data,~Accumulator: Data,~Context: Data,~ReaderEvidence: @-reader: Reader -> Data, ~read: Reader -> Context -> Reader & Traversal.Visited,~combine: Accumulator -> Element -> Accumulator, ~read_preserves: @-reader: Reader -> @context: Context -> ReaderEvidence(reader) -> Sample, -reader: Reader,-state: Traversal.State<&1,&2,Reader,Accumulator,Context>,reader_evidence: ReaderEvidence(reader), evidence: TraversalWitness.FoldEvidence) -> TraversalWitness.FoldEvidence: match evidence: case TraversalWitness.FoldEvidence{accumulator,position,context,equation}: %Equal.sym(Traversal.State<&1,&2,Reader,Accumulator,Context>,state,Traversal.State{reader,accumulator,position,context},equation) : TraversalWitness.FoldEvidence fold_value(~Reader,~Element,~Accumulator,~Context,~combine,reader,position,accumulator,read(reader,context),read_preserves(reader,context,reader_evidence)) def fold_run(~Reader: Type,~Element: Data,~Accumulator: Data,~Context: Data,~ReaderEvidence: @-reader: Reader -> Data, ~read: Reader -> Context -> Reader & Traversal.Visited,~combine: Accumulator -> Element -> Accumulator, ~read_preserves: @-reader: Reader -> @context: Context -> ReaderEvidence(reader) -> Sample, count: Nat,-reader: Reader,-state: Traversal.State<&1,&2,Reader,Accumulator,Context>,+reader_evidence: ReaderEvidence(reader), evidence: TraversalWitness.FoldEvidence) -> TraversalWitness.FoldEvidence: match count: case 0n: evidence case 1n+rest: fold_run(~Reader,~Element,~Accumulator,~Context,~ReaderEvidence,~read,~combine,~read_preserves,rest,reader, Traversal.visit_fold_step(~Reader,~Element,~Accumulator,~Context,~read,~combine,state),reader_evidence, fold_step(~Reader,~Element,~Accumulator,~Context,~ReaderEvidence,~read,~combine,~read_preserves,reader,state,reader_evidence,evidence))