123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160(*s: unparse_php.ml *)(*s: Facebook copyright *)(* Yoann Padioleau
*
* Copyright (C) 2009-2013 Facebook
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation, with the
* special exception on linking described in file license.txt.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
* license.txt for more details.
*)(*e: Facebook copyright *)openCommonopenCst_phpmoduleV=Visitor_phpmoduleTH=Token_helpers_php(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* There are multiple ways to unparse PHP code:
* - one can iterate over the AST, and print its leaves, but
* comments and spaces are not in the AST so you need
* some extra code that also visits the tokens and try to "sync" the
* visit of the AST with the tokens
* - one can iterate over the tokens which contain comments and spaces
* but this can be too low level
* - one can use a real pretty printer with a boxing or backtracking model
* working on a AST extended with comments (see julien's ast_pretty_print/)
*
* Right now the preferred method for spatch is the second one. The pretty
* printer currently is too different from our coding conventions
* (also because we don't have precise coding conventions).
* This token-based unparser handles transfo annotations (Add/Remove).
*
* related: the sexp/json "exporters".
*
* note: this module could be in analyze_php/ instead of parsing_php/,
* but it's maybe good to have the basic parser/unparser together.
*)(*****************************************************************************)(* Unparsing using AST visitor *)(*****************************************************************************)(* This will not preserve spaces and comments but it's useful
* and good enough for printing small chunk of PHP code for debugging
* purpose. We also try to preserve the line numbers.
*)letstring_of_programast=Common2.with_open_stringbuf(fun(_pr_with_nl,buf)->letpps=Buffer.add_stringbufsinletcur_line=ref1inpp"<?php";pp"\n";incrcur_line;letvisitor=V.mk_visitor{V.default_visitorwithV.kinfo=(fun(_k,_)info->matchinfo.Parse_info.tokenwith|Parse_info.OriginTokp->letline=p.Parse_info.lineinifline>!cur_linethenbegin(line-!cur_line)|>Common2.times(fun()->pp"\n");cur_line:=line;end;lets=p.Parse_info.strinpps;pp" ";|Parse_info.FakeTokStr(s,_opt)->pps;pp" ";ifs=";"thenbeginpp"\n";incrcur_line;end|Parse_info.Ab->()|Parse_info.ExpandedTok_->raiseTodo);}invisitor(Programast);)(*****************************************************************************)(* Even simpler unparser using AST visitor *)(*****************************************************************************)(* This function is used notably in spatch to pretty print matched code
* in metavariables.
*)letstring_of_anyany=Common2.with_open_stringbuf(fun(_pr_with_nl,buf)->letpps=Buffer.add_stringbufsinlettoks=ref[]inlethooks={V.default_visitorwithV.kinfo=(fun(_k,_)info->matchinfo.Parse_info.tokenwith|Parse_info.OriginTokp->lets=p.Parse_info.strinCommon.pushstoks|Parse_info.FakeTokStr(s,_opt)->Common.pushstoks|Parse_info.Ab->()|Parse_info.ExpandedTok_->failwith"unparse_php: should not have ExpandedTok");}in(V.mk_visitorhooks)any;letrecauxxs=matchxswith|[]->()|[x]->ppx|x::y::xs->(matchx=~".*[a-zA-Z_0-9]$",y=~"^[a-zA-Z_0-9]",xwith(* e.g. when have "$x" and "instanceof", or when have
* "<div>" and "a=", we need to add a space
*)|true,true,_->ppx;pp" "|_,_,(";"|"{"|"}")->ppx;pp"\n"|_,_,_->ppx);aux(y::xs)inaux(List.rev!toks))(* convenient shortcut *)letstring_of_exprx=string_of_any(Exprx)(*****************************************************************************)(* Transformation-aware unparser (using the tokens) *)(*****************************************************************************)(* less:
* - use a AddedBefore where should use a AddedAfter on bar.spatch
* - put some newline in the Added of a spatch, add_statement.spatch
* too many places where we do ugly hack around newline
*)letstring_of_program_with_comments_using_transfo(_ast,toks)=lettoks'=toks|>List.map(funtok->TH.token_kind_of_toktok,TH.info_of_toktok)inLib_unparser.string_of_toks_using_transfotoks'(*e: unparse_php.ml *)