123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470openBaseopenPpxlibopenAst_builder.DefaultmoduleFilename=Caml.FilenamemoduleParsing=Caml.ParsingmoduleType=structtypet=|Varofstring|Bool|Int|Char|String|Tupleoftlistletrecto_string=function|Varv->"'"^v|Bool->"bool"|Int->"int"|Char->"char"|String->"string"|Tuplel->"("^String.concat~sep:" * "(List.mapl~f:to_string)^")"endmoduleValue=structtypet=|Boolofbool|Intofint|Charofchar|Stringofstring|Tupleoftlistletocaml_version=Caml.Scanf.sscanfCaml.Sys.ocaml_version"%d.%d.%d"(funmajorminorpatchlevel->Tuple[Intmajor;Intminor;Intpatchlevel]);;letrecto_expressionloct=matchtwith|Boolx->ebool~locx|Intx->eint~locx|Charx->echar~locx|Stringx->estring~locx|Tuple[]->eunit~loc|Tuple[x]->to_expressionlocx|Tuplel->pexp_tuple~loc(List.mapl~f:(to_expressionloc));;letrecto_patternloct=matchtwith|Boolx->pbool~locx|Intx->pint~locx|Charx->pchar~locx|Stringx->pstring~locx|Tuple[]->punit~loc|Tuple[x]->to_patternlocx|Tuplel->ppat_tuple~loc(List.mapl~f:(to_patternloc));;letto_string_prettyv=lete=to_expressionLocation.nonevinPprintast.string_of_expressioneletto_stringv=letbuf=Buffer.create128inletrecaux=function|Boolb->Buffer.add_stringbuf(Bool.to_stringb)|Intn->Buffer.add_stringbuf(Int.to_stringn)|Charch->Buffer.add_charbufch|Strings->Buffer.add_stringbufs;|Tuple[]->Buffer.add_stringbuf"()"|Tuple(x::l)->Buffer.add_charbuf'(';auxx;List.iterl~f:(funx->Buffer.add_stringbuf", ";auxx);Buffer.add_charbuf')'inauxv;Buffer.contentsbuf;;letrectype_:t->Type.t=function|Bool_->Bool|Int_->Int|Char_->Char|String_->String|Tuplel->Tuple(List.mapl~f:type_);;endmoduleEnv:sigtypetvalinit:tvalempty:tvaladd:t->var:stringLocation.loc->value:Value.t->tvalundefine:t->stringLocation.loc->tvalof_list:(stringLocation.loc*Value.t)list->tvaleval:t->stringLocation.loc->Value.tvalis_defined:?permissive:bool->t->stringLocation.loc->boolvalseen:t->stringLocation.loc->boolvalto_expression:t->expressionend=structtypevar_state=|DefinedofValue.t|Undefinedtypeentry={loc:Location.t(** Location at which it was defined/undefined *);state:var_state}typet=entryMap.M(String).tletempty=Map.empty(moduleString)letto_expressiont=pexp_apply~loc:Location.none(evar~loc:Location.none"env")(List.map(Map.to_alistt)~f:(fun(var,{loc;state})->(Labelledvar,matchstatewith|Definedv->pexp_construct~loc{txt=Lident"Defined";loc}(Some(Value.to_expressionlocv))|Undefined->pexp_construct~loc{txt=Lident"Undefined";loc}None)))letseent(var:_Loc.t)=Map.memtvar.txtletaddt~(var:_Loc.t)~value=Map.sett~key:var.txt~data:{loc=var.loc;state=Definedvalue};;letundefinet(var:_Loc.t)=Map.sett~key:var.txt~data:{loc=var.loc;state=Undefined};;letof_listl=List.fold_leftl~init:empty~f:(funacc(var,value)->addacc~var~value);;letinit=of_list[{loc=Location.none;txt="ocaml_version"},Value.ocaml_version]letshort_loc_string(loc:Location.t)=Printf.sprintf"%s:%d"loc.loc_start.pos_fnameloc.loc_start.pos_lnum;;leteval(t:t)(var:stringLoc.t)=matchMap.findtvar.txtwith|Some{state=Definedv;loc=_}->v|Some{state=Undefined;loc}->Location.raise_errorf~loc:var.loc"optcomp: %s is undefined (undefined at %s)"var.txt(short_loc_stringloc)|None->Location.raise_errorf~loc:var.loc"optcomp: unbound value %s"var.txt;;letis_defined?(permissive=false)(t:t)(var:stringLoc.t)=matchMap.findtvar.txtwith|Some{state=Defined_;_}->true|Some{state=Undefined;_}->false|None->ifpermissivethenfalseelseLocation.raise_errorf~loc:var.loc"optcomp: doesn't know about %s.\n\
You need to either define it or undefine it with #undef.\n\
Optcomp doesn't accept variables it doesn't know about to avoid typos."var.txt;;end(* +-----------------------------------------------------------------+
| Expression evaluation |
+-----------------------------------------------------------------+ *)letinvalid_typelocexpectedreal=Location.raise_errorf~loc"optcomp: this expression has type %s but is used with type %s"(Type.to_stringreal)(Type.to_stringexpected);;letvar_of_lid(id:_Located.t)=matchLongident.flatten_exnid.txtwith|l->{idwithtxt=String.concat~sep:"."l}|exception_->Location.raise_errorf~loc:id.loc"optcomp: invalid variable name";;letcannot_convertlocdstx=Location.raise_errorf~loc"cannot convert %s to %s"(Value.to_string_prettyx)dst;;letconvert_from_stringlocdstfx=tryfxwith_->Location.raise_errorf~loc"optcomp: cannot convert %S to %s"xdst;;exceptionPattern_match_failureofpattern*Value.tletlid_of_expre=matche.pexp_descwith|Pexp_identid|Pexp_construct(id,None)->id|_->Location.raise_errorf~loc:e.pexp_loc"optcomp: identifier expected";;letvar_of_expre=var_of_lid(lid_of_expre)letnot_supportede=Location.raise_errorf~loc:e.pexp_loc"optcomp: expression not supported";;letparse_intlocx=matchInt.of_stringxwith|v->v|exception_->Location.raise_errorf~loc"optcomp: invalid integer";;letrecevalenve:Value.t=letloc=e.pexp_locinmatche.pexp_descwith|Pexp_constant(Pconst_integer(x,None))->Int(parse_intlocx)|Pexp_constant(Pconst_charx)->Charx|Pexp_constant(Pconst_string(x,_,_))->Stringx|Pexp_construct({txt=Lident"true";_},None)->Booltrue|Pexp_construct({txt=Lident"false";_},None)->Boolfalse|Pexp_construct({txt=Lident"()";_},None)->Tuple[]|Pexp_tuplel->Tuple(List.mapl~f:(evalenv))|Pexp_identid|Pexp_construct(id,None)->Env.evalenv(var_of_lidid)|Pexp_apply({pexp_desc=Pexp_ident{txt=Lidents;_};_},args)->beginletargs=List.mapargs~f:(fun(l,x)->matchlwithNolabel->x|_->not_supportede)inmatchs,argswith|"=",[x;y]->eval_cmpenvPoly.(=)xy|"<",[x;y]->eval_cmpenvPoly.(<)xy|">",[x;y]->eval_cmpenvPoly.(>)xy|"<=",[x;y]->eval_cmpenvPoly.(<=)xy|">=",[x;y]->eval_cmpenvPoly.(>=)xy|"<>",[x;y]->eval_cmpenvPoly.(<>)xy|"min",[x;y]->eval_poly2envPoly.minxy|"max",[x;y]->eval_poly2envPoly.maxxy|"+",[x;y]->eval_int2env(+)xy|"-",[x;y]->eval_int2env(-)xy|"*",[x;y]->eval_int2env(*)xy|"/",[x;y]->eval_int2env(/)xy|"mod",[x;y]->eval_int2envCaml.(mod)xy|"not",[x]->Bool(not(eval_boolenvx))|"||",[x;y]->eval_bool2env(||)xy|"&&",[x;y]->eval_bool2env(&&)xy|"^",[x;y]->eval_string2env(^)xy|"fst",[x]->fst(eval_pairenvx)|"snd",[x]->snd(eval_pairenvx)|"to_string",[x]->String(Value.to_string(evalenvx))|"to_int",[x]->Int(matchevalenvxwith|Stringx->convert_from_stringloc"int"Int.of_stringx|Intx->x|Charx->Char.to_intx|Bool_|Tuple_asx->cannot_convertloc"int"x)|"to_bool",[x]->Bool(matchevalenvxwith|Stringx->convert_from_stringloc"bool"Bool.of_stringx|Boolx->x|Int_|Char_|Tuple_asx->cannot_convertloc"bool"x)|"to_char",[x]->Char(matchevalenvxwith|Stringx->convert_from_stringloc"char"(funs->assert(String.lengths=1);s.[0])x|Charx->x|Intx->beginmatchChar.of_intxwith|Somex->x|None->Location.raise_errorf~loc"optcomp: cannot convert %d to char"xend|Bool_|Tuple_asx->cannot_convertloc"char"x)|"show",[x]->letv=evalenvxinletppf=Caml.Format.err_formatterinletpprinted=Value.to_string_prettyvinCaml.Format.fprintfppf"%a:@.SHOW %s@."Location.printlocpprinted;v|"defined",[x]->Bool(Env.is_definedenv(var_of_exprx))|"not_defined",[x]->Bool(not(Env.is_definedenv(var_of_exprx)))|"not_defined_permissive",[x]->Bool(not(Env.is_defined~permissive:trueenv(var_of_exprx)))|_->not_supportedeend(* Let-binding *)|Pexp_let(Nonrecursive,vbs,e)->letenv=List.fold_leftvbs~init:env~f:(funnew_envvb->letv=evalenvvb.pvb_exprindo_bindnew_envvb.pvb_patv)inevalenve(* Pattern matching *)|Pexp_match(e,cases)->letv=evalenveinletrecloop=function|[]->Location.raise_errorf~loc"optcomp: cannot match %s against any of the cases"(Value.to_stringv)|case::rest->matchbindenvcase.pc_lhsvwith|exceptionPattern_match_failure_->looprest|env->letguard_ok=matchcase.pc_guardwith|None->true|Somee->eval_boolenveinifguard_okthenevalenvcase.pc_rhselselooprestinloopcases|_->not_supportedeandbindenvpattvalue=letloc=patt.ppat_locinmatchpatt.ppat_desc,valuewith|Ppat_any,_->env|Ppat_constant(Pconst_integer(x,None)),Intywhenparse_intlocx=y->env|Ppat_constant(Pconst_charx),CharywhenChar.equalxy->env|Ppat_constant(Pconst_string(x,_,_)),StringywhenString.equalxy->env|Ppat_construct({txt=Lident"true";_},None),Booltrue->env|Ppat_construct({txt=Lident"false";_},None),Boolfalse->env|Ppat_construct({txt=Lident"()";_},None),Tuple[]->env|Ppat_varvar,_->Env.addenv~var~value|Ppat_construct(id,None),_->Env.addenv~var:(var_of_lidid)~value|Ppat_alias(patt,var),_->Env.add(bindenvpattvalue)~var~value|Ppat_tuplex,TupleywhenList.lengthx=List.lengthy->Caml.ListLabels.fold_left2xy~init:env~f:bind|_->raise(Pattern_match_failure(patt,value))anddo_bindenvpattvalue=trybindenvpattvaluewithPattern_match_failure(pat,v)->Location.raise_errorf~loc:pat.ppat_loc"Cannot match %s with this pattern"(Value.to_string_prettyv)andeval_sameenvexey=letvx=evalenvexandvy=evalenveyinlettx=Value.type_vxandty=Value.type_vyinifPoly.equaltxtythen(vx,vy)elseinvalid_typeey.pexp_loctxtyandeval_intenve=matchevalenvewith|Intx->x|v->invalid_typee.pexp_locInt(Value.type_v)andeval_boolenve=matchevalenvewith|Boolx->x|v->invalid_typee.pexp_locBool(Value.type_v)andeval_stringenve=matchevalenvewith|Stringx->x|v->invalid_typee.pexp_locString(Value.type_v)andeval_pairenve=matchevalenvewith|Tuple[x;y]->(x,y)|v->invalid_typee.pexp_loc(Tuple[Var"a";Var"b"])(Value.type_v)andeval_int2envfab=leta=eval_intenvainletb=eval_intenvbinInt(fab)andeval_bool2envfab=leta=eval_boolenvainletb=eval_boolenvbinBool(fab)andeval_string2envfab=leta=eval_stringenvainletb=eval_stringenvbinString(fab)andeval_cmpenvfab=leta,b=eval_sameenvabinBool(fab)andeval_poly2envfab=leta,b=eval_sameenvabinfab(* +-----------------------------------------------------------------+
| Environment serialization |
+-----------------------------------------------------------------+ *)moduleEnvIO=structletto_expression=Env.to_expressionletof_expressionexpr=Ast_pattern.parseAst_pattern.(pexp_apply(pexp_ident(lident(string"env")))__)expr.pexp_locexpr(funargs->List.foldargs~init:Env.empty~f:(funenvarg->matchargwith|Labelledvar,{pexp_desc=Pexp_construct({txt=Lident"Defined";_},Somee);pexp_loc=loc;_}->Env.addenv~var:{txt=var;loc}~value:(evalEnv.emptye)|Labelledvar,{pexp_desc=Pexp_construct({txt=Lident"Undefined";_},None);pexp_loc=loc;_}->Env.undefineenv{txt=var;loc}|_,e->Location.raise_errorf~loc:e.pexp_loc"ppx_optcomp: invalid cookie"))end