Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file interpolation_emitter.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135openPpxlibopenPpxlib.Ast_builder.Defaulttypeelement=string*Location.ttypetoken=|Stringofelement|EscapedPercentofLocation.t|Expressionofelement*elementoption|Variableofelement*elementoptionlettoken_to_string=function|String(s,_)->s|Expression((e,_),_)->"{"^e^"}"|Variable((v,_),_)->"["^v^"]"|EscapedPercent_->"%"(* Debug printing of tokens. Compresses %% into % *)letprint_tokens=List.iter(funp->print_string(token_to_stringp))(* Convert commented out expression to a string.
Here we also rely on UTF8/single codepage - '(','*' and ')' occupy only one byte. *)letconvert_commented_out=function|Expression((str,loc),fmt)->ifString.lengthstr>=4&&str.[1]='*'&&str.[String.lengthstr-2]='*'then(matchfmtwith|Some(fmt,_)->String("%"^fmt^"$"^str,loc)|None->String("$"^str,loc))elseExpression((str,loc),fmt)|x->x(* Generate a list of sprintf arguments from tokens. *)letto_argumentstokens=letshiftby({Location.loc_start;_}asloc)={locwithLocation.loc_start={loc_startwithLexing.pos_cnum=loc_start.pos_cnum+by}}inList.rev@@List.fold_left(funacctoken->matchtokenwith|Expression((e,loc),_)->letlexbuf=Lexing.from_stringeinletopenLexinginletopenLocationinlexbuf.lex_curr_p<-loc.loc_start;lexbuf.lex_abs_pos<-loc.loc_start.pos_cnum+1;(Nolabel,Parse.expressionlexbuf)::acc|Variable((v,loc),_)->letloc=shift1locin(Nolabel,pexp_ident~loc{txt=Lidentv;loc})::acc|_->acc)[]tokens(* Check invalid format before composing whole string to report correct location. *)letverify_formatstokens=letcheckfmtloc=trylet_=CamlinternalFormat.fmt_ebb_of_stringfmtin()with|Failuremsg->Location.raise_errorf~loc"%s"msg|_->()inList.iter(funtoken->matchtokenwith|Expression(_,Some(fmt,loc))->checkfmtloc|Variable(_,Some(fmt,loc))->checkfmtloc|_->())tokens(* Generate format string for sprintf from tokens. NOTE, we always manually compress "$$"
into "$" since [sprintf] does not treat is specially. However, "%%" is compressed into "%"
only if the string does not contain interpolations, and therefore [sprintf] call is not emitted. *)letto_format_string~escape_percenttokens=letjoined=String.concat""@@List.rev@@List.fold_left(funacctoken->matchtokenwith|Expression(_,Some(fmt,_))->fmt::acc|Expression(_,None)->"%s"::acc|Variable(_,Some(fmt,_))->fmt::acc|Variable(_,None)->"%s"::acc|String(s,_)->s::acc|EscapedPercent_whenescape_percent->"%%"::acc|EscapedPercent_->"%"::acc)[]tokensinpexp_constant~loc:Location.none(Pconst_string(joined,Location.none,None))(* Convert list of expressions with formats to ast. *)letgeneratetokens=letsprintf=letopenLongidentinpexp_ident~loc:Location.none{txt=Ldot(Lident"Printf","sprintf");loc=Location.none}inletapplyfuncargs=pexp_apply~loc:Location.nonefuncargsinmatchto_argumentstokenswith|[]->to_format_string~escape_percent:falsetokens|args->applysprintf@@((Nolabel,to_format_string~escape_percent:truetokens)::args)letemit_asttokens=verify_formatstokens;List.mapconvert_commented_outtokens|>generate