123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173openCoreletsimple_queryquerysexp=Lazy_list.to_list(Semantics.queryquerysexp)letget_fieldssexpfield=simple_query(Syntax.Pipe(Syntax.Smash,Syntax.Fieldfield))sexp;;moduleNon_unique_field=structtypet={field:string;sexp:Sexp.t;matches:Sexp.tlist}[@@derivingsexp]endletget_one_fieldsexpfield=letresults=get_fieldssexpfieldinmatchresultswith|[]|_::_::_->Or_error.error"non-unique field"{Non_unique_field.field;sexp;matches=results}Non_unique_field.sexp_of_t|[result]->Okresult;;letsexp_rewritesexp~f:visit=letrecauxsexp=matchvisitsexpwith|`Changedsexp'->sexp'|`Unchanged->(matchsexpwith|Sexp.Atom_->sexp|Sexp.Listsexps->letsexps'=List.map~f:auxsexpsinifList.for_all2_exn~f:phys_equalsexpssexps'thensexpelseSexp.Listsexps')inauxsexp;;letimmediate_fields=function|Sexp.Listchildren->List.fold~init:(Ok[])children~f:(funaccchild->matchaccwith|Error_->acc|Okby_field->(matchchildwith|Sexp.List[Sexp.Atomfield;value]->(matchList.Assoc.findby_field~equal:String.equalfieldwith|None->Ok(List.Assoc.addby_field~equal:String.equalfieldvalue)|Some_->Or_error.error"multiple values for field"fieldString.sexp_of_t)|_->Or_error.error"not a field"childFn.id))|>funresult->(* Restore original order *)Or_error.mapresult~f:List.rev|Sexp.Atomatom->Or_error.error"not a record"atomString.sexp_of_t;;letto_record_sexpby_fields=Sexp.List(List.mapby_fields~f:(fun(field,value)->Sexp.List[Sexp.Atomfield;value]));;letreplace_immediate_field~field~valuesexp=Or_error.map(immediate_fieldssexp)~f:(funby_field->List.Assoc.removeby_field~equal:String.equalfield|>(funby_field->List.Assoc.addby_field~equal:String.equalfieldvalue)|>to_record_sexp);;letreplace_field_recursively~field~valuesexp=sexp_rewritesexp~f:(function|Sexp.List[Sexp.Atomf;_]whenString.equalfieldf->`Changed(Sexp.List[Sexp.Atomf;value])|_->`Unchanged);;letreplace_field~field~valuesexpimmediate_or_recursive=matchimmediate_or_recursivewith|`Immediate->replace_immediate_field~field~valuesexp|`Recursive->letresult=replace_field_recursively~field~valuesexpinifSexp.(=)resultsexpthenOr_error.error"field not found"fieldString.sexp_of_telseOkresult;;let%test_module"Utils"=(modulestructletsexp=Sexp.of_string"((first (a b c)) (second 123) (third ()) (fourth ((foo a) (boo b))))";;let%test_=[%compare.equal:Sexp.tOr_error.t](get_one_fieldsexp"second")(Ok(Sexp.Atom"123"));;let%test_=Result.is_error(get_one_fieldsexp"zoo")let%test_=[%compare.equal:Sexp.tOr_error.t](get_one_fieldsexp"boo")(Ok(Sexp.Atom"b"));;let%test_=Result.is_error(immediate_fields(Sexp.of_string"zoo"))let%test_=Result.is_error(immediate_fields(Sexp.of_string"(zoo)"))let%test_=Result.is_error(immediate_fields(Sexp.of_string"(zoo boo)"))let%test_=Result.is_error(immediate_fields(Sexp.of_string"((good true)(bad))"))let%test_=[%equal:Sexp.t](List.Assoc.find_exn(Or_error.ok_exn(immediate_fieldssexp))~equal:String.equal"second")(Atom"123");;let%test_=[%equal:Sexp.t](List.Assoc.find_exn(Or_error.ok_exn(immediate_fieldssexp))~equal:String.equal"third")(List[]);;let%test_=[%equal:Sexp.t](List.Assoc.find_exn(Or_error.ok_exn(immediate_fieldssexp))~equal:String.equal"fourth")(Sexp.of_string"((foo a) (boo b))");;let%test_=[%equal:Sexp.t](to_record_sexp(Or_error.ok_exn(immediate_fieldssexp)))sexp;;let%test_=letvalue=Sexp.Atom"my-new-value"inletsexp=Or_error.ok_exn(replace_field~field:"second"~valuesexp`Immediate)in[%equal:Sexp.t](List.Assoc.find_exn(Or_error.ok_exn(immediate_fieldssexp))~equal:String.equal"second")value;;let%test_=letvalue=Sexp.Atom"my-new-value"inletsexp=Or_error.ok_exn(replace_field~field:"foo"~valuesexp`Recursive)inletfourth_value=List.Assoc.find_exn(Or_error.ok_exn(immediate_fieldssexp))~equal:String.equal"fourth"in[%equal:Sexp.t](List.Assoc.find_exn(Or_error.ok_exn(immediate_fieldsfourth_value))~equal:String.equal"foo")value;;end);;