Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file value.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227(*****************************************************************************
Liquidsoap, a programmable audio stream generator.
Copyright 2003-2023 Savonet team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details, fully stated in the COPYING
file at the root of the liquidsoap distribution.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************)(** Values are untyped normal forms of terms. *)(** Ground values. *)moduleGround=Term.GroundmoduleMethods=Term.Methodstypet={pos:Pos.Option.t;value:in_value;methods:tMethods.t}andenv=(string*t)list(* Some values have to be lazy in the environment because of recursive functions. *)andlazy_env=(string*tLazy.t)listandin_value=|GroundofGround.t|Listoftlist|Tupleoftlist|Null(* Function with given list of argument name, argument variable and default
value, the (relevant part of the) closure, and the body. *)|Funof(string*string*toption)list*lazy_env*Term.t(* For a foreign function only the arguments are visible, the closure
doesn't capture anything in the environment. *)|FFIof(string*string*toption)list*(env->t)letunit:in_value=Tuple[]letstring_of_floatf=lets=string_of_floatfinifs.[String.lengths-1]='.'thens^"0"elsesletrecto_stringv=letbase_stringv=matchv.valuewith|Groundg->Ground.to_stringg|Listl->"["^String.concat", "(List.mapto_stringl)^"]"|Tuplel->"("^String.concat", "(List.mapto_stringl)^")"|Null->"null"|Fun([],_,x)whenTerm.is_groundx->"{"^Term.to_stringx^"}"|Fun(l,_,x)whenTerm.is_groundx->letf(label,_,value)=match(label,value)with|"",None->"_"|"",Somev->Printf.sprintf"_=%s"(to_stringv)|label,Somev->Printf.sprintf"~%s=%s"label(to_stringv)|label,None->Printf.sprintf"~%s=_"labelinletargs=List.mapflinPrintf.sprintf"fun (%s) -> %s"(String.concat","args)(Term.to_stringx)|Fun_|FFI_->"<fun>"inlets=base_stringvinifMethods.is_emptyv.methodsthenselse(letmethods=Methods.bindingsv.methodsin(ifv.value=Tuple[]then""elses^".")^"{"^String.concat", "(List.map(fun(l,meth_term)->l^"="^to_stringmeth_term)methods)^"}")(** Find a method in a value. *)letinvokexl=tryMethods.findlx.methodswithNot_found->failwith("Could not find method "^l^" of "^to_stringx)(** Perform a sequence of invokes: invokes x [l1;l2;l3;...] is x.l1.l2.l3... *)letrecinvokesx=functionl::ll->invokes(invokexl)ll|[]->xletdemethe={ewithmethods=Methods.empty}letremethtu={uwithmethods=Methods.foldMethods.addt.methodsu.methods}letsplit_methse=(Methods.bindingse.methods,demethe)letcompareab=letrecaux=function|Grounda,Groundb->Ground.compareab|Tuplel,Tuplem->List.fold_left2(funcmpab->ifcmp<>0thencmpelsecompareab)0lm|Listl1,Listl2->letreccmp=function|[],[]->0|[],_->-1|_,[]->1|h1::l1,h2::l2->letc=compareh1h2inifc=0thencmp(l1,l2)elsecincmp(l1,l2)|Null,Null->0|Null,_->-1|_,Null->1|_->assertfalseandcompareab=(* For records, we compare the list ["label", field; ..] of common fields. *)ifa.value=Tuple[]&&b.value=Tuple[]then(letra=letm,_=split_methsainminleta=rainletb=rbin(* Keep only common fields: with subtyping it might happen that some fields are ignored. *)leta=List.filter(fun(l,_)->List.exists(fun(l',_)->l=l')b)ainletb=List.filter(fun(l,_)->List.exists(fun(l',_)->l=l')a)binleta=List.sort(funxx'->Stdlib.compare(fstx)(fstx'))ainletb=List.sort(funxx'->Stdlib.compare(fstx)(fstx'))binleta=Tuple(List.map(fun(lbl,v)->{pos=None;value=Tuple[{pos=None;value=Ground(Ground.Stringlbl);methods=Methods.empty;};v;];methods=Methods.empty;})a)inletb=Tuple(List.map(fun(lbl,v)->{pos=None;value=Tuple[{pos=None;value=Ground(Ground.Stringlbl);methods=Methods.empty;};v;];methods=Methods.empty;})b)inaux(a,b))elseaux(a.value,b.value)incompareab(* Abstract values. *)moduletypeAbstract=sigincludeTerm.Abstractvalto_value:?pos:Pos.t->content->tvalof_value:t->contentvalis_value:t->boolendmoduletypeAbstractDef=Term.AbstractDefmoduleMkAbstractFromTerm(Term:Term.Abstract)=structincludeTermletto_value?posc={pos;value=Ground(to_groundc);methods=Methods.empty}letof_valuet=matcht.valuewith|Groundgwhenis_groundg->of_groundg|_->assertfalseletis_valuet=matcht.valuewithGroundg->is_groundg|_->falseendmoduleMkAbstract(Def:AbstractDef)=structmoduleTerm=Term.MkAbstract(Def)includeMkAbstractFromTerm(Term)endmoduleRuntimeType=MkAbstract(structtypecontent=Type.tletname="type"letdescr_="type"letto_json~pos_=Runtime_error.raise~pos~message:"Types cannot be represented as json""json"letcompare=Stdlib.compareend)