gencs.ml 79 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014
  1. (*
  2. * haXe/C# & Java Compiler
  3. * Copyright (c)2011 Cauê Waneck
  4. * based on and including code by (c)2005-2008 Nicolas Cannasse, Hugh Sanderson and Franco Ponticelli
  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 Gencommon.ReflectionCFs
  21. open Ast
  22. open Common
  23. open Gencommon
  24. open Gencommon.SourceWriter
  25. open Type
  26. open Printf
  27. open Option
  28. let is_cs_basic_type t =
  29. match follow t with
  30. | TInst( { cl_path = (["haxe"], "Int32") }, [] )
  31. | TInst( { cl_path = (["haxe"], "Int64") }, [] )
  32. | TInst( { cl_path = ([], "Int") }, [] )
  33. | TInst( { cl_path = ([], "Float") }, [] )
  34. | TEnum( { e_path = ([], "Bool") }, [] ) ->
  35. true
  36. | TEnum(e, _) when not (has_meta ":$class" e.e_meta) -> true
  37. | TInst(cl, _) when has_meta ":struct" cl.cl_meta -> true
  38. | _ -> false
  39. let is_tparam t =
  40. match follow t with
  41. | TInst( { cl_kind = KTypeParameter }, [] ) -> true
  42. | _ -> false
  43. let rec is_int_float t =
  44. match follow t with
  45. | TInst( { cl_path = (["haxe"], "Int32") }, [] )
  46. | TInst( { cl_path = (["haxe"], "Int64") }, [] )
  47. | TInst( { cl_path = ([], "Int") }, [] )
  48. | TInst( { cl_path = ([], "Float") }, [] ) ->
  49. true
  50. | TInst( { cl_path = (["haxe"; "lang"], "Null") }, [t] ) -> is_int_float t
  51. | _ -> false
  52. let rec is_null t =
  53. match t with
  54. | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ )
  55. | TType( { t_path = ([], "Null") }, _ ) -> true
  56. | TType( t, tl ) -> is_null (apply_params t.t_types tl t.t_type)
  57. | TMono r ->
  58. (match !r with
  59. | Some t -> is_null t
  60. | _ -> false)
  61. | TLazy f ->
  62. is_null (!f())
  63. | _ -> false
  64. let parse_explicit_iface =
  65. let regex = Str.regexp "\\." in
  66. let parse_explicit_iface str =
  67. let split = Str.split regex str in
  68. let rec get_iface split pack =
  69. match split with
  70. | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname)
  71. | pack_piece :: tl -> get_iface tl (pack_piece :: pack)
  72. | _ -> assert false
  73. in
  74. get_iface split []
  75. in parse_explicit_iface
  76. let is_string t =
  77. match follow t with
  78. | TInst( { cl_path = ([], "String") }, [] ) -> true
  79. | _ -> false
  80. (* ******************************************* *)
  81. (* CSharpSpecificESynf *)
  82. (* ******************************************* *)
  83. (*
  84. Some CSharp-specific syntax filters that must run before ExpressionUnwrap
  85. dependencies:
  86. It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions
  87. It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr
  88. *)
  89. module CSharpSpecificESynf =
  90. struct
  91. let name = "csharp_specific_e"
  92. let priority = solve_deps name [DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter TryCatchWrapper.priority]
  93. let get_cl_from_t t =
  94. match follow t with
  95. | TInst(cl,_) -> cl
  96. | _ -> assert false
  97. let traverse gen runtime_cl =
  98. let basic = gen.gcon.basic in
  99. let uint = match ( get_type gen ([], "UInt") ) with | TTypeDecl t -> t | _ -> assert false in
  100. let is_var = alloc_var "__is__" t_dynamic in
  101. let rec run e =
  102. match e.eexpr with
  103. (* Std.is() *)
  104. | TCall(
  105. { eexpr = TField( { eexpr = TTypeExpr ( TClassDecl { cl_path = ([], "Std") } ) }, "is") },
  106. [ obj; { eexpr = TTypeExpr(TClassDecl { cl_path = [], "Dynamic" }) }]
  107. ) ->
  108. Type.map_expr run e
  109. | TCall(
  110. { eexpr = TField( { eexpr = TTypeExpr ( TClassDecl { cl_path = ([], "Std") } ) }, "is") },
  111. [ obj; { eexpr = TTypeExpr(md) }]
  112. ) ->
  113. let mk_is obj md =
  114. { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [
  115. obj;
  116. { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos }
  117. ] ) }
  118. in
  119. let obj = run obj in
  120. (match follow_module follow md with
  121. | TClassDecl{ cl_path = ([], "Float") } ->
  122. (* on the special case of seeing if it is a Float, we need to test if both it is a float and if it is an Int *)
  123. let mk_is local =
  124. mk_paren {
  125. eexpr = TBinop(Ast.OpBoolOr, mk_is local md, mk_is local (TClassDecl (get_cl_from_t basic.tint)));
  126. etype = basic.tbool;
  127. epos = e.epos
  128. }
  129. in
  130. let ret = match obj.eexpr with
  131. | TLocal(v) -> mk_is obj
  132. | _ ->
  133. let var = mk_temp gen "is" obj.etype in
  134. let added = { obj with eexpr = TVars([var, Some(obj)]); etype = basic.tvoid } in
  135. let local = mk_local var obj.epos in
  136. {
  137. eexpr = TBlock([ added; mk_is local ]);
  138. etype = basic.tbool;
  139. epos = e.epos
  140. }
  141. in
  142. ret
  143. | TClassDecl{ cl_path = ([], "Int") } ->
  144. {
  145. eexpr = TCall(
  146. mk_static_field_access_infer runtime_cl "isInt" e.epos [],
  147. [ obj ]
  148. );
  149. etype = basic.tbool;
  150. epos = e.epos
  151. }
  152. | _ ->
  153. mk_is obj md
  154. )
  155. (* end Std.is() *)
  156. | TBinop( Ast.OpUShr, e1, e2 ) ->
  157. mk_cast e.etype { e with eexpr = TBinop( Ast.OpShr, mk_cast (TType(uint,[])) (run e1), run e2 ) }
  158. | TBinop( Ast.OpAssignOp Ast.OpUShr, e1, e2 ) ->
  159. let mk_ushr local =
  160. { e with eexpr = TBinop(Ast.OpAssign, local, run { e with eexpr = TBinop(Ast.OpUShr, local, run e2) }) }
  161. in
  162. let mk_local obj =
  163. let var = mk_temp gen "opUshr" obj.etype in
  164. let added = { obj with eexpr = TVars([var, Some(obj)]); etype = basic.tvoid } in
  165. let local = mk_local var obj.epos in
  166. local, added
  167. in
  168. let e1 = run e1 in
  169. let ret = match e1.eexpr with
  170. | TField({ eexpr = TLocal _ }, _)
  171. | TField({ eexpr = TTypeExpr _ }, _)
  172. | TArray({ eexpr = TLocal _ }, _)
  173. | TLocal(_) ->
  174. mk_ushr e1
  175. | TField(fexpr, field) ->
  176. let local, added = mk_local fexpr in
  177. { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TField(local, field) } ]); }
  178. | TArray(ea1, ea2) ->
  179. let local, added = mk_local ea1 in
  180. { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TArray(local, ea2) } ]); }
  181. | _ -> (* invalid left-side expression *)
  182. assert false
  183. in
  184. ret
  185. | _ -> Type.map_expr run e
  186. in
  187. run
  188. let configure gen (mapping_func:texpr->texpr) =
  189. let map e = Some(mapping_func e) in
  190. gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
  191. end;;
  192. (* ******************************************* *)
  193. (* CSharpSpecificSynf *)
  194. (* ******************************************* *)
  195. (*
  196. Some CSharp-specific syntax filters that can run after ExprUnwrap
  197. dependencies:
  198. Runs after ExprUnwrap
  199. *)
  200. module CSharpSpecificSynf =
  201. struct
  202. let name = "csharp_specific"
  203. let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DBefore IntDivisionSynf.priority; DAfter HardNullableSynf.priority ]
  204. let get_cl_from_t t =
  205. match follow t with
  206. | TInst(cl,_) -> cl
  207. | _ -> assert false
  208. let is_tparam t =
  209. match follow t with
  210. | TInst( { cl_kind = KTypeParameter }, _ ) -> true
  211. | _ -> false
  212. let traverse gen runtime_cl =
  213. let basic = gen.gcon.basic in
  214. let tchar = match ( get_type gen (["cs"], "Char16") ) with | TTypeDecl t -> t | _ -> assert false in
  215. let tchar = TType(tchar,[]) in
  216. let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in
  217. let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in
  218. let clstring = match basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in
  219. let is_struct t = (* not basic type *)
  220. match follow t with
  221. | TInst(cl, _) when has_meta ":struct" cl.cl_meta -> true
  222. | _ -> false
  223. in
  224. let is_cl t = match gen.greal_type t with | TInst ( { cl_path = (["System"], "Type") }, [] ) -> true | _ -> false in
  225. let rec run e =
  226. match e.eexpr with
  227. (* Std.int() *)
  228. | TCall(
  229. { eexpr = TField( { eexpr = TTypeExpr ( TClassDecl ({ cl_path = ([], "Std") }) ) }, "int") },
  230. [obj]
  231. ) ->
  232. run (mk_cast basic.tint obj)
  233. (* end Std.int() *)
  234. | TField(ef, "length") when is_string ef.etype ->
  235. { e with eexpr = TField(run ef, "Length") }
  236. | TField(ef, ("toLowerCase")) when is_string ef.etype ->
  237. { e with eexpr = TField(run ef, "ToLower") }
  238. | TField(ef, ("toUpperCase")) when is_string ef.etype ->
  239. { e with eexpr = TField(run ef, "ToUpper") }
  240. | TCall( ( { eexpr = TField({ eexpr = TTypeExpr (TClassDecl cl) }, "fromCharCode") } ), [cc] ) ->
  241. { e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); mk_int gen 1 cc.epos]) }
  242. | TCall( ( { eexpr = TField({ eexpr = TTypeExpr (TTypeDecl t) }, "fromCharCode") } ), [cc] ) when is_string (follow (TType(t,List.map snd t.t_types))) ->
  243. { e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); mk_int gen 1 cc.epos]) }
  244. | TCall( ( { eexpr = TField(ef, ("charAt" as field)) } ), args )
  245. | TCall( ( { eexpr = TField(ef, ("charCodeAt" as field)) } ), args )
  246. | TCall( ( { eexpr = TField(ef, ("indexOf" as field)) } ), args )
  247. | TCall( ( { eexpr = TField(ef, ("lastIndexOf" as field)) } ), args )
  248. | TCall( ( { eexpr = TField(ef, ("split" as field)) } ), args )
  249. | TCall( ( { eexpr = TField(ef, ("substring" as field)) } ), args )
  250. | TCall( ( { eexpr = TField(ef, ("substr" as field)) } ), args ) when is_string ef.etype ->
  251. { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) }
  252. | TCast(expr, _) when is_int_float e.etype && not (is_int_float expr.etype) && not (is_null e.etype) ->
  253. let needs_cast = match gen.gfollow#run_f e.etype with
  254. | TInst _ -> false
  255. | _ -> true
  256. in
  257. let fun_name = match follow e.etype with
  258. | TInst ({ cl_path = ([], "Float") },[]) -> "toDouble"
  259. | _ -> "toInt"
  260. in
  261. let ret = {
  262. eexpr = TCall(
  263. mk_static_field_access_infer runtime_cl fun_name expr.epos [],
  264. [ run expr ]
  265. );
  266. etype = basic.tint;
  267. epos = expr.epos
  268. } in
  269. if needs_cast then mk_cast e.etype ret else ret
  270. | TCast(expr, _) when is_string e.etype ->
  271. { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) }
  272. | TBinop( (Ast.OpNotEq as op), e1, e2)
  273. | TBinop( (Ast.OpEq as op), e1, e2) when is_string e1.etype || is_string e2.etype ->
  274. let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in
  275. mk_ret { e with
  276. eexpr = TCall({
  277. eexpr = TField(mk_classtype_access clstring e.epos, "Equals");
  278. etype = TFun(["obj1",false,basic.tstring; "obj2",false,basic.tstring], basic.tbool);
  279. epos = e1.epos
  280. }, [ run e1; run e2 ])
  281. }
  282. | TCast(expr, _) when is_tparam e.etype ->
  283. let static = mk_static_field_access_infer (runtime_cl) "genericCast" e.epos [e.etype] in
  284. { e with eexpr = TCall(static, [mk_local (alloc_var "$type_param" e.etype) expr.epos; run expr]); }
  285. | TBinop( (Ast.OpNotEq as op), e1, e2)
  286. | TBinop( (Ast.OpEq as op), e1, e2) when is_struct e1.etype || is_struct e2.etype ->
  287. let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in
  288. mk_ret { e with
  289. eexpr = TCall({
  290. eexpr = TField(run e1, "Equals");
  291. etype = TFun(["obj1",false,t_dynamic;], basic.tbool);
  292. epos = e1.epos
  293. }, [ run e2 ])
  294. }
  295. | TBinop ( (Ast.OpEq as op), e1, e2 )
  296. | TBinop ( (Ast.OpNotEq as op), e1, e2 ) when is_cl e1.etype ->
  297. let static = mk_static_field_access_infer (runtime_cl) "typeEq" e.epos [] in
  298. let ret = { e with eexpr = TCall(static, [run e1; run e2]); } in
  299. if op = Ast.OpNotEq then
  300. { ret with eexpr = TUnop(Ast.Not, Ast.Prefix, ret) }
  301. else
  302. ret
  303. | _ -> Type.map_expr run e
  304. in
  305. run
  306. let configure gen (mapping_func:texpr->texpr) =
  307. let map e = Some(mapping_func e) in
  308. gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
  309. end;;
  310. (* Type Parameters Handling *)
  311. let handle_type_params gen ifaces base_generic =
  312. let basic = gen.gcon.basic in
  313. (*
  314. starting to set gtparam_cast.
  315. *)
  316. (* NativeArray: the most important. *)
  317. (*
  318. var new_arr = new NativeArray<TO_T>(old_arr.Length);
  319. var i = -1;
  320. while( i < old_arr.Length )
  321. {
  322. new_arr[i] = (TO_T) old_arr[i];
  323. }
  324. *)
  325. let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in
  326. let get_narr_param t = match follow t with
  327. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> param
  328. | _ -> assert false
  329. in
  330. let gtparam_cast_native_array e to_t =
  331. let old_param = get_narr_param e.etype in
  332. let new_param = get_narr_param to_t in
  333. let new_v = mk_temp gen "new_arr" to_t in
  334. let i = mk_temp gen "i" basic.tint in
  335. let old_len = { eexpr = TField(e, "Length"); etype = basic.tint; epos = e.epos } in
  336. let obj_v = mk_temp gen "obj" t_dynamic in
  337. let block = [
  338. {
  339. eexpr = TVars(
  340. [
  341. new_v, Some( {
  342. eexpr = TNew(native_arr_cl, [new_param], [old_len] );
  343. etype = to_t;
  344. epos = e.epos
  345. } );
  346. i, Some( mk_int gen (-1) e.epos )
  347. ]);
  348. etype = basic.tvoid;
  349. epos = e.epos };
  350. {
  351. eexpr = TWhile(
  352. {
  353. eexpr = TBinop(
  354. Ast.OpLt,
  355. { eexpr = TUnop(Ast.Increment, Ast.Prefix, mk_local i e.epos); etype = basic.tint; epos = e.epos },
  356. old_len
  357. );
  358. etype = basic.tbool;
  359. epos = e.epos
  360. },
  361. { eexpr = TBlock [
  362. {
  363. eexpr = TVars([obj_v, Some (mk_cast t_dynamic { eexpr = TArray(e, mk_local i e.epos); etype = old_param; epos = e.epos })]);
  364. etype = basic.tvoid;
  365. epos = e.epos
  366. };
  367. {
  368. eexpr = TIf({
  369. eexpr = TBinop(Ast.OpNotEq, mk_local obj_v e.epos, null e.etype e.epos);
  370. etype = basic.tbool;
  371. epos = e.epos
  372. },
  373. {
  374. eexpr = TBinop(
  375. Ast.OpAssign,
  376. { eexpr = TArray(mk_local new_v e.epos, mk_local i e.epos); etype = new_param; epos = e.epos },
  377. mk_cast new_param (mk_local obj_v e.epos)
  378. );
  379. etype = new_param;
  380. epos = e.epos
  381. },
  382. None);
  383. etype = basic.tvoid;
  384. epos = e.epos
  385. }
  386. ]; etype = basic.tvoid; epos = e.epos },
  387. Ast.NormalWhile
  388. );
  389. etype = basic.tvoid;
  390. epos = e.epos;
  391. };
  392. mk_local new_v e.epos
  393. ] in
  394. { eexpr = TBlock(block); etype = to_t; epos = e.epos }
  395. in
  396. Hashtbl.add gen.gtparam_cast (["cs"], "NativeArray") gtparam_cast_native_array;
  397. (* end set gtparam_cast *)
  398. TypeParams.RealTypeParams.default_config gen (fun e t -> gen.gcon.warning ("Cannot cast to " ^ (debug_type t)) e.epos; mk_cast t e) ifaces base_generic
  399. let connecting_string = "?" (* ? see list here http://www.fileformat.info/info/unicode/category/index.htm and here for C# http://msdn.microsoft.com/en-us/library/aa664670.aspx *)
  400. let default_package = "cs" (* I'm having this separated as I'm still not happy with having a cs package. Maybe dotnet would be better? *)
  401. let strict_mode = ref false (* strict mode is so we can check for unexpected information *)
  402. (* reserved c# words *)
  403. let reserved = let res = Hashtbl.create 120 in
  404. List.iter (fun lst -> Hashtbl.add res lst ("@" ^ lst)) ["abstract"; "as"; "base"; "bool"; "break"; "byte"; "case"; "catch"; "char"; "checked"; "class";
  405. "const"; "continue"; "decimal"; "default"; "delegate"; "do"; "double"; "else"; "enum"; "event"; "explicit";
  406. "extern"; "false"; "finally"; "fixed"; "float"; "for"; "foreach"; "goto"; "if"; "implicit"; "in"; "int";
  407. "interface"; "internal"; "is"; "lock"; "long"; "namespace"; "new"; "null"; "object"; "operator"; "out"; "override";
  408. "params"; "private"; "protected"; "public"; "readonly"; "ref"; "return"; "sbyte"; "sealed"; "short"; "sizeof";
  409. "stackalloc"; "static"; "string"; "struct"; "switch"; "this"; "throw"; "true"; "try"; "typeof"; "uint"; "ulong";
  410. "unchecked"; "unsafe"; "ushort"; "using"; "virtual"; "volatile"; "void"; "while"; "add"; "ascending"; "by"; "descending";
  411. "dynamic"; "equals"; "from"; "get"; "global"; "group"; "into"; "join"; "let"; "on"; "orderby"; "partial";
  412. "remove"; "select"; "set"; "value"; "var"; "where"; "yield"];
  413. res
  414. let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } )
  415. let rec get_class_modifiers meta cl_type cl_access cl_modifiers =
  416. match meta with
  417. | [] -> cl_type,cl_access,cl_modifiers
  418. | (":struct",[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers
  419. | (":protected",[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers
  420. | (":internal",[],_) :: meta -> get_class_modifiers meta cl_type "internal" cl_modifiers
  421. (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers)
  422. | (":static",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *)
  423. | (":final",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("sealed" :: cl_modifiers)
  424. | (":unsafe",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("unsafe" :: cl_modifiers)
  425. | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers
  426. let rec get_fun_modifiers meta access modifiers =
  427. match meta with
  428. | [] -> access,modifiers
  429. | (":protected",[],_) :: meta -> get_fun_modifiers meta "protected" modifiers
  430. | (":internal",[],_) :: meta -> get_fun_modifiers meta "internal" modifiers
  431. | (":readonly",[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers)
  432. | (":unsafe",[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers)
  433. | (":volatile",[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers)
  434. | _ :: meta -> get_fun_modifiers meta access modifiers
  435. (* this was the way I found to pass the generator context to be accessible across all functions here *)
  436. (* so 'configure' is almost 'top-level' and will have all functions needed to make this work *)
  437. let configure gen =
  438. let basic = gen.gcon.basic in
  439. let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in
  440. let null_t = (get_cl (get_type gen (["haxe";"lang"],"Null")) ) in
  441. let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in
  442. let no_root = Common.defined gen.gcon "no-root" in
  443. let change_ns = if no_root then
  444. function
  445. | [] -> ["haxe";"root"]
  446. | ns -> ns
  447. else fun ns -> ns in
  448. let change_clname n = n in
  449. let change_id name = try Hashtbl.find reserved name with | Not_found -> name in
  450. let change_field = change_id in
  451. let write_id w name = write w (change_id name) in
  452. let write_field w name = write w (change_field name) in
  453. gen.gfollow#add ~name:"follow_basic" (fun t -> match t with
  454. | TEnum ({ e_path = ([], "Bool") }, [])
  455. | TEnum ({ e_path = ([], "Void") }, [])
  456. | TInst ({ cl_path = ([],"Float") },[])
  457. | TInst ({ cl_path = ([],"Int") },[])
  458. | TType ({ t_path = [],"UInt" },[])
  459. | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
  460. | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[])
  461. | TType ({ t_path = ["cs"],"UInt64" },[])
  462. | TType ({ t_path = ["cs"],"UInt8" },[])
  463. | TType ({ t_path = ["cs"],"Int8" },[])
  464. | TType ({ t_path = ["cs"],"Int16" },[])
  465. | TType ({ t_path = ["cs"],"UInt16" },[])
  466. | TType ({ t_path = ["cs"],"Char16" },[])
  467. | TType ({ t_path = ["cs"],"Ref" },_)
  468. | TType ({ t_path = ["cs"],"Out" },_)
  469. | TType ({ t_path = [],"Single" },[]) -> Some t
  470. | TInst( { cl_path = ([], "EnumValue") }, _ ) -> Some t_dynamic
  471. | _ -> None);
  472. let path_s path = match path with
  473. | ([], "String") -> "string"
  474. | ([], "Null") -> path_s (change_ns ["haxe"; "lang"], change_clname "Null")
  475. | (ns,clname) -> path_s (change_ns ns, change_clname clname)
  476. in
  477. let ifaces = Hashtbl.create 1 in
  478. let ti64 = match ( get_type gen (["haxe";"_Int64"], "NativeInt64") ) with | TTypeDecl t -> TType(t,[]) | _ -> assert false in
  479. let ttype = get_cl ( get_type gen (["System"], "Type") ) in
  480. let rec real_type t =
  481. let t = gen.gfollow#run_f t in
  482. let ret = match t with
  483. | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint
  484. | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64
  485. | TInst( { cl_path = ([], "Class") }, _ )
  486. | TInst( { cl_path = ([], "Enum") }, _ ) -> TInst(ttype,[])
  487. | TEnum(_, [])
  488. | TInst(_, []) -> t
  489. | TInst(cl, params) when
  490. List.exists (fun t -> match follow t with | TDynamic _ -> true | _ -> false) params &&
  491. Hashtbl.mem ifaces cl.cl_path ->
  492. TInst(Hashtbl.find ifaces cl.cl_path, [])
  493. | TEnum(e, params) when
  494. List.exists (fun t -> match follow t with | TDynamic _ -> true | _ -> false) params &&
  495. Hashtbl.mem ifaces e.e_path ->
  496. TInst(Hashtbl.find ifaces e.e_path, [])
  497. | TInst(cl, params) -> TInst(cl, change_param_type (TClassDecl cl) params)
  498. | TEnum(e, params) -> TEnum(e, change_param_type (TEnumDecl e) params)
  499. | TType({ t_path = ([], "Null") }, [t]) ->
  500. (*
  501. Null<> handling is a little tricky.
  502. It will only change to haxe.lang.Null<> when the actual type is non-nullable or a type parameter
  503. It works on cases such as Hash<T> returning Null<T> since cast_detect will invoke real_type at the original type,
  504. Null<T>, which will then return the type haxe.lang.Null<>
  505. *)
  506. (match real_type t with
  507. | TInst( { cl_kind = KTypeParameter }, _ ) -> TInst(null_t, [t])
  508. | _ when is_cs_basic_type t -> TInst(null_t, [t])
  509. | _ -> real_type t)
  510. | TType _ -> t
  511. | TAnon (anon) when (match !(anon.a_status) with | Statics _ | EnumStatics _ -> true | _ -> false) -> t
  512. | TAnon _ -> dynamic_anon
  513. | TFun _ -> TInst(fn_cl,[])
  514. | _ -> t_dynamic
  515. in
  516. ret
  517. and
  518. (*
  519. On hxcs, the only type parameters allowed to be declared are the basic c# types.
  520. That's made like this to avoid casting problems when type parameters in this case
  521. add nothing to performance, since the memory layout is always the same.
  522. To avoid confusion between Generic<Dynamic> (which has a different meaning in hxcs AST),
  523. all those references are using dynamic_anon, which means Generic<{}>
  524. *)
  525. change_param_type md tl =
  526. let is_hxgeneric = (TypeParams.RealTypeParams.is_hxgeneric md) in
  527. let ret t = match is_hxgeneric, real_type t with
  528. | false, _ -> t
  529. (*
  530. Because Null<> types need a special compiler treatment for many operations (e.g. boxing/unboxing),
  531. Null<> type parameters will be transformed into Dynamic.
  532. *)
  533. | true, TInst ( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> dynamic_anon
  534. | true, TInst ( { cl_kind = KTypeParameter }, _ ) -> t
  535. | true, TInst _ | true, TEnum _ when is_cs_basic_type t -> t
  536. | true, TDynamic _ -> t
  537. | true, _ -> dynamic_anon
  538. in
  539. if is_hxgeneric && List.exists (fun t -> match follow t with | TDynamic _ -> true | _ -> false) tl then
  540. List.map (fun _ -> t_dynamic) tl
  541. else
  542. List.map ret tl
  543. in
  544. let is_dynamic t = match real_type t with
  545. | TMono _ | TDynamic _ -> true
  546. | TAnon anon ->
  547. (match !(anon.a_status) with
  548. | EnumStatics _ | Statics _ -> false
  549. | _ -> true
  550. )
  551. | _ -> false
  552. in
  553. let rec t_s t =
  554. match real_type t with
  555. (* basic types *)
  556. | TEnum ({ e_path = ([], "Bool") }, []) -> "bool"
  557. | TEnum ({ e_path = ([], "Void") }, []) -> "object"
  558. | TInst ({ cl_path = ([],"Float") },[]) -> "double"
  559. | TInst ({ cl_path = ([],"Int") },[]) -> "int"
  560. | TType ({ t_path = [],"UInt" },[]) -> "uint"
  561. | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> "long"
  562. | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[]) -> "ulong"
  563. | TType ({ t_path = ["cs"],"UInt64" },[]) -> "ulong"
  564. | TType ({ t_path = ["cs"],"UInt8" },[]) -> "byte"
  565. | TType ({ t_path = ["cs"],"Int8" },[]) -> "sbyte"
  566. | TType ({ t_path = ["cs"],"Int16" },[]) -> "short"
  567. | TType ({ t_path = ["cs"],"UInt16" },[]) -> "ushort"
  568. | TType ({ t_path = ["cs"],"Char16" },[]) -> "char"
  569. | TType ({ t_path = [],"Single" },[]) -> "float"
  570. | TInst ({ cl_path = ["haxe"],"Int32" },[]) -> "int"
  571. | TInst ({ cl_path = ["haxe"],"Int64" },[]) -> "long"
  572. | TInst ({ cl_path = ([], "Dynamic") }, _) -> "object"
  573. | TType ({ t_path = ["cs"],"Out" },[t])
  574. | TType ({ t_path = ["cs"],"Ref" },[t]) -> t_s t
  575. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
  576. let rec check_t_s t =
  577. match real_type t with
  578. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
  579. (check_t_s param) ^ "[]"
  580. | _ -> t_s (run_follow gen t)
  581. in
  582. (check_t_s param) ^ "[]"
  583. | TInst({ cl_path = (["cs"], "Pointer") }, [ t ]) ->
  584. t_s t ^ "*"
  585. (* end of basic types *)
  586. | TInst ({ cl_kind = KTypeParameter; cl_path=p }, []) -> snd p
  587. | TMono r -> (match !r with | None -> "object" | Some t -> t_s (run_follow gen t))
  588. | TInst ({ cl_path = [], "String" }, []) -> "string"
  589. | TEnum ({ e_path = p }, params) -> (path_s p)
  590. | TInst (({ cl_path = p } as cl), params) -> (path_param_s (TClassDecl cl) p params)
  591. | TType (({ t_path = p } as t), params) -> (path_param_s (TTypeDecl t) p params)
  592. | TAnon (anon) ->
  593. (match !(anon.a_status) with
  594. | Statics _ | EnumStatics _ -> "System.Type"
  595. | _ -> "object")
  596. | TDynamic _ -> "object"
  597. (* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *)
  598. | _ -> if !strict_mode then begin trace ("[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"); assert false end else "[ !TypeError " ^ (Type.s_type (Type.print_context()) t) ^ " ]"
  599. and path_param_s md path params =
  600. match params with
  601. | [] -> path_s path
  602. | _ -> sprintf "%s<%s>" (path_s path) (String.concat ", " (List.map (fun t -> t_s t) (change_param_type md params)))
  603. in
  604. let rett_s t =
  605. match t with
  606. | TEnum ({e_path = ([], "Void")}, []) -> "void"
  607. | _ -> t_s t
  608. in
  609. let argt_s t =
  610. match t with
  611. | TType ({ t_path = (["cs"], "Ref") }, [t]) -> "ref " ^ t_s t
  612. | TType ({ t_path = (["cs"], "Out") }, [t]) -> "out " ^ t_s t
  613. | _ -> t_s t
  614. in
  615. let escape ichar b =
  616. match ichar with
  617. | 92 (* \ *) -> Buffer.add_string b "\\\\"
  618. | 39 (* ' *) -> Buffer.add_string b "\\\'"
  619. | 34 -> Buffer.add_string b "\\\""
  620. | 13 (* \r *) -> Buffer.add_string b "\\r"
  621. | 10 (* \n *) -> Buffer.add_string b "\\n"
  622. | 9 (* \t *) -> Buffer.add_string b "\\t"
  623. | c when c < 32 || c >= 127 -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c)
  624. | c -> Buffer.add_char b (Char.chr c)
  625. in
  626. let escape s =
  627. let b = Buffer.create 0 in
  628. (try
  629. UTF8.validate s;
  630. UTF8.iter (fun c -> escape (UChar.code c) b) s
  631. with
  632. UTF8.Malformed_code ->
  633. String.iter (fun c -> escape (Char.code c) b) s
  634. );
  635. Buffer.contents b
  636. in
  637. let has_semicolon e =
  638. match e.eexpr with
  639. | TBlock _ | TFor _ | TSwitch _ | TMatch _ | TTry _ | TIf _ -> false
  640. | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
  641. | _ -> true
  642. in
  643. let in_value = ref false in
  644. let rec md_s md =
  645. let md = follow_module (gen.gfollow#run_f) md in
  646. match md with
  647. | TClassDecl ({ cl_types = [] } as cl) ->
  648. t_s (TInst(cl,[]))
  649. | TClassDecl (cl) when not (is_hxgen md) ->
  650. t_s (TInst(cl,List.map (fun t -> t_dynamic) cl.cl_types))
  651. | TEnumDecl ({ e_types = [] } as e) ->
  652. t_s (TEnum(e,[]))
  653. | TEnumDecl (e) when not (is_hxgen md) ->
  654. t_s (TEnum(e,List.map (fun t -> t_dynamic) e.e_types))
  655. | TClassDecl cl ->
  656. t_s (TInst(cl,[]))
  657. | TEnumDecl e ->
  658. t_s (TEnum(e,[]))
  659. | TTypeDecl t ->
  660. t_s (TType(t, List.map (fun t -> t_dynamic) t.t_types))
  661. in
  662. let rec ensure_local e explain =
  663. match e.eexpr with
  664. | TLocal _ -> e
  665. | TCast(e,_)
  666. | TParenthesis e -> ensure_local e explain
  667. | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e
  668. in
  669. let is_pointer t = match follow t with | TInst({ cl_path = (["cs"], "Pointer") }, _) -> true | _ -> false in
  670. let expr_s w e =
  671. in_value := false;
  672. let rec expr_s w e =
  673. let was_in_value = !in_value in
  674. in_value := true;
  675. (match e.eexpr with
  676. | TConst c ->
  677. (match c with
  678. | TInt i32 ->
  679. write w (Int32.to_string i32);
  680. (*match real_type e.etype with
  681. | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) -> write w "L";
  682. | _ -> ()
  683. *)
  684. | TFloat s ->
  685. write w s;
  686. (if String.get s (String.length s - 1) = '.' then write w "0");
  687. (*match real_type e.etype with
  688. | TType( { t_path = ([], "Single") }, [] ) -> write w "f"
  689. | _ -> ()
  690. *)
  691. | TString s ->
  692. write w "\"";
  693. write w (escape s);
  694. write w "\""
  695. | TBool b -> write w (if b then "true" else "false")
  696. | TNull ->
  697. write w "default(";
  698. write w (t_s e.etype);
  699. write w ")"
  700. | TThis -> write w "this"
  701. | TSuper -> write w "base")
  702. | TLocal { v_name = "__sbreak__" } -> write w "break"
  703. | TLocal { v_name = "__undefined__" } ->
  704. write w (t_s (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types)));
  705. write w ".undefined";
  706. | TLocal { v_name = "__typeof__" } -> write w "typeof"
  707. | TLocal { v_name = "__sizeof__" } -> write w "sizeof"
  708. | TLocal var ->
  709. write_id w var.v_name
  710. | TEnumField (e, s) ->
  711. print w "%s." (path_s e.e_path); write_field w s
  712. | TArray (e1, e2) ->
  713. expr_s w e1; write w "["; expr_s w e2; write w "]"
  714. | TBinop ((Ast.OpAssign as op), e1, e2)
  715. | TBinop ((Ast.OpAssignOp _ as op), e1, e2) ->
  716. expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2
  717. | TBinop (op, e1, e2) ->
  718. write w "( ";
  719. expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2;
  720. write w " )"
  721. | TField (e, s) | TClosure (e, s) ->
  722. expr_s w e; write w "."; write_field w s
  723. | TTypeExpr mt ->
  724. (match mt with
  725. | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w (path_s (["haxe"], "Int64"))
  726. | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w (path_s (["haxe"], "Int32"))
  727. | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_empty) cl.cl_types)))
  728. | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_empty) en.e_types)))
  729. | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_empty) td.t_types)))) )
  730. | TParenthesis e ->
  731. write w "("; expr_s w e; write w ")"
  732. | TArrayDecl el ->
  733. print w "new %s" (t_s e.etype);
  734. write w "{";
  735. ignore (List.fold_left (fun acc e ->
  736. (if acc <> 0 then write w ", ");
  737. expr_s w e;
  738. acc + 1
  739. ) 0 el);
  740. write w "}"
  741. | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) ->
  742. write w "( ";
  743. expr_s w expr;
  744. write w " is ";
  745. write w (md_s md);
  746. write w " )"
  747. | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) ->
  748. write w "( ";
  749. expr_s w expr;
  750. write w " as ";
  751. write w (md_s md);
  752. write w " )"
  753. | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) ->
  754. write w s
  755. | TCall ({ eexpr = TLocal( { v_name = "__unsafe__" } ) }, [ e ] ) ->
  756. write w "unsafe";
  757. expr_s w (mk_block e)
  758. | TCall ({ eexpr = TLocal( { v_name = "__checked__" } ) }, [ e ] ) ->
  759. write w "checked";
  760. expr_s w (mk_block e)
  761. | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) ->
  762. write w "lock(";
  763. expr_s w eobj;
  764. write w ")";
  765. expr_s w (mk_block eblock)
  766. | TCall ({ eexpr = TLocal( { v_name = "__fixed__" } ) }, [ e ] ) ->
  767. let first = ref true in
  768. let rec loop = function
  769. | ({ eexpr = TVars([v, Some({ eexpr = TCast( { eexpr = TCast(e, _) }, _) }) ]) } as expr) :: tl when is_pointer v.v_type ->
  770. (if !first then first := false);
  771. write w "fixed(";
  772. let vf = mk_temp gen "fixed" v.v_type in
  773. expr_s w { expr with eexpr = TVars([vf, Some e]) };
  774. write w ")";
  775. begin_block w;
  776. expr_s w { expr with eexpr = TVars([v, Some (mk_local vf expr.epos)]) };
  777. write w ";";
  778. loop tl;
  779. end_block w
  780. | el when not !first ->
  781. expr_s w { e with eexpr = TBlock el }
  782. | _ ->
  783. trace (debug_expr e);
  784. gen.gcon.error "Invalid 'fixed' keyword format" e.epos
  785. in
  786. (match e.eexpr with
  787. | TBlock bl -> loop bl
  788. | _ ->
  789. trace "not block";
  790. trace (debug_expr e);
  791. gen.gcon.error "Invalid 'fixed' keyword format" e.epos
  792. )
  793. | TCall ({ eexpr = TLocal( { v_name = "__addressOf__" } ) }, [ e ] ) ->
  794. let e = ensure_local e "for addressOf" in
  795. write w "&";
  796. expr_s w e
  797. | TCall ({ eexpr = TLocal( { v_name = "__valueOf__" } ) }, [ e ] ) ->
  798. write w "*(";
  799. expr_s w e;
  800. write w ")"
  801. | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
  802. print w "goto label%ld" v
  803. | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
  804. print w "label%ld: {}" v
  805. | TCall ({ eexpr = TLocal( { v_name = "__rethrow__" } ) }, _) ->
  806. write w "throw"
  807. | TCall (e, el) ->
  808. let rec extract_tparams params el =
  809. match el with
  810. | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl ->
  811. extract_tparams (tp.etype :: params) tl
  812. | _ -> (params, el)
  813. in
  814. let params, el = extract_tparams [] el in
  815. let params = List.rev params in
  816. expr_s w e;
  817. (match params with
  818. | [] -> ()
  819. | params ->
  820. let md = match e.eexpr with
  821. | TField(ef, _) -> t_to_md (run_follow gen ef.etype)
  822. | _ -> assert false
  823. in
  824. write w "<";
  825. ignore (List.fold_left (fun acc t ->
  826. (if acc <> 0 then write w ", ");
  827. write w (t_s t);
  828. acc + 1
  829. ) 0 (change_param_type md params));
  830. write w ">"
  831. );
  832. let rec loop acc elist tlist =
  833. match elist, tlist with
  834. | e :: etl, (_,_,t) :: ttl ->
  835. (if acc <> 0 then write w ", ");
  836. (match real_type t with
  837. | TType({ t_path = (["cs"], "Ref") }, _) ->
  838. let e = ensure_local e "of type cs.Ref" in
  839. write w "ref ";
  840. expr_s w e
  841. | TType({ t_path = (["cs"], "Out") }, _) ->
  842. let e = ensure_local e "of type cs.Out" in
  843. write w "out ";
  844. expr_s w e
  845. | _ ->
  846. expr_s w e
  847. );
  848. loop (acc + 1) etl ttl
  849. | e :: etl, [] ->
  850. (if acc <> 0 then write w ", ");
  851. expr_s w e;
  852. loop (acc + 1) etl []
  853. | _ -> ()
  854. in
  855. write w "(";
  856. let ft = match follow e.etype with
  857. | TFun(args,_) -> args
  858. | _ -> []
  859. in
  860. loop 0 el ft;
  861. write w ")"
  862. | TNew (({ cl_path = (["cs"], "NativeArray") } as cl), params, [ size ]) ->
  863. let rec check_t_s t times =
  864. match real_type t with
  865. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
  866. (check_t_s param (times+1))
  867. | _ ->
  868. print w "new %s[" (t_s (run_follow gen t));
  869. expr_s w size;
  870. print w "]";
  871. let rec loop i =
  872. if i <= 0 then () else (write w "[]"; loop (i-1))
  873. in
  874. loop (times - 1)
  875. in
  876. check_t_s (TInst(cl, params)) 0
  877. | TNew ({ cl_path = ([], "String") } as cl, [], el) ->
  878. write w "new ";
  879. write w (t_s (TInst(cl, [])));
  880. write w "(";
  881. ignore (List.fold_left (fun acc e ->
  882. (if acc <> 0 then write w ", ");
  883. expr_s w e;
  884. acc + 1
  885. ) 0 el);
  886. write w ")"
  887. | TNew (cl, params, el) ->
  888. write w "new ";
  889. write w (path_param_s (TClassDecl cl) cl.cl_path params);
  890. write w "(";
  891. ignore (List.fold_left (fun acc e ->
  892. (if acc <> 0 then write w ", ");
  893. expr_s w e;
  894. acc + 1
  895. ) 0 el);
  896. write w ")"
  897. | TUnop ((Ast.Increment as op), flag, e)
  898. | TUnop ((Ast.Decrement as op), flag, e) ->
  899. (match flag with
  900. | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e
  901. | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op))
  902. | TUnop (op, flag, e) ->
  903. (match flag with
  904. | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") "
  905. | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op))
  906. | TVars (v_eop_l) ->
  907. ignore (List.fold_left (fun acc (var, eopt) ->
  908. (if acc <> 0 then write w ", ");
  909. print w "%s " (t_s var.v_type);
  910. write_id w var.v_name;
  911. (match eopt with
  912. | None -> ()
  913. | Some e ->
  914. write w " = ";
  915. expr_s w e
  916. );
  917. acc + 1
  918. ) 0 v_eop_l);
  919. | TBlock [e] when was_in_value ->
  920. expr_s w e
  921. | TBlock el ->
  922. begin_block w;
  923. (*
  924. Line directives are turned off right now because:
  925. 1 - It makes harder to debug when the generated code internals are the problem
  926. 2 - Lexer.get_error_line is a very expensive operation
  927. let last_line = ref (-1) in
  928. let line_directive p =
  929. let cur_line = Lexer.get_error_line p in
  930. let is_relative_path = (String.sub p.pfile 0 1) = "." in
  931. let file = if is_relative_path then "../" ^ p.pfile else p.pfile in
  932. if cur_line <> ((!last_line)+1) then begin print w "//#line %d \"%s\"" cur_line (Ast.s_escape file); newline w end;
  933. last_line := cur_line
  934. in *)
  935. List.iter (fun e ->
  936. (*line_directive e.epos;*)
  937. in_value := false;
  938. expr_s w e;
  939. (if has_semicolon e then write w ";");
  940. newline w
  941. ) el;
  942. end_block w
  943. | TIf (econd, e1, Some(eelse)) when was_in_value ->
  944. write w "( ";
  945. expr_s w (mk_paren econd);
  946. write w " ? ";
  947. expr_s w (mk_paren e1);
  948. write w " : ";
  949. expr_s w (mk_paren eelse);
  950. write w " )";
  951. | TIf (econd, e1, eelse) ->
  952. write w "if ";
  953. expr_s w (mk_paren econd);
  954. write w " ";
  955. in_value := false;
  956. expr_s w (mk_block e1);
  957. (match eelse with
  958. | None -> ()
  959. | Some e ->
  960. write w " else ";
  961. in_value := false;
  962. expr_s w (mk_block e)
  963. )
  964. | TWhile (econd, eblock, flag) ->
  965. (match flag with
  966. | Ast.NormalWhile ->
  967. write w "while ";
  968. expr_s w (mk_paren econd);
  969. write w "";
  970. in_value := false;
  971. expr_s w (mk_block eblock)
  972. | Ast.DoWhile ->
  973. write w "do ";
  974. in_value := false;
  975. expr_s w (mk_block eblock);
  976. write w "while ";
  977. in_value := true;
  978. expr_s w (mk_paren econd);
  979. )
  980. | TSwitch (econd, ele_l, default) ->
  981. write w "switch ";
  982. expr_s w (mk_paren econd);
  983. begin_block w;
  984. List.iter (fun (el, e) ->
  985. List.iter (fun e ->
  986. write w "case ";
  987. in_value := true;
  988. expr_s w e;
  989. write w ":";
  990. ) el;
  991. newline w;
  992. in_value := false;
  993. expr_s w (mk_block e);
  994. newline w;
  995. newline w
  996. ) ele_l;
  997. if is_some default then begin
  998. write w "default:";
  999. newline w;
  1000. in_value := false;
  1001. expr_s w (get default);
  1002. newline w;
  1003. end;
  1004. end_block w
  1005. | TTry (tryexpr, ve_l) ->
  1006. write w "try ";
  1007. in_value := false;
  1008. expr_s w (mk_block tryexpr);
  1009. List.iter (fun (var, e) ->
  1010. print w "catch (%s %s)" (t_s var.v_type) (var.v_name);
  1011. in_value := false;
  1012. expr_s w (mk_block e);
  1013. newline w
  1014. ) ve_l
  1015. | TReturn eopt ->
  1016. write w "return ";
  1017. if is_some eopt then expr_s w (get eopt)
  1018. | TBreak -> write w "break"
  1019. | TContinue -> write w "continue"
  1020. | TThrow e ->
  1021. write w "throw ";
  1022. expr_s w e
  1023. | TCast (e1,md_t) ->
  1024. ((*match gen.gfollow#run_f e.etype with
  1025. | TType({ t_path = ([], "UInt") }, []) ->
  1026. write w "( unchecked ((uint) ";
  1027. expr_s w e1;
  1028. write w ") )"
  1029. | _ ->*)
  1030. (* FIXME I'm ignoring module type *)
  1031. print w "((%s) (" (t_s e.etype);
  1032. expr_s w e1;
  1033. write w ") )"
  1034. )
  1035. | TFor (_,_,content) ->
  1036. write w "[ for not supported ";
  1037. expr_s w content;
  1038. write w " ]";
  1039. if !strict_mode then assert false
  1040. | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
  1041. | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
  1042. | TMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
  1043. )
  1044. in
  1045. expr_s w e
  1046. in
  1047. let get_string_params cl_types =
  1048. match cl_types with
  1049. | [] ->
  1050. ("","")
  1051. | _ ->
  1052. let params = sprintf "<%s>" (String.concat ", " (List.map (fun (_, tcl) -> match follow tcl with | TInst(cl, _) -> snd cl.cl_path | _ -> assert false) cl_types)) in
  1053. let params_extends = List.fold_left (fun acc (name, t) ->
  1054. match run_follow gen t with
  1055. | TInst (cl, p) ->
  1056. (match cl.cl_implements with
  1057. | [] -> acc
  1058. | _ -> acc) (* TODO
  1059. | _ -> (sprintf " where %s : %s" name (String.concat ", " (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements))) :: acc ) *)
  1060. | _ -> trace (t_s t); assert false (* FIXME it seems that a cl_types will never be anything other than cl.cl_types. I'll take the risk and fail if not, just to see if that confirms *)
  1061. ) [] cl_types in
  1062. (params, String.concat " " params_extends)
  1063. in
  1064. let gen_class_field w is_static cl is_final cf =
  1065. let is_interface = cl.cl_interface in
  1066. let name, is_new, is_explicit_iface = match cf.cf_name with
  1067. | "new" -> snd cl.cl_path, true, false
  1068. | name when String.contains name '.' ->
  1069. let fn_name, path = parse_explicit_iface name in
  1070. (path_s path) ^ "." ^ fn_name, false, true
  1071. | name -> name, false, false
  1072. in
  1073. (match cf.cf_kind with
  1074. | Var _
  1075. | Method (MethDynamic) ->
  1076. if not is_interface then begin
  1077. let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in
  1078. (match cf.cf_expr with
  1079. | Some e ->
  1080. print w "%s %s%s %s %s = " access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name);
  1081. expr_s w e;
  1082. write w ";"
  1083. | None ->
  1084. print w "%s %s%s %s %s;" access (if is_static then "static " else "") (String.concat " " modifiers) (t_s (run_follow gen cf.cf_type)) (change_field name)
  1085. )
  1086. end (* TODO see how (get,set) variable handle when they are interfaces *)
  1087. | Method mkind ->
  1088. let is_virtual = not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false in
  1089. let is_virtual = if not is_virtual || has_meta ":final" cf.cf_meta then false else is_virtual in
  1090. let is_override = List.mem cf.cf_name cl.cl_overrides in
  1091. let is_override = is_override || match cf.cf_name, follow cf.cf_type with
  1092. | "Equals", TFun([_,_,targ], tret) ->
  1093. (match follow targ, follow tret with
  1094. | TDynamic _, TEnum({ e_path = ([], "Bool") }, []) -> true
  1095. | _ -> false)
  1096. | _ -> false
  1097. in
  1098. let is_virtual = is_virtual && not (has_meta ":final" cl.cl_meta) && not (is_interface) in
  1099. let visibility = if is_interface then "" else "public" in
  1100. let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in
  1101. let visibility, is_virtual = if is_explicit_iface then "",false else visibility, is_virtual in
  1102. let v_n = if is_static then "static " else if is_override && not is_interface then "override " else if is_virtual then "virtual " else "" in
  1103. let ret_type, args = match cf.cf_type with | TFun (strbtl, t) -> (t, strbtl) | _ -> assert false in
  1104. (* public static void funcName *)
  1105. print w "%s %s %s %s %s" (visibility) v_n (String.concat " " modifiers) (if is_new then "" else rett_s (run_follow gen ret_type)) (change_field name);
  1106. let params, params_ext = get_string_params cf.cf_params in
  1107. (* <T>(string arg1, object arg2) with T : object *)
  1108. print w "%s(%s)%s" (params) (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s (run_follow gen t)) (change_id name)) args)) (params_ext);
  1109. if is_interface then
  1110. write w ";"
  1111. else begin
  1112. let rec loop meta =
  1113. match meta with
  1114. | [] ->
  1115. let expr = match cf.cf_expr with
  1116. | None -> mk (TBlock([])) t_dynamic Ast.null_pos
  1117. | Some s ->
  1118. match s.eexpr with
  1119. | TFunction tf ->
  1120. mk_block (tf.tf_expr)
  1121. | _ -> assert false (* FIXME *)
  1122. in
  1123. (if is_new then begin
  1124. let rec get_super_call el =
  1125. match el with
  1126. | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest ->
  1127. Some call, rest
  1128. | ( { eexpr = TBlock(bl) } as block ) :: rest ->
  1129. let ret, mapped = get_super_call bl in
  1130. ret, ( { block with eexpr = TBlock(mapped) } :: rest )
  1131. | _ ->
  1132. None, el
  1133. in
  1134. match expr.eexpr with
  1135. | TBlock(bl) ->
  1136. let super_call, rest = get_super_call bl in
  1137. (match super_call with
  1138. | None -> ()
  1139. | Some sc ->
  1140. write w " : ";
  1141. let t = Common.timer "expression to string" in
  1142. expr_s w sc;
  1143. t()
  1144. );
  1145. begin_block w;
  1146. write w "unchecked ";
  1147. let t = Common.timer "expression to string" in
  1148. expr_s w { expr with eexpr = TBlock(rest) };
  1149. t();
  1150. end_block w
  1151. | _ -> assert false
  1152. end else begin
  1153. begin_block w;
  1154. write w "unchecked ";
  1155. let t = Common.timer "expression to string" in
  1156. expr_s w expr;
  1157. t();
  1158. end_block w
  1159. end)
  1160. | (":functionBody", [Ast.EConst (Ast.String contents),_],_) :: tl ->
  1161. begin_block w;
  1162. write w contents;
  1163. end_block w
  1164. | _ :: tl -> loop tl
  1165. in
  1166. loop cf.cf_meta
  1167. end);
  1168. newline w;
  1169. newline w;
  1170. in
  1171. let check_special_behaviors w cl =
  1172. (if PMap.mem "__get" cl.cl_fields then begin
  1173. let get = PMap.find "__get" cl.cl_fields in
  1174. let idx_t, v_t = match follow get.cf_type with
  1175. | TFun([_,_,arg_t],ret_t) ->
  1176. t_s (run_follow gen arg_t), t_s (run_follow gen ret_t)
  1177. | _ -> gen.gcon.error "The __get function must be a function with one argument. " get.cf_pos; assert false
  1178. in
  1179. List.iter (fun (cl,args) ->
  1180. match cl.cl_array_access with
  1181. | None -> ()
  1182. | Some t ->
  1183. let changed_t = apply_params cl.cl_types (List.map (fun _ -> t_dynamic) cl.cl_types) t in
  1184. let t_as_s = t_s (run_follow gen changed_t) in
  1185. print w "%s %s.this[int key]" t_as_s (t_s (TInst(cl, args)));
  1186. begin_block w;
  1187. write w "get";
  1188. begin_block w;
  1189. print w "return ((%s) this.__get(key));" t_as_s;
  1190. end_block w;
  1191. write w "set";
  1192. begin_block w;
  1193. print w "this.__set(key, (%s) value);" v_t;
  1194. end_block w;
  1195. end_block w;
  1196. newline w;
  1197. newline w
  1198. ) cl.cl_implements
  1199. end);
  1200. if is_some cl.cl_array_access then begin
  1201. if not cl.cl_interface && PMap.mem "__get" cl.cl_fields && PMap.mem "__set" cl.cl_fields && not (List.mem "__get" cl.cl_overrides) then begin
  1202. let get = PMap.find "__get" cl.cl_fields in
  1203. let idx_t, v_t = match follow get.cf_type with
  1204. | TFun([_,_,arg_t],ret_t) ->
  1205. t_s (run_follow gen arg_t), t_s (run_follow gen ret_t)
  1206. | _ -> gen.gcon.error "The __get function must be a function with one argument. " get.cf_pos; assert false
  1207. in
  1208. print w "public %s this[%s key]" v_t idx_t;
  1209. begin_block w;
  1210. write w "get";
  1211. begin_block w;
  1212. write w "return this.__get(key);";
  1213. end_block w;
  1214. write w "set";
  1215. begin_block w;
  1216. write w "this.__set(key, value);";
  1217. end_block w;
  1218. end_block w;
  1219. newline w;
  1220. newline w;
  1221. end else if cl.cl_interface && is_hxgen (TClassDecl cl) then begin
  1222. let changed_t = apply_params cl.cl_types (List.map (fun _ -> t_dynamic) cl.cl_types) (get cl.cl_array_access) in
  1223. print w "%s this[int key]" (t_s (run_follow gen changed_t));
  1224. begin_block w;
  1225. write w "get;";
  1226. newline w;
  1227. write w "set;";
  1228. newline w;
  1229. end_block w;
  1230. newline w;
  1231. newline w
  1232. end
  1233. end;
  1234. (try
  1235. let cf = PMap.find "toString" cl.cl_fields in
  1236. (if List.mem "toString" cl.cl_overrides then raise Not_found);
  1237. (match cf.cf_type with
  1238. | TFun([], ret) ->
  1239. (match real_type ret with
  1240. | TInst( { cl_path = ([], "String") }, []) ->
  1241. write w "public override string ToString()";
  1242. begin_block w;
  1243. write w "return this.toString();";
  1244. end_block w;
  1245. newline w;
  1246. newline w
  1247. | _ ->
  1248. gen.gcon.error "A toString() function should return a String!" cf.cf_pos
  1249. )
  1250. | _ -> ()
  1251. )
  1252. with | Not_found -> ())
  1253. in
  1254. let gen_class w cl =
  1255. let should_close = match change_ns (fst (cl.cl_path)) with
  1256. | [] -> false
  1257. | ns ->
  1258. print w "namespace %s" (String.concat "." (change_ns ns));
  1259. begin_block w;
  1260. true
  1261. in
  1262. let is_main =
  1263. match gen.gcon.main_class with
  1264. | Some ( (_,"Main") as path) when path = cl.cl_path ->
  1265. (*
  1266. for cases where the main class is called Main, there will be a problem with creating the entry point there.
  1267. In this special case, a special entry point class will be created
  1268. *)
  1269. write w "public class EntryPoint__Main";
  1270. begin_block w;
  1271. write w "public static void Main()";
  1272. begin_block w;
  1273. (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "cs.Boot.init();"; newline w);
  1274. print w "global::%s.main();" (path_s path);
  1275. end_block w;
  1276. end_block w;
  1277. false
  1278. | Some path when path = cl.cl_path -> true
  1279. | _ -> false
  1280. in
  1281. let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in
  1282. let is_final = clt = "struct" || has_meta ":final" cl.cl_meta in
  1283. print w "%s %s %s %s" access (String.concat " " modifiers) clt (change_clname (snd cl.cl_path));
  1284. (* type parameters *)
  1285. let params, params_ext = get_string_params cl.cl_types in
  1286. let extends_implements = (match cl.cl_super with | None -> [] | Some (cl,p) -> [path_param_s (TClassDecl cl) cl.cl_path p]) @ (List.map (fun (cl,p) -> path_param_s (TClassDecl cl) cl.cl_path p) cl.cl_implements) in
  1287. (match extends_implements with
  1288. | [] -> print w "%s %s" params params_ext
  1289. | _ -> print w "%s : %s %s" params (String.concat ", " extends_implements) params_ext);
  1290. (* class head ok: *)
  1291. (* public class Test<A> : X, Y, Z where A : Y *)
  1292. begin_block w;
  1293. (* our constructor is expected to be a normal "new" function *
  1294. if !strict_mode && is_some cl.cl_constructor then assert false;*)
  1295. let rec loop meta =
  1296. match meta with
  1297. | [] -> ()
  1298. | (":classContents", [Ast.EConst (Ast.String contents),_],_) :: tl ->
  1299. write w contents
  1300. | _ :: tl -> loop tl
  1301. in
  1302. loop cl.cl_meta;
  1303. if is_main then begin
  1304. write w "public static void Main()";
  1305. begin_block w;
  1306. (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "cs.Boot.init();"; newline w);
  1307. write w "main();";
  1308. end_block w
  1309. end;
  1310. (match cl.cl_init with
  1311. | None -> ()
  1312. | Some init ->
  1313. print w "static %s() " (snd cl.cl_path);
  1314. expr_s w (mk_block init));
  1315. (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor));
  1316. (if not cl.cl_interface then
  1317. List.iter (gen_class_field w true cl is_final) cl.cl_ordered_statics);
  1318. List.iter (gen_class_field w false cl is_final) cl.cl_ordered_fields;
  1319. check_special_behaviors w cl;
  1320. end_block w;
  1321. if should_close then end_block w
  1322. in
  1323. let gen_enum w e =
  1324. let should_close = match change_ns (fst e.e_path) with
  1325. | [] -> false
  1326. | ns ->
  1327. print w "namespace %s" (String.concat "." ns);
  1328. begin_block w;
  1329. true
  1330. in
  1331. print w "public enum %s" (change_clname (snd e.e_path));
  1332. begin_block w;
  1333. write w (String.concat ", " e.e_names);
  1334. end_block w;
  1335. if should_close then end_block w
  1336. in
  1337. let module_type_gen w md_tp =
  1338. match md_tp with
  1339. | TClassDecl cl ->
  1340. if not cl.cl_extern then begin
  1341. (if no_root && len w = 0 then write w "using haxe.root;"; newline w;);
  1342. gen_class w cl;
  1343. newline w;
  1344. newline w
  1345. end;
  1346. (not cl.cl_extern)
  1347. | TEnumDecl e ->
  1348. if not e.e_extern then begin
  1349. (if no_root && len w = 0 then write w "using haxe.root;"; newline w;);
  1350. gen_enum w e;
  1351. newline w;
  1352. newline w
  1353. end;
  1354. (not e.e_extern)
  1355. | TTypeDecl e ->
  1356. false
  1357. in
  1358. let module_gen w md_def =
  1359. List.fold_left (fun should md -> module_type_gen w md or should) false md_def.m_types
  1360. in
  1361. (* generate source code *)
  1362. init_ctx gen;
  1363. Hashtbl.add gen.gspecial_vars "__rethrow__" true;
  1364. Hashtbl.add gen.gspecial_vars "__typeof__" true;
  1365. Hashtbl.add gen.gspecial_vars "__label__" true;
  1366. Hashtbl.add gen.gspecial_vars "__goto__" true;
  1367. Hashtbl.add gen.gspecial_vars "__is__" true;
  1368. Hashtbl.add gen.gspecial_vars "__as__" true;
  1369. Hashtbl.add gen.gspecial_vars "__cs__" true;
  1370. Hashtbl.add gen.gspecial_vars "__checked__" true;
  1371. Hashtbl.add gen.gspecial_vars "__lock__" true;
  1372. Hashtbl.add gen.gspecial_vars "__fixed__" true;
  1373. Hashtbl.add gen.gspecial_vars "__unsafe__" true;
  1374. Hashtbl.add gen.gspecial_vars "__addressOf__" true;
  1375. Hashtbl.add gen.gspecial_vars "__valueOf__" true;
  1376. Hashtbl.add gen.gspecial_vars "__sizeof__" true;
  1377. Hashtbl.add gen.gsupported_conversions (["haxe"; "lang"], "Null") (fun t1 t2 -> true);
  1378. let last_needs_box = gen.gneeds_box in
  1379. gen.gneeds_box <- (fun t -> match t with | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) -> true | _ -> last_needs_box t);
  1380. gen.greal_type <- real_type;
  1381. gen.greal_type_param <- change_param_type;
  1382. SetHXGen.run_filter gen SetHXGen.default_hxgen_func;
  1383. let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in
  1384. (*let closure_t = ClosuresToClass.create gen 10 float_cl
  1385. (fun l -> l)
  1386. (fun l -> l)
  1387. (fun args -> args)
  1388. (fun args -> [])
  1389. in
  1390. ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e));
  1391. StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*)
  1392. let tp_v = alloc_var "$type_param" t_dynamic in
  1393. let mk_tp t pos = { eexpr = TLocal(tp_v); etype = t; epos = pos } in
  1394. TypeParams.configure gen (fun ecall efield params elist ->
  1395. { ecall with eexpr = TCall(efield, (List.map (fun t -> mk_tp t ecall.epos ) params) @ elist) }
  1396. );
  1397. HardNullableSynf.configure gen (HardNullableSynf.traverse gen
  1398. (fun e ->
  1399. match real_type e.etype with
  1400. | TInst({ cl_path = (["haxe";"lang"], "Null") }, [t]) ->
  1401. { eexpr = TField(e, "value"); etype = t; epos = e.epos }
  1402. | _ ->
  1403. trace (debug_type e.etype); gen.gcon.error "This expression is not a Nullable expression" e.epos; assert false
  1404. )
  1405. (fun v t has_value ->
  1406. match has_value, real_type v.etype with
  1407. | true, TDynamic _ | true, TAnon _ | true, TMono _ ->
  1408. {
  1409. eexpr = TCall(mk_static_field_access_infer null_t "ofDynamic" v.epos [t], [mk_tp t v.epos; v]);
  1410. etype = TInst(null_t, [t]);
  1411. epos = v.epos
  1412. }
  1413. | _ ->
  1414. { eexpr = TNew(null_t, [t], [gen.ghandle_cast t v.etype v; { eexpr = TConst(TBool has_value); etype = gen.gcon.basic.tbool; epos = v.epos } ]); etype = TInst(null_t, [t]); epos = v.epos }
  1415. )
  1416. (fun e ->
  1417. {
  1418. eexpr = TCall({
  1419. eexpr = TField(mk_paren e, "toDynamic");
  1420. etype = TFun([], t_dynamic);
  1421. epos = e.epos
  1422. }, []);
  1423. etype = t_dynamic;
  1424. epos = e.epos
  1425. }
  1426. )
  1427. (fun e ->
  1428. {
  1429. eexpr = TField(e, "hasValue");
  1430. etype = basic.tbool;
  1431. epos = e.epos
  1432. }
  1433. )
  1434. (fun e1 e2 ->
  1435. {
  1436. eexpr = TCall({
  1437. eexpr = TField(e1, "Equals");
  1438. etype = TFun(["obj",false,t_dynamic],basic.tbool);
  1439. epos = e1.epos
  1440. }, [e2]);
  1441. etype = basic.tbool;
  1442. epos = e1.epos;
  1443. }
  1444. )
  1445. true
  1446. true
  1447. );
  1448. IteratorsInterface.configure gen (fun e -> e);
  1449. ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
  1450. EnumToClass.configure gen (Some (fun e -> mk_cast gen.gcon.basic.tint e)) false true (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) true false;
  1451. InterfaceVarsDeleteModf.configure gen;
  1452. let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in
  1453. let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in
  1454. (*fixme: THIS IS A HACK. take this off *)
  1455. let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in
  1456. (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*)
  1457. OverloadingConstructor.configure gen (TEnum(empty_e, [])) ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;}) false;
  1458. let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in
  1459. let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in
  1460. let can_be_float t = match follow t with
  1461. | TInst({ cl_path = ([], "Int") }, [])
  1462. | TInst({ cl_path = ([], "Float") }, []) -> true
  1463. | _ -> false
  1464. in
  1465. let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe =
  1466. let is_float = can_be_float (real_type main_expr.etype) in
  1467. let fn_name = if is_some may_set then "setField" else "getField" in
  1468. let fn_name = if is_float then fn_name ^ "_f" else fn_name in
  1469. let pos = field_expr.epos in
  1470. let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in
  1471. let should_cast = match main_expr.etype with | TInst({ cl_path = ([], "Float") }, []) -> false | _ -> true in
  1472. let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in
  1473. let first_args =
  1474. [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ]
  1475. @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else []
  1476. in
  1477. let args = first_args @ match is_float, may_set with
  1478. | true, Some(set) ->
  1479. [ if should_cast then mk_cast basic.tfloat set else set ]
  1480. | false, Some(set) ->
  1481. [ set ]
  1482. | _ ->
  1483. [ is_unsafe ]
  1484. in
  1485. let call = { main_expr with eexpr = TCall(infer,args) } in
  1486. let call = if is_float && should_cast then mk_cast main_expr.etype call else call in
  1487. call
  1488. in
  1489. let rcf_on_call_field ecall field_expr field may_hash args =
  1490. let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in
  1491. let hash_arg = match may_hash with
  1492. | None -> []
  1493. | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ]
  1494. in
  1495. let arr_call = if args <> [] then
  1496. { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos }
  1497. else
  1498. null (basic.tarray t_dynamic) ecall.epos
  1499. in
  1500. let call_args =
  1501. [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ]
  1502. @ hash_arg
  1503. @ [ arr_call ]
  1504. in
  1505. mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args) }
  1506. in
  1507. handle_type_params gen ifaces (get_cl (get_type gen (["haxe";"lang"], "IGenericObject")));
  1508. let rcf_ctx = ReflectionCFs.new_ctx gen closure_t object_iface true rcf_on_getset_field rcf_on_call_field (fun hash hash_array ->
  1509. { hash with eexpr = TCall(rcf_static_find, [hash; hash_array]); etype=basic.tint }
  1510. ) (fun hash -> { hash with eexpr = TCall(rcf_static_lookup, [hash]); etype = gen.gcon.basic.tstring } ) false in
  1511. ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object;
  1512. ReflectionCFs.configure_dynamic_field_access rcf_ctx false;
  1513. (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *)
  1514. let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in
  1515. let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in
  1516. ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
  1517. let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in
  1518. ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> {
  1519. eexpr = TCall(slow_invoke, [ethis; efield; eargs]);
  1520. etype = t_dynamic;
  1521. epos = ethis.epos;
  1522. } );
  1523. let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
  1524. ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn);
  1525. InitFunction.configure gen true;
  1526. TArrayTransform.configure gen (TArrayTransform.default_implementation gen (
  1527. fun e ->
  1528. match e.eexpr with
  1529. | TArray(e1, e2) ->
  1530. ( match follow e1.etype with
  1531. | TDynamic _ | TAnon _ | TMono _ -> true
  1532. | TInst({ cl_kind = KTypeParameter }, _) -> true
  1533. | _ -> false )
  1534. | _ -> assert false
  1535. ) "__get" "__set" );
  1536. let field_is_dynamic t field =
  1537. match field_access gen (gen.greal_type t) field with
  1538. | FClassField _ -> false
  1539. | _ -> true
  1540. in
  1541. let is_type_param e = match follow e with
  1542. | TInst( { cl_kind = KTypeParameter },[]) -> true
  1543. | _ -> false
  1544. in
  1545. let is_dynamic_expr e = is_dynamic e.etype || match e.eexpr with
  1546. | TField(tf, f) -> field_is_dynamic tf.etype f
  1547. | _ -> false
  1548. in
  1549. let may_nullable t = match gen.gfollow#run_f t with
  1550. | TType({ t_path = ([], "Null") }, [t]) ->
  1551. (match follow t with
  1552. | TInst({ cl_path = ([], "String") }, [])
  1553. | TInst({ cl_path = ([], "Float") }, [])
  1554. | TInst({ cl_path = (["haxe"], "Int32")}, [] )
  1555. | TInst({ cl_path = (["haxe"], "Int64")}, [] )
  1556. | TInst({ cl_path = ([], "Int") }, [])
  1557. | TEnum({ e_path = ([], "Bool") }, []) -> Some t
  1558. | _ -> None )
  1559. | _ -> None
  1560. in
  1561. let is_double t = match follow t with | TInst({ cl_path = ([], "Float") }, []) -> true | _ -> false in
  1562. let is_int t = match follow t with | TInst({ cl_path = ([], "Int") }, []) -> true | _ -> false in
  1563. let is_null t = match real_type t with
  1564. | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true
  1565. | _ -> false
  1566. in
  1567. let is_null_expr e = is_null e.etype || match e.eexpr with
  1568. | TField(tf, f) -> (match field_access gen (real_type tf.etype) f with
  1569. | FClassField(_,_,_,_,actual_t) -> is_null actual_t
  1570. | _ -> false)
  1571. | _ -> false
  1572. in
  1573. let should_handle_opeq t =
  1574. match real_type t with
  1575. | TDynamic _ | TAnon _ | TMono _
  1576. | TInst( { cl_kind = KTypeParameter }, _ )
  1577. | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true
  1578. | _ -> false
  1579. in
  1580. DynamicOperators.configure gen
  1581. (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with
  1582. | TBinop (Ast.OpEq, e1, e2)
  1583. | TBinop (Ast.OpNotEq, e1, e2) -> should_handle_opeq e1.etype or should_handle_opeq e2.etype
  1584. | TBinop (Ast.OpAssignOp Ast.OpAdd, e1, e2) ->
  1585. is_dynamic_expr e1 || is_null_expr e1 || is_string e.etype
  1586. | TBinop (Ast.OpAdd, e1, e2) -> is_dynamic e1.etype or is_dynamic e2.etype or is_type_param e1.etype or is_type_param e2.etype or is_string e1.etype or is_string e2.etype or is_string e.etype
  1587. | TBinop (Ast.OpLt, e1, e2)
  1588. | TBinop (Ast.OpLte, e1, e2)
  1589. | TBinop (Ast.OpGte, e1, e2)
  1590. | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype or is_dynamic_expr e1 or is_dynamic_expr e2 or is_string e1.etype or is_string e2.etype
  1591. | TBinop (_, e1, e2) -> is_dynamic e.etype or is_dynamic_expr e1 or is_dynamic_expr e2
  1592. | TUnop (_, _, e1) -> is_dynamic_expr e1 || is_null_expr e1 (* we will see if the expression is Null<T> also, as the unwrap from Unop will be the same *)
  1593. | _ -> false)
  1594. (fun e1 e2 ->
  1595. let is_null e = match e.eexpr with | TConst(TNull) | TLocal({ v_name = "__undefined__" }) -> true | _ -> false in
  1596. if is_null e1 || is_null e2 then
  1597. { e1 with eexpr = TBinop(Ast.OpEq, e1, e2); etype = basic.tbool }
  1598. else begin
  1599. let is_basic = is_cs_basic_type (follow e1.etype) || is_cs_basic_type (follow e2.etype) in
  1600. let is_ref = if is_basic then false else match follow e1.etype, follow e2.etype with
  1601. | TDynamic _, _
  1602. | _, TDynamic _
  1603. | TInst( { cl_path = ([], "String") }, [] ), _
  1604. | _, TInst( { cl_path = ([], "String") }, [] )
  1605. | TInst( { cl_kind = KTypeParameter }, [] ), _
  1606. | _, TInst( { cl_kind = KTypeParameter }, [] ) -> false
  1607. | _, _ -> true
  1608. in
  1609. let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in
  1610. { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos }
  1611. end
  1612. )
  1613. (fun e e1 e2 ->
  1614. match may_nullable e1.etype, may_nullable e2.etype with
  1615. | Some t1, Some t2 ->
  1616. let t1, t2 = if is_string t1 || is_string t2 then
  1617. basic.tstring, basic.tstring
  1618. else if is_double t1 || is_double t2 then
  1619. basic.tfloat, basic.tfloat
  1620. else if is_int t1 || is_int t2 then
  1621. basic.tint, basic.tint
  1622. else t1, t2 in
  1623. { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos }
  1624. | _ when is_string e.etype || is_string e1.etype || is_string e2.etype ->
  1625. {
  1626. eexpr = TCall(
  1627. mk_static_field_access_infer runtime_cl "concat" e.epos [],
  1628. [ e1; e2 ]
  1629. );
  1630. etype = basic.tstring;
  1631. epos = e.epos
  1632. }
  1633. | _ ->
  1634. let static = mk_static_field_access_infer (runtime_cl) "plus" e1.epos [] in
  1635. mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos })
  1636. (fun e1 e2 ->
  1637. if is_string e1.etype then begin
  1638. { e1 with eexpr = TCall({ e1 with eexpr = TField(e1, "CompareTo"); etype = TFun(["anotherString",false,gen.gcon.basic.tstring], gen.gcon.basic.tint) }, [ e2 ]); etype = gen.gcon.basic.tint }
  1639. end else begin
  1640. let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in
  1641. { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }
  1642. end) ~handle_strings:false);
  1643. FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func);
  1644. let base_exception = get_cl (get_type gen (["System"], "Exception")) in
  1645. let base_exception_t = TInst(base_exception, []) in
  1646. let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in
  1647. let hx_exception_t = TInst(hx_exception, []) in
  1648. let rec is_exception t =
  1649. match follow t with
  1650. | TInst(cl,_) ->
  1651. if cl == base_exception then
  1652. true
  1653. else
  1654. (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg)))
  1655. | _ -> false
  1656. in
  1657. TryCatchWrapper.configure gen
  1658. (
  1659. TryCatchWrapper.traverse gen
  1660. (fun t -> not (is_exception (real_type t)))
  1661. (fun throwexpr expr ->
  1662. let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) expr.epos in
  1663. { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]) }; etype = gen.gcon.basic.tvoid }
  1664. )
  1665. (fun v_to_unwrap pos ->
  1666. let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in
  1667. { eexpr = TField(local, "obj"); epos = pos; etype = t_dynamic }
  1668. )
  1669. (fun rethrow ->
  1670. { rethrow with eexpr = TCall(mk_local (alloc_var "__rethrow__" t_dynamic) rethrow.epos, [rethrow]) }
  1671. )
  1672. (base_exception_t)
  1673. (hx_exception_t)
  1674. (fun v e -> e)
  1675. );
  1676. let get_typeof e =
  1677. { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) }
  1678. in
  1679. ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt ->
  1680. get_typeof e
  1681. ));
  1682. CastDetect.configure gen (CastDetect.default_implementation gen (Some (TEnum(empty_e, []))) false ~native_string_cast:false);
  1683. (*FollowAll.configure gen;*)
  1684. SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e ->
  1685. match e.eexpr with
  1686. | TSwitch(cond, cases, def) ->
  1687. (match gen.gfollow#run_f cond.etype with
  1688. | TInst({ cl_path = ([], "Int") },[])
  1689. | TInst({ cl_path = ([], "String") },[]) ->
  1690. (List.exists (fun (c,_) ->
  1691. List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c
  1692. ) cases)
  1693. | _ -> true
  1694. )
  1695. | _ -> assert false
  1696. ) true ) ;
  1697. ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVars([mk_temp gen "expr" e.etype, Some e]); etype = gen.gcon.basic.tvoid; epos = e.epos }));
  1698. UnnecessaryCastsRemoval.configure gen;
  1699. IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true);
  1700. UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen true true true false);
  1701. let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in
  1702. ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl);
  1703. let goto_special = alloc_var "__goto__" t_dynamic in
  1704. let label_special = alloc_var "__label__" t_dynamic in
  1705. SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen
  1706. (fun e_loop n api ->
  1707. api ({ eexpr = TCall( mk_local label_special e_loop.epos, [ mk_int gen n e_loop.epos ] ); etype = t_dynamic; epos = e_loop.epos }) false;
  1708. e_loop
  1709. )
  1710. (fun e_break n api ->
  1711. { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos }
  1712. )
  1713. );
  1714. DefaultArguments.configure gen (DefaultArguments.traverse gen);
  1715. CSharpSpecificSynf.configure gen (CSharpSpecificSynf.traverse gen runtime_cl);
  1716. CSharpSpecificESynf.configure gen (CSharpSpecificESynf.traverse gen runtime_cl);
  1717. let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in
  1718. mkdir (gen.gcon.file ^ "/src");
  1719. (* add resources array *)
  1720. (try
  1721. let res = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in
  1722. mkdir (gen.gcon.file ^ "/src/Resources");
  1723. let cf = PMap.find "content" res.cl_statics in
  1724. let res = ref [] in
  1725. Hashtbl.iter (fun name v ->
  1726. res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res;
  1727. let f = open_out (gen.gcon.file ^ "/src/Resources/" ^ name) in
  1728. output_string f v;
  1729. close_out f
  1730. ) gen.gcon.resources;
  1731. cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos })
  1732. with | Not_found -> ());
  1733. run_filters gen;
  1734. (* after the filters have been run, add all hashed fields to FieldLookup *)
  1735. let normalize_i i =
  1736. let i = Int32.of_int (i) in
  1737. if i < Int32.zero then
  1738. Int32.logor (Int32.logand i (Int32.of_int 0x3FFFFFFF)) (Int32.shift_left Int32.one 30)
  1739. else i
  1740. in
  1741. let hashes = Hashtbl.fold (fun i s acc -> (normalize_i i,s) :: acc) rcf_ctx.rcf_hash_fields [] in
  1742. let hashes = List.sort (fun (i,s) (i2,s2) -> compare i i2) hashes in
  1743. let flookup_cl = get_cl (get_type gen (["haxe";"lang"], "FieldLookup")) in
  1744. (try
  1745. let basic = gen.gcon.basic in
  1746. let change_array = ArrayDeclSynf.default_implementation gen native_arr_cl in
  1747. let cl = flookup_cl in
  1748. let field_ids = PMap.find "fieldIds" cl.cl_statics in
  1749. let fields = PMap.find "fields" cl.cl_statics in
  1750. field_ids.cf_expr <- Some (change_array {
  1751. eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TInt (i)); etype = basic.tint; epos = field_ids.cf_pos }) hashes);
  1752. etype = basic.tarray basic.tint;
  1753. epos = field_ids.cf_pos
  1754. });
  1755. fields.cf_expr <- Some (change_array {
  1756. eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TString s); etype = basic.tstring; epos = fields.cf_pos }) hashes);
  1757. etype = basic.tarray basic.tstring;
  1758. epos = fields.cf_pos
  1759. })
  1760. with | Not_found ->
  1761. gen.gcon.error "Fields 'fieldIds' and 'fields' were not found in class haxe.lang.FieldLookup" flookup_cl.cl_pos
  1762. );
  1763. TypeParams.RenameTypeParameters.run gen;
  1764. let t = Common.timer "code generation" in
  1765. generate_modules gen "cs" "src" module_gen;
  1766. dump_descriptor gen ("hxcs_build.txt") path_s;
  1767. if ( not (Common.defined gen.gcon "no-compilation") ) then begin
  1768. let old_dir = Sys.getcwd() in
  1769. Sys.chdir gen.gcon.file;
  1770. let cmd = "haxelib run hxcs hxcs_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) in
  1771. print_endline cmd;
  1772. if Sys.command cmd <> 0 then failwith "Build failed";
  1773. Sys.chdir old_dir;
  1774. end;
  1775. t()
  1776. (* end of configure function *)
  1777. let before_generate con =
  1778. ()
  1779. let generate con =
  1780. (try
  1781. let gen = new_ctx con in
  1782. let basic = con.basic in
  1783. (* make the basic functions in C# *)
  1784. let type_cl = get_cl ( get_type gen (["System"], "Type")) in
  1785. let basic_fns =
  1786. [
  1787. mk_class_field "Equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) [];
  1788. mk_class_field "ToString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) [];
  1789. mk_class_field "GetHashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) [];
  1790. mk_class_field "GetType" (TFun([], TInst(type_cl, []))) true Ast.null_pos (Method MethNormal) [];
  1791. ] in
  1792. List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns;
  1793. configure gen
  1794. with | TypeNotFound path ->
  1795. con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.") Ast.null_pos);
  1796. debug_mode := false