gencpp.ml 115 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189
  1. (*
  2. * haXe/CPP Compiler
  3. * Copyright (c)2008 Hugh Sanderson
  4. * based on and including code by (c)2005-2008 Nicolas Cannasse
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *)
  20. open Ast
  21. open Type
  22. open Common
  23. (*
  24. Code for generating source files.
  25. It manages creating diretories, indents, blocks and only modifying files
  26. when the content changes.
  27. *)
  28. (*
  29. A class_path is made from a package (array of strings) and a class name.
  30. Join these together, inclding a separator. eg, "/" for includes : pack1/pack2/Name or "::"
  31. for namespace "pack1::pack2::Name"
  32. *)
  33. let join_class_path path separator =
  34. let result = match fst path, snd path with
  35. | [], s -> s
  36. | el, s -> String.concat separator el ^ separator ^ s in
  37. if (String.contains result '+') then begin
  38. let idx = String.index result '+' in
  39. (String.sub result 0 idx) ^ (String.sub result (idx+1) ((String.length result) - idx -1 ) )
  40. end else
  41. result;;
  42. class source_writer write_func close_func=
  43. object(this)
  44. val indent_str = "\t"
  45. val mutable indent = ""
  46. val mutable indents = []
  47. val mutable just_finished_block = false
  48. method close = close_func(); ()
  49. method write x = write_func x; just_finished_block <- false
  50. method indent_one = this#write indent_str
  51. method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents
  52. method pop_indent = match indents with
  53. | h::tail -> indents <- tail; indent <- String.concat "" indents
  54. | [] -> indent <- "/*?*/";
  55. method write_i x = this#write (indent ^ x)
  56. method get_indent = indent
  57. method begin_block = this#write ("{\n"); this#push_indent
  58. method end_block = this#pop_indent; this#write_i "}\n"; just_finished_block <- true
  59. method end_block_line = this#pop_indent; this#write_i "}"; just_finished_block <- true
  60. method terminate_line = this#write (if just_finished_block then "" else ";\n")
  61. method add_include class_path =
  62. this#write ("#ifndef INCLUDED_" ^ (join_class_path class_path "_") ^ "\n");
  63. this#write ("#include <" ^ (join_class_path class_path "/") ^ ".h>\n");
  64. this#write ("#endif\n")
  65. end;;
  66. let file_source_writer filename =
  67. let out_file = open_out filename in
  68. new source_writer (output_string out_file) (fun ()-> close_out out_file);;
  69. let read_whole_file chan =
  70. Std.input_all chan;;
  71. (* The cached_source_writer will not write to the file if it has not changed,
  72. thus allowing the makefile dependencies to work correctly *)
  73. let cached_source_writer filename =
  74. try
  75. let in_file = open_in filename in
  76. let old_contents = read_whole_file in_file in
  77. close_in in_file;
  78. let buffer = Buffer.create 0 in
  79. let add_buf str = Buffer.add_string buffer str in
  80. let close = fun () ->
  81. let contents = Buffer.contents buffer in
  82. if (not (contents=old_contents) ) then begin
  83. let out_file = open_out filename in
  84. output_string out_file contents;
  85. close_out out_file;
  86. end;
  87. in
  88. new source_writer (add_buf) (close);
  89. with _ ->
  90. file_source_writer filename;;
  91. let rec make_class_directories base dir_list =
  92. ( match dir_list with
  93. | [] -> ()
  94. | dir :: remaining ->
  95. let path = match base with
  96. | "" -> dir
  97. | "/" -> "/" ^ dir
  98. | _ -> base ^ "/" ^ dir in
  99. if ( not ( (path="") ||
  100. ( ((String.length path)=2) && ((String.sub path 1 1)=":") ) ) ) then
  101. if not (Sys.file_exists path) then
  102. Unix.mkdir path 0o755;
  103. make_class_directories (if (path="") then "/" else path) remaining
  104. );;
  105. let new_source_file base_dir sub_dir extension class_path =
  106. make_class_directories base_dir ( sub_dir :: (fst class_path));
  107. cached_source_writer
  108. ( base_dir ^ "/" ^ sub_dir ^ "/" ^ ( String.concat "/" (fst class_path) ) ^ "/" ^
  109. (snd class_path) ^ extension);;
  110. let new_cpp_file base_dir = new_source_file base_dir "src" ".cpp";;
  111. let new_header_file base_dir = new_source_file base_dir "include" ".h";;
  112. let make_base_directory file =
  113. make_class_directories "" ( ( Str.split_delim (Str.regexp "[\\/]+") file ) );
  114. (* CPP code generation context *)
  115. type context =
  116. {
  117. mutable ctx_common : Common.context;
  118. mutable ctx_output : string -> unit;
  119. mutable ctx_dbgout : string -> unit;
  120. mutable ctx_writer : source_writer;
  121. mutable ctx_calling : bool;
  122. mutable ctx_assigning : bool;
  123. mutable ctx_return_from_block : bool;
  124. (* This is for returning from the child nodes of TMatch, TSwitch && TTry *)
  125. mutable ctx_return_from_internal_node : bool;
  126. mutable ctx_debug : bool;
  127. mutable ctx_debug_type : bool;
  128. mutable ctx_real_this_ptr : bool;
  129. mutable ctx_dynamic_this_ptr : bool;
  130. mutable ctx_dump_src_pos : unit -> unit;
  131. mutable ctx_dump_stack_line : bool;
  132. mutable ctx_static_id_curr : int;
  133. mutable ctx_static_id_used : int;
  134. mutable ctx_static_id_depth : int;
  135. mutable ctx_switch_id : int;
  136. mutable ctx_class_name : string;
  137. mutable ctx_local_function_args : (string,string) Hashtbl.t;
  138. mutable ctx_local_return_block_args : (string,string) Hashtbl.t;
  139. mutable ctx_class_member_types : (string,string) Hashtbl.t;
  140. mutable ctx_file_info : (string,string) PMap.t ref;
  141. }
  142. let new_context common_ctx writer debug file_info =
  143. {
  144. ctx_common = common_ctx;
  145. ctx_writer = writer;
  146. ctx_output = (writer#write);
  147. ctx_dbgout = if debug then (writer#write) else (fun _ -> ());
  148. ctx_calling = false;
  149. ctx_assigning = false;
  150. ctx_debug = debug;
  151. ctx_debug_type = debug;
  152. ctx_dump_src_pos = (fun() -> ());
  153. ctx_dump_stack_line = true;
  154. ctx_return_from_block = false;
  155. ctx_return_from_internal_node = false;
  156. ctx_real_this_ptr = true;
  157. ctx_dynamic_this_ptr = false;
  158. ctx_static_id_curr = 0;
  159. ctx_static_id_used = 0;
  160. ctx_static_id_depth = 0;
  161. ctx_switch_id = 0;
  162. ctx_class_name = "";
  163. ctx_local_function_args = Hashtbl.create 0;
  164. ctx_local_return_block_args = Hashtbl.create 0;
  165. ctx_class_member_types = Hashtbl.create 0;
  166. ctx_file_info = file_info;
  167. }
  168. (* The internal classes are implemented by the core hxcpp system, so the cpp
  169. classes should not be generated *)
  170. let is_internal_class = function
  171. | ([],"Int") | ([],"Void") | ([],"String") | ([], "Null") | ([], "Float")
  172. | ([],"Array") | ([], "Class") | ([], "Enum") | ([], "Bool")
  173. | ([], "Dynamic") | ([], "ArrayAccess") | (["cpp"], "FastIterator")-> true
  174. | (["cpp"], "CppInt32__") | ([],"Math") | (["haxe";"io"], "Unsigned_char__") -> true
  175. | _ -> false
  176. (* The internal header files are also defined in the hx/Object.h file, so you do
  177. #include them separately. However, the Int32 and Math classes do have their
  178. own header files (these are under the hxcpp tree) so these should be included *)
  179. let include_class_header = function
  180. | ([],"@Main") -> false
  181. | (["cpp"], "CppInt32__") | ([],"Math") -> true
  182. | path -> not ( is_internal_class path )
  183. let is_cpp_class = function
  184. | ("cpp"::_ , _) -> true
  185. | ( [] , "Xml" ) -> true
  186. | ( [] , "EReg" ) -> true
  187. | ( ["haxe"] , "Log" ) -> true
  188. | _ -> false;;
  189. let is_block exp = match exp.eexpr with | TBlock _ -> true | _ -> false ;;
  190. let to_block expression =
  191. if is_block expression then expression else (mk_block expression);;
  192. (* todo - is this how it's done? *)
  193. let hash_keys hash =
  194. let key_list = ref [] in
  195. Hashtbl.iter (fun key value -> key_list := key :: !key_list ) hash;
  196. !key_list;;
  197. let pmap_keys pmap =
  198. let key_list = ref [] in
  199. PMap.iter (fun key value -> key_list := key :: !key_list ) pmap;
  200. !key_list;;
  201. (* The Hashtbl structure seems a little odd - but here is a helper function *)
  202. let hash_iterate hash visitor =
  203. let result = ref [] in
  204. Hashtbl.iter (fun key value -> result := (visitor key value) :: !result ) hash;
  205. !result
  206. (* Convert function names that can't be written in c++ ... *)
  207. let keyword_remap name =
  208. match name with
  209. | "int"
  210. | "auto" | "char" | "const" | "delete" | "double" | "Float" | "enum"
  211. | "extern" | "float" | "friend" | "goto" | "long" | "operator" | "protected"
  212. | "register" | "short" | "signed" | "sizeof" | "template" | "typedef"
  213. | "union" | "unsigned" | "void" | "volatile" | "or" | "and" | "xor" | "or_eq" | "not"
  214. | "and_eq" | "xor_eq" | "typeof" | "stdin" | "stdout" | "stderr"
  215. | "BIG_ENDIAN" | "LITTLE_ENDIAN" | "assert" | "NULL" | "wchar_t" | "EOF"
  216. | "bool" | "const_cast" | "dynamic_cast" | "explicit" | "export" | "mutable" | "namespace"
  217. | "reinterpret_cast" | "static_cast" | "typeid" | "typename" | "virtual"
  218. | "struct" -> "_" ^ name
  219. | "asm" -> "_asm_"
  220. | x -> x
  221. (*
  222. While #include "Math.h" sould be different from "#include <math.h>", and it may be possible
  223. to use include paths to get this right, I think it is easier just to chnage the name *)
  224. let include_remap = function | ([],"Math") -> ([],"hxMath") | x -> x;;
  225. let get_code meta key =
  226. let rec loop = function
  227. | [] -> ""
  228. | (k,[Ast.EConst (Ast.String name),_],_) :: _ when k=key-> name ^ "\n"
  229. | _ :: l -> loop l
  230. in
  231. loop meta
  232. ;;
  233. (* Add include to source code *)
  234. let add_include writer class_path =
  235. writer#add_include (include_remap class_path);;
  236. (* This gets the class include order correct. In the header files, we forward declare
  237. the class types so the header file does not have any undefined variables.
  238. In the cpp files, we include all the required header files, providing the actual
  239. types for everything. This way there is no problem with circular class references.
  240. *)
  241. let gen_forward_decl writer class_path =
  242. if ( class_path = (["cpp"],"CppInt32__")) then
  243. writer#add_include class_path
  244. else begin
  245. let output = writer#write in
  246. output ("HX_DECLARE_CLASS" ^ (string_of_int (List.length (fst class_path) ) ) ^ "(");
  247. List.iter (fun package_part -> output (package_part ^ ",") ) (fst class_path);
  248. output ( (snd class_path) ^ ")\n")
  249. end;;
  250. let real_interfaces =
  251. List.filter (function (t,pl) ->
  252. match t, pl with
  253. | { cl_path = ["cpp";"rtti"],_ },[] -> false
  254. | _ -> true
  255. );;
  256. let rec is_function_expr expr =
  257. match expr.eexpr with
  258. | TParenthesis expr -> is_function_expr expr
  259. | TCast (e,None) -> is_function_expr e
  260. | TFunction _ -> true
  261. | _ -> false;;
  262. let rec has_rtti_interface c interface =
  263. List.exists (function (t,pl) ->
  264. (snd t.cl_path) = interface && (match fst t.cl_path with | ["cpp";"rtti"] -> true | _ -> false )
  265. ) c.cl_implements ||
  266. (match c.cl_super with None -> false | Some (c,_) -> has_rtti_interface c interface);;
  267. let has_field_integer_lookup class_def =
  268. has_rtti_interface class_def "FieldIntegerLookup";;
  269. let has_field_integer_numeric_lookup class_def =
  270. has_rtti_interface class_def "FieldNumericIntegerLookup";;
  271. (* Output required code to place contents in required namespace *)
  272. let gen_open_namespace output class_path =
  273. List.iter (fun namespace -> output ("namespace " ^ namespace ^ "{\n")) (fst class_path);;
  274. let gen_close_namespace output class_path =
  275. List.iter
  276. (fun namespace -> output ( "}" ^ " // end namespace " ^ namespace ^"\n"))
  277. (fst class_path);;
  278. (* The basic types can have default values and are passesby value *)
  279. let cant_be_null = function
  280. | "Int" | "Bool" | "Float" | "::haxe::io::Unsigned_char__" -> true
  281. | "int" | "bool" | "double" | "float" -> true
  282. | _ -> false
  283. (* Get a string to represent a type.
  284. The "suffix" will be nothing or "_obj", depending if we want the name of the
  285. pointer class or the pointee (_obj class *)
  286. let rec class_string klass suffix params =
  287. (match klass.cl_path with
  288. (* Array class *)
  289. | ([],"Array") when is_dynamic_array_param (List.hd params) -> "Dynamic"
  290. | ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "< " ^ (String.concat ","
  291. (List.map type_string params) ) ^ " >"
  292. (* FastIterator class *)
  293. | (["cpp"],"FastIterator") -> "::cpp::FastIterator" ^ suffix ^ "< " ^ (String.concat ","
  294. (List.map type_string params) ) ^ " >"
  295. | _ when klass.cl_kind=KTypeParameter -> "Dynamic"
  296. | ([],"#Int") -> "/* # */int"
  297. | (["haxe";"io"],"Unsigned_char__") -> "unsigned char"
  298. | ([],"Class") -> "::Class"
  299. | ([],"EnumValue") -> "Dynamic"
  300. | ([],"Null") -> (match params with
  301. | [t] ->
  302. (match follow t with
  303. | TInst ({ cl_path = [],"Int" },_)
  304. | TInst ({ cl_path = [],"Float" },_)
  305. | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
  306. | _ -> "/*NULL*/" ^ (type_string t) )
  307. | _ -> assert false);
  308. (* Normal class *)
  309. | path when klass.cl_extern && (not (is_internal_class path) )->
  310. (join_class_path klass.cl_path "::") ^ suffix
  311. | _ -> "::" ^ (join_class_path klass.cl_path "::") ^ suffix
  312. )
  313. and type_string_suff suffix haxe_type =
  314. (match haxe_type with
  315. | TMono r -> (match !r with None -> "Dynamic" ^ suffix | Some t -> type_string_suff suffix t)
  316. | TEnum ({ e_path = ([],"Void") },[]) -> "Void"
  317. | TEnum ({ e_path = ([],"Bool") },[]) -> "bool"
  318. | TInst ({ cl_path = ([],"Float") },[]) -> "Float"
  319. | TInst ({ cl_path = ([],"Int") },[]) -> "int"
  320. | TEnum (enum,params) -> "::" ^ (join_class_path enum.e_path "::") ^ suffix
  321. | TInst (klass,params) -> (class_string klass suffix params)
  322. | TType (type_def,params) ->
  323. (match type_def.t_path with
  324. | [] , "Null" ->
  325. (match params with
  326. | [t] ->
  327. (match follow t with
  328. | TInst ({ cl_path = [],"Int" },_)
  329. | TInst ({ cl_path = [],"Float" },_)
  330. | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic" ^ suffix
  331. | _ -> type_string_suff suffix t)
  332. | _ -> assert false);
  333. | [] , "Array" ->
  334. (match params with
  335. | [t] when (type_string (follow t)) = "Dynamic" -> "Dynamic"
  336. | [t] -> "Array< " ^ (type_string (follow t) ) ^ " >"
  337. | _ -> assert false)
  338. | ["cpp"] , "FastIterator" ->
  339. (match params with
  340. | [t] -> "::cpp::FastIterator< " ^ (type_string (follow t) ) ^ " >"
  341. | _ -> assert false)
  342. | _ -> type_string_suff suffix (apply_params type_def.t_types params type_def.t_type)
  343. )
  344. | TFun (args,haxe_type) -> "Dynamic" ^ suffix
  345. | TAnon a -> "Dynamic"
  346. (*
  347. (match !(a.a_status) with
  348. | Statics c -> type_string_suff suffix (TInst (c,List.map snd c.cl_types))
  349. | EnumStatics e -> type_string_suff suffix (TEnum (e,List.map snd e.e_types))
  350. | _ -> "Dynamic" ^ suffix )
  351. *)
  352. | TDynamic haxe_type -> "Dynamic" ^ suffix
  353. | TLazy func -> type_string_suff suffix ((!func)())
  354. )
  355. and type_string haxe_type =
  356. type_string_suff "" haxe_type
  357. and is_dynamic_array_param haxe_type =
  358. if (type_string (follow haxe_type)) = "Dynamic" then true
  359. else (match follow haxe_type with
  360. | TInst (klass,params) ->
  361. (match klass.cl_path with
  362. | ([],"Array") | ([],"Class") | (["cpp"],"FastIterator") -> false
  363. | _ -> klass.cl_kind = KTypeParameter
  364. )
  365. | _ -> false
  366. )
  367. ;;
  368. let is_array haxe_type =
  369. match follow haxe_type with
  370. | TInst (klass,params) ->
  371. (match klass.cl_path with
  372. | [] , "Array" -> not (is_dynamic_array_param (List.hd params))
  373. | _ -> false )
  374. | TType (type_def,params) ->
  375. (match type_def.t_path with
  376. | [] , "Array" -> not (is_dynamic_array_param (List.hd params))
  377. | _ -> false )
  378. | _ -> false
  379. ;;
  380. let is_array_implementer haxe_type =
  381. match follow haxe_type with
  382. | TInst (klass,params) ->
  383. (match klass.cl_array_access with
  384. | Some _ -> true
  385. | _ -> false )
  386. | _ -> false
  387. ;;
  388. (* Get the type and output it to the stream *)
  389. let gen_type ctx haxe_type =
  390. ctx.ctx_output (type_string haxe_type)
  391. ;;
  392. (* Get the type and output it to the stream *)
  393. let gen_type_suff ctx haxe_type suff =
  394. ctx.ctx_output (type_string_suff suff haxe_type);;
  395. let member_type ctx field_object member =
  396. let name = (if (is_array field_object.etype) then "::Array"
  397. else (type_string field_object.etype)) ^ "." ^ member in
  398. try ( Hashtbl.find ctx.ctx_class_member_types name )
  399. with Not_found -> "?";;
  400. let is_interface_type t =
  401. match follow t with
  402. | TInst (klass,params) -> klass.cl_interface
  403. | _ -> false
  404. ;;
  405. let is_interface obj = is_interface_type obj.etype;;
  406. let is_function_member expression =
  407. match (follow expression.etype) with | TFun (_,_) -> true | _ -> false;;
  408. let is_internal_member member =
  409. match member with
  410. | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString"
  411. | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal"
  412. | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "toString" | "__HasField"
  413. -> true
  414. | _ -> false;;
  415. let rec is_dynamic_accessor name acc field class_def =
  416. ( ( acc ^ "_" ^ field.cf_name) = name ) &&
  417. ( not (List.exists (fun f -> f.cf_name=name) class_def.cl_ordered_fields) )
  418. && (match class_def.cl_super with None -> true | Some (parent,_) -> is_dynamic_accessor name acc field parent )
  419. ;;
  420. let gen_arg_type_name name default_val arg_type prefix =
  421. let remap_name = keyword_remap name in
  422. let type_str = (type_string arg_type) in
  423. match default_val with
  424. | Some TNull -> (type_str,remap_name)
  425. | Some constant when (cant_be_null type_str) -> ("hx::Null< " ^ type_str ^ " > ",prefix ^ remap_name)
  426. | Some constant -> (type_str,prefix ^ remap_name)
  427. | _ -> (type_str,remap_name);;
  428. let gen_interface_arg_type_name name opt typ =
  429. let type_str = (type_string typ) in
  430. (if (opt && (cant_be_null type_str) ) then
  431. "hx::Null< " ^ type_str ^ " > "
  432. else
  433. type_str )
  434. ^ " " ^ (keyword_remap name)
  435. ;;
  436. (* Generate prototype text, including allowing default values to be null *)
  437. let gen_arg name default_val arg_type prefix =
  438. let pair = gen_arg_type_name name default_val arg_type prefix in
  439. (fst pair) ^ " " ^ (snd pair);;
  440. let rec gen_arg_list arg_list prefix =
  441. String.concat "," (List.map (fun (v,o) -> (gen_arg v.v_name o v.v_type prefix) ) arg_list)
  442. let rec gen_tfun_arg_list arg_list =
  443. match arg_list with
  444. | [] -> ""
  445. | [(name,o,arg_type)] -> gen_arg name None arg_type ""
  446. | (name,o,arg_type) :: remaining ->
  447. (gen_arg name None arg_type "") ^ "," ^ (gen_tfun_arg_list remaining)
  448. (* Check to see if we are the first object in the parent tree to implement a dynamic interface *)
  449. let implement_dynamic_here class_def =
  450. let implements_dynamic c = match c.cl_dynamic with None -> false | _ -> true in
  451. let rec super_implements_dynamic c = match c.cl_super with
  452. | None -> false
  453. | Some (csup, _) -> if (implements_dynamic csup) then true else
  454. super_implements_dynamic csup;
  455. in
  456. ( (implements_dynamic class_def) && (not (super_implements_dynamic class_def) ) );;
  457. (* Make string printable for c++ code *)
  458. (* Here we know there are no utf8 characters, so use the L"" notation to avoid conversion *)
  459. let escape_stringw s l =
  460. let b = Buffer.create 0 in
  461. Buffer.add_char b 'L';
  462. Buffer.add_char b '"';
  463. let skip = ref 0 in
  464. for i = 0 to String.length s - 1 do
  465. if (!skip>0) then begin
  466. skip := !skip -1;
  467. l := !l-1;
  468. end else
  469. match Char.code (String.unsafe_get s i) with
  470. | c when (c>127) ->
  471. let encoded = ((c land 0x3F) lsl 6) lor ( Char.code ((String.unsafe_get s (i+1))) land 0x7F) in
  472. skip := 1;
  473. Buffer.add_string b (Printf.sprintf "\\x%X\"L\"" encoded)
  474. | c when (c < 32) -> Buffer.add_string b (Printf.sprintf "\\x%X\"L\"" c)
  475. | c -> Buffer.add_char b (Char.chr c)
  476. done;
  477. Buffer.add_char b '"';
  478. Buffer.contents b;;
  479. let special_to_hex s =
  480. let l = String.length s in
  481. let b = Buffer.create 0 in
  482. for i = 0 to l - 1 do
  483. match Char.code (String.unsafe_get s i) with
  484. | c when (c>127) || (c<32) ->
  485. Buffer.add_string b (Printf.sprintf "\\x%02x\"\"" c)
  486. | c -> Buffer.add_char b (Char.chr c)
  487. done;
  488. Buffer.contents b;;
  489. let has_utf8_chars s =
  490. let result = ref false in
  491. for i = 0 to String.length s - 1 do
  492. result := !result || ( Char.code (String.unsafe_get s i) > 127 )
  493. done;
  494. !result;;
  495. let escape_null s =
  496. let b = Buffer.create 0 in
  497. String.iter (fun ch -> if (ch=='\x00') then Buffer.add_string b "\\000" else Buffer.add_char b ch ) s;
  498. Buffer.contents b;;
  499. let str s =
  500. let escaped = Ast.s_escape s in
  501. let null_escaped = escape_null escaped in
  502. if (has_utf8_chars escaped) then begin
  503. (* Output both wide and thin versions - let the compiler choose ... *)
  504. let l = ref (String.length escaped) in
  505. let q = escape_stringw (Ast.s_escape s) l in
  506. ("HX_CSTRING2(" ^ q ^ "," ^ (string_of_int !l) ^ ",\"" ^ (special_to_hex null_escaped) ^ "\" )")
  507. end else
  508. (* The wide and thin versions are the same ... *)
  509. ("HX_CSTRING(\"" ^ null_escaped ^ "\")")
  510. ;;
  511. (* When we are in a "real" object, we refer to ourselves as "this", but
  512. if we are in a local class that is used to generate return values,
  513. we use the fake "__this" pointer.
  514. If we are in an "Anon" object, then the "this" refers to the anon object (eg List iterator) *)
  515. let clear_real_this_ptr ctx dynamic_this =
  516. let old_flag = ctx.ctx_real_this_ptr in
  517. let old_dynamic = ctx.ctx_dynamic_this_ptr in
  518. ctx.ctx_real_this_ptr <- false;
  519. ctx.ctx_dynamic_this_ptr <- dynamic_this;
  520. fun () -> ( ctx.ctx_real_this_ptr <- old_flag; ctx.ctx_dynamic_this_ptr <- old_dynamic; );;
  521. (* Generate temp variable names *)
  522. let next_anon_function_name ctx =
  523. ctx.ctx_static_id_curr <- ctx.ctx_static_id_curr + 1;
  524. "_Function_" ^ (string_of_int ctx.ctx_static_id_depth) ^"_"^ (string_of_int ctx.ctx_static_id_curr);;
  525. let use_anon_function_name ctx =
  526. ctx.ctx_static_id_used <- ctx.ctx_static_id_used + 1;
  527. "_Function_" ^ (string_of_int ctx.ctx_static_id_depth) ^"_"^ (string_of_int ctx.ctx_static_id_used);;
  528. let push_anon_names ctx =
  529. let old_used = ctx.ctx_static_id_used in
  530. let old_curr = ctx.ctx_static_id_curr in
  531. let old_depth = ctx.ctx_static_id_depth in
  532. ctx.ctx_static_id_used <- 0;
  533. ctx.ctx_static_id_curr <- 0;
  534. ctx.ctx_static_id_depth <- ctx.ctx_static_id_depth + 1;
  535. ( function () -> (
  536. ctx.ctx_static_id_used <- old_used;
  537. ctx.ctx_static_id_curr <- old_curr;
  538. ctx.ctx_static_id_depth <- old_depth; ) )
  539. ;;
  540. let get_switch_var ctx =
  541. ctx.ctx_switch_id <- ctx.ctx_switch_id + 1;
  542. "_switch_" ^ (string_of_int ctx.ctx_switch_id)
  543. (* If you put on the "-debug" flag, you get extra comments in the source code *)
  544. let debug_expression expression type_too =
  545. "/* " ^ Type.s_expr_kind expression ^ (if (type_too) then " = " ^ (type_string expression.etype) else "") ^ " */";;
  546. (* This is like the Type.iter, but also keeps the "retval" flag up to date *)
  547. let rec iter_retval f retval e =
  548. match e.eexpr with
  549. | TConst _
  550. | TLocal _
  551. | TEnumField _
  552. | TBreak
  553. | TContinue
  554. | TTypeExpr _ ->
  555. ()
  556. | TArray (e1,e2)
  557. | TBinop (_,e1,e2) ->
  558. f true e1;
  559. f true e2;
  560. | TWhile (e1,e2,_) ->
  561. f true e1;
  562. f false e2;
  563. | TFor (_,e1,e2) ->
  564. f true e1;
  565. f false e2;
  566. | TThrow e
  567. | TField (e,_)
  568. | TClosure (e,_)
  569. | TUnop (_,_,e) ->
  570. f true e
  571. | TParenthesis e ->
  572. f retval e
  573. | TBlock expr_list when retval ->
  574. let rec return_last = function
  575. | [] -> ()
  576. | expr :: [] -> f true expr
  577. | expr :: exprs -> f false expr; return_last exprs in
  578. return_last expr_list
  579. | TArrayDecl el
  580. | TNew (_,_,el) ->
  581. List.iter (f true ) el
  582. | TBlock el ->
  583. List.iter (f false ) el
  584. | TObjectDecl fl ->
  585. List.iter (fun (_,e) -> f true e) fl
  586. | TCall (e,el) ->
  587. f true e;
  588. List.iter (f true) el
  589. | TVars vl ->
  590. List.iter (fun (_,e) -> match e with None -> () | Some e -> f true e) vl
  591. | TFunction fu ->
  592. f false fu.tf_expr
  593. | TIf (e,e1,e2) ->
  594. f true e;
  595. f retval e1;
  596. (match e2 with None -> () | Some e -> f retval e)
  597. | TSwitch (e,cases,def) ->
  598. f true e;
  599. List.iter (fun (el,e2) -> List.iter (f true) el; f retval e2) cases;
  600. (match def with None -> () | Some e -> f retval e)
  601. | TMatch (e,_,cases,def) ->
  602. f true e;
  603. List.iter (fun (_,_,e) -> f false e) cases;
  604. (match def with None -> () | Some e -> f false e)
  605. | TTry (e,catches) ->
  606. f retval e;
  607. List.iter (fun (_,e) -> f false e) catches
  608. | TReturn eo ->
  609. (match eo with None -> () | Some e -> f true e)
  610. | TCast (e,None) ->
  611. f retval e
  612. | TCast (e,_) ->
  613. f true e
  614. ;;
  615. (* Convert an array to a comma separated list of values *)
  616. let array_arg_list inList =
  617. let i = ref (0-1) in
  618. String.concat "," (List.map (fun _ -> incr i; "inArgs[" ^ (string_of_int !i) ^ "]" ) inList)
  619. let list_num l = string_of_int (List.length l);;
  620. let only_int_cases cases =
  621. match cases with
  622. | [] -> false
  623. | _ ->
  624. not (List.exists (fun (cases,expression) ->
  625. List.exists (fun case -> match case.eexpr with TConst (TInt _) -> false | _ -> true ) cases
  626. ) cases );;
  627. (* See if there is a haxe break statement that will be swollowed by c++ break *)
  628. exception BreakFound;;
  629. let contains_break expression =
  630. try (
  631. let rec check_all expression =
  632. Type.iter (fun expr -> match expr.eexpr with
  633. | TBreak -> raise BreakFound
  634. | TFor _
  635. | TFunction _
  636. | TWhile (_,_,_) -> ()
  637. | _ -> check_all expr;
  638. ) expression in
  639. check_all expression;
  640. false;
  641. ) with BreakFound -> true;;
  642. (* Decide is we should look the field up by name *)
  643. let dynamic_internal = function | "__Is" -> true | _ -> false
  644. (* Get a list of variables to extract from a enum tmatch *)
  645. let tmatch_params_to_args params =
  646. (match params with
  647. | None | Some [] -> []
  648. | Some l ->
  649. let n = ref (-1) in
  650. List.fold_left
  651. (fun acc v -> incr n; match v with None -> acc | Some v -> (v.v_name,v.v_type,!n) :: acc) [] l)
  652. let rec is_null expr =
  653. match expr.eexpr with
  654. | TConst TNull -> true
  655. | TParenthesis expr -> is_null expr
  656. | TCast (e,None) -> is_null e
  657. | _ -> false
  658. ;;
  659. let find_undeclared_variables_ctx ctx undeclared declarations this_suffix allow_this expression =
  660. let output = ctx.ctx_output in
  661. let rec find_undeclared_variables undeclared declarations this_suffix allow_this expression =
  662. match expression.eexpr with
  663. | TVars var_list ->
  664. List.iter (fun (tvar, optional_init) ->
  665. Hashtbl.add declarations (keyword_remap tvar.v_name) ();
  666. if (ctx.ctx_debug) then
  667. output ("/* found var " ^ tvar.v_name ^ "*/ ");
  668. match optional_init with
  669. | Some expression -> find_undeclared_variables undeclared declarations this_suffix allow_this expression
  670. | _ -> ()
  671. ) var_list
  672. | TFunction func -> List.iter ( fun (tvar, opt_val) ->
  673. if (ctx.ctx_debug) then
  674. output ("/* found arg " ^ tvar.v_name ^ " = " ^ (type_string tvar.v_type) ^ " */ ");
  675. Hashtbl.add declarations (keyword_remap tvar.v_name) () ) func.tf_args;
  676. find_undeclared_variables undeclared declarations this_suffix false func.tf_expr
  677. | TTry (try_block,catches) ->
  678. find_undeclared_variables undeclared declarations this_suffix allow_this try_block;
  679. List.iter (fun (tvar,catch_expt) ->
  680. let old_decs = Hashtbl.copy declarations in
  681. Hashtbl.add declarations (keyword_remap tvar.v_name) ();
  682. find_undeclared_variables undeclared declarations this_suffix allow_this catch_expt;
  683. Hashtbl.clear declarations;
  684. Hashtbl.iter ( Hashtbl.add declarations ) old_decs
  685. ) catches;
  686. | TLocal tvar ->
  687. let name = keyword_remap tvar.v_name in
  688. if not (Hashtbl.mem declarations name) then
  689. Hashtbl.replace undeclared name (type_string expression.etype)
  690. | TMatch (condition, enum, cases, default) ->
  691. find_undeclared_variables undeclared declarations this_suffix allow_this condition;
  692. List.iter (fun (case_ids,params,expression) ->
  693. let old_decs = Hashtbl.copy declarations in
  694. (match params with
  695. | None -> ()
  696. | Some l -> List.iter (fun (opt_var) ->
  697. match opt_var with | Some v -> Hashtbl.add declarations (keyword_remap v.v_name) () | _ -> () )
  698. l );
  699. find_undeclared_variables undeclared declarations this_suffix allow_this expression;
  700. Hashtbl.clear declarations;
  701. Hashtbl.iter ( Hashtbl.add declarations ) old_decs
  702. ) cases;
  703. (match default with | None -> ()
  704. | Some expr ->
  705. find_undeclared_variables undeclared declarations this_suffix allow_this expr;
  706. );
  707. | TFor (tvar, init, loop) ->
  708. let old_decs = Hashtbl.copy declarations in
  709. Hashtbl.add declarations (keyword_remap tvar.v_name) ();
  710. find_undeclared_variables undeclared declarations this_suffix allow_this init;
  711. find_undeclared_variables undeclared declarations this_suffix allow_this loop;
  712. Hashtbl.clear declarations;
  713. Hashtbl.iter ( Hashtbl.add declarations ) old_decs
  714. | TConst TSuper
  715. | TConst TThis ->
  716. if ((not (Hashtbl.mem declarations "this")) && allow_this) then
  717. Hashtbl.replace undeclared "this" (type_string_suff this_suffix expression.etype)
  718. | TBlock expr_list ->
  719. let old_decs = Hashtbl.copy declarations in
  720. List.iter (find_undeclared_variables undeclared declarations this_suffix allow_this ) expr_list;
  721. (* what is the best way for this ? *)
  722. Hashtbl.clear declarations;
  723. Hashtbl.iter ( Hashtbl.add declarations ) old_decs
  724. | _ -> Type.iter (find_undeclared_variables undeclared declarations this_suffix allow_this) expression
  725. in
  726. find_undeclared_variables undeclared declarations this_suffix allow_this expression
  727. ;;
  728. let rec is_dynamic_in_cpp ctx expr =
  729. let expr_type = type_string ( match follow expr.etype with TFun (args,ret) -> ret | _ -> expr.etype) in
  730. ctx.ctx_dbgout ( "/* idic: " ^ expr_type ^ " */" );
  731. if ( expr_type="Dynamic" ) then
  732. true
  733. else begin
  734. let result = (
  735. match expr.eexpr with
  736. | TField( obj, name ) -> ctx.ctx_dbgout ("/* ?tfield "^name^" */");
  737. if (is_dynamic_member_lookup_in_cpp ctx obj name) then
  738. (
  739. ctx.ctx_dbgout "/* tf=dynobj */";
  740. true
  741. )
  742. else if (is_dynamic_member_return_in_cpp ctx obj name) then
  743. (
  744. ctx.ctx_dbgout "/* tf=dynret */";
  745. true
  746. )
  747. else
  748. (
  749. ctx.ctx_dbgout "/* tf=notdyn */";
  750. false
  751. )
  752. | TConst TThis when ((not ctx.ctx_real_this_ptr) && ctx.ctx_dynamic_this_ptr) ->
  753. ctx.ctx_dbgout ("/* dthis */"); true
  754. | TArray (obj,index) -> let dyn = is_dynamic_in_cpp ctx obj in
  755. ctx.ctx_dbgout ("/* aidr:" ^ (if dyn then "Dyn" else "Not") ^ " */");
  756. dyn;
  757. | TTypeExpr _ -> false
  758. | TCall(func,args) ->
  759. (match follow func.etype with
  760. | TFun (args,ret) -> ctx.ctx_dbgout ("/* ret = "^ (type_string ret) ^" */");
  761. is_dynamic_in_cpp ctx func
  762. | _ -> ctx.ctx_dbgout "/* not TFun */"; true
  763. );
  764. | TParenthesis(expr) -> is_dynamic_in_cpp ctx expr
  765. | TCast (e,None) -> is_dynamic_in_cpp ctx e
  766. | TLocal { v_name = "__global__" } -> false
  767. | TConst TNull -> true
  768. | _ -> ctx.ctx_dbgout "/* other */"; false (* others ? *) )
  769. in
  770. ctx.ctx_dbgout (if result then "/* Y */" else "/* N */" );
  771. result
  772. end
  773. and is_dynamic_member_lookup_in_cpp ctx field_object member =
  774. ctx.ctx_dbgout ("/*mem."^member^".*/");
  775. if (is_internal_member member) then false else
  776. if (match field_object.eexpr with | TTypeExpr _ -> ctx.ctx_dbgout "/*!TTypeExpr*/"; true | _ -> false) then false else
  777. if (is_dynamic_in_cpp ctx field_object) then true else
  778. if (is_array field_object.etype) then false else (
  779. let tstr = type_string field_object.etype in
  780. ctx.ctx_dbgout ("/* ts:"^tstr^"*/");
  781. match tstr with
  782. (* Internal classes have no dynamic members *)
  783. | "::String" | "Null" | "::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> ctx.ctx_dbgout ("/* ok:" ^ (type_string field_object.etype) ^ " */"); false
  784. | "Dynamic" -> true
  785. | name ->
  786. let full_name = name ^ "." ^ member in
  787. ctx.ctx_dbgout ("/* t:" ^ full_name ^ " */");
  788. try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in
  789. ctx.ctx_dbgout ("/* =" ^ mem_type ^ "*/");
  790. false )
  791. with Not_found -> true
  792. )
  793. and is_dynamic_member_return_in_cpp ctx field_object member =
  794. if (is_array field_object.etype) then false else
  795. if (is_internal_member member) then false else
  796. match field_object.eexpr with
  797. | TTypeExpr t ->
  798. let full_name = "::" ^ (join_class_path (t_path t) "::" ) ^ "." ^ member in
  799. ctx.ctx_dbgout ("/*static:"^ full_name^"*/");
  800. ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic" )
  801. with Not_found -> true )
  802. | _ ->
  803. let tstr = type_string field_object.etype in
  804. (match tstr with
  805. (* Internal classes have no dynamic members *)
  806. | "::String" | "Null" | "::Class" | "::Enum" | "::Math" | "::ArrayAccess" -> false
  807. | "Dynamic" -> ctx.ctx_dbgout "/*D*/"; true
  808. | name ->
  809. let full_name = name ^ "." ^ member in
  810. ctx.ctx_dbgout ("/*R:"^full_name^"*/");
  811. try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in mem_type="Dynamic" )
  812. with Not_found -> true )
  813. ;;
  814. let cast_if_required ctx expr to_type =
  815. let expr_type = (type_string expr.etype) in
  816. ctx.ctx_dbgout ( "/* cir: " ^ expr_type ^ " */" );
  817. if (is_dynamic_in_cpp ctx expr) then
  818. ctx.ctx_output (".Cast< " ^ to_type ^ " >()" )
  819. ;;
  820. let default_value_string = function
  821. | TInt i -> Printf.sprintf "%ld" i
  822. | TFloat float_as_string -> float_as_string
  823. | TString s -> str s
  824. | TBool b -> (if b then "true" else "false")
  825. | TNull -> "null()"
  826. | _ -> "/* Hmmm */"
  827. ;;
  828. let generate_default_values ctx args prefix =
  829. List.iter ( fun (v,o) -> let type_str = type_string v.v_type in
  830. let name = (keyword_remap v.v_name) in
  831. match o with
  832. | Some TNull -> ()
  833. | Some const ->
  834. ctx.ctx_output (type_str ^ " " ^ name ^ " = " ^ prefix ^ name ^ ".Default(" ^
  835. (default_value_string const) ^ ");\n")
  836. | _ -> () ) args;;
  837. let has_default_values args =
  838. List.exists ( fun (_,o) -> match o with
  839. | Some TNull -> false
  840. | Some _ -> true
  841. | _ -> false ) args ;;
  842. exception PathFound of string;;
  843. let hx_stack_push ctx output clazz func_name pos =
  844. let file = pos.pfile in
  845. let flen = String.length file in
  846. (* Not quite right - should probably test is file exists *)
  847. let stripped_file = try
  848. List.iter (fun path ->
  849. let plen = String.length path in
  850. if (flen>plen && path=(String.sub file 0 plen ))
  851. then raise (PathFound (String.sub file plen (flen-plen)) ) )
  852. (ctx.ctx_common.class_path @ ctx.ctx_common.std_path);
  853. file;
  854. with PathFound tail -> tail in
  855. let qfile = "\"" ^ (Ast.s_escape stripped_file) ^ "\"" in
  856. ctx.ctx_file_info := PMap.add qfile qfile !(ctx.ctx_file_info);
  857. if (ctx.ctx_dump_stack_line) then
  858. output ("HX_STACK_PUSH(\"" ^ clazz ^ "::" ^ func_name ^ "\"," ^ qfile ^ ","
  859. ^ (string_of_int (Lexer.get_error_line pos) ) ^ ");\n")
  860. ;;
  861. (*
  862. This is the big one.
  863. Once you get inside a function, all code is generated (recursively) as a "expression".
  864. "retval" is tracked to determine whether the value on an expression is actually used.
  865. eg, if the result of a block (ie, the last expression in the list) is used, then
  866. we have to do some funky stuff to generate a local function.
  867. Some things that change less often are stored in the context and are extracted
  868. at the top for simplicity.
  869. *)
  870. let rec define_local_function_ctx ctx func_name func_def =
  871. let writer = ctx.ctx_writer in
  872. let output_i = writer#write_i in
  873. let output = ctx.ctx_output in
  874. let remap_this = function | "this" -> "__this" | other -> other in
  875. let rec define_local_function func_name func_def =
  876. let declarations = Hashtbl.create 0 in
  877. let undeclared = Hashtbl.create 0 in
  878. (* '__global__', '__cpp__' are always defined *)
  879. Hashtbl.add declarations "__global__" ();
  880. Hashtbl.add declarations "__cpp__" ();
  881. (* Add args as defined variables *)
  882. List.iter ( fun (arg_var, opt_val) ->
  883. if (ctx.ctx_debug) then
  884. output ("/* found arg " ^ arg_var.v_name ^ " = " ^ (type_string arg_var.v_type) ^" */ ");
  885. Hashtbl.add declarations (keyword_remap arg_var.v_name) () ) func_def.tf_args;
  886. find_undeclared_variables_ctx ctx undeclared declarations "" true func_def.tf_expr;
  887. let has_this = Hashtbl.mem undeclared "this" in
  888. if (has_this) then Hashtbl.remove undeclared "this";
  889. let typed_vars = hash_iterate undeclared (fun key value -> value ^ "," ^ (keyword_remap key) ) in
  890. let func_name_sep = func_name ^ (if List.length typed_vars > 0 then "," else "") in
  891. output_i ("HX_BEGIN_LOCAL_FUNC_S" ^ (list_num typed_vars) ^ "(" ^
  892. (if has_this then "hx::LocalThisFunc," else "hx::LocalFunc,") ^ func_name_sep ^
  893. (String.concat "," typed_vars) ^ ")\n" );
  894. (* actual function, called "run" *)
  895. let args_and_types = List.map
  896. (fun (v,_) -> (type_string v.v_type) ^ " " ^ (keyword_remap v.v_name) ) func_def.tf_args in
  897. let block = is_block func_def.tf_expr in
  898. let func_type = type_string func_def.tf_type in
  899. output_i (func_type ^ " run(" ^ (gen_arg_list func_def.tf_args "__o_") ^ ")");
  900. let close_defaults =
  901. if (has_default_values func_def.tf_args) then begin
  902. writer#begin_block;
  903. output_i "";
  904. generate_default_values ctx func_def.tf_args "__o_";
  905. output_i "";
  906. true;
  907. end
  908. else
  909. false in
  910. let pop_real_this_ptr = clear_real_this_ptr ctx true in
  911. writer#begin_block;
  912. hx_stack_push ctx output_i "*" func_name func_def.tf_expr.epos;
  913. if (has_this && ctx.ctx_dump_stack_line) then
  914. output_i ("HX_STACK_THIS(__this.mPtr);\n");
  915. List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\");\n") )
  916. func_def.tf_args;
  917. if (block) then begin
  918. output_i "";
  919. gen_expression ctx false func_def.tf_expr;
  920. output_i "return null();\n";
  921. end else begin
  922. (* Save old values, and equalize for new input ... *)
  923. let pop_names = push_anon_names ctx in
  924. find_local_functions_and_return_blocks_ctx ctx false func_def.tf_expr;
  925. (match func_def.tf_expr.eexpr with
  926. | TReturn (Some return_expression) when (func_type<>"Void") ->
  927. output_i "return ";
  928. gen_expression ctx true return_expression;
  929. | TReturn (Some return_expression) ->
  930. output_i "";
  931. gen_expression ctx false return_expression;
  932. | _ ->
  933. output_i "";
  934. gen_expression ctx false (to_block func_def.tf_expr);
  935. );
  936. output ";\n";
  937. output_i "return null();\n";
  938. pop_names();
  939. end;
  940. writer#end_block;
  941. if close_defaults then writer#end_block;
  942. pop_real_this_ptr();
  943. let return = if (type_string func_def.tf_type ) = "Void" then "(void)" else "return" in
  944. output_i ("HX_END_LOCAL_FUNC" ^ (list_num args_and_types) ^ "(" ^ return ^ ")\n\n");
  945. Hashtbl.replace ctx.ctx_local_function_args func_name
  946. (if (ctx.ctx_real_this_ptr) then
  947. String.concat "," (hash_keys undeclared)
  948. else
  949. String.concat "," (List.map remap_this (hash_keys undeclared)) )
  950. in
  951. define_local_function func_name func_def
  952. and find_local_functions_and_return_blocks_ctx ctx retval expression =
  953. let output = ctx.ctx_output in
  954. let rec find_local_functions_and_return_blocks retval expression =
  955. match expression.eexpr with
  956. | TBlock _ ->
  957. if (retval) then begin
  958. define_local_return_block_ctx ctx expression (next_anon_function_name ctx);
  959. end (* else we are done *)
  960. | TMatch (_, _, _, _)
  961. | TTry (_, _)
  962. | TSwitch (_, _, _) when retval ->
  963. define_local_return_block_ctx ctx expression (next_anon_function_name ctx)
  964. | TObjectDecl ( ("fileName" , { eexpr = (TConst (TString file)) }) ::
  965. ("lineNumber" , { eexpr = (TConst (TInt line)) }) ::
  966. ("className" , { eexpr = (TConst (TString class_name)) }) ::
  967. ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) -> ()
  968. | TObjectDecl decl_list ->
  969. let name = next_anon_function_name ctx in
  970. define_local_return_block_ctx ctx expression name;
  971. (*| TCall (e,el) -> (* visit function object first, then args *)
  972. find_local_functions_and_return_blocks e;
  973. List.iter find_local_functions_and_return_blocks el *)
  974. | TFunction func ->
  975. let func_name = next_anon_function_name ctx in
  976. output "\n";
  977. define_local_function_ctx ctx func_name func
  978. | TField (obj,_) when (is_null obj) -> ( )
  979. | TArray (obj,_) when (is_null obj) -> ( )
  980. | TIf ( _ , _ , _ ) when retval -> (* ? operator style *)
  981. iter_retval find_local_functions_and_return_blocks retval expression
  982. | TMatch (_, _, _, _)
  983. | TSwitch (_, _, _) when retval -> ( )
  984. | TMatch ( cond , _, _, _)
  985. | TWhile ( cond , _, _ )
  986. | TIf ( cond , _, _ )
  987. | TSwitch ( cond , _, _) -> iter_retval find_local_functions_and_return_blocks true cond
  988. | _ -> iter_retval find_local_functions_and_return_blocks retval expression
  989. in find_local_functions_and_return_blocks retval expression
  990. and define_local_return_block_ctx ctx expression name =
  991. let writer = ctx.ctx_writer in
  992. let output_i = writer#write_i in
  993. let output = ctx.ctx_output in
  994. let check_this = function | "this" when not ctx.ctx_real_this_ptr -> "__this" | x -> x in
  995. let reference = function | "this" -> " *__this" | name -> " &" ^name in
  996. let rec define_local_return_block expression =
  997. let declarations = Hashtbl.create 0 in
  998. let undeclared = Hashtbl.create 0 in
  999. (* '__global__' is always defined *)
  1000. Hashtbl.add declarations "__global__" ();
  1001. Hashtbl.add declarations "__cpp__" ();
  1002. find_undeclared_variables_ctx ctx undeclared declarations "_obj" true expression;
  1003. let vars = (hash_keys undeclared) in
  1004. let args = String.concat "," (List.map check_this (hash_keys undeclared)) in
  1005. Hashtbl.replace ctx.ctx_local_return_block_args name args;
  1006. output_i ("struct " ^ name);
  1007. writer#begin_block;
  1008. let ret_type = match expression.eexpr with
  1009. | TObjectDecl _ -> "Dynamic" | _ -> type_string expression.etype in
  1010. output_i ("inline static " ^ ret_type ^ " Block( ");
  1011. output (String.concat "," ( (List.map (fun var ->
  1012. (Hashtbl.find undeclared var) ^ (reference var)) ) vars));
  1013. output (")");
  1014. let return_data = ret_type <> "Void" in
  1015. writer#begin_block;
  1016. hx_stack_push ctx output_i "*" "closure" expression.epos;
  1017. output_i "";
  1018. let pop_real_this_ptr = clear_real_this_ptr ctx false in
  1019. (match expression.eexpr with
  1020. | TObjectDecl decl_list ->
  1021. writer#begin_block;
  1022. output_i "hx::Anon __result = hx::Anon_obj::Create();\n";
  1023. let pop_names = push_anon_names ctx in
  1024. List.iter (function (name,value) ->
  1025. find_local_functions_and_return_blocks_ctx ctx true value;
  1026. output_i ( "__result->Add(" ^ (str name) ^ " , ");
  1027. gen_expression ctx true value;
  1028. output (if is_function_expr value then ",true" else ",false" );
  1029. output (");\n");
  1030. ) decl_list;
  1031. pop_names();
  1032. output_i "return __result;\n";
  1033. writer#end_block;
  1034. | TBlock _ ->
  1035. ctx.ctx_return_from_block <- return_data;
  1036. ctx.ctx_return_from_internal_node <- false;
  1037. gen_expression ctx false expression;
  1038. | _ ->
  1039. ctx.ctx_return_from_block <- false;
  1040. ctx.ctx_return_from_internal_node <- return_data;
  1041. gen_expression ctx false (to_block expression);
  1042. );
  1043. output_i "return null();\n";
  1044. writer#end_block;
  1045. pop_real_this_ptr();
  1046. writer#end_block_line;
  1047. output ";\n";
  1048. in
  1049. define_local_return_block expression
  1050. and gen_expression ctx retval expression =
  1051. let output = ctx.ctx_output in
  1052. let writer = ctx.ctx_writer in
  1053. let output_i = writer#write_i in
  1054. let calling = ctx.ctx_calling in
  1055. ctx.ctx_calling <- false;
  1056. let assigning = ctx.ctx_assigning in
  1057. ctx.ctx_assigning <- false;
  1058. let return_from_block = ctx.ctx_return_from_block in
  1059. ctx.ctx_return_from_block <- false;
  1060. let return_from_internal_node = ctx.ctx_return_from_internal_node in
  1061. ctx.ctx_return_from_internal_node <- false;
  1062. let dump_src_pos = ctx.ctx_dump_src_pos in
  1063. ctx.ctx_dump_src_pos <- (fun() -> ());
  1064. (* Annotate source code with debug - can get a bit verbose. Mainly for debugging code gen,
  1065. rather than the run time *)
  1066. if (ctx.ctx_debug) then begin
  1067. (*if calling then output "/* Call */";*)
  1068. (*if ctx.ctx_real_this_ptr then output "/* this */" else output "/* FAKE __this */";*)
  1069. output (debug_expression expression ctx.ctx_debug_type);
  1070. end;
  1071. (* Write comma separated list of variables - useful for function args. *)
  1072. let rec gen_expression_list expressions =
  1073. (match expressions with
  1074. | [] -> ()
  1075. | [single] -> gen_expression ctx true single
  1076. | first :: remaining ->
  1077. gen_expression ctx true first;
  1078. output ",";
  1079. gen_expression_list remaining
  1080. ) in
  1081. let rec gen_bin_op_string expr1 op expr2 =
  1082. let cast = (match op with
  1083. | ">>" | "<<" | "&" | "|" | "^" -> "int("
  1084. | "&&" | "||" -> "bool("
  1085. | "/" -> "Float("
  1086. | _ -> "") in
  1087. if (op <> "=") then output "(";
  1088. if ( cast <> "") then output cast;
  1089. gen_expression ctx true expr1;
  1090. if ( cast <> "") then output ")";
  1091. output (" " ^ op ^ " ");
  1092. if ( cast <> "") then output cast;
  1093. gen_expression ctx true expr2;
  1094. if ( cast <> "") then output ")";
  1095. if (op <> "=") then output ")";
  1096. in
  1097. let rec gen_bin_op op expr1 expr2 =
  1098. match op with
  1099. | Ast.OpAssign -> ctx.ctx_assigning <- true;
  1100. gen_bin_op_string expr1 "=" expr2
  1101. | Ast.OpUShr ->
  1102. output "hx::UShr(";
  1103. gen_expression ctx true expr1;
  1104. output ",";
  1105. gen_expression ctx true expr2;
  1106. output ")";
  1107. | Ast.OpMod ->
  1108. output "hx::Mod(";
  1109. gen_expression ctx true expr1;
  1110. output ",";
  1111. gen_expression ctx true expr2;
  1112. output ")";
  1113. | Ast.OpAssignOp bin_op ->
  1114. output (match bin_op with
  1115. | Ast.OpAdd -> "hx::AddEq("
  1116. | Ast.OpMult -> "hx::MultEq("
  1117. | Ast.OpDiv -> "hx::DivEq("
  1118. | Ast.OpSub -> "hx::SubEq("
  1119. | Ast.OpAnd -> "hx::AndEq("
  1120. | Ast.OpOr -> "hx::OrEq("
  1121. | Ast.OpXor -> "hx::XorEq("
  1122. | Ast.OpShl -> "hx::ShlEq("
  1123. | Ast.OpShr -> "hx::ShrEq("
  1124. | Ast.OpUShr -> "hx::UShrEq("
  1125. | Ast.OpMod -> "hx::ModEq("
  1126. | _ -> error "Unknown OpAssignOp" expression.epos );
  1127. ctx.ctx_assigning <- true;
  1128. gen_expression ctx true expr1;
  1129. output ",";
  1130. gen_expression ctx true expr2;
  1131. output ")"
  1132. | Ast.OpNotEq -> gen_bin_op_string expr1 "!=" expr2
  1133. | Ast.OpEq -> gen_bin_op_string expr1 "==" expr2
  1134. | _ -> gen_bin_op_string expr1 (Ast.s_binop op) expr2
  1135. in
  1136. (match expression.eexpr with
  1137. | TConst TNull when not retval ->
  1138. output "Dynamic()";
  1139. | TCall (func, arg_list) when (match func.eexpr with | TConst TSuper -> true | _ -> false ) ->
  1140. output "super::__construct(";
  1141. gen_expression_list arg_list;
  1142. output ")";
  1143. | TCall (func, arg_list) when (match func.eexpr with
  1144. | TLocal { v_name = "__cpp__" } -> true
  1145. | _ -> false) ->
  1146. ( match arg_list with
  1147. | [{ eexpr = TConst (TString code) }] -> output code;
  1148. | _ -> error "__cpp__ accepts only one string as an argument" func.epos;
  1149. )
  1150. | TCall (func, arg_list) ->
  1151. let rec is_variable e = match e.eexpr with
  1152. | TField _ -> false
  1153. | TEnumField _ -> false
  1154. | TLocal { v_name = "__global__" } -> false
  1155. | TParenthesis p -> is_variable p
  1156. | TCast (e,None) -> is_variable e
  1157. | _ -> true
  1158. in
  1159. let expr_type = type_string expression.etype in
  1160. if (ctx.ctx_debug_type) then output ("/* TCALL ret=" ^ expr_type ^ "*/");
  1161. ctx.ctx_calling <- true;
  1162. gen_expression ctx true func;
  1163. output "(";
  1164. gen_expression_list arg_list;
  1165. output ")";
  1166. if ( (is_variable func) && (expr_type<>"Dynamic") ) then
  1167. ctx.ctx_output (".Cast< " ^ expr_type ^ " >()" );
  1168. | TBlock expr_list ->
  1169. if (retval) then begin
  1170. let func_name = use_anon_function_name ctx in
  1171. (
  1172. try
  1173. output ( func_name ^ "::Block(" ^
  1174. (Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" )
  1175. with Not_found ->
  1176. (*error ("Block function " ^ func_name ^ " not found" ) expression.epos;*)
  1177. output ("/* Block function " ^ func_name ^ " not found */" );
  1178. )
  1179. end else begin
  1180. writer#begin_block;
  1181. dump_src_pos();
  1182. (* Save old values, and equalize for new input ... *)
  1183. let pop_names = push_anon_names ctx in
  1184. let remaining = ref (List.length expr_list) in
  1185. List.iter (fun expression ->
  1186. let want_value = (return_from_block && !remaining = 1) in
  1187. find_local_functions_and_return_blocks_ctx ctx want_value expression;
  1188. if (ctx.ctx_dump_stack_line) then
  1189. output_i ("HX_STACK_LINE(" ^ (string_of_int (Lexer.get_error_line expression.epos)) ^ ")\n" );
  1190. output_i "";
  1191. ctx.ctx_return_from_internal_node <- return_from_internal_node;
  1192. if (want_value) then output "return ";
  1193. gen_expression ctx want_value expression;
  1194. decr remaining;
  1195. writer#terminate_line
  1196. ) expr_list;
  1197. writer#end_block;
  1198. pop_names()
  1199. end
  1200. | TTypeExpr type_expr ->
  1201. let klass = "::" ^ (join_class_path (t_path type_expr) "::" ) in
  1202. let klass1 = if klass="::Array" then "Array<int>" else klass in
  1203. output ("hx::ClassOf< " ^ klass1 ^ " >()")
  1204. | TReturn optional_expr ->
  1205. output "";
  1206. ( match optional_expr with
  1207. | Some return_expression when ( (type_string expression.etype)="Void") ->
  1208. output "return null(";
  1209. gen_expression ctx true return_expression;
  1210. output ")";
  1211. | Some return_expression ->
  1212. output "return ";
  1213. gen_expression ctx true return_expression
  1214. | _ -> output "return null()"
  1215. )
  1216. | TConst const ->
  1217. (match const with
  1218. | TInt i -> output (Printf.sprintf "(int)%ld" i)
  1219. | TFloat float_as_string -> output float_as_string
  1220. | TString s -> output (str s)
  1221. | TBool b -> output (if b then "true" else "false")
  1222. (*| TNull -> output ("((" ^ (type_string expression.etype) ^ ")null())")*)
  1223. | TNull -> output "null()"
  1224. | TThis -> output (if ctx.ctx_real_this_ptr then "hx::ObjectPtr<OBJ_>(this)" else "__this")
  1225. | TSuper -> output ("hx::ObjectPtr<super>(" ^ (if ctx.ctx_real_this_ptr then "this" else "__this.mPtr") ^ ")")
  1226. )
  1227. | TLocal v -> output (keyword_remap v.v_name);
  1228. | TEnumField (enum, name) ->
  1229. output ("::" ^ (join_class_path enum.e_path "::") ^ "_obj::" ^ name);
  1230. if ( not calling ) then output "_dyn()";
  1231. | TArray (array_expr,_) when (is_null array_expr) -> output "Dynamic()"
  1232. | TArray (array_expr,index) ->
  1233. let dynamic = is_dynamic_in_cpp ctx array_expr in
  1234. if ( assigning && (not dynamic) ) then begin
  1235. if (is_array_implementer array_expr.etype) then begin
  1236. output "hx::__ArrayImplRef(";
  1237. gen_expression ctx true array_expr;
  1238. output ",";
  1239. gen_expression ctx true index;
  1240. output ")";
  1241. end else begin
  1242. gen_expression ctx true array_expr;
  1243. output "[";
  1244. gen_expression ctx true index;
  1245. output "]";
  1246. end
  1247. end else if (assigning) then begin
  1248. (* output (" /*" ^ (type_string array_expr.etype) ^ " */ "); *)
  1249. output "hx::IndexRef((";
  1250. gen_expression ctx true array_expr;
  1251. output ").mPtr,";
  1252. gen_expression ctx true index;
  1253. output ")";
  1254. end else if ( dynamic ) then begin
  1255. gen_expression ctx true array_expr;
  1256. output "->__GetItem(";
  1257. gen_expression ctx true index;
  1258. output ")";
  1259. end else begin
  1260. gen_expression ctx true array_expr;
  1261. output "->__get(";
  1262. gen_expression ctx true index;
  1263. output ")";
  1264. end
  1265. (* Get precidence matching haxe ? *)
  1266. | TBinop (op,expr1,expr2) -> gen_bin_op op expr1 expr2
  1267. | TField (expr,name) when (is_null expr) -> output "Dynamic()"
  1268. | TClosure (field_object,member)
  1269. | TField (field_object,member) ->
  1270. let remap_name = keyword_remap member in
  1271. let already_dynamic = ref false in
  1272. (match field_object.eexpr with
  1273. (* static access ... *)
  1274. | TTypeExpr type_def ->
  1275. let class_name = "::" ^ (join_class_path (t_path type_def) "::" ) in
  1276. if (class_name="::String") then
  1277. output ("::String::" ^ remap_name)
  1278. else
  1279. output (class_name ^ "_obj::" ^ remap_name);
  1280. (* Special internal access *)
  1281. | TLocal { v_name = "__global__" } ->
  1282. output ("::" ^ member )
  1283. | TConst TSuper -> output (if ctx.ctx_real_this_ptr then "this" else "__this");
  1284. output ("->super::" ^ remap_name)
  1285. | TConst TThis when ctx.ctx_real_this_ptr -> output ( "this->" ^ remap_name )
  1286. | TConst TNull -> output "null()"
  1287. | _ ->
  1288. gen_expression ctx true field_object;
  1289. ctx.ctx_dbgout "/* TField */";
  1290. if (is_internal_member member) then begin
  1291. output ( "->" ^ member );
  1292. end else if (is_dynamic_member_lookup_in_cpp ctx field_object member) then begin
  1293. if assigning then
  1294. output ( "->__FieldRef(" ^ (str member) ^ ")" )
  1295. else
  1296. output ( "->__Field(" ^ (str member) ^ ",true)" );
  1297. already_dynamic := true;
  1298. end else begin
  1299. if ((type_string field_object.etype)="::String" ) then
  1300. output ( "." ^ remap_name )
  1301. else begin
  1302. cast_if_required ctx field_object (type_string field_object.etype);
  1303. output ( "->" ^ remap_name )
  1304. end;
  1305. end;
  1306. );
  1307. if ( (not !already_dynamic) && (not calling) && (not assigning) && (is_function_member expression) ) then
  1308. output "_dyn()";
  1309. | TParenthesis expr when not retval ->
  1310. gen_expression ctx retval expr;
  1311. | TParenthesis expr -> output "("; gen_expression ctx retval expr; output ")"
  1312. | TObjectDecl (
  1313. ("fileName" , { eexpr = (TConst (TString file)) }) ::
  1314. ("lineNumber" , { eexpr = (TConst (TInt line)) }) ::
  1315. ("className" , { eexpr = (TConst (TString class_name)) }) ::
  1316. ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) ->
  1317. output ("hx::SourceInfo(" ^ (str file) ^ "," ^ (Printf.sprintf "%ld" line) ^ "," ^
  1318. (str class_name) ^ "," ^ (str meth) ^ ")" )
  1319. | TObjectDecl decl_list ->
  1320. let func_name = use_anon_function_name ctx in
  1321. (try output ( func_name ^ "::Block(" ^
  1322. (Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" )
  1323. with Not_found ->
  1324. output ("/* TObjectDecl block " ^ func_name ^ " not found */" ); )
  1325. | TArrayDecl decl_list ->
  1326. (* gen_type output expression.etype; *)
  1327. let tstr = (type_string_suff "_obj" expression.etype) in
  1328. if tstr="Dynamic" then
  1329. output "Dynamic( Array_obj<Dynamic>::__new()"
  1330. else
  1331. output ( (type_string_suff "_obj" expression.etype) ^ "::__new()");
  1332. List.iter ( fun elem -> output ".Add(";
  1333. gen_expression ctx true elem;
  1334. output ")" ) decl_list;
  1335. if tstr="Dynamic" then output ")";
  1336. | TNew (klass,params,expressions) ->
  1337. let is_param_array = match klass.cl_path with
  1338. | ([],"Array") when is_dynamic_array_param (List.hd params) -> true | _ -> false
  1339. in
  1340. if is_param_array then
  1341. output "Dynamic( Array_obj<Dynamic>::__new() )"
  1342. else begin
  1343. if (klass.cl_path = ([],"String")) then
  1344. output "::String("
  1345. else
  1346. output ( ( class_string klass "_obj" params) ^ "::__new(" );
  1347. gen_expression_list expressions;
  1348. output ")"
  1349. end
  1350. | TUnop (Ast.NegBits,Ast.Prefix,expr) ->
  1351. output "~(int)(";
  1352. gen_expression ctx true expr;
  1353. output ")"
  1354. | TUnop (op,Ast.Prefix,expr) ->
  1355. ctx.ctx_assigning <- (match op with Ast.Increment | Ast.Decrement -> true | _ ->false);
  1356. output (Ast.s_unop op);
  1357. output "(";
  1358. gen_expression ctx true expr;
  1359. output ")"
  1360. | TUnop (op,Ast.Postfix,expr) ->
  1361. ctx.ctx_assigning <- true;
  1362. output "(";
  1363. gen_expression ctx true expr;
  1364. output ")";
  1365. output (Ast.s_unop op)
  1366. | TFunction func ->
  1367. let func_name = use_anon_function_name ctx in
  1368. (
  1369. try
  1370. output ( " Dynamic(new " ^ func_name ^ "(" ^
  1371. (Hashtbl.find ctx.ctx_local_function_args func_name) ^ "))" )
  1372. with Not_found ->
  1373. (*error ("function " ^ func_name ^ " not found.") expression.epos; *)
  1374. output ("function " ^ func_name ^ " not found.");
  1375. )
  1376. | TVars var_list ->
  1377. let count = ref (List.length var_list) in
  1378. List.iter (fun (tvar, optional_init) ->
  1379. if (retval && !count==1) then
  1380. (match optional_init with
  1381. | None -> output "null()"
  1382. | Some expression -> gen_expression ctx true expression )
  1383. else begin
  1384. let type_name = (type_string tvar.v_type) in
  1385. output (if type_name="Void" then "Dynamic" else type_name );
  1386. let name = (keyword_remap tvar.v_name) in
  1387. output (" " ^ name );
  1388. (match optional_init with
  1389. | None -> ()
  1390. | Some expression -> output " = "; gen_expression ctx true expression);
  1391. count := !count -1;
  1392. if (ctx.ctx_dump_stack_line) then
  1393. output (";\t\tHX_STACK_VAR(" ^name ^",\""^ tvar.v_name ^"\")");
  1394. if (!count > 0) then begin output ";\n"; output_i "" end
  1395. end
  1396. ) var_list
  1397. | TFor (tvar, init, loop) ->
  1398. output ("for(::cpp::FastIterator_obj< " ^ (type_string tvar.v_type) ^
  1399. " > *__it = ::cpp::CreateFastIterator< "^(type_string tvar.v_type) ^ " >(");
  1400. gen_expression ctx true init;
  1401. output ("); __it->hasNext(); )");
  1402. ctx.ctx_writer#begin_block;
  1403. output_i ( (type_string tvar.v_type) ^ " " ^ (keyword_remap tvar.v_name) ^ " = __it->next();\n" );
  1404. output_i "";
  1405. gen_expression ctx false loop;
  1406. output ";\n";
  1407. ctx.ctx_writer#end_block;
  1408. | TIf (condition, if_expr, optional_else_expr) ->
  1409. (match optional_else_expr with
  1410. | Some else_expr ->
  1411. if (retval) then begin
  1412. output "( (";
  1413. gen_expression ctx true condition;
  1414. output ") ? ";
  1415. let type_str = match (type_string expression.etype) with
  1416. | "Void" -> "Dynamic"
  1417. | other -> other
  1418. in
  1419. output (type_str ^ "(");
  1420. gen_expression ctx true if_expr;
  1421. output ") : ";
  1422. output (type_str ^ "(");
  1423. gen_expression ctx true else_expr;
  1424. output ") )";
  1425. end else begin
  1426. output "if (";
  1427. gen_expression ctx true condition;
  1428. output ")";
  1429. gen_expression ctx false (to_block if_expr);
  1430. output_i "else";
  1431. gen_expression ctx false (to_block else_expr);
  1432. end
  1433. | _ -> output "if (";
  1434. gen_expression ctx true condition;
  1435. output ")";
  1436. gen_expression ctx false (to_block if_expr);
  1437. )
  1438. | TWhile (condition, repeat, Ast.NormalWhile ) ->
  1439. output "while(";
  1440. gen_expression ctx true condition;
  1441. output ")";
  1442. gen_expression ctx false (to_block repeat)
  1443. | TWhile (condition, repeat, Ast.DoWhile ) ->
  1444. output "do";
  1445. gen_expression ctx false (to_block repeat);
  1446. output "while(";
  1447. gen_expression ctx true condition;
  1448. output ")"
  1449. (* These have already been defined in find_local_return_blocks ... *)
  1450. | TTry (_,_)
  1451. | TSwitch (_,_,_)
  1452. | TMatch (_, _, _, _) when (retval && (not return_from_internal_node) )->
  1453. let func_name = use_anon_function_name ctx in
  1454. (try output ( func_name ^ "::Block(" ^
  1455. (Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" )
  1456. with Not_found ->
  1457. output ("/* return block " ^ func_name ^ " not found */" ); )
  1458. (*error ("return block " ^ func_name ^ " not found" ) expression.epos;*)
  1459. | TSwitch (condition,cases,optional_default) ->
  1460. let switch_on_int_constants = (only_int_cases cases) && (not (contains_break expression)) in
  1461. if (switch_on_int_constants) then begin
  1462. output "switch( (int)";
  1463. gen_expression ctx true condition;
  1464. output ")";
  1465. ctx.ctx_writer#begin_block;
  1466. List.iter (fun (cases_list,expression) ->
  1467. output_i "";
  1468. List.iter (fun value -> output "case ";
  1469. gen_expression ctx true value;
  1470. output ": " ) cases_list;
  1471. ctx.ctx_return_from_block <- return_from_internal_node;
  1472. gen_expression ctx false (to_block expression);
  1473. output_i ";break;\n";
  1474. ) cases;
  1475. (match optional_default with | None -> ()
  1476. | Some default ->
  1477. output_i "default: ";
  1478. ctx.ctx_return_from_block <- return_from_internal_node;
  1479. gen_expression ctx false (to_block default);
  1480. );
  1481. ctx.ctx_writer#end_block;
  1482. end else begin
  1483. let tmp_name = get_switch_var ctx in
  1484. output ( (type_string condition.etype) ^ " " ^ tmp_name ^ " = " );
  1485. gen_expression ctx true condition;
  1486. output ";\n";
  1487. let else_str = ref "" in
  1488. if (List.length cases > 0) then
  1489. List.iter (fun (cases,expression) ->
  1490. output_i ( !else_str ^ "if ( ");
  1491. else_str := "else ";
  1492. let or_str = ref "" in
  1493. List.iter (fun value ->
  1494. output (!or_str ^ " ( " ^ tmp_name ^ "==");
  1495. gen_expression ctx true value;
  1496. output ")";
  1497. or_str := " || ";
  1498. ) cases;
  1499. output (")");
  1500. ctx.ctx_return_from_block <- return_from_internal_node;
  1501. gen_expression ctx false (to_block expression);
  1502. ) cases;
  1503. (match optional_default with | None -> ()
  1504. | Some default ->
  1505. output_i ( !else_str ^ " ");
  1506. ctx.ctx_return_from_block <- return_from_internal_node;
  1507. gen_expression ctx false (to_block default);
  1508. output ";\n";
  1509. );
  1510. end
  1511. | TMatch (condition, enum, cases, default) ->
  1512. let tmp_var = get_switch_var ctx in
  1513. writer#begin_block;
  1514. output_i ( "::" ^ (join_class_path (fst enum).e_path "::") ^ " " ^ tmp_var ^ " = " );
  1515. gen_expression ctx true condition;
  1516. output ";\n";
  1517. let use_if_statements = contains_break expression in
  1518. let dump_condition = if (use_if_statements) then begin
  1519. let tmp_name = get_switch_var ctx in
  1520. output_i ( "int " ^ tmp_name ^ " = (" ^ tmp_var ^ ")->GetIndex();" );
  1521. let elif = ref "if" in
  1522. ( fun case_ids -> output (!elif ^ " (" ); elif := "else if";
  1523. output (String.concat "||"
  1524. (List.map (fun id -> (string_of_int id) ^ "==" ^ tmp_name ) case_ids ) );
  1525. output ") " )
  1526. end else begin
  1527. output_i ("switch((" ^ tmp_var ^ ")->GetIndex())");
  1528. ( fun case_ids ->
  1529. List.iter (fun id -> output ("case " ^ (string_of_int id) ^ ": ") ) case_ids;
  1530. )
  1531. end in
  1532. writer#begin_block;
  1533. List.iter (fun (case_ids,params,expression) ->
  1534. output_i "";
  1535. dump_condition case_ids;
  1536. let has_params = match params with | Some _ -> true | _ -> false in
  1537. if (has_params) then begin
  1538. writer#begin_block;
  1539. List.iter (fun (name,vtype,id) -> output_i
  1540. ((type_string vtype) ^ " " ^ (keyword_remap name) ^
  1541. " = " ^ tmp_var ^ "->__Param(" ^ (string_of_int id) ^ ");\n"))
  1542. (tmatch_params_to_args params);
  1543. end;
  1544. ctx.ctx_return_from_block <- return_from_internal_node;
  1545. gen_expression ctx false (to_block expression);
  1546. if (has_params) then writer#end_block;
  1547. if (not use_if_statements) then output_i ";break;\n";
  1548. ) cases;
  1549. (match default with
  1550. | None -> ()
  1551. | Some e ->
  1552. if (use_if_statements) then
  1553. output_i "else "
  1554. else
  1555. output_i "default: ";
  1556. ctx.ctx_return_from_block <- return_from_internal_node;
  1557. gen_expression ctx false (to_block e);
  1558. );
  1559. writer#end_block;
  1560. writer#end_block;
  1561. | TTry (expression, catch_list) ->
  1562. output "try";
  1563. (* Move this "inside" the try call ... *)
  1564. ctx.ctx_return_from_block <-return_from_internal_node;
  1565. gen_expression ctx false (to_block expression);
  1566. if (List.length catch_list > 0 ) then begin
  1567. output_i "catch(Dynamic __e)";
  1568. ctx.ctx_writer#begin_block;
  1569. let seen_dynamic = ref false in
  1570. let else_str = ref "" in
  1571. List.iter (fun (v,expression) ->
  1572. let type_name = type_string v.v_type in
  1573. if (type_name="Dynamic") then begin
  1574. seen_dynamic := true;
  1575. output_i !else_str;
  1576. end else
  1577. output_i (!else_str ^ "if (__e.IsClass< " ^ type_name ^ " >() )");
  1578. ctx.ctx_writer#begin_block;
  1579. output_i (type_name ^ " " ^ v.v_name ^ " = __e;");
  1580. (* Move this "inside" the catch call too ... *)
  1581. ctx.ctx_return_from_block <-return_from_internal_node;
  1582. gen_expression ctx false (to_block expression);
  1583. ctx.ctx_writer#end_block;
  1584. else_str := "else ";
  1585. ) catch_list;
  1586. if (not !seen_dynamic) then begin
  1587. output_i "else throw(__e);\n";
  1588. end;
  1589. ctx.ctx_writer#end_block;
  1590. end;
  1591. | TBreak -> output "break"
  1592. | TContinue -> output "continue"
  1593. | TThrow expression -> output "hx::Throw (";
  1594. gen_expression ctx true expression;
  1595. output ")"
  1596. | TCast (cast,None) ->
  1597. let void_cast = retval && ((type_string expression.etype)="Void" ) in
  1598. if (void_cast) then output "Void(";
  1599. gen_expression ctx retval cast;
  1600. if (void_cast) then output ")";
  1601. | TCast (e1,Some t) ->
  1602. let class_name = (join_class_path (t_path t) "::" ) in
  1603. if (class_name="Array") then
  1604. output ("hx::TCastToArray(" )
  1605. else
  1606. output ("hx::TCast< " ^ class_name ^ " >::cast(" );
  1607. gen_expression ctx true e1;
  1608. output ")";
  1609. );;
  1610. (*
  1611. let is_dynamic_haxe_method f =
  1612. match follow f.cf_type with
  1613. | TFun _ when f.cf_expr = None -> true
  1614. | _ ->
  1615. (match f.cf_expr with
  1616. | Some { eexpr = TFunction fd } when f.cf_set = MethodAccess true -> true
  1617. | Some { eexpr = TFunction fd } when f.cf_set = NormalAccess -> true
  1618. | _ -> false);;
  1619. *)
  1620. let is_dynamic_haxe_method f =
  1621. (match f.cf_expr, f.cf_kind with
  1622. | Some { eexpr = TFunction _ }, (Var _ | Method MethDynamic) -> true
  1623. | _ -> false);;
  1624. let is_data_member field =
  1625. match field.cf_expr with
  1626. | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field
  1627. | _ -> true;;
  1628. let is_override class_def field =
  1629. List.mem field class_def.cl_overrides
  1630. ;;
  1631. (* external mem Dynamic & *)
  1632. let gen_field ctx class_def class_name ptr_name is_static is_interface field =
  1633. let output = ctx.ctx_output in
  1634. ctx.ctx_real_this_ptr <- not is_static;
  1635. let remap_name = keyword_remap field.cf_name in
  1636. if (is_interface) then begin
  1637. (* Just the dynamic glue ... *)
  1638. match follow field.cf_type, field.cf_kind with
  1639. | TFun (args,result), Method _ ->
  1640. if (is_static) then output "STATIC_";
  1641. let ret = if ((type_string result ) = "Void" ) then "" else "return " in
  1642. output ("HX_DEFINE_DYNAMIC_FUNC" ^ (string_of_int (List.length args)) ^
  1643. "(" ^ class_name ^ "," ^ remap_name ^ "," ^ ret ^ ")\n\n");
  1644. | _ -> ()
  1645. end else (match field.cf_expr with
  1646. (* Function field *)
  1647. | Some { eexpr = TFunction function_def } ->
  1648. let return_type = (type_string function_def.tf_type) in
  1649. let nargs = string_of_int (List.length function_def.tf_args) in
  1650. let is_void = (type_string function_def.tf_type ) = "Void" in
  1651. let ret = if is_void then "(void)" else "return " in
  1652. let output_i = ctx.ctx_writer#write_i in
  1653. let dump_src = if (Type.has_meta ":noStack" field.cf_meta) then begin
  1654. ctx.ctx_dump_stack_line <- false;
  1655. (fun()->())
  1656. end else begin
  1657. ctx.ctx_dump_stack_line <- true;
  1658. (fun() ->
  1659. hx_stack_push ctx output_i ptr_name field.cf_name function_def.tf_expr.epos;
  1660. if (not is_static) then output_i ("HX_STACK_THIS(this);\n");
  1661. List.iter (fun (v,_) -> output_i ("HX_STACK_ARG(" ^ (keyword_remap v.v_name) ^ ",\"" ^ v.v_name ^"\");\n") )
  1662. function_def.tf_args )
  1663. end in
  1664. if (not (is_dynamic_haxe_method field)) then begin
  1665. (* The actual function definition *)
  1666. output return_type;
  1667. output (" " ^ class_name ^ "::" ^ remap_name ^ "( " );
  1668. output (gen_arg_list function_def.tf_args "__o_");
  1669. output ")";
  1670. ctx.ctx_real_this_ptr <- true;
  1671. ctx.ctx_dynamic_this_ptr <- false;
  1672. let code = (get_code field.cf_meta ":functionCode") in
  1673. let tail_code = (get_code field.cf_meta ":functionTailCode") in
  1674. if (has_default_values function_def.tf_args) then begin
  1675. ctx.ctx_writer#begin_block;
  1676. generate_default_values ctx function_def.tf_args "__o_";
  1677. dump_src();
  1678. output code;
  1679. gen_expression ctx false function_def.tf_expr;
  1680. output tail_code;
  1681. if (is_void) then output "return null();\n";
  1682. ctx.ctx_writer#end_block;
  1683. end else begin
  1684. let add_block = is_void || (code <> "") || (tail_code <> "") in
  1685. if (add_block) then ctx.ctx_writer#begin_block;
  1686. ctx.ctx_dump_src_pos <- dump_src;
  1687. output code;
  1688. gen_expression ctx false (to_block function_def.tf_expr);
  1689. output tail_code;
  1690. if (add_block) then begin
  1691. if (is_void) then output "return null();\n";
  1692. ctx.ctx_writer#end_block;
  1693. end;
  1694. end;
  1695. output "\n\n";
  1696. (* generate dynamic version too ... *)
  1697. if ( not (is_override class_def field.cf_name ) ) then begin
  1698. if (is_static) then output "STATIC_";
  1699. output ("HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^
  1700. remap_name ^ "," ^ ret ^ ")\n\n");
  1701. end;
  1702. end else begin
  1703. ctx.ctx_real_this_ptr <- false;
  1704. ctx.ctx_dynamic_this_ptr <- false;
  1705. let func_name = "__default_" ^ (remap_name) in
  1706. output ("HX_BEGIN_DEFAULT_FUNC(" ^ func_name ^ "," ^ class_name ^ ")\n");
  1707. output return_type;
  1708. output (" run(" ^ (gen_arg_list function_def.tf_args "") ^ ")");
  1709. ctx.ctx_dump_src_pos <- dump_src;
  1710. if (is_void) then begin
  1711. ctx.ctx_writer#begin_block;
  1712. gen_expression ctx false function_def.tf_expr;
  1713. output "return null();\n";
  1714. ctx.ctx_writer#end_block;
  1715. end else
  1716. gen_expression ctx false (to_block function_def.tf_expr);
  1717. output ("HX_END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n");
  1718. output ("HX_END_DEFAULT_FUNC\n\n");
  1719. if (is_static) then
  1720. output ( "Dynamic " ^ class_name ^ "::" ^ remap_name ^ ";\n\n");
  1721. end
  1722. (* Data field *)
  1723. | _ ->
  1724. if is_static then begin
  1725. gen_type ctx field.cf_type;
  1726. output ( " " ^ class_name ^ "::" ^ remap_name ^ ";\n\n");
  1727. end
  1728. )
  1729. ;;
  1730. let gen_field_init ctx field =
  1731. let output = ctx.ctx_output in
  1732. let remap_name = keyword_remap field.cf_name in
  1733. (match field.cf_expr with
  1734. (* Function field *)
  1735. | Some { eexpr = TFunction function_def } ->
  1736. if (is_dynamic_haxe_method field) then begin
  1737. let func_name = "__default_" ^ (remap_name) in
  1738. output ( " " ^ remap_name ^ " = new " ^ func_name ^ ";\n\n" );
  1739. end
  1740. (* Data field *)
  1741. | _ -> (match field.cf_expr with
  1742. | Some expr ->
  1743. find_local_functions_and_return_blocks_ctx ctx true expr;
  1744. output ( match remap_name with "__meta__" -> " __mClass->__meta__=" | _ -> " " ^ remap_name ^ "= ");
  1745. gen_expression ctx true expr;
  1746. output ";\n"
  1747. | _ -> ( )
  1748. );
  1749. )
  1750. ;;
  1751. let gen_member_def ctx class_def is_static is_interface field =
  1752. let output = ctx.ctx_output in
  1753. let remap_name = keyword_remap field.cf_name in
  1754. if (is_interface) then begin
  1755. match follow field.cf_type, field.cf_kind with
  1756. | TFun (args,return_type), Method _ ->
  1757. output ( (if (not is_static) then "virtual " else "" ) ^ type_string return_type);
  1758. output (" " ^ remap_name ^ "( " );
  1759. output (String.concat "," (List.map (fun (name,opt,typ) -> gen_interface_arg_type_name name opt typ) args));
  1760. output (if (not is_static) then ")=0;\n" else ");\n");
  1761. output (if is_static then " static " else " ");
  1762. output ("Dynamic " ^ remap_name ^ "_dyn();\n" );
  1763. | _ -> ( )
  1764. end else begin
  1765. output (if is_static then " static " else " ");
  1766. (match field.cf_expr with
  1767. | Some { eexpr = TFunction function_def } ->
  1768. if ( is_dynamic_haxe_method field ) then begin
  1769. if ( not (is_override class_def field.cf_name ) ) then begin
  1770. output ("Dynamic " ^ remap_name ^ ";\n");
  1771. output (if is_static then " static " else " ");
  1772. output ("inline Dynamic &" ^ remap_name ^ "_dyn() " ^ "{return " ^ remap_name^ "; }\n")
  1773. end
  1774. end else begin
  1775. let return_type = (type_string function_def.tf_type) in
  1776. if (not is_static) then output "virtual ";
  1777. output return_type;
  1778. output (" " ^ remap_name ^ "( " );
  1779. output (gen_arg_list function_def.tf_args "" );
  1780. output ");\n";
  1781. if ( not (is_override class_def field.cf_name ) ) then begin
  1782. output (if is_static then " static " else " ");
  1783. output ("Dynamic " ^ remap_name ^ "_dyn();\n" )
  1784. end;
  1785. end;
  1786. output "\n";
  1787. | _ ->
  1788. (* Variable access *)
  1789. gen_type ctx field.cf_type;
  1790. output (" " ^ remap_name ^ "; /* REM */ \n" );
  1791. (* Add a "dyn" function for variable to unify variable/function access *)
  1792. (match follow field.cf_type with
  1793. | TFun (_,_) ->
  1794. output (if is_static then " static " else " ");
  1795. gen_type ctx field.cf_type;
  1796. output (" &" ^ remap_name ^ "_dyn() { return " ^ remap_name ^ ";}\n" )
  1797. | _ -> (match field.cf_kind with
  1798. | Var { v_read = AccCall name } when (not is_static) && (is_dynamic_accessor name "get" field class_def) ->
  1799. output ("\t\tDynamic get_" ^ field.cf_name ^ ";\n" )
  1800. | _ -> ()
  1801. );
  1802. (match field.cf_kind with
  1803. | Var { v_write = AccCall name } when (not is_static) && (is_dynamic_accessor name "set" field class_def) ->
  1804. output ("\t\tDynamic set_" ^ field.cf_name ^ ";\n" )
  1805. | _ -> ()
  1806. )
  1807. )
  1808. );
  1809. end
  1810. ;;
  1811. (*
  1812. Get a list of all classes referred to by the class/enum definition
  1813. These are used for "#include"ing the appropriate header files.
  1814. *)
  1815. let find_referenced_types ctx obj super_deps constructor_deps header_only =
  1816. let types = ref PMap.empty in
  1817. let rec add_type in_path =
  1818. if ( not (PMap.mem in_path !types)) then begin
  1819. types := (PMap.add in_path () !types);
  1820. try
  1821. List.iter add_type (Hashtbl.find super_deps in_path);
  1822. with Not_found -> ()
  1823. end
  1824. in
  1825. let rec visit_type in_type =
  1826. match (follow in_type) with
  1827. | TMono r -> (match !r with None -> () | Some t -> visit_type t)
  1828. (*| TEnum ({ e_path = ([],"Void") },[]) -> ()
  1829. | TEnum ({ e_path = ([],"Bool") },[]) -> () *)
  1830. | TEnum (enum,params) -> add_type enum.e_path
  1831. (* If a class has a template parameter, then we treat it as dynamic - except
  1832. for the Array or Class class, for which we do a fully typed object *)
  1833. | TInst (klass,params) ->
  1834. (match klass.cl_path with
  1835. | ([],"Array") | ([],"Class") | (["cpp"],"FastIterator") -> List.iter visit_type params
  1836. | (["cpp"],"CppInt32__") -> add_type klass.cl_path;
  1837. | _ when klass.cl_extern -> ()
  1838. | _ -> if (klass.cl_kind <> KTypeParameter ) then add_type klass.cl_path;
  1839. )
  1840. | TFun (args,haxe_type) -> visit_type haxe_type;
  1841. List.iter (fun (_,_,t) -> visit_type t; ) args;
  1842. | _ -> ()
  1843. in
  1844. let rec visit_types expression =
  1845. begin
  1846. let rec visit_expression = fun expression ->
  1847. (* Expand out TTypeExpr ... *)
  1848. (match expression.eexpr with
  1849. | TTypeExpr type_def -> add_type (t_path type_def)
  1850. (* Must visit the types, Type.iter will visit the expressions ... *)
  1851. | TTry (e,catches) ->
  1852. List.iter (fun (v,_) -> visit_type v.v_type) catches
  1853. (* Must visit the enum param types, Type.iter will visit the rest ... *)
  1854. | TMatch (_,enum,cases,_) ->
  1855. add_type (fst enum).e_path;
  1856. List.iter (fun (case_ids,params,expression) ->
  1857. (match params with
  1858. | None -> ()
  1859. | Some l -> List.iter (function None -> () | Some v -> visit_type v.v_type) l ) ) cases;
  1860. (* Must visit type too, Type.iter will visit the expressions ... *)
  1861. | TNew (klass,params,_) -> begin
  1862. visit_type (TInst (klass,params));
  1863. try
  1864. let construct_type = Hashtbl.find constructor_deps klass.cl_path in
  1865. visit_type construct_type.cf_type
  1866. with Not_found -> ();
  1867. end
  1868. (* Must visit type too, Type.iter will visit the expressions ... *)
  1869. | TVars var_list ->
  1870. List.iter (fun (v, _) -> visit_type v.v_type) var_list
  1871. (* Must visit args too, Type.iter will visit the expressions ... *)
  1872. | TFunction func_def ->
  1873. List.iter (fun (v,_) -> visit_type v.v_type) func_def.tf_args;
  1874. | TConst TSuper ->
  1875. (match expression.etype with
  1876. | TInst (klass,params) ->
  1877. (try let construct_type = Hashtbl.find constructor_deps klass.cl_path in
  1878. visit_type construct_type.cf_type
  1879. with Not_found -> () )
  1880. | _ -> print_endline ("TSuper : Odd etype?")
  1881. )
  1882. | _ -> ()
  1883. );
  1884. Type.iter visit_expression expression;
  1885. visit_type (follow expression.etype)
  1886. in
  1887. visit_expression expression
  1888. end
  1889. in
  1890. let visit_field field =
  1891. (* Add the type of the expression ... *)
  1892. visit_type field.cf_type;
  1893. if (not header_only) then
  1894. (match field.cf_expr with
  1895. | Some expression -> visit_types expression | _ -> ());
  1896. in
  1897. let visit_class class_def =
  1898. let fields = List.append class_def.cl_ordered_fields class_def.cl_ordered_statics in
  1899. let fields_and_constructor = List.append fields
  1900. (match class_def.cl_constructor with | Some expr -> [expr] | _ -> [] ) in
  1901. List.iter visit_field fields_and_constructor;
  1902. (* Add super & interfaces *)
  1903. add_type class_def.cl_path;
  1904. in
  1905. let visit_enum enum_def =
  1906. add_type enum_def.e_path;
  1907. PMap.iter (fun _ constructor ->
  1908. (match constructor.ef_type with
  1909. | TFun (args,_) ->
  1910. List.iter (fun (_,_,t) -> visit_type t; ) args;
  1911. | _ -> () );
  1912. ) enum_def.e_constrs;
  1913. if (not header_only) then begin
  1914. let meta = Codegen.build_metadata ctx (TEnumDecl enum_def) in
  1915. match meta with Some expr -> visit_types expr | _ -> ();
  1916. end;
  1917. in
  1918. let inc_cmp i1 i2 =
  1919. String.compare (join_class_path i1 ".") (join_class_path i2 ".")
  1920. in
  1921. (* Body of main function *)
  1922. (match obj with
  1923. | TClassDecl class_def -> visit_class class_def;
  1924. (match class_def.cl_init with Some expression -> visit_types expression | _ -> ())
  1925. | TEnumDecl enum_def -> visit_enum enum_def
  1926. | TTypeDecl _ -> (* These are expanded *) ());
  1927. List.sort inc_cmp (List.filter (fun path -> (include_class_header path) ) (pmap_keys !types))
  1928. ;;
  1929. let generate_main common_ctx member_types super_deps class_def file_info =
  1930. (* main routine should be a single static function *)
  1931. let main_expression =
  1932. (match class_def.cl_ordered_statics with
  1933. | [{ cf_expr = Some expression }] -> expression;
  1934. | _ -> assert false ) in
  1935. let referenced = find_referenced_types common_ctx (TClassDecl class_def) super_deps (Hashtbl.create 0) false in
  1936. let generate_startup filename is_main =
  1937. (*make_class_directories base_dir ( "src" :: []);*)
  1938. let cpp_file = new_cpp_file common_ctx.file ([],filename) in
  1939. let output_main = (cpp_file#write) in
  1940. output_main "#include <hxcpp.h>\n\n";
  1941. output_main "#include <stdio.h>\n\n";
  1942. List.iter ( add_include cpp_file ) referenced;
  1943. output_main "\n\n";
  1944. output_main ( if is_main then "HX_BEGIN_MAIN\n\n" else "HX_BEGIN_LIB_MAIN\n\n" );
  1945. gen_expression (new_context common_ctx cpp_file false file_info) false main_expression;
  1946. output_main ";\n";
  1947. output_main ( if is_main then "HX_END_MAIN\n\n" else "HX_END_LIB_MAIN\n\n" );
  1948. cpp_file#close;
  1949. in
  1950. generate_startup "__main__" true;
  1951. generate_startup "__lib__" false
  1952. ;;
  1953. let generate_dummy_main common_ctx =
  1954. let generate_startup filename is_main =
  1955. let main_file = new_cpp_file common_ctx.file ([],filename) in
  1956. let output_main = (main_file#write) in
  1957. output_main "#include <hxcpp.h>\n\n";
  1958. output_main "#include <stdio.h>\n\n";
  1959. output_main ( if is_main then "HX_BEGIN_MAIN\n\n" else "HX_BEGIN_LIB_MAIN\n\n" );
  1960. output_main ( if is_main then "HX_END_MAIN\n\n" else "HX_END_LIB_MAIN\n\n" );
  1961. main_file#close;
  1962. in
  1963. generate_startup "__main__" true;
  1964. generate_startup "__lib__" false
  1965. ;;
  1966. let generate_boot common_ctx boot_classes init_classes =
  1967. (* Write boot class too ... *)
  1968. let base_dir = common_ctx.file in
  1969. let boot_file = new_cpp_file base_dir ([],"__boot__") in
  1970. let output_boot = (boot_file#write) in
  1971. output_boot "#include <hxcpp.h>\n\n";
  1972. List.iter ( fun class_path ->
  1973. output_boot ("#include <" ^
  1974. ( join_class_path (include_remap class_path) "/" ) ^ ".h>\n")
  1975. ) boot_classes;
  1976. output_boot "\nvoid __boot_all()\n{\n";
  1977. output_boot "hx::RegisterResources( hx::GetResources() );\n";
  1978. List.iter ( fun class_path ->
  1979. output_boot ("::" ^ ( join_class_path class_path "::" ) ^ "_obj::__register();\n") ) boot_classes;
  1980. List.iter ( fun class_path ->
  1981. output_boot ("::" ^ ( join_class_path class_path "::" ) ^ "_obj::__init__();\n") ) (List.rev init_classes);
  1982. let dump_boot =
  1983. List.iter ( fun class_path ->
  1984. output_boot ("::" ^ ( join_class_path class_path "::" ) ^ "_obj::__boot();\n") ) in
  1985. dump_boot (List.filter (fun path -> is_cpp_class path ) (List.rev boot_classes));
  1986. dump_boot (List.filter (fun path -> not (is_cpp_class path) ) (List.rev boot_classes));
  1987. output_boot "}\n\n";
  1988. boot_file#close;;
  1989. let generate_files common_ctx file_info =
  1990. (* Write __files__ class too ... *)
  1991. let base_dir = common_ctx.file in
  1992. let files_file = new_cpp_file base_dir ([],"__files__") in
  1993. let output_files = (files_file#write) in
  1994. output_files "#include <hxcpp.h>\n\n";
  1995. output_files "namespace hx {\n";
  1996. output_files "const char *__hxcpp_all_files[] = {\n";
  1997. output_files "#ifdef HXCPP_DEBUGGER\n";
  1998. List.iter ( fun file -> output_files (" " ^ file ^ ",\n" ) ) ( List.sort String.compare ( pmap_keys !file_info) );
  1999. output_files "#endif\n";
  2000. output_files " 0 };\n";
  2001. output_files "const char *__hxcpp_class_path[] = {\n";
  2002. output_files "#ifdef HXCPP_DEBUGGER\n";
  2003. List.iter ( fun file -> output_files (" \"" ^ file ^ "\",\n" ) ) (common_ctx.class_path @ common_ctx.std_path);
  2004. output_files "#endif\n";
  2005. output_files " 0 };\n";
  2006. output_files "} // namespace hx\n";
  2007. files_file#close;;
  2008. let begin_header_file output_h def_string =
  2009. output_h ("#ifndef INCLUDED_" ^ def_string ^ "\n");
  2010. output_h ("#define INCLUDED_" ^ def_string ^ "\n\n");
  2011. output_h "#ifndef HXCPP_H\n";
  2012. output_h "#include <hxcpp.h>\n";
  2013. output_h "#endif\n\n";;
  2014. let end_header_file output_h def_string =
  2015. output_h ("\n#endif /* INCLUDED_" ^ def_string ^ " */ \n");;
  2016. let new_placed_cpp_file common_ctx class_path =
  2017. let base_dir = common_ctx.file in
  2018. if (Common.defined common_ctx "vcproj" ) then begin
  2019. make_class_directories base_dir ("src"::[]);
  2020. cached_source_writer
  2021. ( base_dir ^ "/src/" ^ ( String.concat "-" (fst class_path) ) ^ "-" ^
  2022. (snd class_path) ^ ".cpp")
  2023. end else
  2024. new_cpp_file common_ctx.file class_path;;
  2025. let generate_enum_files common_ctx enum_def super_deps meta file_info =
  2026. let class_path = enum_def.e_path in
  2027. let just_class_name = (snd class_path) in
  2028. let class_name = just_class_name ^ "_obj" in
  2029. let smart_class_name = ("::" ^ (join_class_path class_path "::") ) in
  2030. (*let cpp_file = new_cpp_file common_ctx.file class_path in*)
  2031. let cpp_file = new_placed_cpp_file common_ctx class_path in
  2032. let output_cpp = (cpp_file#write) in
  2033. let debug = false in
  2034. let ctx = new_context common_ctx cpp_file debug file_info in
  2035. if (debug) then
  2036. print_endline ("Found enum definition:" ^ (join_class_path class_path "::" ));
  2037. output_cpp "#include <hxcpp.h>\n\n";
  2038. let referenced = find_referenced_types common_ctx (TEnumDecl enum_def) super_deps (Hashtbl.create 0) false in
  2039. List.iter (add_include cpp_file) referenced;
  2040. gen_open_namespace output_cpp class_path;
  2041. output_cpp "\n";
  2042. PMap.iter (fun _ constructor ->
  2043. let name = keyword_remap constructor.ef_name in
  2044. match constructor.ef_type with
  2045. | TFun (args,_) ->
  2046. output_cpp (smart_class_name ^ " " ^ class_name ^ "::" ^ name ^ "(" ^
  2047. (gen_tfun_arg_list args) ^")\n");
  2048. output_cpp (" { return hx::CreateEnum< " ^ class_name ^ " >(" ^ (str name) ^ "," ^
  2049. (string_of_int constructor.ef_index) ^ ",hx::DynamicArray(0," ^
  2050. (string_of_int (List.length args)) ^ ")" );
  2051. List.iter (fun (arg,_,_) -> output_cpp (".Add(" ^ (keyword_remap arg) ^ ")")) args;
  2052. output_cpp "); }\n\n"
  2053. | _ ->
  2054. output_cpp ( smart_class_name ^ " " ^ class_name ^ "::" ^ name ^ ";\n\n" )
  2055. ) enum_def.e_constrs;
  2056. output_cpp ("HX_DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n");
  2057. output_cpp ("int " ^ class_name ^ "::__FindIndex(::String inName)\n{\n");
  2058. PMap.iter (fun _ constructor ->
  2059. let name = constructor.ef_name in
  2060. let idx = string_of_int constructor.ef_index in
  2061. output_cpp (" if (inName==" ^ (str name) ^ ") return " ^ idx ^ ";\n") ) enum_def.e_constrs;
  2062. output_cpp (" return super::__FindIndex(inName);\n");
  2063. output_cpp ("}\n\n");
  2064. let constructor_arg_count constructor =
  2065. (match constructor.ef_type with | TFun(args,_) -> List.length args | _ -> 0 )
  2066. in
  2067. (* Dynamic versions of constructors *)
  2068. let dump_dynamic_constructor _ constr =
  2069. let count = constructor_arg_count constr in
  2070. if (count>0) then begin
  2071. let nargs = string_of_int count in
  2072. output_cpp ("STATIC_HX_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^
  2073. (keyword_remap constr.ef_name) ^ ",return)\n\n");
  2074. end
  2075. in
  2076. PMap.iter dump_dynamic_constructor enum_def.e_constrs;
  2077. output_cpp ("int " ^ class_name ^ "::__FindArgCount(::String inName)\n{\n");
  2078. PMap.iter (fun _ constructor ->
  2079. let name = constructor.ef_name in
  2080. let count = string_of_int (constructor_arg_count constructor) in
  2081. output_cpp (" if (inName==" ^ (str name) ^ ") return " ^ count ^ ";\n") ) enum_def.e_constrs;
  2082. output_cpp (" return super::__FindArgCount(inName);\n");
  2083. output_cpp ("}\n\n");
  2084. (* Dynamic "Get" Field function - string version *)
  2085. output_cpp ("Dynamic " ^ class_name ^ "::__Field(const ::String &inName,bool inCallProp)\n{\n");
  2086. let dump_constructor_test _ constr =
  2087. output_cpp (" if (inName==" ^ (str constr.ef_name) ^ ") return " ^
  2088. (keyword_remap constr.ef_name) );
  2089. if ( (constructor_arg_count constr) > 0 ) then output_cpp "_dyn()";
  2090. output_cpp (";\n")
  2091. in
  2092. PMap.iter dump_constructor_test enum_def.e_constrs;
  2093. output_cpp (" return super::__Field(inName,inCallProp);\n}\n\n");
  2094. output_cpp "static ::String sStaticFields[] = {\n";
  2095. let sorted =
  2096. List.sort (fun f1 f2 -> (PMap.find f1 enum_def.e_constrs ).ef_index -
  2097. (PMap.find f2 enum_def.e_constrs ).ef_index )
  2098. (pmap_keys enum_def.e_constrs) in
  2099. List.iter (fun name -> output_cpp (" " ^ (str name) ^ ",\n") ) sorted;
  2100. output_cpp " ::String(null()) };\n\n";
  2101. (* ENUM - Mark static as used by GC *)
  2102. output_cpp "static void sMarkStatics(HX_MARK_PARAMS) {\n";
  2103. PMap.iter (fun _ constructor ->
  2104. let name = keyword_remap constructor.ef_name in
  2105. match constructor.ef_type with
  2106. | TFun (_,_) -> ()
  2107. | _ -> output_cpp (" HX_MARK_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") )
  2108. enum_def.e_constrs;
  2109. output_cpp "};\n\n";
  2110. (* ENUM - Visit static as used by GC *)
  2111. output_cpp "static void sVisitStatic(HX_VISIT_PARAMS) {\n";
  2112. output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n");
  2113. PMap.iter (fun _ constructor ->
  2114. let name = keyword_remap constructor.ef_name in
  2115. match constructor.ef_type with
  2116. | TFun (_,_) -> ()
  2117. | _ -> output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ name ^ ",\"" ^ name ^ "\");\n") )
  2118. enum_def.e_constrs;
  2119. output_cpp "};\n\n";
  2120. output_cpp "static ::String sMemberFields[] = { ::String(null()) };\n";
  2121. output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n");
  2122. output_cpp ("Dynamic __Create_" ^ class_name ^ "() { return new " ^ class_name ^ "; }\n\n");
  2123. output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
  2124. let text_name = str (join_class_path class_path ".") in
  2125. output_cpp ("\nStatic(__mClass) = hx::RegisterClass(" ^ text_name ^
  2126. ", hx::TCanCast< " ^ class_name ^ " >,sStaticFields,sMemberFields,\n");
  2127. output_cpp (" &__Create_" ^ class_name ^ ", &__Create,\n");
  2128. output_cpp (" &super::__SGetClass(), &Create" ^ class_name ^ ", sMarkStatics, sVisitStatic);\n");
  2129. output_cpp ("}\n\n");
  2130. output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
  2131. (match meta with
  2132. | Some expr ->
  2133. let ctx = new_context common_ctx cpp_file false file_info in
  2134. find_local_functions_and_return_blocks_ctx ctx true expr;
  2135. output_cpp ("__mClass->__meta__ = ");
  2136. gen_expression ctx true expr;
  2137. output_cpp ";\n"
  2138. | _ -> () );
  2139. PMap.iter (fun _ constructor ->
  2140. let name = constructor.ef_name in
  2141. match constructor.ef_type with
  2142. | TFun (_,_) -> ()
  2143. | _ ->
  2144. output_cpp ( "Static(" ^ (keyword_remap name) ^ ") = hx::CreateEnum< " ^ class_name ^ " >(" ^ (str name) ^ "," ^
  2145. (string_of_int constructor.ef_index) ^ ");\n" )
  2146. ) enum_def.e_constrs;
  2147. output_cpp ("}\n\n");
  2148. output_cpp "\n";
  2149. gen_close_namespace output_cpp class_path;
  2150. cpp_file#close;
  2151. let h_file = new_header_file common_ctx.file class_path in
  2152. let super = "hx::EnumBase_obj" in
  2153. let output_h = (h_file#write) in
  2154. let def_string = join_class_path class_path "_" in
  2155. ctx.ctx_output <- output_h;
  2156. begin_header_file output_h def_string;
  2157. List.iter (gen_forward_decl h_file ) referenced;
  2158. gen_open_namespace output_h class_path;
  2159. output_h "\n\n";
  2160. output_h ("class " ^ class_name ^ " : public " ^ super ^ "\n");
  2161. output_h ("{\n typedef " ^ super ^ " super;\n");
  2162. output_h (" typedef " ^ class_name ^ " OBJ_;\n");
  2163. output_h "\n public:\n";
  2164. output_h (" " ^ class_name ^ "() {};\n");
  2165. output_h (" HX_DO_ENUM_RTTI;\n");
  2166. output_h (" static void __boot();\n");
  2167. output_h (" static void __register();\n");
  2168. output_h (" ::String GetEnumName( ) const { return " ^
  2169. (str (join_class_path class_path ".")) ^ "; }\n" );
  2170. output_h (" ::String __ToString() const { return " ^
  2171. (str (just_class_name ^ ".") )^ " + tag; }\n\n");
  2172. PMap.iter (fun _ constructor ->
  2173. let name = keyword_remap constructor.ef_name in
  2174. output_h ( " static " ^ smart_class_name ^ " " ^ name );
  2175. match constructor.ef_type with
  2176. | TFun (args,_) ->
  2177. output_h ( "(" ^ (gen_tfun_arg_list args) ^");\n");
  2178. output_h ( " static Dynamic " ^ name ^ "_dyn();\n");
  2179. | _ ->
  2180. output_h ";\n";
  2181. output_h ( " static inline " ^ smart_class_name ^ " " ^ name ^
  2182. "_dyn() { return " ^name ^ "; }\n" );
  2183. ) enum_def.e_constrs;
  2184. output_h "};\n\n";
  2185. gen_close_namespace output_h class_path;
  2186. end_header_file output_h def_string;
  2187. h_file#close;
  2188. referenced;;
  2189. let has_init_field class_def =
  2190. match class_def.cl_init with
  2191. | Some _ -> true
  2192. | _ -> false;;
  2193. let is_macro meta =
  2194. Type.has_meta ":macro" meta
  2195. ;;
  2196. let generate_class_files common_ctx member_types super_deps constructor_deps class_def file_info =
  2197. let class_path = class_def.cl_path in
  2198. let class_name = (snd class_def.cl_path) ^ "_obj" in
  2199. let smart_class_name = (snd class_def.cl_path) in
  2200. (*let cpp_file = new_cpp_file common_ctx.file class_path in*)
  2201. let cpp_file = new_placed_cpp_file common_ctx class_path in
  2202. let output_cpp = (cpp_file#write) in
  2203. let debug = false in
  2204. let ctx = new_context common_ctx cpp_file debug file_info in
  2205. ctx.ctx_class_name <- "::" ^ (join_class_path class_path "::");
  2206. ctx.ctx_class_member_types <- member_types;
  2207. if debug then print_endline ("Found class definition:" ^ ctx.ctx_class_name);
  2208. let ptr_name = "hx::ObjectPtr< " ^ class_name ^ " >" in
  2209. let constructor_type_var_list =
  2210. match class_def.cl_constructor with
  2211. | Some definition ->
  2212. (match definition.cf_expr with
  2213. | Some { eexpr = TFunction function_def } ->
  2214. List.map (fun (v,o) -> gen_arg_type_name v.v_name o v.v_type "__o_")
  2215. function_def.tf_args;
  2216. | _ ->
  2217. (match follow definition.cf_type with
  2218. | TFun (args,_) -> List.map (fun (a,_,t) -> (type_string t,a) ) args
  2219. | _ -> [])
  2220. )
  2221. | _ -> [] in
  2222. let constructor_var_list = List.map snd constructor_type_var_list in
  2223. let constructor_type_args = String.concat ","
  2224. (List.map (fun (t,a) -> t ^ " " ^ a) constructor_type_var_list) in
  2225. let constructor_args = String.concat "," constructor_var_list in
  2226. let implement_dynamic = implement_dynamic_here class_def in
  2227. output_cpp "#include <hxcpp.h>\n\n";
  2228. let field_integer_dynamic = has_field_integer_lookup class_def in
  2229. let field_integer_numeric = has_field_integer_numeric_lookup class_def in
  2230. let all_referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps constructor_deps false in
  2231. List.iter ( add_include cpp_file ) all_referenced;
  2232. (* All interfaces (and sub-interfaces) implemented *)
  2233. let implemented_hash = Hashtbl.create 0 in
  2234. List.iter (fun imp ->
  2235. let rec descend_interface interface =
  2236. let imp_path = (fst interface).cl_path in
  2237. let interface_name = "::" ^ (join_class_path imp_path "::" ) in
  2238. if ( not (Hashtbl.mem implemented_hash interface_name) ) then begin
  2239. Hashtbl.add implemented_hash interface_name ();
  2240. List.iter descend_interface (fst interface).cl_implements;
  2241. end
  2242. in descend_interface imp
  2243. ) (real_interfaces class_def.cl_implements);
  2244. let implemented = hash_keys implemented_hash in
  2245. output_cpp ( get_code class_def.cl_meta ":cppFileCode" );
  2246. gen_open_namespace output_cpp class_path;
  2247. output_cpp "\n";
  2248. output_cpp ( get_code class_def.cl_meta ":cppNamespaceCode" );
  2249. if (not class_def.cl_interface) then begin
  2250. output_cpp ("Void " ^ class_name ^ "::__construct(" ^ constructor_type_args ^ ")\n{\n");
  2251. (match class_def.cl_constructor with
  2252. | Some definition ->
  2253. (match definition.cf_expr with
  2254. | Some { eexpr = TFunction function_def } ->
  2255. hx_stack_push ctx output_cpp smart_class_name "new" function_def.tf_expr.epos;
  2256. if (has_default_values function_def.tf_args) then begin
  2257. generate_default_values ctx function_def.tf_args "__o_";
  2258. gen_expression ctx false (to_block function_def.tf_expr);
  2259. output_cpp ";\n";
  2260. end else begin
  2261. gen_expression ctx false (to_block function_def.tf_expr);
  2262. output_cpp ";\n";
  2263. (*gen_expression (new_context common_ctx cpp_file debug ) false function_def.tf_expr;*)
  2264. end
  2265. | _ -> ()
  2266. )
  2267. | _ -> ());
  2268. output_cpp " return null();\n";
  2269. output_cpp "}\n\n";
  2270. (* Destructor goes in the cpp file so we can "see" the full definition of the member vars *)
  2271. output_cpp ( class_name ^ "::~" ^ class_name ^ "() { }\n\n");
  2272. output_cpp ("Dynamic " ^ class_name ^ "::__CreateEmpty() { return new " ^ class_name ^ "; }\n");
  2273. output_cpp (ptr_name ^ " " ^ class_name ^ "::__new(" ^constructor_type_args ^")\n");
  2274. let create_result () =
  2275. output_cpp ("{ " ^ ptr_name ^ " result = new " ^ class_name ^ "();\n");
  2276. in
  2277. create_result ();
  2278. output_cpp (" result->__construct(" ^ constructor_args ^ ");\n");
  2279. output_cpp (" return result;}\n\n");
  2280. output_cpp ("Dynamic " ^ class_name ^ "::__Create(hx::DynamicArray inArgs)\n");
  2281. create_result ();
  2282. output_cpp (" result->__construct(" ^ (array_arg_list constructor_var_list) ^ ");\n");
  2283. output_cpp (" return result;}\n\n");
  2284. if ( (List.length implemented) > 0 ) then begin
  2285. output_cpp ("hx::Object *" ^ class_name ^ "::__ToInterface(const type_info &inType) {\n");
  2286. List.iter (fun interface_name ->
  2287. output_cpp (" if (inType==typeid( " ^ interface_name ^ "_obj)) " ^
  2288. "return operator " ^ interface_name ^ "_obj *();\n");
  2289. ) implemented;
  2290. output_cpp (" return super::__ToInterface(inType);\n}\n\n");
  2291. end;
  2292. end;
  2293. (match class_def.cl_init with
  2294. | Some expression ->
  2295. output_cpp ("void " ^ class_name^ "::__init__() {\n");
  2296. hx_stack_push ctx output_cpp smart_class_name "__init__" expression.epos;
  2297. gen_expression (new_context common_ctx cpp_file debug file_info) false (to_block expression);
  2298. output_cpp "}\n\n";
  2299. | _ -> ());
  2300. let statics_except_meta = (List.filter (fun static -> static.cf_name <> "__meta__") class_def.cl_ordered_statics) in
  2301. List.iter
  2302. (gen_field ctx class_def class_name smart_class_name false class_def.cl_interface)
  2303. class_def.cl_ordered_fields;
  2304. List.iter
  2305. (gen_field ctx class_def class_name smart_class_name true class_def.cl_interface) statics_except_meta;
  2306. output_cpp "\n";
  2307. (* Initialise non-static variables *)
  2308. if (not class_def.cl_interface) then begin
  2309. output_cpp (class_name ^ "::" ^ class_name ^ "()\n{\n");
  2310. if (implement_dynamic) then
  2311. output_cpp " HX_INIT_IMPLEMENT_DYNAMIC;\n";
  2312. List.iter
  2313. (fun field -> let remap_name = keyword_remap field.cf_name in
  2314. match field.cf_expr with
  2315. | Some { eexpr = TFunction function_def } ->
  2316. if (is_dynamic_haxe_method field) then
  2317. output_cpp (" " ^ remap_name ^ " = new __default_" ^ remap_name ^ "(this);\n")
  2318. | _ -> ()
  2319. )
  2320. class_def.cl_ordered_fields;
  2321. output_cpp "}\n\n";
  2322. let dump_field_iterator macro field =
  2323. if (is_data_member field) then begin
  2324. let remap_name = keyword_remap field.cf_name in
  2325. output_cpp (" " ^ macro ^ "(" ^ remap_name ^ ",\"" ^ field.cf_name^ "\");\n");
  2326. (match field.cf_kind with Var { v_read = AccCall name } when (is_dynamic_accessor name "get" field class_def) ->
  2327. output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n" ) | _ -> ());
  2328. (match field.cf_kind with Var { v_write = AccCall name } when (is_dynamic_accessor name "set" field class_def) ->
  2329. output_cpp ("\t" ^ macro ^ "(" ^ name ^ "," ^ "\"" ^ name ^ "\");\n" ) | _ -> ());
  2330. end
  2331. in
  2332. (* MARK function - explicitly mark all child pointers *)
  2333. output_cpp ("void " ^ class_name ^ "::__Mark(HX_MARK_PARAMS)\n{\n");
  2334. output_cpp (" HX_MARK_BEGIN_CLASS(" ^ smart_class_name ^ ");\n");
  2335. if (implement_dynamic) then
  2336. output_cpp " HX_MARK_DYNAMIC;\n";
  2337. List.iter (dump_field_iterator "HX_MARK_MEMBER_NAME") class_def.cl_ordered_fields;
  2338. (match class_def.cl_super with Some _ -> output_cpp " super::__Mark(HX_MARK_ARG);\n" | _ -> () );
  2339. output_cpp " HX_MARK_END_CLASS();\n";
  2340. output_cpp "}\n\n";
  2341. (* Visit function - explicitly visit all child pointers *)
  2342. output_cpp ("void " ^ class_name ^ "::__Visit(HX_VISIT_PARAMS)\n{\n");
  2343. if (implement_dynamic) then
  2344. output_cpp " HX_VISIT_DYNAMIC;\n";
  2345. List.iter (dump_field_iterator "HX_VISIT_MEMBER_NAME") class_def.cl_ordered_fields;
  2346. (match class_def.cl_super with Some _ -> output_cpp " super::__Visit(HX_VISIT_ARG);\n" | _ -> () );
  2347. output_cpp "}\n\n";
  2348. let variable_field field =
  2349. (match field.cf_expr with
  2350. | Some { eexpr = TFunction function_def } -> is_dynamic_haxe_method field
  2351. | _ -> true)
  2352. in
  2353. let all_fields = statics_except_meta @ class_def.cl_ordered_fields in
  2354. let all_variables = List.filter variable_field all_fields in
  2355. let dump_quick_field_test fields =
  2356. if ( (List.length fields) > 0) then begin
  2357. let len = function (_,l,_) -> l in
  2358. let sfields = List.sort (fun f1 f2 -> (len f1)-(len f2)) fields in
  2359. let len_case = ref (-1) in
  2360. output_cpp " switch(inName.length) {\n";
  2361. List.iter (fun (field,l,result) ->
  2362. if (l <> !len_case) then begin
  2363. if (!len_case>=0) then output_cpp " break;\n";
  2364. output_cpp (" case " ^ (string_of_int l) ^ ":\n");
  2365. len_case := l;
  2366. end;
  2367. output_cpp (" if (HX_FIELD_EQ(inName,\"" ^ (Ast.s_escape field) ^ "\") ) { " ^ result ^ " }\n");
  2368. ) sfields;
  2369. output_cpp " }\n";
  2370. end;
  2371. in
  2372. (* Dynamic "Get" Field function - string version *)
  2373. output_cpp ("Dynamic " ^ class_name ^ "::__Field(const ::String &inName,bool inCallProp)\n{\n");
  2374. let get_field_dat = List.map (fun f ->
  2375. (f.cf_name, String.length f.cf_name, "return " ^
  2376. (match f.cf_kind with
  2377. | Var { v_read = AccCall prop } -> "inCallProp ? " ^ (keyword_remap prop) ^ "() : " ^
  2378. ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()")
  2379. | _ -> ((keyword_remap f.cf_name) ^ if (variable_field f) then "" else "_dyn()")
  2380. ) ^ ";"
  2381. ) )
  2382. in
  2383. dump_quick_field_test (get_field_dat all_fields);
  2384. if (implement_dynamic) then
  2385. output_cpp " HX_CHECK_DYNAMIC_GET_FIELD(inName);\n";
  2386. output_cpp (" return super::__Field(inName,inCallProp);\n}\n\n");
  2387. (* Dynamic "Get" Field function - int version *)
  2388. if ( field_integer_numeric || field_integer_dynamic) then begin
  2389. let dump_static_ids = (fun field ->
  2390. let remap_name = keyword_remap field.cf_name in
  2391. output_cpp ("static int __id_" ^ remap_name ^ " = __hxcpp_field_to_id(\"" ^
  2392. (field.cf_name) ^ "\");\n");
  2393. ) in
  2394. List.iter dump_static_ids all_fields;
  2395. output_cpp "\n\n";
  2396. let output_ifield return_type function_name =
  2397. output_cpp (return_type ^" " ^ class_name ^ "::" ^ function_name ^ "(int inFieldID)\n{\n");
  2398. let dump_field_test = (fun f ->
  2399. let remap_name = keyword_remap f.cf_name in
  2400. output_cpp (" if (inFieldID==__id_" ^ remap_name ^ ") return " ^
  2401. ( if (return_type="Float") then "hx::ToDouble( " else "" ) ^
  2402. (match f.cf_kind with
  2403. | Var { v_read = AccCall prop } -> (keyword_remap prop) ^ "()"
  2404. | _ -> ((keyword_remap f.cf_name) ^ if ( variable_field f) then "" else "_dyn()")
  2405. ) ^ ( if (return_type="Float") then " ) " else "" ) ^ ";\n");
  2406. ) in
  2407. List.iter dump_field_test all_fields;
  2408. if (implement_dynamic) then
  2409. output_cpp " HX_CHECK_DYNAMIC_GET_INT_FIELD(inFieldID);\n";
  2410. output_cpp (" return super::" ^ function_name ^ "(inFieldID);\n}\n\n");
  2411. in
  2412. if (field_integer_dynamic) then output_ifield "Dynamic" "__IField";
  2413. if (field_integer_numeric) then output_ifield "double" "__INumField";
  2414. end;
  2415. (* Dynamic "Set" Field function *)
  2416. output_cpp ("Dynamic " ^ class_name ^ "::__SetField(const ::String &inName,const Dynamic &inValue,bool inCallProp)\n{\n");
  2417. let set_field_dat = List.map (fun f ->
  2418. (f.cf_name, String.length f.cf_name,
  2419. (match f.cf_kind with
  2420. | Var { v_write = AccCall prop } -> "if (inCallProp) return " ^ (keyword_remap prop) ^ "(inValue);"
  2421. | _ -> ""
  2422. ) ^ (keyword_remap f.cf_name) ^ "=inValue.Cast< " ^ (type_string f.cf_type) ^ " >(); return inValue;"
  2423. )
  2424. ) in
  2425. dump_quick_field_test (set_field_dat all_variables);
  2426. if (implement_dynamic) then begin
  2427. output_cpp (" try { return super::__SetField(inName,inValue,inCallProp); }\n");
  2428. output_cpp (" catch(Dynamic e) { HX_DYNAMIC_SET_FIELD(inName,inValue); }\n");
  2429. output_cpp " return inValue;\n}\n\n";
  2430. end else
  2431. output_cpp (" return super::__SetField(inName,inValue,inCallProp);\n}\n\n");
  2432. (* For getting a list of data members (eg, for serialization) *)
  2433. let append_field =
  2434. (fun field -> output_cpp (" outFields->push(" ^( str field.cf_name )^ ");\n")) in
  2435. let is_data_field field = (match follow field.cf_type with | TFun _ -> false | _ -> true) in
  2436. output_cpp ("void " ^ class_name ^ "::__GetFields(Array< ::String> &outFields)\n{\n");
  2437. List.iter append_field (List.filter is_data_field class_def.cl_ordered_fields);
  2438. if (implement_dynamic) then
  2439. output_cpp " HX_APPEND_DYNAMIC_FIELDS(outFields);\n";
  2440. output_cpp " super::__GetFields(outFields);\n";
  2441. output_cpp "};\n\n";
  2442. let dump_field_name = (fun field -> output_cpp (" " ^ (str field.cf_name) ^ ",\n")) in
  2443. output_cpp "static ::String sStaticFields[] = {\n";
  2444. List.iter dump_field_name statics_except_meta;
  2445. output_cpp " String(null()) };\n\n";
  2446. output_cpp "static ::String sMemberFields[] = {\n";
  2447. List.iter dump_field_name class_def.cl_ordered_fields;
  2448. output_cpp " String(null()) };\n\n";
  2449. end; (* cl_interface *)
  2450. (* Mark static variables as used *)
  2451. output_cpp "static void sMarkStatics(HX_MARK_PARAMS) {\n";
  2452. output_cpp (" HX_MARK_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n");
  2453. List.iter (fun field ->
  2454. if (is_data_member field) then
  2455. output_cpp (" HX_MARK_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^ field.cf_name ^ "\");\n") )
  2456. statics_except_meta;
  2457. output_cpp "};\n\n";
  2458. (* Visit static variables *)
  2459. output_cpp "static void sVisitStatics(HX_VISIT_PARAMS) {\n";
  2460. output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::__mClass,\"__mClass\");\n");
  2461. List.iter (fun field ->
  2462. if (is_data_member field) then
  2463. output_cpp (" HX_VISIT_MEMBER_NAME(" ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ",\"" ^ field.cf_name ^ "\");\n") )
  2464. statics_except_meta;
  2465. output_cpp "};\n\n";
  2466. (* Initialise static in boot function ... *)
  2467. if (not class_def.cl_interface) then begin
  2468. (* Remap the specialised "extern" classes back to the generic names *)
  2469. let class_name_text = match class_path with
  2470. | path -> join_class_path path "." in
  2471. output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n");
  2472. output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
  2473. output_cpp (" Static(__mClass) = hx::RegisterClass(" ^ (str class_name_text) ^
  2474. ", hx::TCanCast< " ^ class_name ^ "> ,sStaticFields,sMemberFields,\n");
  2475. output_cpp (" &__CreateEmpty, &__Create,\n");
  2476. output_cpp (" &super::__SGetClass(), 0, sMarkStatics, sVisitStatics);\n");
  2477. output_cpp ("}\n\n");
  2478. end else begin
  2479. let class_name_text = join_class_path class_path "." in
  2480. output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n");
  2481. output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
  2482. output_cpp (" Static(__mClass) = hx::RegisterClass(" ^ (str class_name_text) ^
  2483. ", hx::TCanCast< " ^ class_name ^ "> ,0,0,\n");
  2484. output_cpp (" 0, 0,\n");
  2485. output_cpp (" &super::__SGetClass(), 0, sMarkStatics, sVisitStatics);\n");
  2486. output_cpp ("}\n\n");
  2487. end;
  2488. output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
  2489. List.iter (gen_field_init ctx ) class_def.cl_ordered_statics;
  2490. output_cpp ("}\n\n");
  2491. gen_close_namespace output_cpp class_path;
  2492. cpp_file#close;
  2493. let h_file = new_header_file common_ctx.file class_path in
  2494. let super = match class_def.cl_super with
  2495. | Some (klass,params) -> (class_string klass "_obj" params)
  2496. | _ -> if (class_def.cl_interface) then "hx::Interface" else "hx::Object"
  2497. in
  2498. let output_h = (h_file#write) in
  2499. let def_string = join_class_path class_path "_" in
  2500. ctx.ctx_output <- output_h;
  2501. begin_header_file output_h def_string;
  2502. (* Include the real header file for the super class *)
  2503. (match class_def.cl_super with
  2504. | Some super ->
  2505. let super_path = (fst super).cl_path in
  2506. output_h ("#include <" ^ ( join_class_path super_path "/" ) ^ ".h>\n")
  2507. | _ -> () );
  2508. (* And any interfaces ... *)
  2509. List.iter (fun imp->
  2510. let imp_path = (fst imp).cl_path in
  2511. output_h ("#include <" ^ ( join_class_path imp_path "/" ) ^ ".h>\n") )
  2512. (real_interfaces class_def.cl_implements);
  2513. (* Only need to foreward-declare classes that are mentioned in the header file
  2514. (ie, not the implementation) *)
  2515. let referenced = find_referenced_types ctx.ctx_common (TClassDecl class_def) super_deps (Hashtbl.create 0) true in
  2516. List.iter ( gen_forward_decl h_file ) referenced;
  2517. output_h ( get_code class_def.cl_meta ":headerCode" );
  2518. gen_open_namespace output_h class_path;
  2519. output_h "\n\n";
  2520. output_h ( get_code class_def.cl_meta ":headerNamespaceCode" );
  2521. output_h ("class " ^ class_name ^ " : public " ^ super );
  2522. output_h "{\n public:\n";
  2523. output_h (" typedef " ^ super ^ " super;\n");
  2524. output_h (" typedef " ^ class_name ^ " OBJ_;\n");
  2525. if (not class_def.cl_interface) then begin
  2526. output_h (" " ^ class_name ^ "();\n");
  2527. output_h (" Void __construct(" ^ constructor_type_args ^ ");\n");
  2528. output_h "\n public:\n";
  2529. output_h (" static " ^ptr_name^ " __new(" ^constructor_type_args ^");\n");
  2530. output_h (" static Dynamic __CreateEmpty();\n");
  2531. output_h (" static Dynamic __Create(hx::DynamicArray inArgs);\n");
  2532. output_h (" ~" ^ class_name ^ "();\n\n");
  2533. output_h (" HX_DO_RTTI;\n");
  2534. if (field_integer_dynamic) then output_h " Dynamic __IField(int inFieldID);\n";
  2535. if (field_integer_numeric) then output_h " double __INumField(int inFieldID);\n";
  2536. if (implement_dynamic) then
  2537. output_h (" HX_DECLARE_IMPLEMENT_DYNAMIC;\n");
  2538. output_h (" static void __boot();\n");
  2539. output_h (" static void __register();\n");
  2540. output_h (" void __Mark(HX_MARK_PARAMS);\n");
  2541. output_h (" void __Visit(HX_VISIT_PARAMS);\n");
  2542. List.iter (fun interface_name ->
  2543. output_h (" inline operator " ^ interface_name ^ "_obj *()\n " ^
  2544. "{ return new " ^ interface_name ^ "_delegate_< " ^ class_name ^" >(this); }\n" );
  2545. ) implemented;
  2546. if ( (List.length implemented) > 0 ) then
  2547. output_h " hx::Object *__ToInterface(const type_info &inType);\n";
  2548. if (has_init_field class_def) then
  2549. output_h " static void __init__();\n\n";
  2550. output_h (" ::String __ToString() const { return " ^ (str smart_class_name) ^ "; }\n\n");
  2551. end else begin
  2552. output_h (" HX_DO_INTERFACE_RTTI;\n");
  2553. output_h (" static void __boot();\n");
  2554. end;
  2555. (match class_def.cl_array_access with
  2556. | Some t -> output_h (" typedef " ^ (type_string t) ^ " __array_access;\n")
  2557. | _ -> ());
  2558. let interface = class_def.cl_interface in
  2559. List.iter (gen_member_def ctx class_def false interface) class_def.cl_ordered_fields;
  2560. List.iter (gen_member_def ctx class_def true interface) class_def.cl_ordered_statics;
  2561. output_h ( get_code class_def.cl_meta ":headerClassCode" );
  2562. output_h "};\n\n";
  2563. if (class_def.cl_interface) then begin
  2564. output_h ("#define DELEGATE_" ^ (join_class_path class_def.cl_path "_" ) ^ " \\\n");
  2565. List.iter (fun field ->
  2566. match follow field.cf_type, field.cf_kind with
  2567. | TFun (args,return_type), Method _ ->
  2568. (* TODO : virtual ? *)
  2569. let remap_name = keyword_remap field.cf_name in
  2570. output_h ( "virtual " ^ (type_string return_type) ^ " " ^ remap_name ^ "( " );
  2571. output_h (String.concat "," (List.map (fun (name,opt,typ) -> gen_interface_arg_type_name name opt typ )args));
  2572. output_h (") { return mDelegate->" ^ remap_name^ "(");
  2573. output_h (String.concat "," (List.map (fun (name,opt,typ) -> (keyword_remap name)) args));
  2574. output_h ");} \\\n";
  2575. output_h ("virtual Dynamic " ^ remap_name ^ "_dyn() { return mDelegate->" ^
  2576. remap_name ^ "_dyn();} \\\n");
  2577. | _ -> ()
  2578. ) class_def.cl_ordered_fields;
  2579. output_h ("\n\n");
  2580. output_h ("template<typename IMPL>\n");
  2581. output_h ("class " ^ smart_class_name ^ "_delegate_ : public " ^ class_name^"\n");
  2582. output_h "{\n protected:\n";
  2583. output_h (" IMPL *mDelegate;\n");
  2584. output_h " public:\n";
  2585. output_h (" " ^ smart_class_name ^ "_delegate_(IMPL *inDelegate) : mDelegate(inDelegate) {}\n");
  2586. output_h (" hx::Object *__GetRealObject() { return mDelegate; }\n");
  2587. output_h (" void __Visit(HX_VISIT_PARAMS) { HX_VISIT_OBJECT(mDelegate); }\n");
  2588. let rec dump_delegate interface =
  2589. output_h (" DELEGATE_" ^ (join_class_path interface.cl_path "_" ) ^ "\n");
  2590. match interface.cl_super with | Some super -> dump_delegate (fst super) | _ -> ();
  2591. in
  2592. dump_delegate class_def;
  2593. output_h "};\n\n";
  2594. end;
  2595. gen_close_namespace output_h class_path;
  2596. end_header_file output_h def_string;
  2597. h_file#close;
  2598. all_referenced;;
  2599. let gen_deps deps =
  2600. let project_deps = List.filter (fun path -> not (is_internal_class path) ) deps in
  2601. String.concat " " (List.map (fun class_path ->
  2602. "include/" ^ (join_class_path class_path "/") ^ ".h") project_deps );;
  2603. let add_class_to_makefile makefile add_obj class_def =
  2604. let class_path = fst class_def in
  2605. let deps = snd class_def in
  2606. let obj_file = "obj/" ^ (join_class_path class_path "-") ^ "$(OBJ)" in
  2607. let cpp = (join_class_path class_path "/") ^ ".cpp" in
  2608. output_string makefile ( obj_file ^ " : src/" ^ cpp ^ " " ^ (gen_deps deps) ^ "\n");
  2609. output_string makefile ("\t$(COMPILE) src/" ^ cpp ^ " $(OUT_FLAGS)$@\n\n");
  2610. output_string makefile (add_obj ^ " " ^ obj_file ^ "\n\n" );;
  2611. let kind_string = function
  2612. | KNormal -> "KNormal"
  2613. | KTypeParameter -> "KTypeParameter"
  2614. | KExtension _ -> "KExtension"
  2615. | KExpr _ -> "KExpr"
  2616. | KGeneric -> "KGeneric"
  2617. | KMacroType -> "KMacroType"
  2618. | KGenericInstance _ -> "KGenericInstance";;
  2619. let write_resources common_ctx =
  2620. let resource_file = new_cpp_file common_ctx.file ([],"__resources__") in
  2621. resource_file#write "#include <hxcpp.h>\n\n";
  2622. let idx = ref 0 in
  2623. Hashtbl.iter (fun _ data ->
  2624. resource_file#write_i ("static unsigned char __res_" ^ (string_of_int !idx) ^ "[] = {\n");
  2625. for i = 0 to String.length data - 1 do
  2626. let code = Char.code (String.unsafe_get data i) in
  2627. resource_file#write (Printf.sprintf "0x%.2x, " code);
  2628. if ( (i mod 10) = 9) then resource_file#write "\n";
  2629. done;
  2630. resource_file#write ("};\n");
  2631. incr idx;
  2632. ) common_ctx.resources;
  2633. idx := 0;
  2634. resource_file#write "hx::Resource __Resources[] =";
  2635. resource_file#begin_block;
  2636. Hashtbl.iter (fun name data ->
  2637. resource_file#write_i
  2638. ("{ " ^ (str name) ^ "," ^ (string_of_int (String.length data)) ^ "," ^
  2639. "__res_" ^ (string_of_int !idx) ^ " },\n");
  2640. incr idx;
  2641. ) common_ctx.resources;
  2642. resource_file#write_i "{String(null()),0,0}";
  2643. resource_file#end_block_line;
  2644. resource_file#write ";\n\n";
  2645. resource_file#write "namespace hx { Resource *GetResources() { return __Resources; } } \n\n";
  2646. resource_file#close;;
  2647. let add_class_to_buildfile buildfile class_def =
  2648. let class_path = fst class_def in
  2649. let deps = snd class_def in
  2650. let cpp = (join_class_path class_path "/") ^ ".cpp" in
  2651. output_string buildfile ( " <file name=\"src/" ^ cpp ^ "\">\n" );
  2652. let project_deps = List.filter (fun path -> not (is_internal_class path) ) deps in
  2653. List.iter (fun path-> output_string buildfile (" <depend name=\"" ^
  2654. "include/" ^ (join_class_path path "/") ^ ".h\"/>\n") ) project_deps;
  2655. output_string buildfile ( " </file>\n" );;
  2656. let write_build_data filename classes main_deps build_extra exe_name =
  2657. let buildfile = open_out filename in
  2658. output_string buildfile "<xml>\n";
  2659. output_string buildfile "<files id=\"haxe\">\n";
  2660. output_string buildfile "<compilerflag value=\"-Iinclude\"/>\n";
  2661. List.iter (add_class_to_buildfile buildfile) classes;
  2662. add_class_to_buildfile buildfile ( ( [] , "__boot__") , [] );
  2663. add_class_to_buildfile buildfile ( ( [] , "__files__") , [] );
  2664. add_class_to_buildfile buildfile ( ( [] , "__resources__") , [] );
  2665. output_string buildfile "</files>\n";
  2666. output_string buildfile "<files id=\"__lib__\">\n";
  2667. output_string buildfile "<compilerflag value=\"-Iinclude\"/>\n";
  2668. add_class_to_buildfile buildfile ( ( [] , "__lib__") , main_deps );
  2669. output_string buildfile "</files>\n";
  2670. output_string buildfile "<files id=\"__main__\">\n";
  2671. output_string buildfile "<compilerflag value=\"-Iinclude\"/>\n";
  2672. add_class_to_buildfile buildfile ( ( [] , "__main__") , main_deps );
  2673. output_string buildfile "</files>\n";
  2674. output_string buildfile ("<set name=\"HAXE_OUTPUT\" value=\"" ^ exe_name ^ "\" />\n");
  2675. output_string buildfile "<include name=\"${HXCPP}/build-tool/BuildCommon.xml\"/>\n";
  2676. output_string buildfile build_extra;
  2677. output_string buildfile "</xml>\n";
  2678. close_out buildfile;;
  2679. let write_build_options filename options =
  2680. let writer = cached_source_writer filename in
  2681. PMap.iter ( fun name _ -> if (name <> "debug") then writer#write ( name ^ "\n") ) options;
  2682. let cmd = Unix.open_process_in "haxelib path hxcpp" in
  2683. writer#write (Pervasives.input_line cmd);
  2684. Pervasives.ignore (Unix.close_process_in cmd);
  2685. writer#close;;
  2686. let create_member_types common_ctx =
  2687. let result = Hashtbl.create 0 in
  2688. let add_member class_name interface member =
  2689. match follow member.cf_type, member.cf_kind with
  2690. | _, Var _ when interface -> ()
  2691. | TFun (_,ret), _ ->
  2692. (*print_endline (class_name ^ "." ^ member.cf_name ^ "=" ^ (type_string ret) );*)
  2693. Hashtbl.add result (class_name ^ "." ^ member.cf_name) (type_string ret)
  2694. | _,_ when not interface ->
  2695. Hashtbl.add result (class_name ^ "." ^ member.cf_name) (type_string member.cf_type)
  2696. | _ -> ()
  2697. in
  2698. List.iter (fun object_def ->
  2699. (match object_def with
  2700. | TClassDecl class_def ->
  2701. let class_name = "::" ^ (join_class_path class_def.cl_path "::") in
  2702. let rec add_all_fields class_def =
  2703. (match class_def.cl_super with Some super -> add_all_fields (fst super) | _->(););
  2704. List.iter (add_member class_name class_def.cl_interface) class_def.cl_ordered_fields;
  2705. List.iter (add_member class_name class_def.cl_interface) class_def.cl_ordered_statics
  2706. in
  2707. add_all_fields class_def
  2708. | _ -> ( )
  2709. ) ) common_ctx.types;
  2710. result;;
  2711. (* Builds inheritance tree, so header files can include parents defs. *)
  2712. let create_super_dependencies common_ctx =
  2713. let result = Hashtbl.create 0 in
  2714. List.iter (fun object_def ->
  2715. (match object_def with
  2716. | TClassDecl class_def ->
  2717. let deps = ref [] in
  2718. (match class_def.cl_super with Some super ->
  2719. deps := ((fst super).cl_path) :: !deps
  2720. | _ ->() );
  2721. List.iter (fun imp -> deps := (fst imp).cl_path :: !deps) (real_interfaces class_def.cl_implements);
  2722. Hashtbl.add result class_def.cl_path !deps;
  2723. | TEnumDecl enum_def ->
  2724. Hashtbl.add result enum_def.e_path [];
  2725. | _ -> () );
  2726. ) common_ctx.types;
  2727. result;;
  2728. let create_constructor_dependencies common_ctx =
  2729. let result = Hashtbl.create 0 in
  2730. List.iter (fun object_def ->
  2731. (match object_def with
  2732. | TClassDecl class_def ->
  2733. (match class_def.cl_constructor with
  2734. | Some func_def -> Hashtbl.add result class_def.cl_path func_def
  2735. | _ -> () )
  2736. | _ -> () );
  2737. ) common_ctx.types;
  2738. result;;
  2739. (* The common_ctx contains the haxe AST in the "types" field and the resources *)
  2740. let generate common_ctx =
  2741. make_base_directory common_ctx.file;
  2742. let debug = false in
  2743. let exe_classes = ref [] in
  2744. let boot_classes = ref [] in
  2745. let init_classes = ref [] in
  2746. let file_info = ref PMap.empty in
  2747. let class_text path = join_class_path path "::" in
  2748. let member_types = create_member_types common_ctx in
  2749. let super_deps = create_super_dependencies common_ctx in
  2750. let constructor_deps = create_constructor_dependencies common_ctx in
  2751. let main_deps = ref [] in
  2752. let build_xml = ref "" in
  2753. List.iter (fun object_def ->
  2754. (match object_def with
  2755. | TClassDecl class_def when class_def.cl_extern -> ()
  2756. | TClassDecl class_def ->
  2757. let name = class_text class_def.cl_path in
  2758. let is_internal = is_internal_class class_def.cl_path in
  2759. if (is_internal || (is_macro class_def.cl_meta) ) then
  2760. ( if debug then print_endline (" internal class " ^ name ))
  2761. else begin
  2762. build_xml := !build_xml ^ (get_code class_def.cl_meta ":buildXml");
  2763. boot_classes := class_def.cl_path :: !boot_classes;
  2764. if (has_init_field class_def) then
  2765. init_classes := class_def.cl_path :: !init_classes;
  2766. let deps = generate_class_files common_ctx member_types super_deps constructor_deps class_def file_info in
  2767. exe_classes := (class_def.cl_path, deps) :: !exe_classes;
  2768. end
  2769. | TEnumDecl enum_def ->
  2770. let name = class_text enum_def.e_path in
  2771. let is_internal = is_internal_class enum_def.e_path in
  2772. if (is_internal) then
  2773. (if debug then print_endline (" internal enum " ^ name ))
  2774. else begin
  2775. let meta = Codegen.build_metadata common_ctx object_def in
  2776. if (enum_def.e_extern) then
  2777. (if debug then print_endline ("external enum " ^ name ));
  2778. boot_classes := enum_def.e_path :: !boot_classes;
  2779. let deps = generate_enum_files common_ctx enum_def super_deps meta file_info in
  2780. exe_classes := (enum_def.e_path, deps) :: !exe_classes;
  2781. end
  2782. | TTypeDecl _ -> (* already done *) ()
  2783. );
  2784. ) common_ctx.types;
  2785. (match common_ctx.main with
  2786. | None -> generate_dummy_main common_ctx
  2787. | Some e ->
  2788. let main_field = { cf_name = "__main__"; cf_type = t_dynamic; cf_expr = Some e; cf_pos = e.epos; cf_public = true; cf_meta = []; cf_overloads = []; cf_doc = None; cf_kind = Var { v_read = AccNormal; v_write = AccNormal; }; cf_params = [] } in
  2789. let class_def = { null_class with cl_path = ([],"@Main"); cl_ordered_statics = [main_field] } in
  2790. main_deps := find_referenced_types common_ctx (TClassDecl class_def) super_deps constructor_deps false;
  2791. generate_main common_ctx member_types super_deps class_def file_info
  2792. );
  2793. generate_boot common_ctx !boot_classes !init_classes;
  2794. generate_files common_ctx file_info;
  2795. write_resources common_ctx;
  2796. let output_name = match common_ctx.main_class with
  2797. | Some path -> (snd path)
  2798. | _ -> "output" in
  2799. write_build_data (common_ctx.file ^ "/Build.xml") !exe_classes !main_deps !build_xml output_name;
  2800. write_build_options (common_ctx.file ^ "/Options.txt") common_ctx.defines;
  2801. if ( not (Common.defined common_ctx "no-compilation") ) then begin
  2802. let old_dir = Sys.getcwd() in
  2803. Sys.chdir common_ctx.file;
  2804. let cmd = ref "haxelib run hxcpp Build.xml haxe" in
  2805. if (common_ctx.debug) then cmd := !cmd ^ " -Ddebug";
  2806. PMap.iter ( fun name _ -> cmd := !cmd ^ " -D" ^ name ^ "" ) common_ctx.defines;
  2807. print_endline !cmd;
  2808. if Sys.command !cmd <> 0 then failwith "Build failed";
  2809. Sys.chdir old_dir;
  2810. end
  2811. ;;