123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785(* Yoann Padioleau
*
* Copyright (C) 2012, 2014 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.
*)openCommonopenCst_cppmoduleA=Ast_c(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* Ast_cpp to Ast_c_simple.
*
* We skip the then part of ifdefs.
*
* todo:
* - lift up local union and struct defined in functions?
* (hmm but better to rewrite the code I think)
*)(*****************************************************************************)(* Globals *)(*****************************************************************************)(* for anon struct, which is dangerous! because the main function
* will return different results given the same input when called
* two times in a row
*)letcnt=ref0(*****************************************************************************)(* Types *)(*****************************************************************************)exceptionObsoleteConstructofstring*Parse_info.texceptionCplusplusConstructexceptionTodoConstructofstring*Parse_info.texceptionCaseOutsideSwitchexceptionMacroInCasetypeenv={mutablestruct_defs_toadd:A.struct_deflist;mutableenum_defs_toadd:A.enum_deflist;mutabletypedefs_toadd:A.type_deflist;}letempty_env()={struct_defs_toadd=[];enum_defs_toadd=[];typedefs_toadd=[];}(*****************************************************************************)(* Helpers *)(*****************************************************************************)letdebugany=letv=Meta_cst_cpp.vof_anyanyinlets=Ocaml.string_of_vvinpr2sletrecifdef_skipperxsf=matchxswith|[]->[]|x::xs->(matchfxwith|None->x::ifdef_skipperxsf|Someifdef->(matchifdefwith|Ifdef,tok->pr2_once(spf"skipping: %s"(Parse_info.str_of_infotok));(trylet(_,x,rest)=xs|>Common2.split_when(funx->matchfxwith|Some(IfdefElse,_)->true|Some(IfdefEndif,_)->true|_->false)in(matchfxwith|Some(IfdefEndif,_)->ifdef_skipperrestf|Some(IfdefElse,_)->let(before,_x,rest)=rest|>Common2.split_when(funx->matchfxwith|Some(IfdefEndif,_)->true|_->false)inifdef_skipperbeforef@ifdef_skipperrestf|_->raiseImpossible)withNot_found->failwith(spf"%s: unclosed ifdef"(Parse_info.string_of_infotok)))|_,tok->failwith(spf"%s: no ifdef"(Parse_info.string_of_infotok))))(*****************************************************************************)(* Main entry point *)(*****************************************************************************)letrecprogramxs=letenv=empty_env()intoplevelsenvxs|>List.flatten(* ---------------------------------------------------------------------- *)(* Toplevels *)(* ---------------------------------------------------------------------- *)andtoplevelsenvxs=ifdef_skipperxs(functionIfdefDeclx->Somex|_->None)|>List.map(toplevelenv)andtoplevelenvx=matchxwith|DeclElemdecl->declarationenvdecl|CppDirectiveDeclx->cpp_directiveenvx|(MacroVarTop(_,_)|MacroTop(_,_,_))->debug(Toplevelx);raiseTodo|IfdefDecl_->raiseImpossible(* see ifdef_skipper *)(* not much we can do here, at least the parsing statistics should warn the
* user that some code was not processed
*)|NotParsedCorrectly_->[]anddeclarationenvx=matchxwith|Func(func_or_else)->(matchfunc_or_elsewith|FunctionOrMethoddef->[A.FuncDef(func_defenvdef)]|Constructor_|Destructor_->debug(Toplevel(DeclElemx));raiseCplusplusConstruct)|BlockDeclbd->(matchblock_declarationenvbdwith|A.Varsxs->letstructs=env.struct_defs_toaddinletenums=env.enum_defs_toaddinlettypedefs=env.typedefs_toaddinenv.struct_defs_toadd<-[];env.enum_defs_toadd<-[];env.typedefs_toadd<-[];(structs|>List.map(funx->A.StructDefx))@(enums|>List.map(funx->A.EnumDefx))@(typedefs|>List.map(funx->A.TypeDefx))@(xs|>List.map(funx->(* could skip extern declaration? *)matchxwith|{A.v_type=A.TFunctionft;v_storage=storage;_}->A.Prototype{A.f_name=x.A.v_name;f_type=ft;f_static=(storage=*=A.Static);f_body=[];}|_->A.Globalx))|_->debug(Toplevel(DeclElemx));raiseTodo)|EmptyDef_->[]|NameSpaceAnon(_,_)|NameSpaceExtend(_,_)|NameSpace(_,_,_)|ExternCList(_,_,_)|ExternC(_,_,_)|TemplateSpecialization(_,_,_)|TemplateDecl_->debug(Toplevel(DeclElemx));raiseCplusplusConstruct|DeclTodo->debug(Toplevel(DeclElemx));raiseTodo(* ---------------------------------------------------------------------- *)(* Functions *)(* ---------------------------------------------------------------------- *)andfunc_defenvdef={A.f_name=nameenvdef.f_name;f_type=function_typeenvdef.f_type;f_static=(matchdef.f_storagewith|Sto(Static,_)->true|_->false);f_body=compoundenvdef.f_body;}andfunction_typeenvx=matchxwith{ft_ret=ret;ft_params=params;ft_dots=_dotsTODO;ft_const=const;ft_throw=throw;}->(matchconst,throwwith|None,None->()|_->raiseCplusplusConstruct);(full_typeenvret,List.map(parameterenv)(params|>unparen|>uncomma))andparameterenvx=matchxwith{p_name=n;p_type=t;p_register=_regTODO;p_val=v;}->(matchvwith|None->()|Some_->debug(Parameterx);raiseCplusplusConstruct);{A.p_name=(matchnwith(* probably a prototype where didn't specify the name *)|None->None|Some(name)->Somename);p_type=full_typeenvt;}(* ---------------------------------------------------------------------- *)(* Variables *)(* ---------------------------------------------------------------------- *)andonedeclenvd=matchdwith{v_namei=ni;v_type=ft;v_storage=sto;}->(matchni,stowith|Some(n,iopt),(NoSto|Sto_)->letinit_opt=matchioptwith|None->None|Some(EqInit(_,ini))->Some(initialiserenvini)|Some(ObjInit_)->debug(OneDecld);raiseCplusplusConstructinSome{A.v_name=nameenvn;v_type=full_typeenvft;v_storage=storageenvsto;v_init=init_opt;}|Some(n,None),(StoTypedef_)->letdef=(nameenvn,full_typeenvft)inenv.typedefs_toadd<-def::env.typedefs_toadd;None|None,NoSto->(matchCst_cpp.unwrap_typeCftwith(* it's ok to not have any var decl as long as a type
* was defined. struct_defs_toadd should not be empty then.
*)|StructDef_|EnumDef_->let_=full_typeenvftinNone(* forward declaration *)|StructUnionName_->None|_->debug(OneDecld);raiseTodo)|_->debug(OneDecld);raiseTodo)andinitialiserenvx=matchxwith|InitExpre->exprenve|InitListxs->(matchxs|>unbrace|>uncommawith|[]->debug(Initx);raiseImpossible|(InitDesignators([DesignatorField(_,_)],_,_init))::_->A.RecordInit(xs|>unbrace|>uncomma|>List.map(function|InitDesignators([DesignatorField(_,ident)],_,init)->ident,initialiserenvinit|_->debug(Initx);raiseTodo))|_->A.ArrayInit((xs|>unbrace|>uncomma)|>List.map(function(* less: todo? *)|InitIndexOld((_,idx,_),ini)->Some(exprenvidx),initialiserenvini|InitDesignators([DesignatorIndex((_,idx,_))],_,ini)->Some(exprenvidx),initialiserenvini|x->None,initialiserenvx)))(* should be covered by caller *)|InitDesignators_->debug(Initx);raiseTodo|InitIndexOld_|InitFieldOld_->debug(Initx);raiseTodoandstorage_envx=matchxwith|NoSto->A.DefaultStorage|StoTypedef_->raiseImpossible|Sto(y,_)->(matchywith|Static->A.Static|Extern->A.Extern|Auto|Register->A.DefaultStorage)(* ---------------------------------------------------------------------- *)(* Cpp *)(* ---------------------------------------------------------------------- *)andcpp_directiveenvx=matchxwith|Define(_tok,name,def_kind,def_val)->letv=cpp_def_valxenvdef_valin(matchdef_kindwith|DefineVar->[A.Define(name,v)]|DefineFunc(args)->[A.Macro(name,args|>unparen|>uncomma|>List.map(fun(s,ii)->(s,List.hdii)),v)])|Include(tok,inc_kind,path)->lets=matchinc_kindwith|Local->"\""^path^"\""|Standard->"<"^path^">"|Weird->debug(Cppx);raiseTodoin[A.Include(s,tok)]|Undef_->debug(Cppx);raiseTodo|PragmaAndCo_->[]andcpp_def_valfor_debugenvx=matchxwith|DefineExpre->A.CppExpr(exprenve)|DefineStmtst->A.CppStmt(stmtenvst)|DefineDoWhileZero(st,_)->A.CppStmt(stmtenvst)|DefinePrintWrapper(_,(_,e,_),id)->A.CppExpr(A.CondExpr(exprenve,A.Id(nameenvid),A.Id(nameenvid)))|DefineInitinit->A.CppExpr(initialiserenvinit)|DefineEmpty(* A.CppEmpty*)|(DefineText_|DefineFunction_|DefineType_|DefineTodo)->debug(Cppfor_debug);raiseTodo(* ---------------------------------------------------------------------- *)(* Stmt *)(* ---------------------------------------------------------------------- *)andstmtenvx=let(st,ii)=xinmatchstwith|Compoundx->A.Block(compoundenvx)|Selections->(matchswith|If(_,(_,e,_),st1,_,st2)->A.If(exprenve,stmtenvst1,stmtenvst2)|Switch(_,(_,e,_),st)->A.Switch(exprenve,casesenvst))|Iterationi->(matchiwith|While(_,(_,e,_),st)->A.While(exprenve,stmtenvst)|DoWhile(_,st,_,(_,e,_),_)->A.DoWhile(stmtenvst,exprenve)|For(_,(_,((est1,_),(est2,_),(est3,_)),_),st)->A.For(Common2.fmap(exprenv)est1,Common2.fmap(exprenv)est2,Common2.fmap(exprenv)est3,stmtenvst)|MacroIteration_->debug(Stmtx);raiseTodo)|ExprStatementeopt->(matcheoptwith|None->A.Block[]|Somee->A.ExprSt(exprenve))|DeclStmtblock_decl->block_declarationenvblock_decl|Labeledlbl->(matchlblwith|Label(s,st)->A.Label((s,List.hdii),stmtenvst)|Case_|CaseRange_|Default_->debug(Stmtx);raiseCaseOutsideSwitch)|Jumpj->(matchjwith|Gotos->A.Goto((s,List.hdii))|Return->A.ReturnNone;|ReturnExpre->A.Return(Some(exprenve))|Continue->A.Continue|Break->A.Break|GotoComputed_->debug(Stmtx);raiseTodo)|Try(_,_,_)->debug(Stmtx);raiseCplusplusConstruct|(NestedFunc_|StmtTodo|MacroStmt)->debug(Stmtx);raiseTodoandcompoundenv(_,xs,_)=statements_sequencableenvxs|>List.flattenandstatements_sequencableenvxs=ifdef_skipperxs(functionIfdefStmtx->Somex|_->None)|>List.map(statement_sequencableenv)andstatement_sequencableenvx=matchxwith|StmtElemst->[stmtenvst]|CppDirectiveStmtx->debug(Cppx);raiseTodo|IfdefStmt_->raiseImpossibleandcasesenvx=let(st,ii)=xinmatchstwith|Compound(l,xs,r)->letrecauxxs=matchxswith|[]->[]|x::xs->(matchxwith|StmtElem((Labeled(Case(_,st))),_)|StmtElem((Labeled(Defaultst)),_)->letxs',rest=(StmtElemst::xs)|>Common.span(function|StmtElem((Labeled(Case(_,_st))),_)|StmtElem((Labeled(Default_st)),_)->false|_->true)inletstmts=List.map(function|StmtElemst->stmtenvst|x->debug(Stmt(Compound(l,[x],r),ii));raiseMacroInCase)xs'in(matchxwith|StmtElem((Labeled(Case(e,_))),_)->A.Case(exprenve,stmts)|StmtElem((Labeled(Default_st)),_)->A.Default(stmts)|_->raiseImpossible)::auxrest|x->debug(Body(l,[x],r));raiseTodo)inauxxs|_->debug(Stmtx);raiseTodoandblock_declarationenvblock_decl=matchblock_declwith|DeclList(xs,_)->letxs=uncommaxsinA.Vars(Common.map_filter(onedeclenv)xs)(* todo *)|Asm(_tok1,_volatile_opt,_asmbody,_tok2)->A.Asm[]|MacroDecl_->debug(BlockDecl2block_decl);raiseTodo|UsingDecl_|UsingDirective_|NameSpaceAlias_->raiseCplusplusConstruct(* ---------------------------------------------------------------------- *)(* Expr *)(* ---------------------------------------------------------------------- *)andexprenve=let(e',toks)=einmatche'with|Ccst->constantenvtokscst|Id(n,_)->A.Id(nameenvn)|Ellipsestok->A.Ellipsestok|RecordAccess(e,n)->A.RecordPtAccess(A.Unary(exprenve,(GetRef,List.hdtoks)),nameenvn)|RecordPtAccess(e,n)->A.RecordPtAccess(exprenve,nameenvn)|Cast((_,ft,_),e)->A.Cast(full_typeenvft,exprenve)|ArrayAccess(e1,(_,e2,_))->A.ArrayAccess(exprenve1,exprenve2)|Binary(e1,op,e2)->A.Binary(exprenve1,(op,List.hdtoks),exprenve2)|Unary(e,op)->A.Unary(exprenve,(op,List.hdtoks))|Infix(e,op)->A.Infix(exprenve,(op,List.hdtoks))|Postfix(e,op)->A.Postfix(exprenve,(op,List.hdtoks))|Assignment(e1,op,e2)->A.Assign((op,List.hdtoks),exprenve1,exprenve2)|Sequence(e1,e2)->A.Sequence(exprenve1,exprenve2)|CondExpr(e1,e2opt,e3)->A.CondExpr(exprenve1,(matche2optwith|Somee2->exprenve2|None->debug(Expre);raiseTodo),exprenve3)|Call(e,args)->A.Call(exprenve,Common.map_filter(argumentenv)(args|>unparen|>uncomma))|SizeOfExpr(_tok,e)->A.SizeOf(Left(exprenve))|SizeOfType(_tok,(_,ft,_))->A.SizeOf(Right(full_typeenvft))|GccConstructor((_,ft,_),xs)->A.GccConstructor(full_typeenvft,initialiserenv(InitListxs))|ConstructedObject(_,_)->pr2_once"BUG PARSING LOCAL DECL PROBABLY";debug(Expre);raiseCplusplusConstruct|StatementExpr_|ExprTodo->debug(Expre);raiseTodo|Throw_|DeleteArray(_,_)|Delete(_,_)|New(_,_,_,_,_)|CplusplusCast(_,_,_)|This_|RecordPtStarAccess(_,_)|RecordStarAccess(_,_)|TypeId(_,_)->debug(Expre);raiseCplusplusConstruct|ParenExpr(_,e,_)->exprenveandconstant_envtoksx=matchxwith|Ints->A.Int(s,List.hdtoks)|Float(s,_)->A.Float(s,List.hdtoks)|Char(s,_)->A.Char(s,List.hdtoks)|String(s,_)->A.String(s,List.hdtoks)|Bool_->raiseCplusplusConstruct|MultiString->A.String("TODO",List.hdtoks)andargumentenvx=matchxwith|Lefte->Some(exprenve)(* TODO! can't just skip it ... *)|Right_w->pr2("type argument, maybe wrong typedef inference!");debug(Argumentx);None(* ---------------------------------------------------------------------- *)(* Type *)(* ---------------------------------------------------------------------- *)andfull_typeenvx=let(_qu,(t,ii))=xinmatchtwith|Pointert->A.TPointer(full_typeenvt)|BaseTypet->lets=(matchtwith|Void->"void"|FloatTypeft->(matchftwith|CFloat->"float"|CDouble->"double"|CLongDouble->"long_double")|IntTypeit->(matchitwith|CChar->"char"|Si(si,base)->(matchsiwith|Signed->""|UnSigned->"unsigned_")^(matchbasewith(* 'char' is a CChar and 'unsigned char' is a Si (_, CChar2) *)|CChar2->"char"|CShort->"short"|CInt->"int"|CLong->"long"(* gccext: *)|CLongLong->"long_long")|CBool|WChar_t->debug(Typex);raiseCplusplusConstruct))inA.TBase(s,List.hdii)|FunctionTypeft->A.TFunction(function_typeenvft)|Array((_,eopt,_),ft)->A.TArray(Common.map_opt(exprenv)eopt,full_typeenvft)|TypeName(n)->A.TTypeName(nameenvn)|StructUnionName((kind,_),name)->A.TStructName(struct_kindenvkind,name)|StructDefdef->(matchdefwith{c_kind=(kind,tok);c_name=name_opt;c_inherit=_inh;c_members=(_,xs,_);}->letname=matchname_optwith|None->incrcnt;lets=spf"__anon_struct_%d"!cntin(s,tok)|Somen->nameenvninletdef'={A.s_name=name;s_kind=struct_kindenvkind;s_flds=class_members_sequencableenvxs|>List.flatten;}inenv.struct_defs_toadd<-def'::env.struct_defs_toadd;A.TStructName(struct_kindenvkind,name))|EnumName(_tok,name)->A.TEnumName(name)|EnumDef(tok,name_opt,xs)->letname=matchname_optwith|None->incrcnt;lets=spf"__anon_enum_%d"!cntin(s,tok)|Somen->ninletxs'=xs|>unbrace|>uncomma|>List.map(funeelem->let(name,e_opt)=eelem.e_name,eelem.e_valinname,matche_optwith|None->None|Some(_tok,e)->Some(exprenve))inletdef=name,xs'inenv.enum_defs_toadd<-def::env.enum_defs_toadd;A.TEnumName(name)|TypeOf(_,_)->debug(Typex);raiseTodo|TypenameKwd(_,_)|Reference_->debug(Typex);raiseCplusplusConstruct|ParenType(_,t,_)->full_typeenvt(* ---------------------------------------------------------------------- *)(* structure *)(* ---------------------------------------------------------------------- *)andclass_memberenvx=matchxwith|MemberField(fldkind,_)->letxs=uncommafldkindinxs|>List.map(fieldkindenv)|(UsingDeclInClass_|TemplateDeclInClass_|QualifiedIdInClass(_,_)|MemberDecl_|MemberFunc_|Access(_,_))->debug(ClassMemberx);raiseTodo|EmptyField_->[]andclass_members_sequencableenvxs=ifdef_skipperxs(functionIfdefStructx->Somex|_->None)|>List.map(class_member_sequencableenv)andclass_member_sequencableenvx=matchxwith|ClassElemx->class_memberenvx|CppDirectiveStructdir->debug(Cppdir);raiseTodo|IfdefStruct_->raiseImpossibleandfieldkindenvx=matchxwith|FieldDecldecl->(matchdeclwith{v_namei=ni;v_type=ft;v_storage=sto;}->(matchni,stowith|Some(n,None),NoSto->{A.fld_name=Some(nameenvn);fld_type=full_typeenvft;}|None,NoSto->{A.fld_name=None;fld_type=full_typeenvft;}|_->debug(OneDecldecl);raiseTodo))|BitField(name_opt,_tok,ft,e)->let_=exprenvein{A.fld_name=name_opt;fld_type=full_typeenvft;}(* ---------------------------------------------------------------------- *)(* Misc *)(* ---------------------------------------------------------------------- *)andname_envx=matchxwith|(None,[],IdIdent(name))->name|_->debug(Namex);raiseCplusplusConstructandstruct_kind_env=function|Struct->A.Struct|Union->A.Union|Class->raiseCplusplusConstruct(*****************************************************************************)(* Other entry points *)(*****************************************************************************)letanyany=letenv=empty_env()inmatchanywith|Exprx->A.Expr(exprenvx)|Stmtx->A.Stmt(stmtenvx)|Stmtsxs->A.Stmts(List.map(stmtenv)xs)|_->failwith"Ast_c_simple_build.any: only Expr/Stmt/Stmts handled"