123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375(**
elpi.trace.ppx provides the following syntax extensions:
{[
type t = { a : T; b : S [@trace] }
let rec f x (w[@trace]) =
[%trace "f" (fun fmt -> .. x ..) begin
match x with
| K1 -> ...
| K2 x -> [%tcall f x]
| K2(x,y) ->
let z = f x in
[%spy "z" ~rid ~gid ~cond (fun fmt z -> .. z ..) z];
[%spyl "z" ~rid ~gid ~cond (fun fmt z -> .. z ..) zs];
[%log "K2" ~rid "whatever" 37];
let x[@trace] = ... in e
let w = { a; b = b[@trace ] } in
match w with
| { a; b = b [@trace] } ->
z + f y (b[@trace])
end]
[%end_trace "stop" ~rid]
]}
If
--cookie "elpi_trace=\"true\""
is not passed to the ppx rewriter:
- [[%end_trace "stop" ~rid]] ---> [()]
- [[%trace "foo" pp code]] ---> [code]
- [[%tcall f x]] ---> [f x]
- [[%spy ...]] [[%spyl ...]] and [[%log ...]] ---> [()]
- [f x (y[@trace]) z] ---> [f x z]
- [let x[@trace] = .. in e] ---> [e]
- [type x = { a : T; b : T [@trace] }] ---> [type x = { a : T }]
- [{ a; b = b [@trace] }] ---> [{ a }] (in both patterns and expressions)
- [T -> (S[@trace]) -> U] ---> [T -> U]
In records, the shorcut "x" to mean "x = x" does not work, you have to use the
longer form.
*)openPpxlibopenAst_builder.Defaultleterr~locstr=Location.raise_errorf~loc"%s"strlettrace~rid~locnameppfunbody=[%exprletwall_clock=Unix.gettimeofday()inTrace_ppx_runtime.Runtime.enter~runtime_id:![%erid][%ename][%eppfun];tryletrc=[%ebody]inletelapsed=Unix.gettimeofday()-.wall_clockinTrace_ppx_runtime.Runtime.exit~runtime_id:![%erid][%ename]falseNoneelapsed;rcwith|Trace_ppx_runtime.Runtime.TREC_CALL(f,x)->letelapsed=Unix.gettimeofday()-.wall_clockinTrace_ppx_runtime.Runtime.exit~runtime_id:![%erid][%ename]trueNoneelapsed;Obj.objf(Obj.objx)|e->letelapsed=Unix.gettimeofday()-.wall_clockinTrace_ppx_runtime.Runtime.exit~runtime_id:![%erid][%ename]false(Somee)elapsed;raisee]letspy~locerr?(cond=[%exprtrue])~rid?gidnamepp=letppl=letrecaux=function|[]->[%expr[]]|[_]->err~loc()|p::x::xs->[%exprTrace_ppx_runtime.Runtime.J([%ep],[%ex])::[%eauxxs]]inauxppinmatchgidwith|None->[%exprif[%econd]thenTrace_ppx_runtime.Runtime.info~runtime_id:![%erid][%ename][%eppl]]|Somegid->[%exprif[%econd]thenTrace_ppx_runtime.Runtime.info~runtime_id:![%erid]~goal_id:(Util.UUID.hash[%egid])[%ename][%eppl]]letspyl~locerr?(cond=[%exprtrue])~rid?gidnamepp=letppl=letrecaux=function|[]->[%expr[]]|[_]->err~loc()|p::xl::xs->[%exprList.map(funx->Trace_ppx_runtime.Runtime.J([%ep],x))[%exl]@[%eauxxs]]inauxppinmatchgidwith|None->[%exprif[%econd]thenTrace_ppx_runtime.Runtime.info~runtime_id:![%erid][%ename][%eppl]]|Somegid->[%exprif[%econd]thenTrace_ppx_runtime.Runtime.info~runtime_id:![%erid]~goal_id:(Util.UUID.hash[%egid])[%ename][%eppl]]letlog~locname~ridkeydata=[%exprTrace_ppx_runtime.Runtime.log~runtime_id:![%erid][%ename][%ekey][%edata]]letcur_pred~locname=[%exprTrace_ppx_runtime.Runtime.set_cur_pred[%ename]]letend_trace~loc~rid=[%exprTrace_ppx_runtime.Runtime.end_trace~runtime_id:![%erid]]lettcall~lochdargs=letl=List.rev(hd::args)inletlast,rest=List.hdl,List.tllinletpapp=matchList.revrestwith|[]->assertfalse|f::a->[%exprObj.repr[%eeapply~locfa]]in[%exprraise(Trace_ppx_runtime.Runtime.TREC_CALL([%epapp],Obj.repr[%elast]))]letenabled=reffalselethas_iftrace_attribute(l:attributes)=List.exists(fun{attr_name={txt;_};_}->txt="trace")llethas_iftrace{ptyp_attributes=l;_}=has_iftrace_attributelletmap_trace=object(self)inheritAst_traverse.mapassupermethod!core_typety=letty=super#core_typetyinmatchty.ptyp_descwith|Ptyp_arrow(lbl,src,tgt)whennot!enabled->ifhas_iftracesrcthentgtelse{tywithptyp_desc=Ptyp_arrow(lbl,self#core_typesrc,self#core_typetgt)}|Ptyp_tuplelwhennot!enabled->letl=l|>List.filter(funx->not(has_iftracex))inletl=List.mapself#core_typelin{tywithptyp_desc=Ptyp_tuplel}|_->tymethod!patternp=letp=super#patternpinmatchp.ppat_descwith|Ppat_record(lp,c)whennot!enabled->letlp=lp|>List.filter(fun(_,{ppat_attributes=l;_})->not(has_iftrace_attributel))inletlp=List.map(fun(x,y)->x,self#patterny)lpin{pwithppat_desc=Ppat_record(lp,c)}|Ppat_tuplelpwhennot!enabled->letlp=lp|>List.filter(fun{ppat_attributes=l;_}->not(has_iftrace_attributel))inletlp=List.mapself#patternlpin{pwithppat_desc=Ppat_tuplelp}|_->pmethod!type_declarationtyd=lettyd=super#type_declarationtydinmatchtyd.ptype_kindwith|Ptype_recordlblswhennot!enabled->letlbls=lbls|>List.filter(fun{pld_attributes=l;_}->not(has_iftrace_attributel))in{tydwithptype_kind=Ptype_recordlbls}|_->tydmethod!expressione=lete=super#expressioneinmatche.pexp_descwith|Pexp_record(fields,def)whennot!enabled->lethas_iftrace{pexp_attributes=l;_}=has_iftrace_attributelinletfields=fields|>List.filter(fun(_,e)->not(has_iftracee))inletfields=List.map(fun(x,y)->x,self#expressiony)fieldsinletdef=matchdefwithNone->None|Somee->Some(self#expressione)in{ewithpexp_desc=Pexp_record(fields,def)}|Pexp_apply(hd,args)whennot!enabled->lethas_iftrace{pexp_attributes=l;_}=has_iftrace_attributelinletargs=args|>List.filter(fun(_,e)->not(has_iftracee))inletargs=List.map(fun(x,y)->x,self#expressiony)argsinifargs=[]thenhdelse{ewithpexp_desc=Pexp_apply(hd,args)}|Pexp_fun(_,_,pat,rest)whennot!enabled->lethas_iftrace{ppat_attributes=l;_}=has_iftrace_attributelinifhas_iftracepatthenself#expressionrestelsee|Pexp_let(_,[{pvb_pat={ppat_attributes=l;_};_}],rest)whennot!enabled->ifhas_iftrace_attributelthenself#expressionrestelsee|Pexp_tuplelwhennot!enabled->lethas_iftrace{pexp_attributes=l;_}=has_iftrace_attributelinletl=l|>List.filter(fune->not(has_iftracee))inletl=List.mapself#expressionlin{ewithpexp_desc=Pexp_tuplel}|_->eend(* ----------------------------------------------------------------- *)(* ------------------------ %extension ----------------------------- *)(* ----------------------------------------------------------------- *)letis_string_literal=function|{pexp_desc=Pexp_constant(Pconst_string_);_}->true|_->falseletis_gidlbl=lbl=Labelled"gid"letis_ridlbl=lbl=Labelled"rid"letis_condlbl=lbl=Labelled"cond"letpullfl=letrecpullacc=function|[]->None,l|(x,y)::xswhenfx->Somey,List.revacc@xs|x::xs->pull(x::acc)xsinpull[]lleterr_spy~loc()=err~loc"use: [%spy id pp x] or [%spy id ~gid ~cond pp x]"letspyl_expand_function~loc~path:_=function|{pexp_desc=Pexp_apply(name,args);_}whenis_string_literalname->letcond,args=pullis_condargsinletgid,args=pullis_gidargsinletrid,args=pullis_ridargsinif!enabledthenmatchridwith|Somerid->spyl~locerr_spy?cond~rid?gidname(List.mapsndargs)|None->err_spy~loc()else[%expr()]|_->err_spy~loc()letspyl_extension=Extension.declare"spyl"Extension.Context.expressionAst_pattern.(single_expr_payload__)spyl_expand_functionletspyl_rule=Context_free.Rule.extensionspyl_extensionletspy_expand_function~loc~path:_=function|{pexp_desc=Pexp_apply(name,args);_}whenis_string_literalname->letcond,args=pullis_condargsinletgid,args=pullis_gidargsinletrid,args=pullis_ridargsinif!enabledthenmatchridwith|Somerid->spy~locerr_spy?cond?gid~ridname(List.mapsndargs)|None->err_spy~loc()else[%expr()]|_->err_spy~loc()letspy_extension=Extension.declare"spy"Extension.Context.expressionAst_pattern.(single_expr_payload__)spy_expand_functionletspy_rule=Context_free.Rule.extensionspy_extension(* ----------------------------------------------------------------- *)lettcall_expand_function~loc~path:_=function|{pexp_desc=Pexp_apply(hd,args);_}when!enabled->tcall~lochd(List.mapsndargs)|{pexp_desc=Pexp_apply(hd,args);_}asr->lethd=[%expr([%ehd][@tailcall])]in{rwithpexp_desc=Pexp_apply(hd,args)}|_->err~loc"use: [%tcall f args]"lettcall_extension=Extension.declare"tcall"Extension.Context.expressionAst_pattern.(single_expr_payload__)tcall_expand_functionlettcall_rule=Context_free.Rule.extensiontcall_extension(* ----------------------------------------------------------------- *)lettrace_expand_function~loc~path:_=function|{pexp_desc=Pexp_apply(name,args);_}when!enabled->letrid,args=pullis_ridargsinbeginmatchrid,argswith|Somerid,[_,code]->trace~rid~locname[%exprfun_->()]code|Somerid,[_,pp;_,code]->letpp=matchppwith|{pexp_desc=Pexp_apply(hd,args);_}->[%exprfunfmt->[%eeapply~loc[%exprFormat.fprintffmt](hd::List.mapsndargs)]]|x->xintrace~rid~locnameppcode|_->err~loc"use: [%trace ~rid name pp code]"end|{pexp_desc=Pexp_apply(_,args);_}->let_,code=List.hd(List.revargs)incode|_->err~loc"use: [%trace ~rid name pp code]"lettrace_extension=Extension.declare"trace"Extension.Context.expressionAst_pattern.(single_expr_payload__)trace_expand_functionlettrace_rule=Context_free.Rule.extensiontrace_extension(* ----------------------------------------------------------------- *)letcur_pred_expand_function~loc~path:_name=if!enabledthencur_pred~locnameelse[%expr()]letcur_pred_extension=Extension.declare"cur_pred"Extension.Context.expressionAst_pattern.(single_expr_payload__)cur_pred_expand_functionletcur_pred_rule=Context_free.Rule.extensioncur_pred_extension(* ----------------------------------------------------------------- *)letlog_expand_function~loc~path:_=function|{pexp_desc=Pexp_apply(name,args);_}when!enabled->letrid,args=pullis_ridargsinbeginmatchrid,argswith|Somerid,[_,key;_,code]->log~loc~ridnamekeycode|_->err~loc"use: [%log id ~rid data]"end|{pexp_desc=Pexp_apply_;_}->[%expr()]|_->err~loc"use: [%log id ~rid data]"letlog_extension=Extension.declare"log"Extension.Context.expressionAst_pattern.(single_expr_payload__)log_expand_functionletlog_rule=Context_free.Rule.extensionlog_extension(* ----------------------------------------------------------------- *)letend_trace_expand_function~loc~path:_=function|{pexp_desc=Pexp_apply(_name,args);_}when!enabled->letrid,args=pullis_ridargsinbeginmatchrid,argswith|Somerid,[]->end_trace~loc~rid|_->err~loc"use: [%end_trace ~rid]"end|{pexp_desc=Pexp_apply_;_}->[%expr()]|_->err~loc"use: [%end_trace ~rid]"letend_trace_extension=Extension.declare"end_trace"Extension.Context.expressionAst_pattern.(single_expr_payload__)end_trace_expand_functionletend_trace_rule=Context_free.Rule.extensionend_trace_extension(* ----------------------------------------------------------------- *)(* ----------------------------------------------------------------- *)(* ----------------------------------------------------------------- *)letarg_tracet=matchDriver.Cookies.gett"elpi_trace"Ast_pattern.(estring__)with|Some"true"->enabled:=true|_->enabled:=falselet()=Driver.Cookies.add_handlerarg_trace;Driver.register_transformation~rules:[log_rule;cur_pred_rule;trace_rule;tcall_rule;spy_rule;spyl_rule;end_trace_rule]~impl:map_trace#structure~intf:map_trace#signature"elpi.trace"