123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311openDomain.LibopenLangopenIlopenAlmoduleTypdef=Runtime.Type.TypdefopenRuntime.Dynamic_AlopenEnvsopenErroropenBacktrackopenUtil.Source(* Error *)leterror_undef(at:region)(kind:string)(id:string)=errorat(Format.asprintf"%s `%s` is undefined"kindid)leterror_dup(at:region)(kind:string)(id:string)=errorat(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={(* 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 layer *)global:global;(* Local layer *)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.itwith|ExternTypD(id,_)->lettd=Typdef.Externinadd_typdef_globalidtd|TypD(id,tparams,deftyp,_)->lettd=Typdef.Defined(tparams,deftyp)inadd_typdef_globalidtd|VarD_->()|ExternRelD(id,nottyp,inputs,_)->letrel=Rel.Extern(nottyp,inputs)inadd_rel_globalidrel|RelD(id,nottyp,input,rulegroups,elsegroup_opt,_)->letrel=Rel.Defined(nottyp,input,rulegroups,elsegroup_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,clauses,elseclause_opt,_)->letfunc=Func.Defined(tparams,params,typ,clauses,elseclause_opt)inadd_func_globalidfuncletinit~(det:bool)(spec:spec):unit=is_det:=det;List.iterload_defspec(* Constructor *)letempty_local():local={tdenv=TDEnv.empty;fenv=FEnv.empty;venv=VEnv.empty}letempty:t={global;local=empty_local()}(* Finders *)(* Finders for values *)letfind_value_opt(ctx:t)(var:Var.t):Value.toption=VEnv.find_optvarctx.local.venvletfind_value(ctx:t)(var:Var.t):Value.t=matchfind_value_optctxvarwith|Somevalue->value|None->letid,_=varinerror_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=matchTDEnv.find_opttidctx.local.tdenvwith|Sometd->Sometd|None->TDTbl.find_opttidctx.global.tdtblletfind_typdef(ctx:t)(tid:TId.t):Typdef.t=matchfind_typdef_optctxtidwith|Sometd->td|None->error_undeftid.at"type"tid.itletfind_defined_typdef(ctx:t)(tid:TId.t):tparamlist*deftyp=matchfind_typdefctxtidwith|Param|Extern|Defining_->error_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->error_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->error_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=matchFEnv.find_optfidctx.local.fenvwith|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->error_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->error_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=letvenv=VEnv.addvarvaluectx.local.venvin{ctxwithlocal={ctx.localwithvenv}}(* Adders for type definitions *)letadd_typdef(ctx:t)(tid:TId.t)(td:Typdef.t):t=ifbound_typdefctxtidthenerror_duptid.at"type"tid.it;lettdenv=TDEnv.addtidtdctx.local.tdenvin{ctxwithlocal={ctx.localwithtdenv}}(* Adders for functions *)letadd_func(ctx:t)(fid:FId.t)(func:Func.t):t=ifbound_funcctxfidthenerror_dupfid.at"function"fid.it;letfenv=FEnv.addfidfuncctx.local.fenvin{ctxwithlocal={ctx.localwithfenv}}(* Constructors *)(* Constructing a local context *)letlocalize(ctx:t):t=letlocal=empty_local()in{ctxwithlocal}(* 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):valuelistlistbacktrack=matchvalue_matrixwith|[]->Ok[]|row_h::_->(letwidth=List.lengthrow_hinletcols=Array.makewidth[]intryList.iter(funrow->ifList.lengthrow<>widththenraise(Invalid_argument"cannot transpose a matrix of value batches");List.iteri(funjv->cols.(j)<-v::cols.(j))row)(List.revvalue_matrix);Ok(Array.to_listcols)withInvalid_argumentmsg->back_errno_regionmsg)letsub_opt(ctx:t)(vars:varlist):toptionbacktrack=(* First collect the values that are to be iterated over *)letvalues=List.map(fun(id,_typ,iters)->find_valuectx(id,iters@[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)ctxvarsvaluesinOk(Somectx_sub)elseifList.for_allOption.is_nonevaluesthenOkNoneelseback_errno_region"mismatch in optionality of iterated variables"letsub_list(ctx:t)(vars:varlist):tlistbacktrack=(* First break the values that are to be iterated over,
into a batch of values *)let*values_batch=List.map(fun(id,_typ,iters)->find_valuectx(id,iters@[List])|>Value.Get.list)vars|>transposein(* For each batch of values, create a sub-context *)letctxs_sub=List.fold_left(functxs_subvalue_batch->letctx_sub=List.fold_left2(functx_sub(id,_typ,iters)value->add_valuectx_sub(id,iters)value)ctxvarsvalue_batchinctxs_sub@[ctx_sub])[]values_batchinOkctxs_subend