123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381openDomain.LibopenLangopenPlmoduleTypdef=Runtime.Type.TypdefopenRuntime.Dynamic_PlopenEnvsopenInterp_common.ErroropenInterp_common.BacktraceopenUtil.Source(* Error *)leterror_undef(at:region)(kind:string)(id:string)=errorat(Format.asprintf"%s `%s` is undefined"kindid)letback_undef(at:region)(kind:string)(id:string)=back_errat(Format.asprintf"%s `%s` is undefined"kindid)leterror_dup(at:region)(kind:string)(id:string)=errorat(Format.asprintf"%s `%s` was already defined"kindid)letback_dup(at:region)(kind:string)(id:string)=back_errat(Format.asprintf"%s `%s` was already defined"kindid)moduleMake()=struct(* Cursor *)typecursor=Global|Local(* Mode *)letis_det:boolref=reffalse(* Context *)(* Global layer *)typeglobal={(* Map from syntax ids to type definitions *)tdtbl:TDTbl.t;(* Map from relation ids to relations *)rtbl:RTbl.t;(* Map from function ids to functions *)ftbl:FTbl.t;}(* Local layer *)typelocal=|Empty|Relof{(* Relation name *)rid:RId.t;(* Input values *)values_input:valuelist;(* Map from variables to values *)venv:VEnv.t;}|Funcof{(* Function name *)fid:FId.t;(* Input values *)values_input:valuelist;(* Map from syntax ids to type definitions *)tdenv:TDEnv.t;(* Map from function ids to functions *)fenv:FEnv.t;(* Map from variables to values *)venv:VEnv.t;}typet={global:global;local:local}(* Global constructor *)letglobal:global=lettdtbl=TDTbl.create~size:500inletrtbl=RTbl.create~size:500inletftbl=FTbl.create~size:500in{tdtbl;rtbl;ftbl}(* Adders for globals *)letadd_typdef_global(tid:TId.t)(td:Typdef.t):unit=ifTDTbl.find_opttidglobal.tdtbl|>Option.is_somethenerror_duptid.at"type"tid.it;TDTbl.addtidtdglobal.tdtblletadd_rel_global(rid:RId.t)(rel:Rel.t):unit=ifRTbl.find_optridglobal.rtbl|>Option.is_somethenerror_duprid.at"relation"rid.it;RTbl.addridrelglobal.rtblletadd_func_global(fid:FId.t)(func:Func.t):unit=ifFTbl.find_optfidglobal.ftbl|>Option.is_somethenerror_dupfid.at"function"fid.it;FTbl.addfidfuncglobal.ftbl(* Global initializer *)letload_def(def:def):unit=matchdef.node.itwith|ExternTypDid->lettd=Typdef.Externinadd_typdef_globalidtd|TypD(id,tparams,deftyp)->lettd=Typdef.Defined(tparams,deftyp)inadd_typdef_globalidtd|VarD_->()|ExternRelD(id,rel_signature,_)->letrel=Rel.Externrel_signatureinadd_rel_globalidrel|RelD(id,rel_signature,exps_match,block,elseblock_opt)->letrel=Rel.Defined(rel_signature,exps_match,block,elseblock_opt)inadd_rel_globalidrel|ExternDecD(id,tparams,params,typ)->letfunc=Func.Extern(tparams,params,typ)inadd_func_globalidfunc|BuiltinDecD(id,tparams,params,typ)->letfunc=Func.Builtin(tparams,params,typ)inadd_func_globalidfunc|TableDecD(id,params,typ,tablerows)->letfunc=Func.Table(params,typ,tablerows)inadd_func_globalidfunc|FuncDecD(id,tparams,params,typ,block,elseblock_opt)->letfunc=Func.Defined(tparams,params,typ,block,elseblock_opt)inadd_func_globalidfuncletinit~(det:bool)(spec:spec):unit=is_det:=det;List.iterload_defspec(* Constructor *)letempty():t={global;local=Empty}(* Finders *)(* Finders for input values *)letfind_values_input_opt(ctx:t):Value.tlistoption=matchctx.localwith|Empty->None|Rel{values_input;_}->Somevalues_input|Func{values_input;_}->Somevalues_inputletfind_values_input(ctx:t):Value.tlist=matchfind_values_input_optctxwith|Somevalues_input->values_input|None->back_errno_region"cannot find input values in empty local context"(* Finders for values *)letfind_value_opt(ctx:t)(var:Var.t):Value.toption=matchctx.localwith|Empty->None|Rel{venv;_}->VEnv.find_optvarvenv|Func{venv;_}->VEnv.find_optvarvenvletfind_value(ctx:t)(var:Var.t):Value.t=matchfind_value_optctxvarwith|Somevalue->value|None->letid,_=varinback_undefid.at"value"(Var.to_stringvar)letbound_value(ctx:t)(var:Var.t):bool=find_value_optctxvar|>Option.is_some(* Finders for type definitions *)letfind_typdef_opt(ctx:t)(tid:TId.t):Typdef.toption=lettdenv=matchctx.localwith|Empty|Rel_->TDEnv.empty|Func{tdenv;_}->tdenvinmatchTDEnv.find_opttidtdenvwith|Sometd->Sometd|None->TDTbl.find_opttidctx.global.tdtblletfind_typdef(ctx:t)(tid:TId.t):Typdef.t=matchfind_typdef_optctxtidwith|Sometd->td|None->back_undeftid.at"type"tid.itletfind_defined_typdef(ctx:t)(tid:TId.t):tparamlist*deftyp=matchfind_typdefctxtidwith|Param|Extern|Defining_->back_undeftid.at"defined type"tid.it|Defined(tparams,deftyp)->(tparams,deftyp)letbound_typdef(ctx:t)(tid:TId.t):bool=find_typdef_optctxtid|>Option.is_some(* Finders for rules *)letfind_rel_opt(ctx:t)(rid:RId.t):Rel.toption=RTbl.find_optridctx.global.rtblletfind_rel(ctx:t)(rid:RId.t):Rel.t=matchfind_rel_optctxridwith|Somerel->rel|None->back_undefrid.at"relation"rid.itletfind_rel_signature_opt(ctx:t)(rid:RId.t):(nottyp*Hints.Input.t)option=find_rel_optctxrid|>Option.mapRel.get_signatureletfind_rel_signature(ctx:t)(rid:RId.t):nottyp*Hints.Input.t=matchfind_rel_signature_optctxridwith|Some(nottyp,inputs)->(nottyp,inputs)|None->back_undefrid.at"relation"rid.itletbound_rel(ctx:t)(rid:RId.t):bool=find_rel_optctxrid|>Option.is_some(* Finders for definitions *)letfind_func_opt(ctx:t)(fid:FId.t):(cursor*Func.t)option=letfenv=matchctx.localwith|Empty|Rel_->FEnv.empty|Func{fenv;_}->fenvinmatchFEnv.find_optfidfenvwith|Somefunc->Some(Local,func)|None->FTbl.find_optfidctx.global.ftbl|>Option.map(funfunc->(Global,func))letfind_func(ctx:t)(fid:FId.t):cursor*Func.t=matchfind_func_optctxfidwith|Some(cursor,func)->(cursor,func)|None->back_undeffid.at"function"fid.itletfind_func_signature_opt(ctx:t)(fid:FId.t):(tparamlist*typlist*typ)option=find_func_optctxfid|>Option.map(fun(_,func)->Func.get_signaturefunc)letfind_func_signature(ctx:t)(fid:FId.t):tparamlist*typlist*typ=matchfind_func_signature_optctxfidwith|Some(tparams,typs,typ)->(tparams,typs,typ)|None->back_undeffid.at"function"fid.itletbound_func(ctx:t)(fid:FId.t):bool=find_func_optctxfid|>Option.is_some(* Adders *)(* Adders for values *)letadd_value(ctx:t)(var:Var.t)(value:Value.t):t=matchctx.localwith|Empty->letid,_=varinback_errid.at"cannot add value to empty local context"|Rel{rid;values_input;venv}->letvenv=VEnv.addvarvaluevenvin{ctxwithlocal=Rel{rid;values_input;venv}}|Func{fid;values_input;tdenv;fenv;venv}->letvenv=VEnv.addvarvaluevenvin{ctxwithlocal=Func{fid;values_input;tdenv;fenv;venv}}(* Adders for type definitions *)letadd_typdef(ctx:t)(tid:TId.t)(td:Typdef.t):t=ifbound_typdefctxtidthenback_duptid.at"type"tid.it;matchctx.localwith|Empty->back_errtid.at"cannot add type to empty local context"|Rel_->back_errtid.at"cannot add type to rule context"|Func{fid;values_input;tdenv;fenv;venv}->lettdenv=TDEnv.addtidtdtdenvin{ctxwithlocal=Func{fid;values_input;tdenv;fenv;venv}}(* Adders for functions *)letadd_func(ctx:t)(fid:FId.t)(func:Func.t):t=ifbound_funcctxfidthenback_dupfid.at"function"fid.it;matchctx.localwith|Empty->back_errfid.at"cannot add function to empty local context"|Rel_->back_errfid.at"cannot add function to relation context"|Func{fid=fid_local;values_input;tdenv;fenv;venv}->letfenv=FEnv.addfidfuncfenvin{ctxwithlocal=Func{fid=fid_local;values_input;tdenv;fenv;venv};}(* Constructors *)(* Constructing a local context *)letlocalize(ctx:t):t={ctxwithlocal=Empty}letlocalize_rule(ctx:t)(rid:RId.t)(values_input:valuelist):t=letlocal=Rel{rid;values_input;venv=VEnv.empty}in{ctxwithlocal}letlocalize_func(ctx:t)(fid:FId.t)(values_input:valuelist)(tdenv:TDEnv.t):t=letlocal=Func{fid;values_input;tdenv;fenv=FEnv.empty;venv=VEnv.empty}in{ctxwithlocal}letlocalize_clear(ctx:t):t=matchctx.localwith|Empty->back_errno_region"cannot clear empty local context"|Rel{rid;values_input;_}->{ctxwithlocal=Rel{rid;values_input;venv=VEnv.empty}}|Func{fid;values_input;tdenv;fenv;_}->{ctxwithlocal=Func{fid;values_input;tdenv;fenv;venv=VEnv.empty};}(* Constructing sub-contexts *)(* Transpose a matrix of values, as a list of value batches
that are to be each fed into an iterated expression *)lettranspose(value_matrix:valuelistlist):valuelistlist=matchvalue_matrixwith|[]->[]|row_h::_->letwidth=List.lengthrow_hinletcols=Array.makewidth[]inList.iter(funrow->check_back_err(List.lengthrow=width)no_region"cannot transpose a matrix of value batches";List.iteri(funjv->cols.(j)<-v::cols.(j))row)(List.revvalue_matrix);Array.to_listcolsletsub_opt(ctx:t)(vars:varlist):toption=(* First collect the values that are to be iterated over *)letvalues=List.map(fun(id,_typ,iters)->find_valuectx(id,iters@[Il.Opt])|>Value.Get.opt)varsin(* Iteration is valid when all variables agree on their optionality *)ifList.for_allOption.is_somevaluesthenletvalues=List.mapOption.getvaluesinletctx_sub=List.fold_left2(functx_sub(id,_typ,iters)value->add_valuectx_sub(id,iters)value)ctxvarsvaluesinSomectx_subelseifList.for_allOption.is_nonevaluesthenNoneelseback_errno_region"mismatch in optionality of iterated variables"letsub_list(ctx:t)(vars:varlist):tlist=(* First break the values that are to be iterated over,
into a batch of values *)letvalues_batch=List.map(fun(id,_typ,iters)->find_valuectx(id,iters@[Il.List])|>Value.Get.list)vars|>transposein(* For each batch of values, create a sub-context *)List.map(funvalue_batch->List.fold_left2(functx_sub(id,_typ,iters)value->add_valuectx_sub(id,iters)value)ctxvarsvalue_batch)values_batchend