gencs.ml 141 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799
  1. (*
  2. * Copyright (C)2005-2013 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open Gencommon.ReflectionCFs
  23. open Ast
  24. open Common
  25. open Gencommon
  26. open Gencommon.SourceWriter
  27. open Type
  28. open Printf
  29. open Option
  30. open ExtString
  31. let rec is_cs_basic_type t =
  32. match follow t with
  33. | TInst( { cl_path = (["haxe"], "Int32") }, [] )
  34. | TInst( { cl_path = (["haxe"], "Int64") }, [] )
  35. | TInst( { cl_path = ([], "Int") }, [] )
  36. | TAbstract ({ a_path = ([], "Int") },[])
  37. | TInst( { cl_path = ([], "Float") }, [] )
  38. | TAbstract ({ a_path = ([], "Float") },[])
  39. | TEnum( { e_path = ([], "Bool") }, [] )
  40. | TAbstract ({ a_path = ([], "Bool") },[]) ->
  41. true
  42. | TAbstract _ when like_float t ->
  43. true
  44. | TAbstract({ a_impl = Some _ } as a,pl) ->
  45. is_cs_basic_type (Codegen.Abstract.get_underlying_type a pl)
  46. | TEnum(e, _) when not (Meta.has Meta.Class e.e_meta) -> true
  47. | TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true
  48. | _ -> false
  49. (* see http://msdn.microsoft.com/en-us/library/2sk3x8a7(v=vs.71).aspx *)
  50. let cs_binops =
  51. [Ast.OpAdd, "op_Addition";
  52. Ast.OpSub, "op_Subtraction";
  53. Ast.OpMult, "op_Multiply";
  54. Ast.OpDiv, "op_Division";
  55. Ast.OpMod, "op_Modulus";
  56. Ast.OpXor, "op_ExclusiveOr";
  57. Ast.OpOr, "op_BitwiseOr";
  58. Ast.OpAnd, "op_BitwiseAnd";
  59. Ast.OpBoolAnd, "op_LogicalAnd";
  60. Ast.OpBoolOr, "op_LogicalOr";
  61. Ast.OpAssign, "op_Assign";
  62. Ast.OpShl, "op_LeftShift";
  63. Ast.OpShr, "op_RightShift";
  64. Ast.OpShr, "op_SignedRightShift";
  65. Ast.OpUShr, "op_UnsignedRightShift";
  66. Ast.OpEq, "op_Equality";
  67. Ast.OpGt, "op_GreaterThan";
  68. Ast.OpLt, "op_LessThan";
  69. Ast.OpNotEq, "op_Inequality";
  70. Ast.OpGte, "op_GreaterThanOrEqual";
  71. Ast.OpLte, "op_LessThanOrEqual";
  72. Ast.OpAssignOp Ast.OpMult, "op_MultiplicationAssignment";
  73. Ast.OpAssignOp Ast.OpSub, "op_SubtractionAssignment";
  74. Ast.OpAssignOp Ast.OpXor, "op_ExclusiveOrAssignment";
  75. Ast.OpAssignOp Ast.OpShl, "op_LeftShiftAssignment";
  76. Ast.OpAssignOp Ast.OpMod, "op_ModulusAssignment";
  77. Ast.OpAssignOp Ast.OpAdd, "op_AdditionAssignment";
  78. Ast.OpAssignOp Ast.OpAnd, "op_BitwiseAndAssignment";
  79. Ast.OpAssignOp Ast.OpOr, "op_BitwiseOrAssignment";
  80. (* op_Comma *)
  81. Ast.OpAssignOp Ast.OpDiv, "op_DivisionAssignment";]
  82. let cs_unops =
  83. [Ast.Decrement, "op_Decrement";
  84. Ast.Increment, "op_Increment";
  85. Ast.Not, "op_UnaryNegation";
  86. Ast.Neg, "op_UnaryMinus";
  87. Ast.NegBits, "op_OnesComplement"]
  88. let binops_names = List.fold_left (fun acc (op,n) -> PMap.add n op acc) PMap.empty cs_binops
  89. let unops_names = List.fold_left (fun acc (op,n) -> PMap.add n op acc) PMap.empty cs_unops
  90. let get_item = "get_Item"
  91. let set_item = "set_Item"
  92. let is_tparam t =
  93. match follow t with
  94. | TInst( { cl_kind = KTypeParameter _ }, [] ) -> true
  95. | _ -> false
  96. let rec is_int_float t =
  97. match follow t with
  98. | TInst( { cl_path = (["haxe"], "Int32") }, [] )
  99. | TInst( { cl_path = (["haxe"], "Int64") }, [] )
  100. | TInst( { cl_path = ([], "Int") }, [] )
  101. | TAbstract ({ a_path = ([], "Int") },[])
  102. | TInst( { cl_path = ([], "Float") }, [] )
  103. | TAbstract ({ a_path = ([], "Float") },[]) ->
  104. true
  105. | TAbstract _ when like_float t ->
  106. true
  107. | TInst( { cl_path = (["haxe"; "lang"], "Null") }, [t] ) -> is_int_float t
  108. | _ -> false
  109. let is_bool t =
  110. match follow t with
  111. | TEnum( { e_path = ([], "Bool") }, [] )
  112. | TAbstract ({ a_path = ([], "Bool") },[]) ->
  113. true
  114. | _ -> false
  115. let rec is_null t =
  116. match t with
  117. | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ )
  118. | TType( { t_path = ([], "Null") }, _ ) -> true
  119. | TType( t, tl ) -> is_null (apply_params t.t_types tl t.t_type)
  120. | TMono r ->
  121. (match !r with
  122. | Some t -> is_null t
  123. | _ -> false)
  124. | TLazy f ->
  125. is_null (!f())
  126. | _ -> false
  127. let parse_explicit_iface =
  128. let regex = Str.regexp "\\." in
  129. let parse_explicit_iface str =
  130. let split = Str.split regex str in
  131. let rec get_iface split pack =
  132. match split with
  133. | clname :: fn_name :: [] -> fn_name, (List.rev pack, clname)
  134. | pack_piece :: tl -> get_iface tl (pack_piece :: pack)
  135. | _ -> assert false
  136. in
  137. get_iface split []
  138. in parse_explicit_iface
  139. let is_string t =
  140. match follow t with
  141. | TInst( { cl_path = ([], "String") }, [] ) -> true
  142. | _ -> false
  143. let change_md = function
  144. | TAbstractDecl( { a_impl = Some impl } as a) when Meta.has Meta.Delegate a.a_meta ->
  145. TClassDecl impl
  146. | TClassDecl( { cl_kind = KAbstractImpl ({ a_this = TInst(impl,_) } as a) }) when Meta.has Meta.Delegate a.a_meta ->
  147. TClassDecl impl
  148. | md -> md
  149. (* ******************************************* *)
  150. (* CSharpSpecificESynf *)
  151. (* ******************************************* *)
  152. (*
  153. Some CSharp-specific syntax filters that must run before ExpressionUnwrap
  154. dependencies:
  155. It must run before ExprUnwrap, as it may not return valid Expr/Statement expressions
  156. It must run before ClassInstance, as it will detect expressions that need unchanged TTypeExpr
  157. *)
  158. module CSharpSpecificESynf =
  159. struct
  160. let name = "csharp_specific_e"
  161. let priority = solve_deps name [DBefore ExpressionUnwrap.priority; DBefore ClassInstance.priority; DAfter TryCatchWrapper.priority]
  162. let get_cl_from_t t =
  163. match follow t with
  164. | TInst(cl,_) -> cl
  165. | _ -> assert false
  166. let get_ab_from_t t =
  167. match follow t with
  168. | TAbstract(ab,_) -> ab
  169. | _ -> assert false
  170. let traverse gen runtime_cl =
  171. let basic = gen.gcon.basic in
  172. let uint = match get_type gen ([], "UInt") with | TTypeDecl t -> TType(t, []) | TAbstractDecl a -> TAbstract(a, []) | _ -> assert false in
  173. let is_var = alloc_var "__is__" t_dynamic in
  174. let rec run e =
  175. match e.eexpr with
  176. (* Std.is() *)
  177. | TCall(
  178. { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is" })) },
  179. [ obj; { eexpr = TTypeExpr(TClassDecl { cl_path = [], "Dynamic" } | TAbstractDecl { a_path = [], "Dynamic" }) }]
  180. ) ->
  181. Type.map_expr run e
  182. | TCall(
  183. { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "is"}) ) },
  184. [ obj; { eexpr = TTypeExpr(md) }]
  185. ) ->
  186. let md = change_md md in
  187. let mk_is obj md =
  188. { e with eexpr = TCall( { eexpr = TLocal is_var; etype = t_dynamic; epos = e.epos }, [
  189. obj;
  190. { eexpr = TTypeExpr md; etype = t_dynamic (* this is after all a syntax filter *); epos = e.epos }
  191. ] ) }
  192. in
  193. let mk_or a b =
  194. {
  195. eexpr = TBinop(Ast.OpBoolOr, a, b);
  196. etype = basic.tbool;
  197. epos = e.epos
  198. }
  199. in
  200. let wrap_if_needed obj f =
  201. (* introduce temp variable for complex expressions *)
  202. match obj.eexpr with
  203. | TLocal(v) -> f obj
  204. | _ ->
  205. let var = mk_temp gen "is" obj.etype in
  206. let added = { obj with eexpr = TVar(var, Some(obj)); etype = basic.tvoid } in
  207. let local = mk_local var obj.epos in
  208. {
  209. eexpr = TBlock([ added; f local ]);
  210. etype = basic.tbool;
  211. epos = e.epos
  212. }
  213. in
  214. let obj = run obj in
  215. (match follow_module follow md with
  216. | TAbstractDecl{ a_path = ([], "Float") } ->
  217. (* 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 *)
  218. let mk_is local =
  219. (* we check if it float or int or uint *)
  220. let eisint = mk_is local (TAbstractDecl (get_ab_from_t basic.tint)) in
  221. let eisuint = mk_is local (TAbstractDecl (get_ab_from_t uint)) in
  222. let eisfloat = mk_is local md in
  223. mk_paren (mk_or eisfloat (mk_or eisint eisuint))
  224. in
  225. wrap_if_needed obj mk_is
  226. | TAbstractDecl{ a_path = ([], "Int") } ->
  227. (* int can be stored in double variable because of anonymous functions, check that case *)
  228. let mk_isint_call local =
  229. {
  230. eexpr = TCall(
  231. mk_static_field_access_infer runtime_cl "isInt" e.epos [],
  232. [ local ]
  233. );
  234. etype = basic.tbool;
  235. epos = e.epos
  236. }
  237. in
  238. let mk_is local =
  239. let eisint = mk_is local (TAbstractDecl (get_ab_from_t basic.tint)) in
  240. let eisuint = mk_is local (TAbstractDecl (get_ab_from_t uint)) in
  241. mk_paren (mk_or (mk_or eisint eisuint) (mk_isint_call local))
  242. in
  243. wrap_if_needed obj mk_is
  244. | TAbstractDecl{ a_path = ([], "UInt") } ->
  245. (* uint can be stored in double variable because of anonymous functions, check that case *)
  246. let mk_isuint_call local =
  247. {
  248. eexpr = TCall(
  249. mk_static_field_access_infer runtime_cl "isUInt" e.epos [],
  250. [ local ]
  251. );
  252. etype = basic.tbool;
  253. epos = e.epos
  254. }
  255. in
  256. let mk_is local =
  257. let eisuint = mk_is local (TAbstractDecl (get_ab_from_t uint)) in
  258. mk_paren (mk_or eisuint (mk_isuint_call local))
  259. in
  260. wrap_if_needed obj mk_is
  261. | _ ->
  262. mk_is obj md
  263. )
  264. (* end Std.is() *)
  265. | TBinop( Ast.OpUShr, e1, e2 ) ->
  266. mk_cast e.etype { e with eexpr = TBinop( Ast.OpShr, mk_cast uint (run e1), run e2 ) }
  267. | TBinop( Ast.OpAssignOp Ast.OpUShr, e1, e2 ) ->
  268. let mk_ushr local =
  269. { e with eexpr = TBinop(Ast.OpAssign, local, run { e with eexpr = TBinop(Ast.OpUShr, local, run e2) }) }
  270. in
  271. let mk_local obj =
  272. let var = mk_temp gen "opUshr" obj.etype in
  273. let added = { obj with eexpr = TVar(var, Some(obj)); etype = basic.tvoid } in
  274. let local = mk_local var obj.epos in
  275. local, added
  276. in
  277. let e1 = run e1 in
  278. let ret = match e1.eexpr with
  279. | TField({ eexpr = TLocal _ }, _)
  280. | TField({ eexpr = TTypeExpr _ }, _)
  281. | TArray({ eexpr = TLocal _ }, _)
  282. | TLocal(_) ->
  283. mk_ushr e1
  284. | TField(fexpr, field) ->
  285. let local, added = mk_local fexpr in
  286. { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TField(local, field) } ]); }
  287. | TArray(ea1, ea2) ->
  288. let local, added = mk_local ea1 in
  289. { e with eexpr = TBlock([ added; mk_ushr { e1 with eexpr = TArray(local, ea2) } ]); }
  290. | _ -> (* invalid left-side expression *)
  291. assert false
  292. in
  293. ret
  294. | _ -> Type.map_expr run e
  295. in
  296. run
  297. let configure gen (mapping_func:texpr->texpr) =
  298. let map e = Some(mapping_func e) in
  299. gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
  300. end;;
  301. (* ******************************************* *)
  302. (* CSharpSpecificSynf *)
  303. (* ******************************************* *)
  304. (*
  305. Some CSharp-specific syntax filters that can run after ExprUnwrap
  306. dependencies:
  307. Runs after ExprUnwrap
  308. *)
  309. module CSharpSpecificSynf =
  310. struct
  311. let name = "csharp_specific"
  312. let priority = solve_deps name [ DAfter ExpressionUnwrap.priority; DAfter ObjectDeclMap.priority; DAfter ArrayDeclSynf.priority; DAfter HardNullableSynf.priority ]
  313. let get_cl_from_t t =
  314. match follow t with
  315. | TInst(cl,_) -> cl
  316. | _ -> assert false
  317. let is_tparam t =
  318. match follow t with
  319. | TInst( { cl_kind = KTypeParameter _ }, _ ) -> true
  320. | _ -> false
  321. let traverse gen runtime_cl =
  322. let basic = gen.gcon.basic in
  323. let tchar = match ( get_type gen (["cs"], "Char16") ) with
  324. | TTypeDecl t -> TType(t,[])
  325. | TAbstractDecl a -> TAbstract(a,[])
  326. | _ -> assert false
  327. in
  328. let string_ext = get_cl ( get_type gen (["haxe";"lang"], "StringExt")) in
  329. let is_string t = match follow t with | TInst({ cl_path = ([], "String") }, []) -> true | _ -> false in
  330. let clstring = match basic.tstring with | TInst(cl,_) -> cl | _ -> assert false in
  331. let is_struct t = (* not basic type *)
  332. match follow t with
  333. | TInst(cl, _) when Meta.has Meta.Struct cl.cl_meta -> true
  334. | _ -> false
  335. in
  336. let is_cl t = match gen.greal_type t with | TInst ( { cl_path = (["System"], "Type") }, [] ) -> true | _ -> false in
  337. let rec run e =
  338. match e.eexpr with
  339. (* Std.int() *)
  340. | TCall(
  341. { eexpr = TField( _, FStatic({ cl_path = ([], "Std") }, { cf_name = "int" }) ) },
  342. [obj]
  343. ) ->
  344. run (mk_cast basic.tint obj)
  345. (* end Std.int() *)
  346. (* TODO: change cf_name *)
  347. | TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = "length" })) ->
  348. { e with eexpr = TField(run ef, FDynamic "Length") }
  349. | TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = "toLowerCase" })) ->
  350. { e with eexpr = TField(run ef, FDynamic "ToLower") }
  351. | TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = "toUpperCase" })) ->
  352. { e with eexpr = TField(run ef, FDynamic "ToUpper") }
  353. | TCall( { eexpr = TField(_, FStatic({ cl_path = [], "String" }, { cf_name = "fromCharCode" })) }, [cc] ) ->
  354. { e with eexpr = TNew(get_cl_from_t basic.tstring, [], [mk_cast tchar (run cc); mk_int gen 1 cc.epos]) }
  355. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("charAt" as field) })) }, args )
  356. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("charCodeAt" as field) })) }, args )
  357. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("indexOf" as field) })) }, args )
  358. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("lastIndexOf" as field) })) }, args )
  359. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("split" as field) })) }, args )
  360. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("substring" as field) })) }, args )
  361. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("substr" as field) })) }, args ) ->
  362. { e with eexpr = TCall(mk_static_field_access_infer string_ext field e.epos [], [run ef] @ (List.map run args)) }
  363. | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("toString") })) }, [] ) ->
  364. run ef
  365. | TNew( { cl_path = ([], "String") }, [], [p] ) -> run p (* new String(myString) -> myString *)
  366. | TCast(expr, _) when is_bool e.etype ->
  367. {
  368. eexpr = TCall(
  369. mk_static_field_access_infer runtime_cl "toBool" expr.epos [],
  370. [ run expr ]
  371. );
  372. etype = basic.tbool;
  373. epos = e.epos
  374. }
  375. | TCast(expr, _) when is_int_float e.etype && not (is_int_float expr.etype) && not (is_null e.etype) ->
  376. let needs_cast = match gen.gfollow#run_f e.etype with
  377. | TInst _ -> false
  378. | _ -> true
  379. in
  380. let fun_name = if like_int e.etype then "toInt" else "toDouble" in
  381. let ret = {
  382. eexpr = TCall(
  383. mk_static_field_access_infer runtime_cl fun_name expr.epos [],
  384. [ run expr ]
  385. );
  386. etype = basic.tint;
  387. epos = expr.epos
  388. } in
  389. if needs_cast then mk_cast e.etype ret else ret
  390. | TCast(expr, _) when (is_string e.etype) && (not (is_string expr.etype)) ->
  391. { e with eexpr = TCall( mk_static_field_access_infer runtime_cl "toString" expr.epos [], [run expr] ) }
  392. | TBinop( (Ast.OpNotEq as op), e1, e2)
  393. | TBinop( (Ast.OpEq as op), e1, e2) when is_string e1.etype || is_string e2.etype ->
  394. let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in
  395. mk_ret { e with
  396. eexpr = TCall({
  397. eexpr = TField(mk_classtype_access clstring e.epos, FDynamic "Equals");
  398. etype = TFun(["obj1",false,basic.tstring; "obj2",false,basic.tstring], basic.tbool);
  399. epos = e1.epos
  400. }, [ run e1; run e2 ])
  401. }
  402. | TCast(expr, _) when is_tparam e.etype ->
  403. let static = mk_static_field_access_infer (runtime_cl) "genericCast" e.epos [e.etype] in
  404. { e with eexpr = TCall(static, [mk_local (alloc_var "$type_param" e.etype) expr.epos; run expr]); }
  405. | TBinop( (Ast.OpNotEq as op), e1, e2)
  406. | TBinop( (Ast.OpEq as op), e1, e2) when is_struct e1.etype || is_struct e2.etype ->
  407. let mk_ret e = match op with | Ast.OpNotEq -> { e with eexpr = TUnop(Ast.Not, Ast.Prefix, e) } | _ -> e in
  408. mk_ret { e with
  409. eexpr = TCall({
  410. eexpr = TField(run e1, FDynamic "Equals");
  411. etype = TFun(["obj1",false,t_dynamic;], basic.tbool);
  412. epos = e1.epos
  413. }, [ run e2 ])
  414. }
  415. | TBinop ( (Ast.OpEq as op), e1, e2 )
  416. | TBinop ( (Ast.OpNotEq as op), e1, e2 ) when is_cl e1.etype ->
  417. let static = mk_static_field_access_infer (runtime_cl) "typeEq" e.epos [] in
  418. let ret = { e with eexpr = TCall(static, [run e1; run e2]); } in
  419. if op = Ast.OpNotEq then
  420. { ret with eexpr = TUnop(Ast.Not, Ast.Prefix, ret) }
  421. else
  422. ret
  423. | _ -> Type.map_expr run e
  424. in
  425. run
  426. let configure gen (mapping_func:texpr->texpr) =
  427. let map e = Some(mapping_func e) in
  428. gen.gsyntax_filters#add ~name:name ~priority:(PCustom priority) map
  429. end;;
  430. (* Type Parameters Handling *)
  431. let handle_type_params gen ifaces base_generic =
  432. let basic = gen.gcon.basic in
  433. (*
  434. starting to set gtparam_cast.
  435. *)
  436. (* NativeArray: the most important. *)
  437. (*
  438. var new_arr = new NativeArray<TO_T>(old_arr.Length);
  439. var i = -1;
  440. while( i < old_arr.Length )
  441. {
  442. new_arr[i] = (TO_T) old_arr[i];
  443. }
  444. *)
  445. let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in
  446. let get_narr_param t = match follow t with
  447. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) -> param
  448. | _ -> assert false
  449. in
  450. let gtparam_cast_native_array e to_t =
  451. let old_param = get_narr_param e.etype in
  452. let new_param = get_narr_param to_t in
  453. let new_v = mk_temp gen "new_arr" to_t in
  454. let i = mk_temp gen "i" basic.tint in
  455. let old_len = mk_field_access gen e "Length" e.epos in
  456. let obj_v = mk_temp gen "obj" t_dynamic in
  457. let check_null = {eexpr = TBinop(Ast.OpNotEq, e, null e.etype e.epos); etype = basic.tbool; epos = e.epos} in
  458. let block = [
  459. {
  460. eexpr = TVar(
  461. new_v, Some( {
  462. eexpr = TNew(native_arr_cl, [new_param], [old_len] );
  463. etype = to_t;
  464. epos = e.epos
  465. } )
  466. );
  467. etype = basic.tvoid;
  468. epos = e.epos
  469. };
  470. {
  471. eexpr = TVar(i, Some( mk_int gen (-1) e.epos ));
  472. etype = basic.tvoid;
  473. epos = e.epos
  474. };
  475. {
  476. eexpr = TWhile(
  477. {
  478. eexpr = TBinop(
  479. Ast.OpLt,
  480. { eexpr = TUnop(Ast.Increment, Ast.Prefix, mk_local i e.epos); etype = basic.tint; epos = e.epos },
  481. old_len
  482. );
  483. etype = basic.tbool;
  484. epos = e.epos
  485. },
  486. { eexpr = TBlock [
  487. {
  488. eexpr = TVar(obj_v, Some (mk_cast t_dynamic { eexpr = TArray(e, mk_local i e.epos); etype = old_param; epos = e.epos }));
  489. etype = basic.tvoid;
  490. epos = e.epos
  491. };
  492. {
  493. eexpr = TIf({
  494. eexpr = TBinop(Ast.OpNotEq, mk_local obj_v e.epos, null e.etype e.epos);
  495. etype = basic.tbool;
  496. epos = e.epos
  497. },
  498. {
  499. eexpr = TBinop(
  500. Ast.OpAssign,
  501. { eexpr = TArray(mk_local new_v e.epos, mk_local i e.epos); etype = new_param; epos = e.epos },
  502. mk_cast new_param (mk_local obj_v e.epos)
  503. );
  504. etype = new_param;
  505. epos = e.epos
  506. },
  507. None);
  508. etype = basic.tvoid;
  509. epos = e.epos
  510. }
  511. ]; etype = basic.tvoid; epos = e.epos },
  512. Ast.NormalWhile
  513. );
  514. etype = basic.tvoid;
  515. epos = e.epos;
  516. };
  517. mk_local new_v e.epos
  518. ] in
  519. {
  520. eexpr = TIf(
  521. check_null,
  522. {
  523. eexpr = TBlock(block);
  524. etype = to_t;
  525. epos = e.epos;
  526. },
  527. Some(null new_v.v_type e.epos)
  528. );
  529. etype = to_t;
  530. epos = e.epos;
  531. }
  532. in
  533. Hashtbl.add gen.gtparam_cast (["cs"], "NativeArray") gtparam_cast_native_array;
  534. (* end set gtparam_cast *)
  535. 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
  536. 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 *)
  537. 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? *)
  538. let strict_mode = ref false (* strict mode is so we can check for unexpected information *)
  539. (* reserved c# words *)
  540. let reserved = let res = Hashtbl.create 120 in
  541. List.iter (fun lst -> Hashtbl.add res lst ("@" ^ lst)) ["abstract"; "as"; "base"; "bool"; "break"; "byte"; "case"; "catch"; "char"; "checked"; "class";
  542. "const"; "continue"; "decimal"; "default"; "delegate"; "do"; "double"; "else"; "enum"; "event"; "explicit";
  543. "extern"; "false"; "finally"; "fixed"; "float"; "for"; "foreach"; "goto"; "if"; "implicit"; "in"; "int";
  544. "interface"; "internal"; "is"; "lock"; "long"; "namespace"; "new"; "null"; "object"; "operator"; "out"; "override";
  545. "params"; "private"; "protected"; "public"; "readonly"; "ref"; "return"; "sbyte"; "sealed"; "short"; "sizeof";
  546. "stackalloc"; "static"; "string"; "struct"; "switch"; "this"; "throw"; "true"; "try"; "typeof"; "uint"; "ulong";
  547. "unchecked"; "unsafe"; "ushort"; "using"; "virtual"; "volatile"; "void"; "while"; "add"; "ascending"; "by"; "descending";
  548. "dynamic"; "equals"; "from"; "get"; "global"; "group"; "into"; "join"; "let"; "on"; "orderby"; "partial";
  549. "remove"; "select"; "set"; "value"; "var"; "where"; "yield"];
  550. res
  551. let dynamic_anon = TAnon( { a_fields = PMap.empty; a_status = ref Closed } )
  552. let rec get_class_modifiers meta cl_type cl_access cl_modifiers =
  553. match meta with
  554. | [] -> cl_type,cl_access,cl_modifiers
  555. | (Meta.Struct,[],_) :: meta -> get_class_modifiers meta "struct" cl_access cl_modifiers
  556. | (Meta.Protected,[],_) :: meta -> get_class_modifiers meta cl_type "protected" cl_modifiers
  557. | (Meta.Internal,[],_) :: meta -> get_class_modifiers meta cl_type "internal" cl_modifiers
  558. (* no abstract for now | (":abstract",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("abstract" :: cl_modifiers)
  559. | (":static",[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("static" :: cl_modifiers) TODO: support those types *)
  560. | (Meta.Final,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("sealed" :: cl_modifiers)
  561. | (Meta.Unsafe,[],_) :: meta -> get_class_modifiers meta cl_type cl_access ("unsafe" :: cl_modifiers)
  562. | _ :: meta -> get_class_modifiers meta cl_type cl_access cl_modifiers
  563. let rec get_fun_modifiers meta access modifiers =
  564. match meta with
  565. | [] -> access,modifiers
  566. | (Meta.Protected,[],_) :: meta -> get_fun_modifiers meta "protected" modifiers
  567. | (Meta.Internal,[],_) :: meta -> get_fun_modifiers meta "internal" modifiers
  568. | (Meta.ReadOnly,[],_) :: meta -> get_fun_modifiers meta access ("readonly" :: modifiers)
  569. | (Meta.Unsafe,[],_) :: meta -> get_fun_modifiers meta access ("unsafe" :: modifiers)
  570. | (Meta.Volatile,[],_) :: meta -> get_fun_modifiers meta access ("volatile" :: modifiers)
  571. | (Meta.Custom "?prop_impl",[],_) :: meta -> get_fun_modifiers meta "private" modifiers
  572. | _ :: meta -> get_fun_modifiers meta access modifiers
  573. (* this was the way I found to pass the generator context to be accessible across all functions here *)
  574. (* so 'configure' is almost 'top-level' and will have all functions needed to make this work *)
  575. let configure gen =
  576. let basic = gen.gcon.basic in
  577. let fn_cl = get_cl (get_type gen (["haxe";"lang"],"Function")) in
  578. let null_t = (get_cl (get_type gen (["haxe";"lang"],"Null")) ) in
  579. let runtime_cl = get_cl (get_type gen (["haxe";"lang"],"Runtime")) in
  580. let no_root = Common.defined gen.gcon Define.NoRoot in
  581. let change_id name = try
  582. Hashtbl.find reserved name
  583. with | Not_found ->
  584. let ret = String.concat "." (String.nsplit name "#") in
  585. List.hd (String.nsplit ret "`")
  586. in
  587. let change_clname n = change_id n in
  588. let change_ns md = if no_root then
  589. function
  590. | [] when is_hxgen md -> ["haxe";"root"]
  591. | [] -> (match md with
  592. | TClassDecl { cl_path = ([],"Std" | [],"Math") } -> ["haxe";"root"]
  593. | _ -> [])
  594. | ns -> List.map change_id ns
  595. else List.map change_id in
  596. let change_field = change_id in
  597. let write_id w name = write w (change_id name) in
  598. let write_field w name = write w (change_field name) in
  599. gen.gfollow#add ~name:"follow_basic" (fun t -> match t with
  600. | TEnum ({ e_path = ([], "Bool") }, [])
  601. | TAbstract ({ a_path = ([], "Bool") },[])
  602. | TEnum ({ e_path = ([], "Void") }, [])
  603. | TAbstract ({ a_path = ([], "Void") },[])
  604. | TInst ({ cl_path = ([],"Float") },[])
  605. | TAbstract ({ a_path = ([],"Float") },[])
  606. | TInst ({ cl_path = ([],"Int") },[])
  607. | TAbstract ({ a_path = ([],"Int") },[])
  608. | TType ({ t_path = [],"UInt" },[])
  609. | TAbstract ({ a_path = [],"UInt" },[])
  610. | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
  611. | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[])
  612. | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[])
  613. | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeUInt64" },[])
  614. | TType ({ t_path = ["cs"],"UInt64" },[])
  615. | TAbstract ({ a_path = ["cs"],"UInt64" },[])
  616. | TType ({ t_path = ["cs"],"UInt8" },[])
  617. | TAbstract ({ a_path = ["cs"],"UInt8" },[])
  618. | TType ({ t_path = ["cs"],"Int8" },[])
  619. | TAbstract ({ a_path = ["cs"],"Int8" },[])
  620. | TType ({ t_path = ["cs"],"Int16" },[])
  621. | TAbstract ({ a_path = ["cs"],"Int16" },[])
  622. | TType ({ t_path = ["cs"],"UInt16" },[])
  623. | TAbstract ({ a_path = ["cs"],"UInt16" },[])
  624. | TType ({ t_path = ["cs"],"Char16" },[])
  625. | TAbstract ({ a_path = ["cs"],"Char16" },[])
  626. | TType ({ t_path = ["cs"],"Ref" },_)
  627. | TAbstract ({ a_path = ["cs"],"Ref" },_)
  628. | TType ({ t_path = ["cs"],"Out" },_)
  629. | TAbstract ({ a_path = ["cs"],"Out" },_)
  630. | TType ({ t_path = [],"Single" },[])
  631. | TAbstract ({ a_path = [],"Single" },[]) -> Some t
  632. | TType ({ t_path = [],"Null" },[_]) -> Some t
  633. | TAbstract ({ a_impl = Some _ } as a, pl) ->
  634. Some (gen.gfollow#run_f ( Codegen.Abstract.get_underlying_type a pl) )
  635. | TAbstract( { a_path = ([], "EnumValue") }, _ )
  636. | TInst( { cl_path = ([], "EnumValue") }, _ ) -> Some t_dynamic
  637. | _ -> None);
  638. let module_s md =
  639. let md = change_md md in
  640. let path = (t_infos md).mt_path in
  641. match path with
  642. | ([], "String") -> "string"
  643. | ([], "Null") -> path_s (change_ns md ["haxe"; "lang"], change_clname "Null")
  644. | (ns,clname) -> path_s (change_ns md ns, change_clname clname)
  645. in
  646. let ifaces = Hashtbl.create 1 in
  647. let ti64 = match ( get_type gen (["haxe";"_Int64"], "NativeInt64") ) with | TTypeDecl t -> TType(t,[]) | TAbstractDecl a -> TAbstract(a,[]) | _ -> assert false in
  648. let ttype = get_cl ( get_type gen (["System"], "Type") ) in
  649. let has_tdyn tl =
  650. List.exists (fun t -> match follow t with
  651. | TDynamic _ | TMono _ -> true
  652. | _ -> false
  653. ) tl
  654. in
  655. let rec real_type t =
  656. let t = gen.gfollow#run_f t in
  657. let ret = match t with
  658. | TAbstract ({ a_impl = Some _ } as a, pl) ->
  659. real_type (Codegen.Abstract.get_underlying_type a pl)
  660. | TInst( { cl_path = (["haxe"], "Int32") }, [] ) -> gen.gcon.basic.tint
  661. | TInst( { cl_path = (["haxe"], "Int64") }, [] ) -> ti64
  662. | TAbstract( { a_path = [],"Class" }, _ )
  663. | TAbstract( { a_path = [],"Enum" }, _ )
  664. | TInst( { cl_path = ([], "Class") }, _ )
  665. | TInst( { cl_path = ([], "Enum") }, _ ) -> TInst(ttype,[])
  666. | TEnum(_, [])
  667. | TInst(_, []) -> t
  668. | TInst(cl, params) when
  669. has_tdyn params &&
  670. Hashtbl.mem ifaces cl.cl_path ->
  671. TInst(Hashtbl.find ifaces cl.cl_path, [])
  672. | TEnum(e, params) ->
  673. TEnum(e, List.map (fun _ -> t_dynamic) params)
  674. | TInst(cl, params) when Meta.has Meta.Enum cl.cl_meta ->
  675. TInst(cl, List.map (fun _ -> t_dynamic) params)
  676. | TInst(cl, params) -> TInst(cl, change_param_type (TClassDecl cl) params)
  677. | TType({ t_path = ([], "Null") }, [t]) ->
  678. (*
  679. Null<> handling is a little tricky.
  680. It will only change to haxe.lang.Null<> when the actual type is non-nullable or a type parameter
  681. It works on cases such as Hash<T> returning Null<T> since cast_detect will invoke real_type at the original type,
  682. Null<T>, which will then return the type haxe.lang.Null<>
  683. *)
  684. (match real_type t with
  685. | TInst( { cl_kind = KTypeParameter _ }, _ ) -> TInst(null_t, [t])
  686. | _ when is_cs_basic_type t -> TInst(null_t, [t])
  687. | _ -> real_type t)
  688. | TAbstract _
  689. | TType _ -> t
  690. | TAnon (anon) when (match !(anon.a_status) with | Statics _ | EnumStatics _ | AbstractStatics _ -> true | _ -> false) -> t
  691. | TFun _ -> TInst(fn_cl,[])
  692. | _ -> t_dynamic
  693. in
  694. ret
  695. and
  696. (*
  697. On hxcs, the only type parameters allowed to be declared are the basic c# types.
  698. That's made like this to avoid casting problems when type parameters in this case
  699. add nothing to performance, since the memory layout is always the same.
  700. To avoid confusion between Generic<Dynamic> (which has a different meaning in hxcs AST),
  701. all those references are using dynamic_anon, which means Generic<{}>
  702. *)
  703. change_param_type md tl =
  704. let is_hxgeneric = (TypeParams.RealTypeParams.is_hxgeneric md) in
  705. let ret t =
  706. let t_changed = real_type t in
  707. match is_hxgeneric, t_changed with
  708. | false, _ -> t
  709. (*
  710. Because Null<> types need a special compiler treatment for many operations (e.g. boxing/unboxing),
  711. Null<> type parameters will be transformed into Dynamic.
  712. *)
  713. | true, TInst ( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> dynamic_anon
  714. | true, TInst ( { cl_kind = KTypeParameter _ }, _ ) -> t
  715. | true, TInst _
  716. | true, TEnum _
  717. | true, TAbstract _ when is_cs_basic_type t_changed -> t
  718. | true, TDynamic _ -> t
  719. | true, x ->
  720. dynamic_anon
  721. in
  722. if is_hxgeneric && List.exists (fun t -> match follow t with | TDynamic _ -> true | _ -> false) tl then
  723. List.map (fun _ -> t_dynamic) tl
  724. else
  725. List.map ret tl
  726. in
  727. let is_dynamic t = match real_type t with
  728. | TMono _ | TDynamic _
  729. | TInst({ cl_kind = KTypeParameter _ }, _) -> true
  730. | TAnon anon ->
  731. (match !(anon.a_status) with
  732. | EnumStatics _ | Statics _ -> false
  733. | _ -> true
  734. )
  735. | _ -> false
  736. in
  737. let rec t_s t =
  738. match real_type t with
  739. (* basic types *)
  740. | TEnum ({ e_path = ([], "Bool") }, [])
  741. | TAbstract ({ a_path = ([], "Bool") },[]) -> "bool"
  742. | TEnum ({ e_path = ([], "Void") }, [])
  743. | TAbstract ({ a_path = ([], "Void") },[]) -> "object"
  744. | TInst ({ cl_path = ([],"Float") },[])
  745. | TAbstract ({ a_path = ([],"Float") },[]) -> "double"
  746. | TInst ({ cl_path = ([],"Int") },[])
  747. | TAbstract ({ a_path = ([],"Int") },[]) -> "int"
  748. | TType ({ t_path = [],"UInt" },[])
  749. | TAbstract ({ a_path = [],"UInt" },[]) -> "uint"
  750. | TType ({ t_path = ["haxe";"_Int64"], "NativeInt64" },[])
  751. | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeInt64" },[]) -> "long"
  752. | TType ({ t_path = ["haxe";"_Int64"], "NativeUInt64" },[])
  753. | TAbstract ({ a_path = ["haxe";"_Int64"], "NativeUInt64" },[]) -> "ulong"
  754. | TType ({ t_path = ["cs"],"UInt64" },[])
  755. | TAbstract ({ a_path = ["cs"],"UInt64" },[]) -> "ulong"
  756. | TType ({ t_path = ["cs"],"UInt8" },[])
  757. | TAbstract ({ a_path = ["cs"],"UInt8" },[]) -> "byte"
  758. | TType ({ t_path = ["cs"],"Int8" },[])
  759. | TAbstract ({ a_path = ["cs"],"Int8" },[]) -> "sbyte"
  760. | TType ({ t_path = ["cs"],"Int16" },[])
  761. | TAbstract ({ a_path = ["cs"],"Int16" },[]) -> "short"
  762. | TType ({ t_path = ["cs"],"UInt16" },[])
  763. | TAbstract ({ a_path = ["cs"],"UInt16" },[]) -> "ushort"
  764. | TType ({ t_path = ["cs"],"Char16" },[])
  765. | TAbstract ({ a_path = ["cs"],"Char16" },[]) -> "char"
  766. | TType ({ t_path = [],"Single" },[])
  767. | TAbstract ({ a_path = [],"Single" },[]) -> "float"
  768. | TInst ({ cl_path = ["haxe"],"Int32" },[])
  769. | TAbstract ({ a_path = ["haxe"],"Int32" },[]) -> "int"
  770. | TInst ({ cl_path = ["haxe"],"Int64" },[])
  771. | TAbstract ({ a_path = ["haxe"],"Int64" },[]) -> "long"
  772. | TInst ({ cl_path = ([], "Dynamic") },_)
  773. | TAbstract ({ a_path = ([], "Dynamic") },_) -> "object"
  774. | TType ({ t_path = ["cs"],"Out" },[t])
  775. | TAbstract ({ a_path = ["cs"],"Out" },[t])
  776. | TType ({ t_path = ["cs"],"Ref" },[t])
  777. | TAbstract ({ a_path = ["cs"],"Ref" },[t]) -> t_s t
  778. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
  779. let rec check_t_s t =
  780. match real_type t with
  781. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
  782. (check_t_s param) ^ "[]"
  783. | _ -> t_s (run_follow gen t)
  784. in
  785. (check_t_s param) ^ "[]"
  786. | TInst({ cl_path = (["cs"], "Pointer") },[t])
  787. | TAbstract({ a_path = (["cs"], "Pointer") },[t])->
  788. t_s t ^ "*"
  789. (* end of basic types *)
  790. | TInst ({ cl_kind = KTypeParameter _; cl_path=p }, []) -> snd p
  791. | TMono r -> (match !r with | None -> "object" | Some t -> t_s (run_follow gen t))
  792. | TInst ({ cl_path = [], "String" }, []) -> "string"
  793. | TEnum (e, params) -> ("global::" ^ (module_s (TEnumDecl e)))
  794. | TInst (cl, _ :: _) when Meta.has Meta.Enum cl.cl_meta ->
  795. "global::" ^ module_s (TClassDecl cl)
  796. | TInst (({ cl_path = p } as cl), params) -> (path_param_s (TClassDecl cl) p params)
  797. | TType (({ t_path = p } as t), params) -> (path_param_s (TTypeDecl t) p params)
  798. | TAnon (anon) ->
  799. (match !(anon.a_status) with
  800. | Statics _ | EnumStatics _ -> "System.Type"
  801. | _ -> "object")
  802. | TDynamic _ -> "object"
  803. | TAbstract(a,pl) when a.a_impl <> None ->
  804. t_s (Codegen.Abstract.get_underlying_type a pl)
  805. (* No Lazy type nor Function type made. That's because function types will be at this point be converted into other types *)
  806. | _ -> 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) ^ " ]"
  807. and path_param_s md path params =
  808. match params with
  809. | [] -> "global::" ^ module_s md
  810. | _ -> sprintf "%s<%s>" ("global::" ^ module_s md) (String.concat ", " (List.map (fun t -> t_s t) (change_param_type md params)))
  811. in
  812. let rett_s t =
  813. match t with
  814. | TEnum ({e_path = ([], "Void")}, [])
  815. | TAbstract ({ a_path = ([], "Void") },[]) -> "void"
  816. | _ -> t_s t
  817. in
  818. let escape ichar b =
  819. match ichar with
  820. | 92 (* \ *) -> Buffer.add_string b "\\\\"
  821. | 39 (* ' *) -> Buffer.add_string b "\\\'"
  822. | 34 -> Buffer.add_string b "\\\""
  823. | 13 (* \r *) -> Buffer.add_string b "\\r"
  824. | 10 (* \n *) -> Buffer.add_string b "\\n"
  825. | 9 (* \t *) -> Buffer.add_string b "\\t"
  826. | c when c < 32 || (c >= 127 && c <= 0xFFFF) -> Buffer.add_string b (Printf.sprintf "\\u%.4x" c)
  827. | c when c > 0xFFFF -> Buffer.add_string b (Printf.sprintf "\\U%.8x" c)
  828. | c -> Buffer.add_char b (Char.chr c)
  829. in
  830. let escape s =
  831. let b = Buffer.create 0 in
  832. (try
  833. UTF8.validate s;
  834. UTF8.iter (fun c -> escape (UChar.code c) b) s
  835. with
  836. UTF8.Malformed_code ->
  837. String.iter (fun c -> escape (Char.code c) b) s
  838. );
  839. Buffer.contents b
  840. in
  841. let has_semicolon e =
  842. match e.eexpr with
  843. | TBlock _ | TFor _ | TSwitch _ | TPatMatch _ | TTry _ | TIf _ -> false
  844. | TWhile (_,_,flag) when flag = Ast.NormalWhile -> false
  845. | _ -> true
  846. in
  847. let in_value = ref false in
  848. let rec md_s md =
  849. let md = follow_module (gen.gfollow#run_f) md in
  850. match md with
  851. | TClassDecl ({ cl_types = [] } as cl) ->
  852. t_s (TInst(cl,[]))
  853. | TClassDecl (cl) when not (is_hxgen md) ->
  854. t_s (TInst(cl,List.map (fun t -> t_dynamic) cl.cl_types))
  855. | TEnumDecl ({ e_types = [] } as e) ->
  856. t_s (TEnum(e,[]))
  857. | TEnumDecl (e) when not (is_hxgen md) ->
  858. t_s (TEnum(e,List.map (fun t -> t_dynamic) e.e_types))
  859. | TClassDecl cl ->
  860. t_s (TInst(cl,[]))
  861. | TEnumDecl e ->
  862. t_s (TEnum(e,[]))
  863. | TTypeDecl t ->
  864. t_s (TType(t, List.map (fun t -> t_dynamic) t.t_types))
  865. | TAbstractDecl a ->
  866. t_s (TAbstract(a, List.map(fun t -> t_dynamic) a.a_types))
  867. in
  868. let rec ensure_local e explain =
  869. match e.eexpr with
  870. | TLocal _ -> e
  871. | TCast(e,_)
  872. | TParenthesis e | TMeta(_,e) -> ensure_local e explain
  873. | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e
  874. in
  875. let rec ensure_refout e explain =
  876. match e.eexpr with
  877. | TField _ | TLocal _ -> e
  878. | TCast(e,_)
  879. | TParenthesis e | TMeta(_,e) -> ensure_refout e explain
  880. | _ -> gen.gcon.error ("This function argument " ^ explain ^ " must be a local variable.") e.epos; e
  881. in
  882. let is_pointer t = match follow t with
  883. | TInst({ cl_path = (["cs"], "Pointer") }, _)
  884. | TAbstract ({ a_path = (["cs"], "Pointer") },_) ->
  885. true
  886. | _ ->
  887. false in
  888. let last_line = ref (-1) in
  889. let begin_block w = write w "{"; push_indent w; newline w; last_line := -1 in
  890. let end_block w = pop_indent w; (if w.sw_has_content then newline w); write w "}"; newline w; last_line := -1 in
  891. let line_directive =
  892. if Common.defined gen.gcon Define.RealPosition then
  893. fun w p -> ()
  894. else fun w p ->
  895. let cur_line = Lexer.get_error_line p in
  896. let file = Common.get_full_path p.pfile in
  897. if cur_line <> ((!last_line)+1) then begin print w "#line %d \"%s\"" cur_line (Ast.s_escape file); newline w end;
  898. last_line := cur_line
  899. in
  900. let rec extract_tparams params el =
  901. match el with
  902. | ({ eexpr = TLocal({ v_name = "$type_param" }) } as tp) :: tl ->
  903. extract_tparams (tp.etype :: params) tl
  904. | _ -> (params, el)
  905. in
  906. let is_extern_prop t name = match follow (run_follow gen t), field_access gen t name with
  907. | TInst({ cl_interface = true; cl_extern = true } as cl, _), FNotFound ->
  908. not (is_hxgen (TClassDecl cl))
  909. | _, FClassField(_,_,decl,v,_,t,_) ->
  910. Type.is_extern_field v && (Meta.has Meta.Property v.cf_meta || (decl.cl_extern && not (is_hxgen (TClassDecl decl))))
  911. | _ -> false
  912. in
  913. let is_event t name = match follow (run_follow gen t), field_access gen t name with
  914. | TInst({ cl_interface = true; cl_extern = true } as cl, _), FNotFound ->
  915. not (is_hxgen (TClassDecl cl))
  916. | _, FClassField(_,_,decl,v,_,_,_) ->
  917. Meta.has Meta.Event v.cf_meta
  918. | _ -> false
  919. in
  920. let expr_s w e =
  921. last_line := -1;
  922. in_value := false;
  923. let rec expr_s w e =
  924. let was_in_value = !in_value in
  925. in_value := true;
  926. (match e.eexpr with
  927. | TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "add_" ->
  928. let name = field_name f in
  929. let propname = String.sub name 4 (String.length name - 4) in
  930. if is_event (gen.greal_type ef.etype) propname then begin
  931. expr_s w ef;
  932. write w ".";
  933. write_field w propname;
  934. write w " += ";
  935. expr_s w ev
  936. end else
  937. do_call w e [ev]
  938. | TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "remove_" ->
  939. let name = field_name f in
  940. let propname = String.sub name 7 (String.length name - 7) in
  941. if is_event (gen.greal_type ef.etype) propname then begin
  942. expr_s w ef;
  943. write w ".";
  944. write_field w propname;
  945. write w " -= ";
  946. expr_s w ev
  947. end else
  948. do_call w e [ev]
  949. | TCall( ({ eexpr = TField(ef,f) } as e), [] ) when String.starts_with (field_name f) "get_" ->
  950. let name = field_name f in
  951. let propname = String.sub name 4 (String.length name - 4) in
  952. if is_extern_prop (gen.greal_type ef.etype) propname then begin
  953. expr_s w ef;
  954. write w ".";
  955. write_field w propname
  956. end else
  957. do_call w e []
  958. | TCall( ({ eexpr = TField(ef,f) } as e), [v] ) when String.starts_with (field_name f) "set_" ->
  959. let name = field_name f in
  960. let propname = String.sub name 4 (String.length name - 4) in
  961. if is_extern_prop (gen.greal_type ef.etype) propname then begin
  962. expr_s w ef;
  963. write w ".";
  964. write_field w propname;
  965. write w " = ";
  966. expr_s w v
  967. end else
  968. do_call w e [v]
  969. | TField (e, (FStatic(_, cf) | FInstance(_, cf))) when Meta.has Meta.Native cf.cf_meta ->
  970. let rec loop meta = match meta with
  971. | (Meta.Native, [EConst (String s), _],_) :: _ ->
  972. expr_s w e; write w "."; write_field w s
  973. | _ :: tl -> loop tl
  974. | [] -> expr_s w e; write w "."; write_field w (cf.cf_name)
  975. in
  976. loop cf.cf_meta
  977. | TConst c ->
  978. (match c with
  979. | TInt i32 ->
  980. write w (Int32.to_string i32);
  981. (*match real_type e.etype with
  982. | TType( { t_path = (["haxe";"_Int64"], "NativeInt64") }, [] ) -> write w "L";
  983. | _ -> ()
  984. *)
  985. | TFloat s ->
  986. write w s;
  987. (if String.get s (String.length s - 1) = '.' then write w "0");
  988. (*match real_type e.etype with
  989. | TType( { t_path = ([], "Single") }, [] ) -> write w "f"
  990. | _ -> ()
  991. *)
  992. | TString s ->
  993. write w "\"";
  994. write w (escape s);
  995. write w "\""
  996. | TBool b -> write w (if b then "true" else "false")
  997. | TNull ->
  998. write w "default(";
  999. write w (t_s e.etype);
  1000. write w ")"
  1001. | TThis -> write w "this"
  1002. | TSuper -> write w "base")
  1003. | TLocal { v_name = "__sbreak__" } -> write w "break"
  1004. | TLocal { v_name = "__undefined__" } ->
  1005. write w (t_s (TInst(runtime_cl, List.map (fun _ -> t_dynamic) runtime_cl.cl_types)));
  1006. write w ".undefined";
  1007. | TLocal { v_name = "__typeof__" } -> write w "typeof"
  1008. | TLocal { v_name = "__sizeof__" } -> write w "sizeof"
  1009. | TLocal var ->
  1010. write_id w var.v_name
  1011. | TField (_, FEnum(e, ef)) ->
  1012. let s = ef.ef_name in
  1013. print w "%s." ("global::" ^ module_s (TEnumDecl e)); write_field w s
  1014. | TArray (e1, e2) ->
  1015. expr_s w e1; write w "["; expr_s w e2; write w "]"
  1016. | TBinop ((Ast.OpAssign as op), e1, e2)
  1017. | TBinop ((Ast.OpAssignOp _ as op), e1, e2) ->
  1018. expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2
  1019. | TBinop (op, e1, e2) ->
  1020. write w "( ";
  1021. expr_s w e1; write w ( " " ^ (Ast.s_binop op) ^ " " ); expr_s w e2;
  1022. write w " )"
  1023. | TField ({ eexpr = TTypeExpr mt }, s) ->
  1024. (match mt with
  1025. | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w ("global::" ^ module_s mt)
  1026. | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w ("global::" ^ module_s mt)
  1027. | TClassDecl { cl_interface = true } ->
  1028. write w ("global::" ^ module_s mt);
  1029. write w "__Statics_";
  1030. | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_empty) cl.cl_types)))
  1031. | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_empty) en.e_types)))
  1032. | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_empty) td.t_types))))
  1033. | TAbstractDecl a -> write w (t_s (TAbstract(a, List.map (fun _ -> t_empty) a.a_types)))
  1034. );
  1035. write w ".";
  1036. write_field w (field_name s)
  1037. | TField (e, s) ->
  1038. expr_s w e; write w "."; write_field w (field_name s)
  1039. | TTypeExpr mt ->
  1040. (match mt with
  1041. | TClassDecl { cl_path = (["haxe"], "Int64") } -> write w ("global::" ^ module_s mt)
  1042. | TClassDecl { cl_path = (["haxe"], "Int32") } -> write w ("global::" ^ module_s mt)
  1043. | TClassDecl cl -> write w (t_s (TInst(cl, List.map (fun _ -> t_dynamic) cl.cl_types)))
  1044. | TEnumDecl en -> write w (t_s (TEnum(en, List.map (fun _ -> t_dynamic) en.e_types)))
  1045. | TTypeDecl td -> write w (t_s (gen.gfollow#run_f (TType(td, List.map (fun _ -> t_dynamic) td.t_types))))
  1046. | TAbstractDecl a -> write w (t_s (TAbstract(a, List.map (fun _ -> t_dynamic) a.a_types)))
  1047. )
  1048. | TParenthesis e ->
  1049. write w "("; expr_s w e; write w ")"
  1050. | TMeta (_,e) ->
  1051. expr_s w e
  1052. | TArrayDecl el ->
  1053. print w "new %s" (t_s e.etype);
  1054. write w "{";
  1055. ignore (List.fold_left (fun acc e ->
  1056. (if acc <> 0 then write w ", ");
  1057. expr_s w e;
  1058. acc + 1
  1059. ) 0 el);
  1060. write w "}"
  1061. | TCall ({ eexpr = TLocal { v_name = "__delegate__" } }, [del]) ->
  1062. expr_s w del
  1063. | TCall ({ eexpr = TLocal( { v_name = "__is__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) ->
  1064. write w "( ";
  1065. expr_s w expr;
  1066. write w " is ";
  1067. write w (md_s md);
  1068. write w " )"
  1069. | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, [ expr; { eexpr = TTypeExpr(md) } ] ) ->
  1070. write w "( ";
  1071. expr_s w expr;
  1072. write w " as ";
  1073. write w (md_s md);
  1074. write w " )"
  1075. | TCall ({ eexpr = TLocal( { v_name = "__as__" } ) }, expr :: _ ) ->
  1076. write w "( ";
  1077. expr_s w expr;
  1078. write w " as ";
  1079. write w (t_s e.etype);
  1080. write w " )";
  1081. | TCall ({ eexpr = TLocal( { v_name = "__cs__" } ) }, [ { eexpr = TConst(TString(s)) } ] ) ->
  1082. write w s
  1083. | TCall ({ eexpr = TLocal( { v_name = "__unsafe__" } ) }, [ e ] ) ->
  1084. write w "unsafe";
  1085. expr_s w (mk_block e)
  1086. | TCall ({ eexpr = TLocal( { v_name = "__checked__" } ) }, [ e ] ) ->
  1087. write w "checked";
  1088. expr_s w (mk_block e)
  1089. | TCall ({ eexpr = TLocal( { v_name = "__lock__" } ) }, [ eobj; eblock ] ) ->
  1090. write w "lock(";
  1091. expr_s w eobj;
  1092. write w ")";
  1093. expr_s w (mk_block eblock)
  1094. | TCall ({ eexpr = TLocal( { v_name = "__fixed__" } ) }, [ e ] ) ->
  1095. let first = ref true in
  1096. let rec loop = function
  1097. | ({ eexpr = TVar(v, Some({ eexpr = TCast( { eexpr = TCast(e, _) }, _) }) ) } as expr) :: tl when is_pointer v.v_type ->
  1098. (if !first then first := false);
  1099. write w "fixed(";
  1100. let vf = mk_temp gen "fixed" v.v_type in
  1101. expr_s w { expr with eexpr = TVar(vf, Some e) };
  1102. write w ")";
  1103. begin_block w;
  1104. expr_s w { expr with eexpr = TVar(v, Some (mk_local vf expr.epos)) };
  1105. write w ";";
  1106. loop tl;
  1107. end_block w
  1108. | el when not !first ->
  1109. expr_s w { e with eexpr = TBlock el }
  1110. | _ ->
  1111. trace (debug_expr e);
  1112. gen.gcon.error "Invalid 'fixed' keyword format" e.epos
  1113. in
  1114. (match e.eexpr with
  1115. | TBlock bl -> loop bl
  1116. | _ ->
  1117. trace "not block";
  1118. trace (debug_expr e);
  1119. gen.gcon.error "Invalid 'fixed' keyword format" e.epos
  1120. )
  1121. | TCall ({ eexpr = TLocal( { v_name = "__addressOf__" } ) }, [ e ] ) ->
  1122. let e = ensure_local e "for addressOf" in
  1123. write w "&";
  1124. expr_s w e
  1125. | TCall ({ eexpr = TLocal( { v_name = "__valueOf__" } ) }, [ e ] ) ->
  1126. write w "*(";
  1127. expr_s w e;
  1128. write w ")"
  1129. | TCall ({ eexpr = TLocal( { v_name = "__goto__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
  1130. print w "goto label%ld" v
  1131. | TCall ({ eexpr = TLocal( { v_name = "__label__" } ) }, [ { eexpr = TConst(TInt v) } ] ) ->
  1132. print w "label%ld: {}" v
  1133. | TCall ({ eexpr = TLocal( { v_name = "__rethrow__" } ) }, _) ->
  1134. write w "throw"
  1135. (* operator overloading handling *)
  1136. | TCall({ eexpr = TField(ef, FInstance(cl,{ cf_name = "__get" })) }, [idx]) when not (is_hxgen (TClassDecl cl)) ->
  1137. expr_s w { e with eexpr = TArray(ef, idx) }
  1138. | TCall({ eexpr = TField(ef, FInstance(cl,{ cf_name = "__set" })) }, [idx; v]) when not (is_hxgen (TClassDecl cl)) ->
  1139. expr_s w { e with eexpr = TBinop(Ast.OpAssign, { e with eexpr = TArray(ef, idx) }, v) }
  1140. | TCall({ eexpr = TField(ef, FStatic(_,cf)) }, el) when PMap.mem cf.cf_name binops_names ->
  1141. let _, elr = extract_tparams [] el in
  1142. (match elr with
  1143. | [e1;e2] ->
  1144. expr_s w { e with eexpr = TBinop(PMap.find cf.cf_name binops_names, e1, e2) }
  1145. | _ -> do_call w e el)
  1146. | TCall({ eexpr = TField(ef, FStatic(_,cf)) }, el) when PMap.mem cf.cf_name unops_names ->
  1147. (match extract_tparams [] el with
  1148. | _, [e1] ->
  1149. expr_s w { e with eexpr = TUnop(PMap.find cf.cf_name unops_names, Ast.Prefix,e1) }
  1150. | _ -> do_call w e el)
  1151. | TCall (e, el) ->
  1152. do_call w e el
  1153. | TNew (({ cl_path = (["cs"], "NativeArray") } as cl), params, [ size ]) ->
  1154. let rec check_t_s t times =
  1155. match real_type t with
  1156. | TInst({ cl_path = (["cs"], "NativeArray") }, [param]) ->
  1157. (check_t_s param (times+1))
  1158. | _ ->
  1159. print w "new %s[" (t_s (run_follow gen t));
  1160. expr_s w size;
  1161. print w "]";
  1162. let rec loop i =
  1163. if i <= 0 then () else (write w "[]"; loop (i-1))
  1164. in
  1165. loop (times - 1)
  1166. in
  1167. check_t_s (TInst(cl, params)) 0
  1168. | TNew ({ cl_path = ([], "String") } as cl, [], el) ->
  1169. write w "new ";
  1170. write w (t_s (TInst(cl, [])));
  1171. write w "(";
  1172. ignore (List.fold_left (fun acc e ->
  1173. (if acc <> 0 then write w ", ");
  1174. expr_s w e;
  1175. acc + 1
  1176. ) 0 el);
  1177. write w ")"
  1178. | TNew ({ cl_kind = KTypeParameter _ } as cl, params, el) ->
  1179. print w "default(%s) /* This code should never be reached. It was produced by the use of @:generic on a new type parameter instance: %s */" (t_s (TInst(cl,params))) (path_param_s (TClassDecl cl) cl.cl_path params)
  1180. | TNew (cl, params, el) ->
  1181. write w "new ";
  1182. write w (path_param_s (TClassDecl cl) cl.cl_path params);
  1183. write w "(";
  1184. ignore (List.fold_left (fun acc e ->
  1185. (if acc <> 0 then write w ", ");
  1186. expr_s w e;
  1187. acc + 1
  1188. ) 0 el);
  1189. write w ")"
  1190. | TUnop ((Ast.Increment as op), flag, e)
  1191. | TUnop ((Ast.Decrement as op), flag, e) ->
  1192. (match flag with
  1193. | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " " ); expr_s w e
  1194. | Ast.Postfix -> expr_s w e; write w (Ast.s_unop op))
  1195. | TUnop (op, flag, e) ->
  1196. (match flag with
  1197. | Ast.Prefix -> write w ( " " ^ (Ast.s_unop op) ^ " (" ); expr_s w e; write w ") "
  1198. | Ast.Postfix -> write w "("; expr_s w e; write w (") " ^ Ast.s_unop op))
  1199. | TVar (var, eopt) ->
  1200. print w "%s " (t_s var.v_type);
  1201. write_id w var.v_name;
  1202. (match eopt with
  1203. | None ->
  1204. write w " = ";
  1205. expr_s w (null var.v_type e.epos)
  1206. | Some e ->
  1207. write w " = ";
  1208. expr_s w e
  1209. )
  1210. | TBlock [e] when was_in_value ->
  1211. expr_s w e
  1212. | TBlock el ->
  1213. begin_block w;
  1214. List.iter (fun e ->
  1215. line_directive w e.epos;
  1216. in_value := false;
  1217. expr_s w e;
  1218. (if has_semicolon e then write w ";");
  1219. newline w
  1220. ) el;
  1221. end_block w
  1222. | TIf (econd, e1, Some(eelse)) when was_in_value ->
  1223. write w "( ";
  1224. expr_s w (mk_paren econd);
  1225. write w " ? ";
  1226. expr_s w (mk_paren e1);
  1227. write w " : ";
  1228. expr_s w (mk_paren eelse);
  1229. write w " )";
  1230. | TIf (econd, e1, eelse) ->
  1231. write w "if ";
  1232. expr_s w (mk_paren econd);
  1233. write w " ";
  1234. in_value := false;
  1235. expr_s w (mk_block e1);
  1236. (match eelse with
  1237. | None -> ()
  1238. | Some e ->
  1239. write w " else ";
  1240. in_value := false;
  1241. expr_s w (mk_block e)
  1242. )
  1243. | TWhile (econd, eblock, flag) ->
  1244. (match flag with
  1245. | Ast.NormalWhile ->
  1246. write w "while ";
  1247. expr_s w (mk_paren econd);
  1248. write w "";
  1249. in_value := false;
  1250. expr_s w (mk_block eblock)
  1251. | Ast.DoWhile ->
  1252. write w "do ";
  1253. in_value := false;
  1254. expr_s w (mk_block eblock);
  1255. write w "while ";
  1256. in_value := true;
  1257. expr_s w (mk_paren econd);
  1258. )
  1259. | TSwitch (econd, ele_l, default) ->
  1260. write w "switch ";
  1261. expr_s w (mk_paren econd);
  1262. begin_block w;
  1263. List.iter (fun (el, e) ->
  1264. List.iter (fun e ->
  1265. write w "case ";
  1266. in_value := true;
  1267. expr_s w e;
  1268. write w ":";
  1269. ) el;
  1270. newline w;
  1271. in_value := false;
  1272. expr_s w (mk_block e);
  1273. newline w;
  1274. newline w
  1275. ) ele_l;
  1276. if is_some default then begin
  1277. write w "default:";
  1278. newline w;
  1279. in_value := false;
  1280. expr_s w (get default);
  1281. newline w;
  1282. end;
  1283. end_block w
  1284. | TTry (tryexpr, ve_l) ->
  1285. write w "try ";
  1286. in_value := false;
  1287. expr_s w (mk_block tryexpr);
  1288. List.iter (fun (var, e) ->
  1289. print w "catch (%s %s)" (t_s var.v_type) (var.v_name);
  1290. in_value := false;
  1291. expr_s w (mk_block e);
  1292. newline w
  1293. ) ve_l
  1294. | TReturn eopt ->
  1295. write w "return ";
  1296. if is_some eopt then expr_s w (get eopt)
  1297. | TBreak -> write w "break"
  1298. | TContinue -> write w "continue"
  1299. | TThrow e ->
  1300. write w "throw ";
  1301. expr_s w e
  1302. | TCast (e1,md_t) ->
  1303. ((*match gen.gfollow#run_f e.etype with
  1304. | TType({ t_path = ([], "UInt") }, []) ->
  1305. write w "( unchecked ((uint) ";
  1306. expr_s w e1;
  1307. write w ") )"
  1308. | _ ->*)
  1309. (* FIXME I'm ignoring module type *)
  1310. print w "((%s) (" (t_s e.etype);
  1311. expr_s w e1;
  1312. write w ") )"
  1313. )
  1314. | TFor (_,_,content) ->
  1315. write w "[ for not supported ";
  1316. expr_s w content;
  1317. write w " ]";
  1318. if !strict_mode then assert false
  1319. | TObjectDecl _ -> write w "[ obj decl not supported ]"; if !strict_mode then assert false
  1320. | TFunction _ -> write w "[ func decl not supported ]"; if !strict_mode then assert false
  1321. | TPatMatch _ -> write w "[ match not supported ]"; if !strict_mode then assert false
  1322. | TEnumParameter _ -> write w "[ enum parameter not supported ]"; if !strict_mode then assert false
  1323. )
  1324. and do_call w e el =
  1325. let params, el = extract_tparams [] el in
  1326. let params = List.rev params in
  1327. expr_s w e;
  1328. (match params with
  1329. | [] -> ()
  1330. | params ->
  1331. let md = match e.eexpr with
  1332. | TField(ef, _) -> t_to_md (run_follow gen ef.etype)
  1333. | _ -> assert false
  1334. in
  1335. write w "<";
  1336. ignore (List.fold_left (fun acc t ->
  1337. (if acc <> 0 then write w ", ");
  1338. write w (t_s t);
  1339. acc + 1
  1340. ) 0 (change_param_type md params));
  1341. write w ">"
  1342. );
  1343. let rec loop acc elist tlist =
  1344. match elist, tlist with
  1345. | e :: etl, (_,_,t) :: ttl ->
  1346. (if acc <> 0 then write w ", ");
  1347. (match real_type t with
  1348. | TType({ t_path = (["cs"], "Ref") }, _)
  1349. | TAbstract ({ a_path = (["cs"], "Ref") },_) ->
  1350. let e = ensure_refout e "of type cs.Ref" in
  1351. write w "ref ";
  1352. expr_s w e
  1353. | TType({ t_path = (["cs"], "Out") }, _)
  1354. | TAbstract ({ a_path = (["cs"], "Out") },_) ->
  1355. let e = ensure_refout e "of type cs.Out" in
  1356. write w "out ";
  1357. expr_s w e
  1358. | _ ->
  1359. expr_s w e
  1360. );
  1361. loop (acc + 1) etl ttl
  1362. | e :: etl, [] ->
  1363. (if acc <> 0 then write w ", ");
  1364. expr_s w e;
  1365. loop (acc + 1) etl []
  1366. | _ -> ()
  1367. in
  1368. write w "(";
  1369. let ft = match follow e.etype with
  1370. | TFun(args,_) -> args
  1371. | _ -> []
  1372. in
  1373. loop 0 el ft;
  1374. write w ")"
  1375. in
  1376. expr_s w e
  1377. in
  1378. let rec gen_fpart_attrib w = function
  1379. | EConst( Ident i ), _ ->
  1380. write w i
  1381. | EField( ef, f ), _ ->
  1382. gen_fpart_attrib w ef;
  1383. write w ".";
  1384. write w f
  1385. | _, p ->
  1386. gen.gcon.error "Invalid expression inside @:meta metadata" p
  1387. in
  1388. let rec gen_spart w = function
  1389. | EConst c, p -> (match c with
  1390. | Int s | Float s | Ident s ->
  1391. write w s
  1392. | String s ->
  1393. write w "\"";
  1394. write w (escape s);
  1395. write w "\""
  1396. | _ -> gen.gcon.error "Invalid expression inside @:meta metadata" p)
  1397. | EField( ef, f ), _ ->
  1398. gen_spart w ef;
  1399. write w ".";
  1400. write w f
  1401. | EBinop( Ast.OpAssign, (EConst (Ident s), _), e2 ), _ ->
  1402. write w s;
  1403. write w " = ";
  1404. gen_spart w e2
  1405. | EArrayDecl( el ), _ ->
  1406. write w "new[] {";
  1407. let fst = ref true in
  1408. List.iter (fun e ->
  1409. if !fst then fst := false else write w ", ";
  1410. gen_spart w e
  1411. ) el;
  1412. write w "}"
  1413. | ECall(fpart,args), _ ->
  1414. gen_fpart_attrib w fpart;
  1415. write w "(";
  1416. let fst = ref true in
  1417. List.iter (fun e ->
  1418. if !fst then fst := false else write w ", ";
  1419. gen_spart w e
  1420. ) args;
  1421. write w ")"
  1422. | _, p ->
  1423. gen.gcon.error "Invalid expression inside @:meta metadata" p
  1424. in
  1425. let gen_attributes w metadata =
  1426. List.iter (function
  1427. | Meta.Meta, [meta], _ ->
  1428. write w "[";
  1429. gen_spart w meta;
  1430. write w "]";
  1431. newline w
  1432. | _ -> ()
  1433. ) metadata
  1434. in
  1435. let argt_s t =
  1436. let w = new_source_writer () in
  1437. let rec run t =
  1438. match t with
  1439. | TType (tdef,p) ->
  1440. gen_attributes w tdef.t_meta;
  1441. run (follow_once t)
  1442. | TMono r ->
  1443. (match !r with
  1444. | Some t -> run t
  1445. | _ -> () (* avoid infinite loop / should be the same in this context *))
  1446. | TLazy f ->
  1447. run (!f())
  1448. | _ -> ()
  1449. in
  1450. run t;
  1451. let ret = match run_follow gen t with
  1452. | TType ({ t_path = (["cs"], "Ref") }, [t])
  1453. | TAbstract ({ a_path = (["cs"], "Ref") },[t]) -> "ref " ^ t_s t
  1454. | TType ({ t_path = (["cs"], "Out") }, [t])
  1455. | TAbstract ({ a_path = (["cs"], "Out") },[t]) -> "out " ^ t_s t
  1456. | t -> t_s t
  1457. in
  1458. let c = contents w in
  1459. if c <> "" then
  1460. c ^ " " ^ ret
  1461. else
  1462. ret
  1463. in
  1464. let get_string_params cl_types =
  1465. match cl_types with
  1466. | [] ->
  1467. ("","")
  1468. | _ ->
  1469. 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
  1470. let params_extends = List.fold_left (fun acc (name, t) ->
  1471. match run_follow gen t with
  1472. | TInst (cl, p) ->
  1473. (match cl.cl_implements with
  1474. | [] -> acc
  1475. | _ -> acc) (* TODO
  1476. | _ -> (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 ) *)
  1477. | _ -> 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 *)
  1478. ) [] cl_types in
  1479. (params, String.concat " " params_extends)
  1480. in
  1481. let rec gen_prop w is_static cl is_final (prop,t,get,set) =
  1482. gen_attributes w prop.cf_meta;
  1483. let is_interface = cl.cl_interface in
  1484. let fn_is_final = function
  1485. | None -> true
  1486. | Some ({ cf_kind = Method mkind } as m) ->
  1487. (match mkind with | MethInline -> true | _ -> false) || Meta.has Meta.Final m.cf_meta
  1488. | _ -> assert false
  1489. in
  1490. let is_virtual = not (is_final || Meta.has Meta.Final prop.cf_meta || fn_is_final get || fn_is_final set) in
  1491. let fn_is_override = function
  1492. | Some cf -> List.memq cf cl.cl_overrides
  1493. | None -> false
  1494. in
  1495. let is_override = fn_is_override get || fn_is_override set in
  1496. let visibility = if is_interface then "" else "public" in
  1497. let visibility, modifiers = get_fun_modifiers prop.cf_meta visibility [] in
  1498. 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
  1499. print w "%s %s %s %s %s" (visibility) v_n (String.concat " " modifiers) (t_s (run_follow gen t)) (change_field prop.cf_name);
  1500. let check cf = match cf with
  1501. | Some ({ cf_overloads = o :: _ } as cf) ->
  1502. gen.gcon.error "Property functions with more than one overload is currently unsupported" cf.cf_pos;
  1503. gen.gcon.error "Property functions with more than one overload is currently unsupported" o.cf_pos
  1504. | _ -> ()
  1505. in
  1506. check get;
  1507. check set;
  1508. begin_block w;
  1509. (match prop.cf_kind with
  1510. | Var { v_read = AccCall } when is_interface ->
  1511. write w "get;";
  1512. | _ -> match get with
  1513. | Some cf ->
  1514. print w "get { return _get_%s(); }" prop.cf_name;
  1515. cf.cf_meta <- (Meta.Custom "?prop_impl", [], null_pos) :: cf.cf_meta;
  1516. newline w
  1517. | _ -> ());
  1518. (match prop.cf_kind with
  1519. | Var { v_write = AccCall } when is_interface ->
  1520. write w "set;";
  1521. | _ -> match set with
  1522. | Some cf ->
  1523. print w "set { _set_%s(value); }" prop.cf_name;
  1524. cf.cf_meta <- (Meta.Custom "?prop_impl", [], null_pos) :: cf.cf_meta;
  1525. newline w
  1526. | _ -> ());
  1527. end_block w;
  1528. in
  1529. let rec gen_class_field w ?(is_overload=false) is_static cl is_final cf =
  1530. gen_attributes w cf.cf_meta;
  1531. let is_interface = cl.cl_interface in
  1532. let name, is_new, is_explicit_iface = match cf.cf_name with
  1533. | "new" -> snd cl.cl_path, true, false
  1534. | name when String.contains name '.' ->
  1535. let fn_name, path = parse_explicit_iface name in
  1536. (path_s path) ^ "." ^ fn_name, false, true
  1537. | name -> try
  1538. let binop = PMap.find name binops_names in
  1539. "operator " ^ s_binop binop, false, false
  1540. with | Not_found -> try
  1541. let unop = PMap.find name unops_names in
  1542. "operator " ^ s_unop unop, false, false
  1543. with | Not_found ->
  1544. if Meta.has (Meta.Custom "?prop_impl") cf.cf_meta then
  1545. "_" ^ name, false, false
  1546. else
  1547. name, false, false
  1548. in
  1549. let rec loop_static cl =
  1550. match is_static, cl.cl_super with
  1551. | false, _ -> []
  1552. | true, None -> []
  1553. | true, Some(cl,_) ->
  1554. (try
  1555. let cf2 = PMap.find cf.cf_name cl.cl_statics in
  1556. Gencommon.CastDetect.type_eq gen EqStrict cf.cf_type cf2.cf_type;
  1557. ["new"]
  1558. with
  1559. | Not_found | Unify_error _ ->
  1560. loop_static cl
  1561. )
  1562. in
  1563. let modf = loop_static cl in
  1564. (match cf.cf_kind with
  1565. | Var _
  1566. | Method (MethDynamic) when not (Type.is_extern_field cf) ->
  1567. (if is_overload || List.exists (fun cf -> cf.cf_expr <> None) cf.cf_overloads then
  1568. gen.gcon.error "Only normal (non-dynamic) methods can be overloaded" cf.cf_pos);
  1569. if not is_interface then begin
  1570. let access, modifiers = get_fun_modifiers cf.cf_meta "public" [] in
  1571. let modifiers = modifiers @ modf in
  1572. (match cf.cf_expr with
  1573. | Some e ->
  1574. 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);
  1575. expr_s w e;
  1576. write w ";"
  1577. | None ->
  1578. 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)
  1579. )
  1580. end (* TODO see how (get,set) variable handle when they are interfaces *)
  1581. | Method _ when Type.is_extern_field cf || (match cl.cl_kind, cf.cf_expr with | KAbstractImpl _, None -> true | _ -> false) ->
  1582. List.iter (fun cf -> if cl.cl_interface || cf.cf_expr <> None then
  1583. gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
  1584. ) cf.cf_overloads
  1585. | Var _ | Method MethDynamic -> ()
  1586. | Method mkind ->
  1587. List.iter (fun cf ->
  1588. if cl.cl_interface || cf.cf_expr <> None then
  1589. gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
  1590. ) cf.cf_overloads;
  1591. let is_virtual = not is_final && match mkind with | MethInline -> false | _ when not is_new -> true | _ -> false in
  1592. let is_virtual = if not is_virtual || Meta.has Meta.Final cf.cf_meta then false else is_virtual in
  1593. let is_override = List.memq cf cl.cl_overrides in
  1594. let is_override = is_override || match cf.cf_name, follow cf.cf_type with
  1595. | "Equals", TFun([_,_,targ], tret) ->
  1596. (match follow targ, follow tret with
  1597. | TDynamic _, TEnum({ e_path = ([], "Bool") }, [])
  1598. | TDynamic _, TAbstract({ a_path = ([], "Bool") }, []) -> true
  1599. | _ -> false)
  1600. | "GetHashCode", TFun([],_) -> true
  1601. | _ -> false
  1602. in
  1603. let is_override = if Meta.has (Meta.Custom "?prop_impl") cf.cf_meta then false else is_override in
  1604. let is_virtual = is_virtual && not (Meta.has Meta.Final cl.cl_meta) && not (is_interface) in
  1605. let visibility = if is_interface then "" else "public" in
  1606. let visibility, modifiers = get_fun_modifiers cf.cf_meta visibility [] in
  1607. let modifiers = modifiers @ modf in
  1608. let visibility, is_virtual = if is_explicit_iface then "",false else if visibility = "private" then "private",false else visibility, is_virtual in
  1609. 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
  1610. let cf_type = if is_override && not is_overload && not (Meta.has Meta.Overload cf.cf_meta) then match field_access gen (TInst(cl, List.map snd cl.cl_types)) cf.cf_name with | FClassField(_,_,_,_,_,actual_t,_) -> actual_t | _ -> assert false else cf.cf_type in
  1611. let ret_type, args = match follow cf_type with | TFun (strbtl, t) -> (t, strbtl) | _ -> assert false in
  1612. (* public static void funcName *)
  1613. 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);
  1614. let params, params_ext = get_string_params cf.cf_params in
  1615. (* <T>(string arg1, object arg2) with T : object *)
  1616. (match cf.cf_expr with
  1617. | Some { eexpr = TFunction tf } ->
  1618. print w "%s(%s)%s" (params) (String.concat ", " (List.map2 (fun (var, _) (_,_,t) -> sprintf "%s %s" (argt_s t) (change_id var.v_name)) tf.tf_args args)) (params_ext)
  1619. | _ ->
  1620. print w "%s(%s)%s" (params) (String.concat ", " (List.map (fun (name, _, t) -> sprintf "%s %s" (argt_s t) (change_id name)) args)) (params_ext)
  1621. );
  1622. if is_interface then
  1623. write w ";"
  1624. else begin
  1625. let rec loop meta =
  1626. match meta with
  1627. | [] ->
  1628. let expr = match cf.cf_expr with
  1629. | None -> mk (TBlock([])) t_dynamic Ast.null_pos
  1630. | Some s ->
  1631. match s.eexpr with
  1632. | TFunction tf ->
  1633. mk_block (tf.tf_expr)
  1634. | _ -> assert false (* FIXME *)
  1635. in
  1636. (if is_new then begin
  1637. let rec get_super_call el =
  1638. match el with
  1639. | ( { eexpr = TCall( { eexpr = TConst(TSuper) }, _) } as call) :: rest ->
  1640. Some call, rest
  1641. | ( { eexpr = TBlock(bl) } as block ) :: rest ->
  1642. let ret, mapped = get_super_call bl in
  1643. ret, ( { block with eexpr = TBlock(mapped) } :: rest )
  1644. | _ ->
  1645. None, el
  1646. in
  1647. match expr.eexpr with
  1648. | TBlock(bl) ->
  1649. let super_call, rest = get_super_call bl in
  1650. (match super_call with
  1651. | None -> ()
  1652. | Some sc ->
  1653. write w " : ";
  1654. let t = Common.timer "expression to string" in
  1655. expr_s w sc;
  1656. t()
  1657. );
  1658. begin_block w;
  1659. write w "unchecked ";
  1660. let t = Common.timer "expression to string" in
  1661. expr_s w { expr with eexpr = TBlock(rest) };
  1662. t();
  1663. if not (Common.defined gen.gcon Define.RealPosition) then write w "#line default";
  1664. end_block w;
  1665. | _ -> assert false
  1666. end else begin
  1667. begin_block w;
  1668. write w "unchecked ";
  1669. let t = Common.timer "expression to string" in
  1670. expr_s w expr;
  1671. t();
  1672. if not (Common.defined gen.gcon Define.RealPosition) then write w "#line default";
  1673. end_block w;
  1674. end)
  1675. | (Meta.FunctionCode, [Ast.EConst (Ast.String contents),_],_) :: tl ->
  1676. begin_block w;
  1677. write w contents;
  1678. end_block w
  1679. | _ :: tl -> loop tl
  1680. in
  1681. loop cf.cf_meta
  1682. end);
  1683. newline w;
  1684. newline w;
  1685. in
  1686. let check_special_behaviors w cl = match cl.cl_kind with
  1687. | KAbstractImpl _ -> ()
  1688. | _ ->
  1689. (* get/set pairs *)
  1690. let pairs = ref PMap.empty in
  1691. (try
  1692. let get = PMap.find "__get" cl.cl_fields in
  1693. List.iter (fun cf ->
  1694. let args,ret = get_fun cf.cf_type in
  1695. match args with
  1696. | [_,_,idx] -> pairs := PMap.add (t_s idx) ( t_s ret, Some cf, None ) !pairs
  1697. | _ -> gen.gcon.warning "The __get function must have exactly one argument (the index)" cf.cf_pos
  1698. ) (get :: get.cf_overloads)
  1699. with | Not_found -> ());
  1700. (try
  1701. let set = PMap.find "__set" cl.cl_fields in
  1702. List.iter (fun cf ->
  1703. let args, ret = get_fun cf.cf_type in
  1704. match args with
  1705. | [_,_,idx; _,_,v] -> (try
  1706. let vt, g, _ = PMap.find (t_s idx) !pairs in
  1707. let tvt = t_s v in
  1708. if vt <> tvt then gen.gcon.warning "The __get function of same index has a different type from this __set function" cf.cf_pos;
  1709. pairs := PMap.add (t_s idx) (vt, g, Some cf) !pairs
  1710. with | Not_found ->
  1711. pairs := PMap.add (t_s idx) (t_s v, None, Some cf) !pairs)
  1712. | _ ->
  1713. gen.gcon.warning "The __set function must have exactly two arguments (index, value)" cf.cf_pos
  1714. ) (set :: set.cf_overloads)
  1715. with | Not_found -> ());
  1716. PMap.iter (fun idx (v, get, set) ->
  1717. print w "public %s this[%s index]" v idx;
  1718. begin_block w;
  1719. (match get with
  1720. | None -> ()
  1721. | Some _ ->
  1722. write w "get";
  1723. begin_block w;
  1724. write w "return this.__get(index);";
  1725. end_block w);
  1726. (match set with
  1727. | None -> ()
  1728. | Some _ ->
  1729. write w "set";
  1730. begin_block w;
  1731. write w "this.__set(index,value);";
  1732. end_block w);
  1733. end_block w) !pairs;
  1734. (if not (PMap.is_empty !pairs) then try
  1735. let get = PMap.find "__get" cl.cl_fields in
  1736. let idx_t, v_t = match follow get.cf_type with
  1737. | TFun([_,_,arg_t],ret_t) ->
  1738. t_s (run_follow gen arg_t), t_s (run_follow gen ret_t)
  1739. | _ -> gen.gcon.error "The __get function must be a function with one argument. " get.cf_pos; assert false
  1740. in
  1741. List.iter (fun (cl,args) ->
  1742. match cl.cl_array_access with
  1743. | None -> ()
  1744. | Some t ->
  1745. let changed_t = apply_params cl.cl_types (List.map (fun _ -> t_dynamic) cl.cl_types) t in
  1746. let t_as_s = t_s (run_follow gen changed_t) in
  1747. print w "%s %s.this[int key]" t_as_s (t_s (TInst(cl, args)));
  1748. begin_block w;
  1749. write w "get";
  1750. begin_block w;
  1751. print w "return ((%s) this.__get(key));" t_as_s;
  1752. end_block w;
  1753. write w "set";
  1754. begin_block w;
  1755. print w "this.__set(key, (%s) value);" v_t;
  1756. end_block w;
  1757. end_block w;
  1758. newline w;
  1759. newline w
  1760. ) cl.cl_implements
  1761. with | Not_found -> ());
  1762. if cl.cl_interface && is_hxgen (TClassDecl cl) && is_some cl.cl_array_access then begin
  1763. let changed_t = apply_params cl.cl_types (List.map (fun _ -> t_dynamic) cl.cl_types) (get cl.cl_array_access) in
  1764. print w "%s this[int key]" (t_s (run_follow gen changed_t));
  1765. begin_block w;
  1766. write w "get;";
  1767. newline w;
  1768. write w "set;";
  1769. newline w;
  1770. end_block w;
  1771. newline w;
  1772. newline w
  1773. end;
  1774. (try
  1775. if cl.cl_interface then raise Not_found;
  1776. let cf = PMap.find "toString" cl.cl_fields in
  1777. (if List.exists (fun c -> c.cf_name = "toString") cl.cl_overrides then raise Not_found);
  1778. (match cf.cf_type with
  1779. | TFun([], ret) ->
  1780. (match real_type ret with
  1781. | TInst( { cl_path = ([], "String") }, []) ->
  1782. write w "public override string ToString()";
  1783. begin_block w;
  1784. write w "return this.toString();";
  1785. end_block w;
  1786. newline w;
  1787. newline w
  1788. | _ ->
  1789. gen.gcon.error "A toString() function should return a String!" cf.cf_pos
  1790. )
  1791. | _ -> ()
  1792. )
  1793. with | Not_found -> ());
  1794. (* properties *
  1795. let handle_prop static f =
  1796. match f.cf_kind with
  1797. | Method _ -> ()
  1798. | Var v when not (Type.is_extern_field f) -> ()
  1799. | Var v ->
  1800. let prop acc = match acc with
  1801. | AccNo | AccNever | AccCall -> true
  1802. | _ -> false
  1803. in
  1804. if prop v.v_read && prop v.v_write && (v.v_read = AccCall || v.v_write = AccCall) then begin
  1805. let this = if static then
  1806. mk_classtype_access cl f.cf_pos
  1807. else
  1808. { eexpr = TConst TThis; etype = TInst(cl,List.map snd cl.cl_types); epos = f.cf_pos }
  1809. in
  1810. print w "public %s%s %s" (if static then "static " else "") (t_s f.cf_type) f.cf_name;
  1811. begin_block w;
  1812. (match v.v_read with
  1813. | AccCall ->
  1814. write w "get";
  1815. begin_block w;
  1816. write w "return ";
  1817. expr_s w this;
  1818. print w "._get_%s();" f.cf_name;
  1819. end_block w
  1820. | _ -> ());
  1821. (match v.v_write with
  1822. | AccCall ->
  1823. write w "set";
  1824. begin_block w;
  1825. expr_s w this;
  1826. print w "._set_%s(value);" f.cf_name;
  1827. end_block w
  1828. | _ -> ());
  1829. end_block w;
  1830. end
  1831. in
  1832. List.iter (handle_prop true) cl.cl_ordered_statics;
  1833. List.iter (handle_prop false) cl.cl_ordered_fields*)
  1834. in
  1835. let gen_class w cl =
  1836. write w "#pragma warning disable 109, 114, 219, 429, 168, 162";
  1837. newline w;
  1838. let should_close = match change_ns (TClassDecl cl) (fst (cl.cl_path)) with
  1839. | [] -> false
  1840. | ns ->
  1841. print w "namespace %s" (String.concat "." ns);
  1842. begin_block w;
  1843. true
  1844. in
  1845. gen_attributes w cl.cl_meta;
  1846. let is_main =
  1847. match gen.gcon.main_class with
  1848. | Some ( (_,"Main") as path) when path = cl.cl_path && not cl.cl_interface ->
  1849. (*
  1850. for cases where the main class is called Main, there will be a problem with creating the entry point there.
  1851. In this special case, a special entry point class will be created
  1852. *)
  1853. write w "public class EntryPoint__Main";
  1854. begin_block w;
  1855. write w "public static void Main()";
  1856. begin_block w;
  1857. (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "global::cs.Boot.init();"; newline w);
  1858. expr_s w { eexpr = TTypeExpr(TClassDecl cl); etype = t_dynamic; epos = Ast.null_pos };
  1859. write w ".main();";
  1860. end_block w;
  1861. end_block w;
  1862. false
  1863. | Some path when path = cl.cl_path && not cl.cl_interface -> true
  1864. | _ -> false
  1865. in
  1866. let clt, access, modifiers = get_class_modifiers cl.cl_meta (if cl.cl_interface then "interface" else "class") "public" [] in
  1867. let is_final = clt = "struct" || Meta.has Meta.Final cl.cl_meta in
  1868. print w "%s %s %s %s" access (String.concat " " modifiers) clt (change_clname (snd cl.cl_path));
  1869. (* type parameters *)
  1870. let params, params_ext = get_string_params cl.cl_types in
  1871. 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
  1872. (match extends_implements with
  1873. | [] -> print w "%s %s" params params_ext
  1874. | _ -> print w "%s : %s %s" params (String.concat ", " extends_implements) params_ext);
  1875. (* class head ok: *)
  1876. (* public class Test<A> : X, Y, Z where A : Y *)
  1877. begin_block w;
  1878. (* our constructor is expected to be a normal "new" function *
  1879. if !strict_mode && is_some cl.cl_constructor then assert false;*)
  1880. let rec loop meta =
  1881. match meta with
  1882. | [] -> ()
  1883. | (Meta.ClassCode, [Ast.EConst (Ast.String contents),_],_) :: tl ->
  1884. write w contents
  1885. | _ :: tl -> loop tl
  1886. in
  1887. loop cl.cl_meta;
  1888. if is_main then begin
  1889. write w "public static void Main()";
  1890. begin_block w;
  1891. (if Hashtbl.mem gen.gtypes (["cs"], "Boot") then write w "global::cs.Boot.init();"; newline w);
  1892. write w "main();";
  1893. end_block w
  1894. end;
  1895. (match cl.cl_init with
  1896. | None -> ()
  1897. | Some init ->
  1898. print w "static %s() " (snd cl.cl_path);
  1899. expr_s w (mk_block init));
  1900. (* collect properties *)
  1901. let partition_props cl cflist =
  1902. let t = TInst(cl, List.map snd cl.cl_types) in
  1903. (* first get all vars declared as properties *)
  1904. let props, nonprops = List.partition (fun v -> match v.cf_kind with
  1905. | Var { v_read = AccCall } | Var { v_write = AccCall } ->
  1906. Type.is_extern_field v && Meta.has Meta.Property v.cf_meta
  1907. | _ -> false
  1908. ) cflist in
  1909. let props = ref (List.map (fun v -> (v.cf_name, ref (v,v.cf_type,None,None))) props) in
  1910. let find_prop name = try
  1911. List.assoc name !props
  1912. with | Not_found -> match field_access gen t name with
  1913. | FClassField (_,_,decl,v,_,t,_) when is_extern_prop (TInst(cl,List.map snd cl.cl_types)) name ->
  1914. let ret = ref (v,t,None,None) in
  1915. props := (name, ret) :: !props;
  1916. ret
  1917. | _ -> raise Not_found
  1918. in
  1919. (* get all functions that are getters/setters *)
  1920. List.iter (function
  1921. | cf when String.starts_with cf.cf_name "get_" -> (try
  1922. (* find the property *)
  1923. let prop = find_prop (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in
  1924. let v, t, get, set = !prop in
  1925. assert (get = None);
  1926. prop := (v,t,Some cf,set);
  1927. with | Not_found -> ())
  1928. | cf when String.starts_with cf.cf_name "set_" -> (try
  1929. (* find the property *)
  1930. let prop = find_prop (String.sub cf.cf_name 4 (String.length cf.cf_name - 4)) in
  1931. let v, t, get, set = !prop in
  1932. assert (set = None);
  1933. prop := (v,t,get,Some cf);
  1934. with | Not_found -> ())
  1935. | _ -> ()
  1936. ) nonprops;
  1937. let ret = List.map (fun (_,v) -> !v) !props in
  1938. let ret = List.filter (function | (_,_,None,None) -> false | _ -> true) ret in
  1939. ret, nonprops
  1940. in
  1941. let fprops, fnonprops = partition_props cl cl.cl_ordered_fields in
  1942. let sprops, snonprops = partition_props cl cl.cl_ordered_statics in
  1943. (if is_some cl.cl_constructor then gen_class_field w false cl is_final (get cl.cl_constructor));
  1944. if not cl.cl_interface then begin
  1945. (* we don't want to generate properties for abstrac implementation classes, because they don't have object to work with *)
  1946. if (match cl.cl_kind with KAbstractImpl _ -> false | _ -> true) then List.iter (gen_prop w true cl is_final) sprops;
  1947. List.iter (gen_class_field w true cl is_final) snonprops
  1948. end;
  1949. List.iter (gen_prop w false cl is_final) fprops;
  1950. List.iter (gen_class_field w false cl is_final) fnonprops;
  1951. check_special_behaviors w cl;
  1952. end_block w;
  1953. if cl.cl_interface && cl.cl_ordered_statics <> [] then begin
  1954. print w "public class %s__Statics_" (snd cl.cl_path);
  1955. begin_block w;
  1956. List.iter (gen_class_field w true { cl with cl_interface = false } is_final) cl.cl_ordered_statics;
  1957. end_block w
  1958. end;
  1959. if should_close then end_block w
  1960. in
  1961. let gen_enum w e =
  1962. let should_close = match change_ns (TEnumDecl e) (fst e.e_path) with
  1963. | [] -> false
  1964. | ns ->
  1965. print w "namespace %s" (String.concat "." ns);
  1966. begin_block w;
  1967. true
  1968. in
  1969. gen_attributes w e.e_meta;
  1970. print w "public enum %s" (change_clname (snd e.e_path));
  1971. begin_block w;
  1972. write w (String.concat ", " (List.map (change_id) e.e_names));
  1973. end_block w;
  1974. if should_close then end_block w
  1975. in
  1976. let module_type_gen w md_tp =
  1977. match md_tp with
  1978. | TClassDecl cl ->
  1979. if not cl.cl_extern then begin
  1980. (if no_root && len w = 0 then write w "using haxe.root;"; newline w;);
  1981. gen_class w cl;
  1982. newline w;
  1983. newline w
  1984. end;
  1985. (not cl.cl_extern)
  1986. | TEnumDecl e ->
  1987. if not e.e_extern then begin
  1988. (if no_root && len w = 0 then write w "using haxe.root;"; newline w;);
  1989. gen_enum w e;
  1990. newline w;
  1991. newline w
  1992. end;
  1993. (not e.e_extern)
  1994. | TAbstractDecl _
  1995. | TTypeDecl _ ->
  1996. false
  1997. in
  1998. let module_gen w md_def =
  1999. List.fold_left (fun should md -> module_type_gen w md || should) false md_def.m_types
  2000. in
  2001. (* generate source code *)
  2002. init_ctx gen;
  2003. Hashtbl.add gen.gspecial_vars "__rethrow__" true;
  2004. Hashtbl.add gen.gspecial_vars "__typeof__" true;
  2005. Hashtbl.add gen.gspecial_vars "__label__" true;
  2006. Hashtbl.add gen.gspecial_vars "__goto__" true;
  2007. Hashtbl.add gen.gspecial_vars "__is__" true;
  2008. Hashtbl.add gen.gspecial_vars "__as__" true;
  2009. Hashtbl.add gen.gspecial_vars "__cs__" true;
  2010. Hashtbl.add gen.gspecial_vars "__checked__" true;
  2011. Hashtbl.add gen.gspecial_vars "__lock__" true;
  2012. Hashtbl.add gen.gspecial_vars "__fixed__" true;
  2013. Hashtbl.add gen.gspecial_vars "__unsafe__" true;
  2014. Hashtbl.add gen.gspecial_vars "__addressOf__" true;
  2015. Hashtbl.add gen.gspecial_vars "__valueOf__" true;
  2016. Hashtbl.add gen.gspecial_vars "__sizeof__" true;
  2017. Hashtbl.add gen.gspecial_vars "__delegate__" true;
  2018. Hashtbl.add gen.gsupported_conversions (["haxe"; "lang"], "Null") (fun t1 t2 -> true);
  2019. let last_needs_box = gen.gneeds_box in
  2020. gen.gneeds_box <- (fun t -> match t with | TInst( { cl_path = (["haxe"; "lang"], "Null") }, _ ) -> true | _ -> last_needs_box t);
  2021. gen.greal_type <- real_type;
  2022. gen.greal_type_param <- change_param_type;
  2023. SetHXGen.run_filter gen SetHXGen.default_hxgen_func;
  2024. (* before running the filters, follow all possible types *)
  2025. (* this is needed so our module transformations don't break some core features *)
  2026. (* like multitype selection *)
  2027. let run_follow_gen = run_follow gen in
  2028. let rec type_map e = Type.map_expr_type (fun e->type_map e) (run_follow_gen) (fun tvar-> tvar.v_type <- (run_follow_gen tvar.v_type); tvar) e in
  2029. let super_map (cl,tl) = (cl, List.map run_follow_gen tl) in
  2030. List.iter (function
  2031. | TClassDecl cl ->
  2032. let all_fields = (Option.map_default (fun cf -> [cf]) [] cl.cl_constructor) @ cl.cl_ordered_fields @ cl.cl_ordered_statics in
  2033. List.iter (fun cf ->
  2034. cf.cf_type <- run_follow_gen cf.cf_type;
  2035. cf.cf_expr <- Option.map type_map cf.cf_expr
  2036. ) all_fields;
  2037. cl.cl_dynamic <- Option.map run_follow_gen cl.cl_dynamic;
  2038. cl.cl_array_access <- Option.map run_follow_gen cl.cl_array_access;
  2039. cl.cl_init <- Option.map type_map cl.cl_init;
  2040. cl.cl_super <- Option.map super_map cl.cl_super;
  2041. cl.cl_implements <- List.map super_map cl.cl_implements
  2042. | _ -> ()
  2043. ) gen.gcon.types;
  2044. let closure_t = ClosuresToClass.DoubleAndDynamicClosureImpl.get_ctx gen 6 in
  2045. (*let closure_t = ClosuresToClass.create gen 10 float_cl
  2046. (fun l -> l)
  2047. (fun l -> l)
  2048. (fun args -> args)
  2049. (fun args -> [])
  2050. in
  2051. ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (fun e _ _ -> e));
  2052. StubClosureImpl.configure gen (StubClosureImpl.default_implementation gen float_cl 10 (fun e _ _ -> e));*)
  2053. let tp_v = alloc_var "$type_param" t_dynamic in
  2054. let mk_tp t pos = { eexpr = TLocal(tp_v); etype = t; epos = pos } in
  2055. TypeParams.configure gen (fun ecall efield params elist ->
  2056. match efield.eexpr with
  2057. | TField(_, FEnum _) ->
  2058. { ecall with eexpr = TCall(efield, elist) }
  2059. | _ ->
  2060. { ecall with eexpr = TCall(efield, (List.map (fun t -> mk_tp t ecall.epos ) params) @ elist) }
  2061. );
  2062. HardNullableSynf.configure gen (HardNullableSynf.traverse gen
  2063. (fun e ->
  2064. match real_type e.etype with
  2065. | TInst({ cl_path = (["haxe";"lang"], "Null") }, [t]) ->
  2066. { (mk_field_access gen e "value" e.epos) with etype = t }
  2067. | _ ->
  2068. trace (debug_type e.etype); gen.gcon.error "This expression is not a Nullable expression" e.epos; assert false
  2069. )
  2070. (fun v t has_value ->
  2071. match has_value, real_type v.etype with
  2072. | true, TDynamic _ | true, TAnon _ | true, TMono _ ->
  2073. {
  2074. eexpr = TCall(mk_static_field_access_infer null_t "ofDynamic" v.epos [t], [mk_tp t v.epos; v]);
  2075. etype = TInst(null_t, [t]);
  2076. epos = v.epos
  2077. }
  2078. | _ ->
  2079. { 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 }
  2080. )
  2081. (fun e ->
  2082. {
  2083. eexpr = TCall(
  2084. { (mk_field_access gen { (mk_paren e) with etype = real_type e.etype } "toDynamic" e.epos) with etype = TFun([], t_dynamic) },
  2085. []);
  2086. etype = t_dynamic;
  2087. epos = e.epos
  2088. }
  2089. )
  2090. (fun e ->
  2091. mk_field_access gen { e with etype = real_type e.etype } "hasValue" e.epos
  2092. )
  2093. (fun e1 e2 ->
  2094. {
  2095. eexpr = TCall(
  2096. mk_field_access gen e1 "Equals" e1.epos,
  2097. [e2]);
  2098. etype = basic.tbool;
  2099. epos = e1.epos;
  2100. }
  2101. )
  2102. true
  2103. false
  2104. );
  2105. let explicit_fn_name c tl fname =
  2106. path_param_s (TClassDecl c) c.cl_path tl ^ "." ^ fname
  2107. in
  2108. FixOverrides.configure ~explicit_fn_name:explicit_fn_name gen;
  2109. Normalize.configure gen ~metas:(Hashtbl.create 0);
  2110. AbstractImplementationFix.configure gen;
  2111. IteratorsInterface.configure gen (fun e -> e);
  2112. OverrideFix.configure gen;
  2113. ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
  2114. 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;
  2115. InterfaceVarsDeleteModf.configure gen;
  2116. InterfaceProps.configure gen;
  2117. let dynamic_object = (get_cl (get_type gen (["haxe";"lang"],"DynamicObject")) ) in
  2118. let object_iface = get_cl (get_type gen (["haxe";"lang"],"IHxObject")) in
  2119. (*fixme: THIS IS A HACK. take this off *)
  2120. let empty_e = match (get_type gen (["haxe";"lang"], "EmptyObject")) with | TEnumDecl e -> e | _ -> assert false in
  2121. (*OverloadingCtor.set_new_create_empty gen ({eexpr=TEnumField(empty_e, "EMPTY"); etype=TEnum(empty_e,[]); epos=null_pos;});*)
  2122. let empty_expr = { eexpr = (TTypeExpr (TEnumDecl empty_e)); etype = (TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics empty_e) }); epos = null_pos } in
  2123. let empty_ef =
  2124. try
  2125. PMap.find "EMPTY" empty_e.e_constrs
  2126. with Not_found -> gen.gcon.error "Required enum field EMPTY was not found" empty_e.e_pos; assert false
  2127. in
  2128. OverloadingConstructor.configure ~empty_ctor_type:(TEnum(empty_e, [])) ~empty_ctor_expr:({ eexpr=TField(empty_expr, FEnum(empty_e, empty_ef)); etype=TEnum(empty_e,[]); epos=null_pos; }) ~supports_ctor_inheritance:false gen;
  2129. let rcf_static_find = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "findHash" Ast.null_pos [] in
  2130. let rcf_static_lookup = mk_static_field_access_infer (get_cl (get_type gen (["haxe";"lang"], "FieldLookup"))) "lookupHash" Ast.null_pos [] in
  2131. let can_be_float = like_float in
  2132. let rcf_on_getset_field main_expr field_expr field may_hash may_set is_unsafe =
  2133. let is_float = can_be_float (real_type main_expr.etype) in
  2134. let fn_name = if is_some may_set then "setField" else "getField" in
  2135. let fn_name = if is_float then fn_name ^ "_f" else fn_name in
  2136. let pos = field_expr.epos in
  2137. let is_unsafe = { eexpr = TConst(TBool is_unsafe); etype = basic.tbool; epos = pos } in
  2138. let should_cast = match main_expr.etype with | TInst({ cl_path = ([], "Float") }, []) -> false | _ -> true in
  2139. let infer = mk_static_field_access_infer runtime_cl fn_name field_expr.epos [] in
  2140. let first_args =
  2141. [ field_expr; { eexpr = TConst(TString field); etype = basic.tstring; epos = pos } ]
  2142. @ if is_some may_hash then [ { eexpr = TConst(TInt (get may_hash)); etype = basic.tint; epos = pos } ] else []
  2143. in
  2144. let args = first_args @ match is_float, may_set with
  2145. | true, Some(set) ->
  2146. [ if should_cast then mk_cast basic.tfloat set else set ]
  2147. | false, Some(set) ->
  2148. [ set ]
  2149. | _ ->
  2150. [ is_unsafe ]
  2151. in
  2152. let call = { main_expr with eexpr = TCall(infer,args) } in
  2153. let call = if is_float && should_cast then mk_cast main_expr.etype call else call in
  2154. call
  2155. in
  2156. let rcf_on_call_field ecall field_expr field may_hash args =
  2157. let infer = mk_static_field_access_infer runtime_cl "callField" field_expr.epos [] in
  2158. let hash_arg = match may_hash with
  2159. | None -> []
  2160. | Some h -> [ { eexpr = TConst(TInt h); etype = basic.tint; epos = field_expr.epos } ]
  2161. in
  2162. let arr_call = if args <> [] then
  2163. { eexpr = TArrayDecl args; etype = basic.tarray t_dynamic; epos = ecall.epos }
  2164. else
  2165. null (basic.tarray t_dynamic) ecall.epos
  2166. in
  2167. let call_args =
  2168. [field_expr; { field_expr with eexpr = TConst(TString field); etype = basic.tstring } ]
  2169. @ hash_arg
  2170. @ [ arr_call ]
  2171. in
  2172. mk_cast ecall.etype { ecall with eexpr = TCall(infer, call_args) }
  2173. in
  2174. handle_type_params gen ifaces (get_cl (get_type gen (["haxe";"lang"], "IGenericObject")));
  2175. let rcf_ctx = ReflectionCFs.new_ctx gen closure_t object_iface true rcf_on_getset_field rcf_on_call_field (fun hash hash_array ->
  2176. { hash with eexpr = TCall(rcf_static_find, [hash; hash_array]); etype=basic.tint }
  2177. ) (fun hash -> { hash with eexpr = TCall(rcf_static_lookup, [hash]); etype = gen.gcon.basic.tstring } ) false in
  2178. ReflectionCFs.UniversalBaseClass.default_config gen (get_cl (get_type gen (["haxe";"lang"],"HxObject")) ) object_iface dynamic_object;
  2179. ReflectionCFs.configure_dynamic_field_access rcf_ctx false;
  2180. (* let closure_func = ReflectionCFs.implement_closure_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"],"Closure")) ) in *)
  2181. let closure_cl = get_cl (get_type gen (["haxe";"lang"],"Closure")) in
  2182. let varargs_cl = get_cl (get_type gen (["haxe";"lang"],"VarArgsFunction")) in
  2183. let dynamic_name = gen.gmk_internal_name "hx" "invokeDynamic" in
  2184. List.iter (fun cl ->
  2185. List.iter (fun cf ->
  2186. if cf.cf_name = dynamic_name then cl.cl_overrides <- cf :: cl.cl_overrides
  2187. ) cl.cl_ordered_fields
  2188. ) [closure_cl; varargs_cl];
  2189. let closure_func = ReflectionCFs.get_closure_func rcf_ctx closure_cl in
  2190. ReflectionCFs.implement_varargs_cl rcf_ctx ( get_cl (get_type gen (["haxe";"lang"], "VarArgsBase")) );
  2191. let slow_invoke = mk_static_field_access_infer (runtime_cl) "slowCallField" Ast.null_pos [] in
  2192. ReflectionCFs.configure rcf_ctx ~slow_invoke:(fun ethis efield eargs -> {
  2193. eexpr = TCall(slow_invoke, [ethis; efield; eargs]);
  2194. etype = t_dynamic;
  2195. epos = ethis.epos;
  2196. } ) object_iface;
  2197. let objdecl_fn = ReflectionCFs.implement_dynamic_object_ctor rcf_ctx dynamic_object in
  2198. ObjectDeclMap.configure gen (ObjectDeclMap.traverse gen objdecl_fn);
  2199. InitFunction.configure gen true;
  2200. TArrayTransform.configure gen (TArrayTransform.default_implementation gen (
  2201. fun e binop ->
  2202. match e.eexpr with
  2203. | TArray(e1, e2) ->
  2204. ( match follow e1.etype with
  2205. | TDynamic _ | TAnon _ | TMono _ -> true
  2206. | TInst({ cl_kind = KTypeParameter _ }, _) -> true
  2207. | _ -> match binop, change_param_type (t_to_md e1.etype) [e.etype] with
  2208. | Some(Ast.OpAssignOp _), ([TDynamic _] | [TAnon _]) ->
  2209. true
  2210. | _ -> false)
  2211. | _ -> assert false
  2212. ) "__get" "__set" );
  2213. let field_is_dynamic t field =
  2214. match field_access_esp gen (gen.greal_type t) field with
  2215. | FEnumField _
  2216. | FClassField _ -> false
  2217. | _ -> true
  2218. in
  2219. let is_type_param e = match follow e with
  2220. | TInst( { cl_kind = KTypeParameter _ },[]) -> true
  2221. | _ -> false
  2222. in
  2223. let is_dynamic_expr e = is_dynamic e.etype || match e.eexpr with
  2224. | TField(tf, f) -> field_is_dynamic tf.etype (f)
  2225. | _ -> false
  2226. in
  2227. let may_nullable t = match gen.gfollow#run_f t with
  2228. | TType({ t_path = ([], "Null") }, [t]) ->
  2229. (match follow t with
  2230. | TInst({ cl_path = ([], "String") }, [])
  2231. | TInst({ cl_path = ([], "Float") }, [])
  2232. | TAbstract ({ a_path = ([], "Float") },[])
  2233. | TInst({ cl_path = (["haxe"], "Int32")}, [] )
  2234. | TInst({ cl_path = (["haxe"], "Int64")}, [] )
  2235. | TInst({ cl_path = ([], "Int") }, [])
  2236. | TAbstract ({ a_path = ([], "Int") },[])
  2237. | TEnum({ e_path = ([], "Bool") }, [])
  2238. | TAbstract ({ a_path = ([], "Bool") },[]) -> Some t
  2239. | TAbstract _ when like_float t -> Some t
  2240. | _ -> None )
  2241. | _ -> None
  2242. in
  2243. let is_double t = like_float t && not (like_int t) in
  2244. let is_int t = like_int t in
  2245. let is_null t = match real_type t with
  2246. | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true
  2247. | _ -> false
  2248. in
  2249. let is_null_expr e = is_null e.etype || match e.eexpr with
  2250. | TField(tf, f) -> (match field_access_esp gen (real_type tf.etype) (f) with
  2251. | FClassField(_,_,_,_,_,actual_t,_) -> is_null actual_t
  2252. | _ -> false)
  2253. | _ -> false
  2254. in
  2255. let should_handle_opeq t =
  2256. match real_type t with
  2257. | TDynamic _ | TAnon _ | TMono _
  2258. | TInst( { cl_kind = KTypeParameter _ }, _ )
  2259. | TInst( { cl_path = (["haxe";"lang"], "Null") }, _ ) -> true
  2260. | _ -> false
  2261. in
  2262. let string_cl = match gen.gcon.basic.tstring with
  2263. | TInst(c,[]) -> c
  2264. | _ -> assert false
  2265. in
  2266. DynamicOperators.configure gen
  2267. (DynamicOperators.abstract_implementation gen (fun e -> match e.eexpr with
  2268. | TBinop (Ast.OpEq, e1, e2)
  2269. | TBinop (Ast.OpNotEq, e1, e2) ->
  2270. (
  2271. (* dont touch (v == null) and (null == v) comparisons because they are handled by HardNullableSynf later *)
  2272. match e1.eexpr, e2.eexpr with
  2273. | TConst(TNull), _ when is_null_expr e2 ->
  2274. false
  2275. | _, TConst(TNull) when is_null_expr e1 ->
  2276. false
  2277. | _ ->
  2278. should_handle_opeq e1.etype || should_handle_opeq e2.etype
  2279. )
  2280. | TBinop (Ast.OpAssignOp Ast.OpAdd, e1, e2) ->
  2281. is_dynamic_expr e1 || is_null_expr e1 || is_string e.etype
  2282. | TBinop (Ast.OpAdd, e1, e2) -> is_dynamic e1.etype || is_dynamic e2.etype || is_type_param e1.etype || is_type_param e2.etype || is_string e1.etype || is_string e2.etype || is_string e.etype
  2283. | TBinop (Ast.OpLt, e1, e2)
  2284. | TBinop (Ast.OpLte, e1, e2)
  2285. | TBinop (Ast.OpGte, e1, e2)
  2286. | TBinop (Ast.OpGt, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2 || is_string e1.etype || is_string e2.etype
  2287. | TBinop (_, e1, e2) -> is_dynamic e.etype || is_dynamic_expr e1 || is_dynamic_expr e2
  2288. | 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 *)
  2289. | _ -> false)
  2290. (fun e1 e2 ->
  2291. let is_basic = is_cs_basic_type (follow e1.etype) || is_cs_basic_type (follow e2.etype) in
  2292. let is_ref = if is_basic then false else match follow e1.etype, follow e2.etype with
  2293. | TDynamic _, _
  2294. | _, TDynamic _
  2295. | TInst( { cl_path = ([], "String") }, [] ), _
  2296. | _, TInst( { cl_path = ([], "String") }, [] )
  2297. | TInst( { cl_kind = KTypeParameter _ }, [] ), _
  2298. | _, TInst( { cl_kind = KTypeParameter _ }, [] ) -> false
  2299. | _, _ -> true
  2300. in
  2301. let static = mk_static_field_access_infer (runtime_cl) (if is_ref then "refEq" else "eq") e1.epos [] in
  2302. { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tbool; epos=e1.epos }
  2303. )
  2304. (fun e e1 e2 ->
  2305. match may_nullable e1.etype, may_nullable e2.etype with
  2306. | Some t1, Some t2 ->
  2307. let t1, t2 = if is_string t1 || is_string t2 then
  2308. basic.tstring, basic.tstring
  2309. else if is_double t1 || is_double t2 then
  2310. basic.tfloat, basic.tfloat
  2311. else if is_int t1 || is_int t2 then
  2312. basic.tint, basic.tint
  2313. else t1, t2 in
  2314. { eexpr = TBinop(Ast.OpAdd, mk_cast t1 e1, mk_cast t2 e2); etype = e.etype; epos = e1.epos }
  2315. | _ when is_string e.etype || is_string e1.etype || is_string e2.etype ->
  2316. {
  2317. eexpr = TCall(
  2318. mk_static_field_access_infer runtime_cl "concat" e.epos [],
  2319. [ e1; e2 ]
  2320. );
  2321. etype = basic.tstring;
  2322. epos = e.epos
  2323. }
  2324. | _ ->
  2325. let static = mk_static_field_access_infer (runtime_cl) "plus" e1.epos [] in
  2326. mk_cast e.etype { eexpr = TCall(static, [e1; e2]); etype = t_dynamic; epos=e1.epos })
  2327. (fun e1 e2 ->
  2328. if is_string e1.etype then begin
  2329. { e1 with eexpr = TCall(mk_static_field_access_infer string_cl "Compare" e1.epos [], [ e1; e2 ]); etype = gen.gcon.basic.tint }
  2330. end else begin
  2331. let static = mk_static_field_access_infer (runtime_cl) "compare" e1.epos [] in
  2332. { eexpr = TCall(static, [e1; e2]); etype = gen.gcon.basic.tint; epos=e1.epos }
  2333. end) ~handle_strings:false);
  2334. FilterClosures.configure gen (FilterClosures.traverse gen (fun e1 s -> true) closure_func);
  2335. let base_exception = get_cl (get_type gen (["System"], "Exception")) in
  2336. let base_exception_t = TInst(base_exception, []) in
  2337. let hx_exception = get_cl (get_type gen (["haxe";"lang"], "HaxeException")) in
  2338. let hx_exception_t = TInst(hx_exception, []) in
  2339. let rec is_exception t =
  2340. match follow t with
  2341. | TInst(cl,_) ->
  2342. if cl == base_exception then
  2343. true
  2344. else
  2345. (match cl.cl_super with | None -> false | Some (cl,arg) -> is_exception (TInst(cl,arg)))
  2346. | _ -> false
  2347. in
  2348. TryCatchWrapper.configure gen
  2349. (
  2350. TryCatchWrapper.traverse gen
  2351. (fun t -> not (is_exception (real_type t)))
  2352. (fun throwexpr expr ->
  2353. let wrap_static = mk_static_field_access (hx_exception) "wrap" (TFun([("obj",false,t_dynamic)], base_exception_t)) expr.epos in
  2354. { throwexpr with eexpr = TThrow { expr with eexpr = TCall(wrap_static, [expr]); etype = hx_exception_t }; etype = gen.gcon.basic.tvoid }
  2355. )
  2356. (fun v_to_unwrap pos ->
  2357. let local = mk_cast hx_exception_t { eexpr = TLocal(v_to_unwrap); etype = v_to_unwrap.v_type; epos = pos } in
  2358. mk_field_access gen local "obj" pos
  2359. )
  2360. (fun rethrow ->
  2361. { rethrow with eexpr = TCall(mk_local (alloc_var "__rethrow__" t_dynamic) rethrow.epos, [rethrow]); etype = gen.gcon.basic.tvoid }
  2362. )
  2363. (base_exception_t)
  2364. (hx_exception_t)
  2365. (fun v e ->
  2366. let exc_cl = get_cl (get_type gen (["haxe";"lang"],"Exceptions")) in
  2367. let exc_field = mk_static_field_access_infer exc_cl "exception" e.epos [] in
  2368. let esetstack = mk (TBinop(Ast.OpAssign, exc_field, mk_local v e.epos)) v.v_type e.epos in
  2369. Type.concat esetstack e;
  2370. )
  2371. );
  2372. let get_typeof e =
  2373. { e with eexpr = TCall( { eexpr = TLocal( alloc_var "__typeof__" t_dynamic ); etype = t_dynamic; epos = e.epos }, [e] ) }
  2374. in
  2375. ClassInstance.configure gen (ClassInstance.traverse gen (fun e mt ->
  2376. get_typeof e
  2377. ));
  2378. CastDetect.configure gen (CastDetect.default_implementation gen (Some (TEnum(empty_e, []))) true ~native_string_cast:false ~overloads_cast_to_base:true);
  2379. (*FollowAll.configure gen;*)
  2380. SwitchToIf.configure gen (SwitchToIf.traverse gen (fun e ->
  2381. match e.eexpr with
  2382. | TSwitch(cond, cases, def) ->
  2383. (match gen.gfollow#run_f cond.etype with
  2384. | TInst({ cl_path = ([], "Int") },[])
  2385. | TAbstract ({ a_path = ([], "Int") },[])
  2386. | TInst({ cl_path = ([], "String") },[]) ->
  2387. (List.exists (fun (c,_) ->
  2388. List.exists (fun expr -> match expr.eexpr with | TConst _ -> false | _ -> true ) c
  2389. ) cases)
  2390. | _ -> true
  2391. )
  2392. | _ -> assert false
  2393. ) true ) ;
  2394. ExpressionUnwrap.configure gen (ExpressionUnwrap.traverse gen (fun e -> Some { eexpr = TVar(mk_temp gen "expr" e.etype, Some e); etype = gen.gcon.basic.tvoid; epos = e.epos }));
  2395. UnnecessaryCastsRemoval.configure gen;
  2396. IntDivisionSynf.configure gen (IntDivisionSynf.default_implementation gen true);
  2397. UnreachableCodeEliminationSynf.configure gen (UnreachableCodeEliminationSynf.traverse gen false true true false);
  2398. let native_arr_cl = get_cl ( get_type gen (["cs"], "NativeArray") ) in
  2399. ArrayDeclSynf.configure gen (ArrayDeclSynf.default_implementation gen native_arr_cl);
  2400. let goto_special = alloc_var "__goto__" t_dynamic in
  2401. let label_special = alloc_var "__label__" t_dynamic in
  2402. SwitchBreakSynf.configure gen (SwitchBreakSynf.traverse gen
  2403. (fun e_loop n api ->
  2404. 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;
  2405. e_loop
  2406. )
  2407. (fun e_break n api ->
  2408. { eexpr = TCall( mk_local goto_special e_break.epos, [ mk_int gen n e_break.epos ] ); etype = t_dynamic; epos = e_break.epos }
  2409. )
  2410. );
  2411. DefaultArguments.configure gen (DefaultArguments.traverse gen);
  2412. CSharpSpecificSynf.configure gen (CSharpSpecificSynf.traverse gen runtime_cl);
  2413. CSharpSpecificESynf.configure gen (CSharpSpecificESynf.traverse gen runtime_cl);
  2414. let mkdir dir = if not (Sys.file_exists dir) then Unix.mkdir dir 0o755 in
  2415. mkdir gen.gcon.file;
  2416. mkdir (gen.gcon.file ^ "/src");
  2417. (* copy resource files *)
  2418. if Hashtbl.length gen.gcon.resources > 0 then begin
  2419. mkdir (gen.gcon.file ^ "/src/Resources");
  2420. Hashtbl.iter (fun name v ->
  2421. let full_path = gen.gcon.file ^ "/src/Resources/" ^ name in
  2422. let parts = Str.split_delim (Str.regexp "[\\/]+") full_path in
  2423. let dir_list = List.rev (List.tl (List.rev parts)) in
  2424. Common.mkdir_recursive "" dir_list;
  2425. let f = open_out full_path in
  2426. output_string f v;
  2427. close_out f
  2428. ) gen.gcon.resources;
  2429. end;
  2430. (* add resources array *)
  2431. (try
  2432. let res = get_cl (Hashtbl.find gen.gtypes (["haxe"], "Resource")) in
  2433. let cf = PMap.find "content" res.cl_statics in
  2434. let res = ref [] in
  2435. Hashtbl.iter (fun name v ->
  2436. res := { eexpr = TConst(TString name); etype = gen.gcon.basic.tstring; epos = Ast.null_pos } :: !res;
  2437. ) gen.gcon.resources;
  2438. cf.cf_expr <- Some ({ eexpr = TArrayDecl(!res); etype = gen.gcon.basic.tarray gen.gcon.basic.tstring; epos = Ast.null_pos })
  2439. with | Not_found -> ());
  2440. run_filters gen;
  2441. (* after the filters have been run, add all hashed fields to FieldLookup *)
  2442. let normalize_i i =
  2443. let i = Int32.of_int (i) in
  2444. if i < Int32.zero then
  2445. Int32.logor (Int32.logand i (Int32.of_int 0x3FFFFFFF)) (Int32.shift_left Int32.one 30)
  2446. else i
  2447. in
  2448. let hashes = Hashtbl.fold (fun i s acc -> (normalize_i i,s) :: acc) rcf_ctx.rcf_hash_fields [] in
  2449. let hashes = List.sort (fun (i,s) (i2,s2) -> compare i i2) hashes in
  2450. let flookup_cl = get_cl (get_type gen (["haxe";"lang"], "FieldLookup")) in
  2451. (try
  2452. let basic = gen.gcon.basic in
  2453. let change_array = ArrayDeclSynf.default_implementation gen native_arr_cl in
  2454. let cl = flookup_cl in
  2455. let field_ids = PMap.find "fieldIds" cl.cl_statics in
  2456. let fields = PMap.find "fields" cl.cl_statics in
  2457. field_ids.cf_expr <- Some (change_array {
  2458. eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TInt (i)); etype = basic.tint; epos = field_ids.cf_pos }) hashes);
  2459. etype = basic.tarray basic.tint;
  2460. epos = field_ids.cf_pos
  2461. });
  2462. fields.cf_expr <- Some (change_array {
  2463. eexpr = TArrayDecl(List.map (fun (i,s) -> { eexpr = TConst(TString s); etype = basic.tstring; epos = fields.cf_pos }) hashes);
  2464. etype = basic.tarray basic.tstring;
  2465. epos = fields.cf_pos
  2466. })
  2467. with | Not_found ->
  2468. gen.gcon.error "Fields 'fieldIds' and 'fields' were not found in class haxe.lang.FieldLookup" flookup_cl.cl_pos
  2469. );
  2470. TypeParams.RenameTypeParameters.run gen;
  2471. let t = Common.timer "code generation" in
  2472. generate_modules gen "cs" "src" module_gen;
  2473. dump_descriptor gen ("hxcs_build.txt") path_s module_s;
  2474. if ( not (Common.defined gen.gcon Define.NoCompilation) ) then begin
  2475. let old_dir = Sys.getcwd() in
  2476. Sys.chdir gen.gcon.file;
  2477. let cmd = "haxelib run hxcs hxcs_build.txt --haxe-version " ^ (string_of_int gen.gcon.version) in
  2478. print_endline cmd;
  2479. if gen.gcon.run_command cmd <> 0 then failwith "Build failed";
  2480. Sys.chdir old_dir;
  2481. end;
  2482. t()
  2483. (* end of configure function *)
  2484. let generate con =
  2485. (try
  2486. let gen = new_ctx con in
  2487. let basic = con.basic in
  2488. (* make the basic functions in C# *)
  2489. let type_cl = get_cl ( get_type gen (["System"], "Type")) in
  2490. let basic_fns =
  2491. [
  2492. mk_class_field "Equals" (TFun(["obj",false,t_dynamic], basic.tbool)) true Ast.null_pos (Method MethNormal) [];
  2493. mk_class_field "ToString" (TFun([], basic.tstring)) true Ast.null_pos (Method MethNormal) [];
  2494. mk_class_field "GetHashCode" (TFun([], basic.tint)) true Ast.null_pos (Method MethNormal) [];
  2495. mk_class_field "GetType" (TFun([], TInst(type_cl, []))) true Ast.null_pos (Method MethNormal) [];
  2496. ] in
  2497. List.iter (fun cf -> gen.gbase_class_fields <- PMap.add cf.cf_name cf gen.gbase_class_fields) basic_fns;
  2498. configure gen
  2499. with | TypeNotFound path ->
  2500. con.error ("Error. Module '" ^ (path_s path) ^ "' is required and was not included in build.") Ast.null_pos);
  2501. debug_mode := false
  2502. (* -net-lib implementation *)
  2503. open IlData
  2504. open IlMeta
  2505. type net_lib_ctx = {
  2506. nstd : bool;
  2507. ncom : Common.context;
  2508. nil : IlData.ilctx;
  2509. }
  2510. let netname_to_hx name =
  2511. let len = String.length name in
  2512. let chr = String.get name 0 in
  2513. String.make 1 (Char.uppercase chr) ^ (String.sub name 1 (len-1))
  2514. let hxpath_to_net ctx path =
  2515. try
  2516. Hashtbl.find ctx.ncom.net_path_map path
  2517. with
  2518. | Not_found ->
  2519. [],[],"Not_found"
  2520. let add_cs = function
  2521. | "haxe" :: ns -> "haxe" :: ns
  2522. | "std" :: ns -> "std" :: ns
  2523. | "cs" :: ns -> "cs" :: ns
  2524. | "system" :: ns -> "cs" :: "system" :: ns
  2525. | ns -> ns
  2526. let netcl_to_hx cl =
  2527. try
  2528. let cl, nargs = String.split cl "`" in
  2529. cl ^ "_" ^ nargs
  2530. with | Invalid_string ->
  2531. cl
  2532. let netpath_to_hx std = function
  2533. | [],[], cl -> [], netcl_to_hx cl
  2534. | ns,[], cl ->
  2535. let ns = (List.map String.lowercase ns) in
  2536. add_cs ns, netcl_to_hx cl
  2537. | ns,(nhd :: ntl as nested), cl ->
  2538. let nested = List.map (netcl_to_hx) nested in
  2539. let ns = (List.map String.lowercase ns) @ [nhd] in
  2540. add_cs ns, String.concat "_" nested ^ "_" ^ netcl_to_hx cl
  2541. let lookup_ilclass std com ilpath =
  2542. let path = netpath_to_hx std ilpath in
  2543. List.fold_right (fun (_,_,_,get_raw_class) acc ->
  2544. match acc with
  2545. | None -> get_raw_class path
  2546. | Some p -> acc
  2547. ) com.net_libs None
  2548. let discard_nested = function
  2549. | (ns,_),cl -> (ns,[]),cl
  2550. let mk_type_path ctx path params =
  2551. let pack, sub, name = match path with
  2552. | ns,[], cl ->
  2553. ns, None, netcl_to_hx cl
  2554. | ns, (nhd :: ntl as nested), cl ->
  2555. let nhd = netcl_to_hx nhd in
  2556. let nested = List.map (netcl_to_hx) nested in
  2557. ns, Some (String.concat "_" nested ^ "_" ^ netcl_to_hx cl), nhd
  2558. in
  2559. CTPath {
  2560. tpackage = fst (netpath_to_hx ctx.nstd (pack,[],""));
  2561. Ast.tname = name;
  2562. tparams = params;
  2563. tsub = sub;
  2564. }
  2565. let raw_type_path ctx path params =
  2566. {
  2567. tpackage = fst path;
  2568. Ast.tname = snd path;
  2569. tparams = params;
  2570. tsub = None;
  2571. }
  2572. let rec convert_signature ctx p = function
  2573. | LVoid ->
  2574. mk_type_path ctx ([],[],"Void") []
  2575. | LBool ->
  2576. mk_type_path ctx ([],[],"Bool") []
  2577. | LChar ->
  2578. mk_type_path ctx (["cs";"types"],[],"Char16") []
  2579. | LInt8 ->
  2580. mk_type_path ctx (["cs";"types"],[],"Int8") []
  2581. | LUInt8 ->
  2582. mk_type_path ctx (["cs";"types"],[],"UInt8") []
  2583. | LInt16 ->
  2584. mk_type_path ctx (["cs";"types"],[],"Int16") []
  2585. | LUInt16 ->
  2586. mk_type_path ctx (["cs";"types"],[],"UInt16") []
  2587. | LInt32 ->
  2588. mk_type_path ctx ([],[],"Int") []
  2589. | LUInt32 ->
  2590. mk_type_path ctx ([],[],"UInt") []
  2591. | LInt64 ->
  2592. mk_type_path ctx (["haxe"],[],"Int64") []
  2593. | LUInt64 ->
  2594. mk_type_path ctx (["cs";"types"],[],"UInt64") []
  2595. | LFloat32 ->
  2596. mk_type_path ctx ([],[],"Single") []
  2597. | LFloat64 ->
  2598. mk_type_path ctx ([],[],"Float") []
  2599. | LString ->
  2600. mk_type_path ctx (["std"],[],"String") []
  2601. | LObject ->
  2602. mk_type_path ctx ([],[],"Dynamic") []
  2603. | LPointer s | LManagedPointer s ->
  2604. mk_type_path ctx (["cs"],[],"Pointer") [ TPType (convert_signature ctx p s) ]
  2605. | LTypedReference ->
  2606. mk_type_path ctx (["cs";"system"],[],"TypedReference") []
  2607. | LIntPtr ->
  2608. mk_type_path ctx (["cs";"system"],[],"IntPtr") []
  2609. | LUIntPtr ->
  2610. mk_type_path ctx (["cs";"system"],[],"UIntPtr") []
  2611. | LValueType (s,args) | LClass (s,args) ->
  2612. mk_type_path ctx s (List.map (fun s -> TPType (convert_signature ctx p s)) args)
  2613. | LTypeParam i ->
  2614. mk_type_path ctx ([],[],"T" ^ string_of_int i) []
  2615. | LMethodTypeParam i ->
  2616. mk_type_path ctx ([],[],"M" ^ string_of_int i) []
  2617. | LVector s ->
  2618. mk_type_path ctx (["cs"],[],"NativeArray") [TPType (convert_signature ctx p s)]
  2619. (* | LArray of ilsig_norm * (int option * int option) array *)
  2620. | LMethod (_,ret,args) ->
  2621. CTFunction (List.map (convert_signature ctx p) args, convert_signature ctx p ret)
  2622. | _ -> mk_type_path ctx ([],[], "Dynamic") []
  2623. let ilpath_s = function
  2624. | ns,[], name -> path_s (ns,name)
  2625. | [],nested,name -> String.concat "#" nested ^ "." ^ name
  2626. | ns, nested, name -> String.concat "." ns ^ "." ^ String.concat "#" nested ^ "." ^ name
  2627. let get_cls = function
  2628. | _,_,c -> c
  2629. let convert_ilenum ctx p ilcls =
  2630. let meta = ref [Meta.Native, [EConst (String (ilpath_s ilcls.cpath) ), p], p ] in
  2631. let data = ref [] in
  2632. List.iter (fun f -> match f.fname with
  2633. | "value__" -> ()
  2634. | _ ->
  2635. data := { ec_name = f.fname; ec_doc = None; ec_meta = []; ec_args = []; ec_pos = p; ec_params = []; ec_type = None; } :: !data;
  2636. ) ilcls.cfields;
  2637. let _, c = netpath_to_hx ctx.nstd ilcls.cpath in
  2638. EEnum {
  2639. d_name = netname_to_hx c;
  2640. d_doc = None;
  2641. d_params = []; (* enums never have type parameters *)
  2642. d_meta = !meta;
  2643. d_flags = [EExtern];
  2644. d_data = List.rev !data;
  2645. }
  2646. let rec has_unmanaged = function
  2647. | LPointer _ -> true
  2648. | LManagedPointer s -> has_unmanaged s
  2649. | LValueType (p,pl) -> List.exists (has_unmanaged) pl
  2650. | LClass (p,pl) -> List.exists (has_unmanaged) pl
  2651. | LVector s -> has_unmanaged s
  2652. | LArray (s,a) -> has_unmanaged s
  2653. | LMethod (c,r,args) -> has_unmanaged r || List.exists (has_unmanaged) args
  2654. | _ -> false
  2655. let convert_ilfield ctx p field =
  2656. if not (Common.defined ctx.ncom Define.Unsafe) && has_unmanaged field.fsig.snorm then raise Exit;
  2657. let p = { p with pfile = p.pfile ^" (" ^field.fname ^")" } in
  2658. let cff_doc = None in
  2659. let cff_pos = p in
  2660. let cff_meta = ref [] in
  2661. let cff_name = match field.fname with
  2662. | name when String.length name > 5 ->
  2663. (match String.sub name 0 5 with
  2664. | "__hx_" -> raise Exit
  2665. | _ -> name)
  2666. | name -> name
  2667. in
  2668. let cff_access = match field.fflags.ff_access with
  2669. | FAFamily | FAFamOrAssem -> APrivate
  2670. | FAPublic -> APublic
  2671. | _ -> raise Exit (* private instances aren't useful on externs *)
  2672. in
  2673. let readonly, acc = List.fold_left (fun (readonly,acc) -> function
  2674. | CStatic -> readonly, AStatic :: acc
  2675. | CInitOnly | CLiteral -> true, acc
  2676. | _ -> readonly,acc
  2677. ) (false,[cff_access]) field.fflags.ff_contract in
  2678. let kind = match readonly with
  2679. | true ->
  2680. FProp ("default", "never", Some (convert_signature ctx p field.fsig.snorm), None)
  2681. | false ->
  2682. FVar (Some (convert_signature ctx p field.fsig.snorm), None)
  2683. in
  2684. let cff_name, cff_meta =
  2685. if String.get cff_name 0 = '%' then
  2686. let name = (String.sub cff_name 1 (String.length cff_name - 1)) in
  2687. "_" ^ name,
  2688. (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: !cff_meta
  2689. else
  2690. cff_name, !cff_meta
  2691. in
  2692. {
  2693. cff_name = cff_name;
  2694. cff_doc = cff_doc;
  2695. cff_pos = cff_pos;
  2696. cff_meta = cff_meta;
  2697. cff_access = acc;
  2698. cff_kind = kind;
  2699. }
  2700. let convert_ilevent ctx p ev =
  2701. let p = { p with pfile = p.pfile ^" (" ^ev.ename ^")" } in
  2702. let name = ev.ename in
  2703. let kind = FVar (Some (convert_signature ctx p ev.esig.snorm), None) in
  2704. let meta = [Meta.Event, [], p; Meta.Keep,[],p; Meta.SkipReflection,[],p] in
  2705. let acc = [APrivate] in
  2706. let add_m acc m = match m with
  2707. | None -> acc
  2708. | Some (name,flags) ->
  2709. if List.mem (CMStatic) flags.mf_contract then
  2710. AStatic :: acc
  2711. else
  2712. acc
  2713. in
  2714. let acc = add_m acc ev.eadd in
  2715. let acc = add_m acc ev.eremove in
  2716. let acc = add_m acc ev.eraise in
  2717. {
  2718. cff_name = name;
  2719. cff_doc = None;
  2720. cff_pos = p;
  2721. cff_meta = meta;
  2722. cff_access = acc;
  2723. cff_kind = kind;
  2724. }
  2725. let convert_ilmethod ctx p m is_explicit_impl =
  2726. if not (Common.defined ctx.ncom Define.Unsafe) && has_unmanaged m.msig.snorm then raise Exit;
  2727. let p = { p with pfile = p.pfile ^" (" ^m.mname ^")" } in
  2728. let cff_doc = None in
  2729. let cff_pos = p in
  2730. let cff_name = match m.mname with
  2731. | ".ctor" -> "new"
  2732. | ".cctor"-> raise Exit (* __init__ field *)
  2733. | "Equals" | "GetHashCode" -> raise Exit
  2734. | name when String.length name > 5 ->
  2735. (match String.sub name 0 5 with
  2736. | "__hx_" -> raise Exit
  2737. | _ -> name)
  2738. | name -> name
  2739. in
  2740. let acc = match m.mflags.mf_access with
  2741. | FAFamily | FAFamOrAssem -> APrivate
  2742. (* | FAPrivate -> APrivate *)
  2743. | FAPublic -> APublic
  2744. | _ ->
  2745. raise Exit
  2746. in
  2747. if PMap.mem "net_loader_debug" ctx.ncom.defines then
  2748. Printf.printf "\tname %s : %s\n" cff_name (IlMetaDebug.ilsig_s m.msig.ssig);
  2749. let is_static = ref false in
  2750. let acc, is_final = List.fold_left (fun (acc,is_final) -> function
  2751. | CMStatic when cff_name <> "new" -> is_static := true; AStatic :: acc, is_final
  2752. | CMVirtual when is_final = None -> acc, Some false
  2753. | CMFinal -> acc, Some true
  2754. | _ -> acc, is_final
  2755. ) ([acc],None) m.mflags.mf_contract in
  2756. let meta = [Meta.Overload, [], p] in
  2757. let meta = match is_final with
  2758. | None | Some false ->
  2759. (Meta.Final, [], p) :: meta
  2760. | _ -> meta
  2761. in
  2762. let meta = if is_explicit_impl then
  2763. (Meta.NoCompletion,[],p) :: (Meta.SkipReflection,[],p) :: meta
  2764. else
  2765. meta
  2766. in
  2767. (* let meta = if List.mem OSynchronized m.mflags.mf_interop then *)
  2768. (* (Meta.Synchronized,[],p) :: meta *)
  2769. (* else *)
  2770. (* meta *)
  2771. (* in *)
  2772. let rec change_sig = function
  2773. | LManagedPointer s -> LManagedPointer (change_sig s)
  2774. | LPointer s -> LPointer (change_sig s)
  2775. | LValueType (p,pl) -> LValueType(p, List.map change_sig pl)
  2776. | LClass (p,pl) -> LClass(p, List.map change_sig pl)
  2777. | LTypeParam i -> LObject
  2778. | LVector s -> LVector (change_sig s)
  2779. | LArray (s,a) -> LArray (change_sig s, a)
  2780. | LMethod (c,r,args) -> LMethod (c, change_sig r, List.map change_sig args)
  2781. | p -> p
  2782. in
  2783. let change_sig = if !is_static then change_sig else (fun s -> s) in
  2784. let ret =
  2785. if String.length cff_name > 4 && String.sub cff_name 0 4 = "set_" then
  2786. match m.mret.snorm, m.margs with
  2787. | LVoid, [_,_,s] ->
  2788. s.snorm
  2789. | _ -> m.mret.snorm
  2790. else
  2791. m.mret.snorm
  2792. in
  2793. let kind =
  2794. let args = List.map (fun (name,flag,s) ->
  2795. let t = match s.snorm with
  2796. | LManagedPointer s ->
  2797. mk_type_path ctx (["cs"],[],"Ref") [ TPType (convert_signature ctx p s) ]
  2798. | _ ->
  2799. convert_signature ctx p (change_sig s.snorm)
  2800. in
  2801. name,false,Some t,None) m.margs
  2802. in
  2803. let ret = convert_signature ctx p (change_sig ret) in
  2804. let types = List.map (fun t ->
  2805. {
  2806. tp_name = "M" ^ string_of_int t.tnumber;
  2807. tp_params = [];
  2808. tp_constraints = [];
  2809. }
  2810. ) m.mtypes in
  2811. FFun {
  2812. f_params = types;
  2813. f_args = args;
  2814. f_type = Some ret;
  2815. f_expr = None;
  2816. }
  2817. in
  2818. let cff_name, cff_meta =
  2819. if String.get cff_name 0 = '%' then
  2820. let name = (String.sub cff_name 1 (String.length cff_name - 1)) in
  2821. "_" ^ name,
  2822. (Meta.Native, [EConst (String (name) ), cff_pos], cff_pos) :: meta
  2823. else
  2824. cff_name, meta
  2825. in
  2826. let acc = match m.moverride with
  2827. | None -> acc
  2828. | Some (path,s) -> match lookup_ilclass ctx.nstd ctx.ncom path with
  2829. | Some ilcls when not (List.mem SInterface ilcls.cflags.tdf_semantics) ->
  2830. AOverride :: acc
  2831. | None when ctx.ncom.verbose ->
  2832. prerr_endline ("(net-lib) A referenced assembly for path " ^ ilpath_s path ^ " was not found");
  2833. acc
  2834. | _ -> acc
  2835. in
  2836. {
  2837. cff_name = cff_name;
  2838. cff_doc = cff_doc;
  2839. cff_pos = cff_pos;
  2840. cff_meta = cff_meta;
  2841. cff_access = acc;
  2842. cff_kind = kind;
  2843. }
  2844. let convert_ilprop ctx p prop is_explicit_impl =
  2845. if not (Common.defined ctx.ncom Define.Unsafe) && has_unmanaged prop.psig.snorm then raise Exit;
  2846. let p = { p with pfile = p.pfile ^" (" ^prop.pname ^")" } in
  2847. let pmflags = match prop.pget, prop.pset with
  2848. | Some(_,fl1), _ -> Some fl1
  2849. | _, Some(_,fl2) -> Some fl2
  2850. | _ -> None
  2851. in
  2852. let cff_access = match pmflags with
  2853. | Some { mf_access = FAFamily | FAFamOrAssem } -> APrivate
  2854. | Some { mf_access = FAPublic } -> APublic
  2855. | _ -> raise Exit (* non-public / protected fields don't interest us *)
  2856. in
  2857. let cff_access = match pmflags with
  2858. | Some m when List.mem CMStatic m.mf_contract ->
  2859. [AStatic;cff_access]
  2860. | _ -> [cff_access]
  2861. in
  2862. let get = match prop.pget with
  2863. | None -> "never"
  2864. | Some(s,_) when String.length s <= 4 || String.sub s 0 4 <> "get_" ->
  2865. raise Exit (* special (?) getter; not used *)
  2866. | Some _ -> "get"
  2867. in
  2868. let set = match prop.pset with
  2869. | None -> "never"
  2870. | Some(s,_) when String.length s <= 4 || String.sub s 0 4 <> "set_" ->
  2871. raise Exit (* special (?) getter; not used *)
  2872. | Some _ -> "set"
  2873. in
  2874. if PMap.mem "net_loader_debug" ctx.ncom.defines then
  2875. Printf.printf "\tproperty %s (%s,%s) : %s\n" prop.pname get set (IlMetaDebug.ilsig_s prop.psig.ssig);
  2876. let ilsig = match prop.psig.snorm with
  2877. | LMethod (_,ret,[]) -> ret
  2878. | s -> raise Exit
  2879. in
  2880. let meta = if is_explicit_impl then
  2881. [ Meta.NoCompletion,[],p; Meta.SkipReflection,[],p ]
  2882. else
  2883. []
  2884. in
  2885. let kind =
  2886. FProp (get, set, Some(convert_signature ctx p ilsig), None)
  2887. in
  2888. {
  2889. cff_name = prop.pname;
  2890. cff_doc = None;
  2891. cff_pos = p;
  2892. cff_meta = meta;
  2893. cff_access = cff_access;
  2894. cff_kind = kind;
  2895. }
  2896. let get_type_path ctx ct = match ct with | CTPath p -> p | _ -> assert false
  2897. let is_explicit ctx ilcls i =
  2898. let s = match i with
  2899. | LClass(path,_) | LValueType(path,_) -> ilpath_s path
  2900. | _ -> assert false
  2901. in
  2902. let len = String.length s in
  2903. List.exists (fun m ->
  2904. String.length m.mname > len && String.sub m.mname 0 len = s
  2905. ) ilcls.cmethods
  2906. let mke e p = (e,p)
  2907. let mk_special_call name p args =
  2908. mke (ECast( mke (EUntyped( mke (ECall( mke (EConst(Ident name)) p, args )) p )) p , None)) p
  2909. let mk_this_call name p args =
  2910. mke (ECall( mke (EField(mke (EConst(Ident "this")) p ,name)) p, args )) p
  2911. let mk_metas metas p =
  2912. List.map (fun m -> m,[],p) metas
  2913. let mk_abstract_fun name p kind metas acc =
  2914. let metas = mk_metas metas p in
  2915. {
  2916. cff_name = name;
  2917. cff_doc = None;
  2918. cff_pos = p;
  2919. cff_meta = metas;
  2920. cff_access = acc;
  2921. cff_kind = kind;
  2922. }
  2923. let convert_fun_arg ctx p = function
  2924. | LManagedPointer s ->
  2925. mk_type_path ctx (["cs"],[],"Ref") [ TPType (convert_signature ctx p s) ]
  2926. | s ->
  2927. convert_signature ctx p s
  2928. let convert_fun ctx p ret args =
  2929. let args = List.map (convert_fun_arg ctx p) args in
  2930. CTFunction(args, convert_signature ctx p ret)
  2931. let convert_delegate ctx p ilcls =
  2932. let p = { p with pfile = p.pfile ^" (abstract delegate)" } in
  2933. (* will have the following methods: *)
  2934. (* - new (haxeType:Func) *)
  2935. (* - FromHaxeFunction(haxeType) *)
  2936. (* - Invoke() *)
  2937. (* - AsDelegate():Super *)
  2938. let invoke = List.find (fun m -> m.mname = "Invoke") ilcls.cmethods in
  2939. let ret = invoke.mret.snorm in
  2940. let args = List.map (fun (_,_,s) -> s.snorm) invoke.margs in
  2941. let haxe_type = convert_fun ctx p ret args in
  2942. let types = List.map (fun t ->
  2943. {
  2944. tp_name = "T" ^ string_of_int t.tnumber;
  2945. tp_params = [];
  2946. tp_constraints = [];
  2947. }
  2948. ) ilcls.ctypes in
  2949. let params = (List.map (fun s ->
  2950. TPType (mk_type_path ctx ([],[],s.tp_name) [])
  2951. ) types) in
  2952. let underlying_type = match ilcls.cpath with
  2953. | ns,inner,name ->
  2954. mk_type_path ctx (ns,inner,"Delegate_" ^ name) params
  2955. in
  2956. let fn_new = FFun {
  2957. f_params = [];
  2958. f_args = ["hxfunc",false,Some haxe_type,None];
  2959. f_type = None;
  2960. f_expr = Some ( EBinop(Ast.OpAssign, (EConst(Ident "this"),p), (mk_special_call "__delegate__" p [EConst(Ident "hxfunc"),p]) ), p );
  2961. } in
  2962. let fn_from_hx = FFun {
  2963. f_params = types;
  2964. f_args = ["hxfunc",false,Some haxe_type,None];
  2965. f_type = Some( mk_type_path ctx ilcls.cpath params );
  2966. f_expr = Some( EReturn( Some (mk_special_call "__delegate__" p [EConst(Ident "hxfunc"),p] )), p);
  2967. } in
  2968. let i = ref 0 in
  2969. let j = ref 0 in
  2970. let fn_invoke = FFun {
  2971. f_params = [];
  2972. f_args = List.map (fun arg ->
  2973. incr i;
  2974. "arg" ^ string_of_int !i, false, Some (convert_fun_arg ctx p arg), None
  2975. ) args;
  2976. f_type = Some(convert_signature ctx p ret);
  2977. f_expr = Some(
  2978. EReturn( Some (
  2979. mk_this_call "Invoke" p (List.map (fun arg ->
  2980. incr j; (EConst( Ident ("arg" ^ string_of_int !j) ), p)
  2981. ) args )
  2982. )), p
  2983. );
  2984. } in
  2985. let fn_asdel = FFun {
  2986. f_params = [];
  2987. f_args = [];
  2988. f_type = None;
  2989. f_expr = Some(
  2990. EReturn( Some ( EUntyped( EConst(Ident "this"), p ), p ) ), p
  2991. );
  2992. } in
  2993. let fn_new = mk_abstract_fun "new" p fn_new [Meta.Extern] [APublic;AInline] in
  2994. let fn_from_hx = mk_abstract_fun "FromHaxeFunction" p fn_from_hx [Meta.Extern;Meta.From] [APublic;AInline;AStatic] in
  2995. let fn_invoke = mk_abstract_fun "Invoke" p fn_invoke [Meta.Extern] [APublic;AInline] in
  2996. let fn_asdel = mk_abstract_fun "AsDelegate" p fn_asdel [Meta.Extern] [APublic;AInline] in
  2997. let _, c = netpath_to_hx ctx.nstd ilcls.cpath in
  2998. EAbstract {
  2999. d_name = netname_to_hx c;
  3000. d_doc = None;
  3001. d_params = types;
  3002. d_meta = mk_metas [Meta.Delegate] p;
  3003. d_flags = [AIsType underlying_type];
  3004. d_data = [fn_new;fn_from_hx;fn_invoke;fn_asdel];
  3005. }
  3006. let convert_ilclass ctx p ?(delegate=false) ilcls = match ilcls.csuper with
  3007. | Some { snorm = LClass ((["System"],[],"Enum"),[]) } ->
  3008. convert_ilenum ctx p ilcls
  3009. | _ ->
  3010. let flags = ref [HExtern] in
  3011. (* todo: instead of CsNative, use more specific definitions *)
  3012. if PMap.mem "net_loader_debug" ctx.ncom.defines then
  3013. print_endline ("converting " ^ ilpath_s ilcls.cpath);
  3014. let meta = ref [Meta.CsNative, [], p; Meta.Native, [EConst (String (ilpath_s ilcls.cpath) ), p], p] in
  3015. let is_interface = ref false in
  3016. List.iter (fun f -> match f with
  3017. | SSealed -> meta := (Meta.Final, [], p) :: !meta
  3018. | SInterface ->
  3019. is_interface := true;
  3020. flags := HInterface :: !flags
  3021. | SAbstract -> meta := (Meta.Abstract, [], p) :: !meta
  3022. | _ -> ()
  3023. ) ilcls.cflags.tdf_semantics;
  3024. (* (match ilcls.cflags.tdf_vis with *)
  3025. (* | VPublic | VNestedFamOrAssem | VNestedFamily -> () *)
  3026. (* | _ -> raise Exit); *)
  3027. (match ilcls.csuper with
  3028. | Some { snorm = LClass ( (["System"],[],"Object"), [] ) } -> ()
  3029. | Some { snorm = LClass ( (["haxe";"lang"],[],"HxObject"), [] ) } ->
  3030. meta := (Meta.HxGen,[],p) :: !meta
  3031. | Some s ->
  3032. flags := HExtends (get_type_path ctx (convert_signature ctx p s.snorm)) :: !flags
  3033. | _ -> ());
  3034. List.iter (fun i ->
  3035. match i.snorm with
  3036. | LClass ( (["haxe";"lang"],[], "IHxObject"), _ ) ->
  3037. meta := (Meta.HxGen,[],p) :: !meta
  3038. | i when is_explicit ctx ilcls i -> ()
  3039. | i -> flags :=
  3040. if !is_interface then
  3041. HExtends (get_type_path ctx (convert_signature ctx p i)) :: !flags
  3042. else
  3043. HImplements (get_type_path ctx (convert_signature ctx p i)) :: !flags
  3044. ) ilcls.cimplements;
  3045. (* ArrayAccess *)
  3046. ignore (List.exists (function
  3047. | { psig = { snorm = LMethod(_,ret,[v]) } } ->
  3048. flags := if !is_interface then
  3049. (HExtends( raw_type_path ctx ([],"ArrayAccess") [ TPType (convert_signature ctx p ret) ]) :: !flags)
  3050. else
  3051. (HImplements( raw_type_path ctx ([],"ArrayAccess") [ TPType (convert_signature ctx p ret) ]) :: !flags);
  3052. true
  3053. | _ -> false) ilcls.cprops);
  3054. let fields = ref [] in
  3055. let run_fields fn f =
  3056. List.iter (fun f ->
  3057. try
  3058. fields := fn f :: !fields
  3059. with
  3060. | Exit -> ()
  3061. ) f
  3062. in
  3063. let meths = if !is_interface then
  3064. List.filter (fun m -> m.moverride = None) ilcls.cmethods
  3065. else
  3066. ilcls.cmethods
  3067. in
  3068. run_fields (fun m ->
  3069. convert_ilmethod ctx p m (List.exists (fun m2 -> m != m2 && String.get m2.mname 0 <> '.' && String.ends_with m2.mname ("." ^ m.mname)) meths)
  3070. ) meths;
  3071. run_fields (convert_ilfield ctx p) ilcls.cfields;
  3072. run_fields (fun prop ->
  3073. convert_ilprop ctx p prop (List.exists (fun p2 -> prop != p2 && String.get p2.pname 0 <> '.' && String.ends_with p2.pname ("." ^ prop.pname)) ilcls.cprops)
  3074. ) ilcls.cprops;
  3075. run_fields (convert_ilevent ctx p) ilcls.cevents;
  3076. let params = List.map (fun p ->
  3077. {
  3078. tp_name = "T" ^ string_of_int p.tnumber;
  3079. tp_params = [];
  3080. tp_constraints = [];
  3081. }) ilcls.ctypes
  3082. in
  3083. let path = match ilcls.cpath with
  3084. | ns,inner,name when delegate ->
  3085. ns,inner,"Delegate_"^name
  3086. | _ -> ilcls.cpath
  3087. in
  3088. let _, c = netpath_to_hx ctx.nstd path in
  3089. EClass {
  3090. d_name = netname_to_hx c;
  3091. d_doc = None;
  3092. d_params = params;
  3093. d_meta = !meta;
  3094. d_flags = !flags;
  3095. d_data = !fields;
  3096. }
  3097. type il_any_field =
  3098. | IlField of ilfield
  3099. | IlMethod of ilmethod
  3100. | IlProp of ilprop
  3101. let get_fname = function
  3102. | IlField f -> f.fname
  3103. | IlMethod m -> m.mname
  3104. | IlProp p -> p.pname
  3105. let is_static = function
  3106. | IlField f ->
  3107. List.mem CStatic f.fflags.ff_contract
  3108. | IlMethod m ->
  3109. List.mem CMStatic m.mflags.mf_contract
  3110. | IlProp p ->
  3111. List.exists (function
  3112. | None -> false
  3113. | Some (_,m) -> List.mem CMStatic m.mf_contract
  3114. ) [p.pget;p.pset]
  3115. (* | _ -> false *)
  3116. let change_name name = function
  3117. | IlField f -> IlField { f with fname = name }
  3118. | IlMethod m -> IlMethod { m with mname = name }
  3119. | IlProp p -> IlProp { p with pname = name }
  3120. let compatible_methods m1 m2 = match m1,m2 with
  3121. | IlMethod { msig = { snorm = LMethod(_,ret1,args1) } }, IlMethod { msig = { snorm = LMethod(_,ret2,args2) } } ->
  3122. ret1 = ret2 && args1 = args2
  3123. | _ -> false
  3124. let ilcls_from_ilsig ctx ilsig =
  3125. let path, params = match ilsig with
  3126. | LClass(path, params) | LValueType(path, params) ->
  3127. path, params
  3128. | LObject ->
  3129. (["System"],[],"Object"),[]
  3130. | _ -> raise Not_found (* all other types won't appear as superclass *)
  3131. in
  3132. match lookup_ilclass ctx.nstd ctx.ncom path with
  3133. | None -> raise Not_found
  3134. | Some c ->
  3135. c, params
  3136. let rec ilapply_params params = function
  3137. | LManagedPointer s -> LManagedPointer (ilapply_params params s)
  3138. | LPointer s -> LPointer (ilapply_params params s)
  3139. | LValueType (p,pl) -> LValueType(p, List.map (ilapply_params params) pl)
  3140. | LClass (p,pl) -> LClass(p, List.map (ilapply_params params) pl)
  3141. | LTypeParam i ->
  3142. List.nth params i (* TODO: maybe i - 1? *)
  3143. | LVector s -> LVector (ilapply_params params s)
  3144. | LArray (s,a) -> LArray (ilapply_params params s, a)
  3145. | LMethod (c,r,args) -> LMethod (c, ilapply_params params r, List.map (ilapply_params params) args)
  3146. | p -> p
  3147. let ilcls_with_params ctx cls params =
  3148. match cls.ctypes with
  3149. | [] -> cls
  3150. | _ ->
  3151. { cls with
  3152. cfields = List.map (fun f -> { f with fsig = { f.fsig with snorm = ilapply_params params f.fsig.snorm } }) cls.cfields;
  3153. cmethods = List.map (fun m -> { m with
  3154. msig = { m.msig with snorm = ilapply_params params m.msig.snorm };
  3155. margs = List.map (fun (n,f,s) -> (n,f,{ s with snorm = ilapply_params params s.snorm })) m.margs;
  3156. mret = { m.mret with snorm = ilapply_params params m.mret.snorm };
  3157. }) cls.cmethods;
  3158. cprops = List.map (fun p -> { p with psig = { p.psig with snorm = ilapply_params params p.psig.snorm } }) cls.cprops;
  3159. csuper = Option.map (fun s -> { s with snorm = ilapply_params params s.snorm } ) cls.csuper;
  3160. cimplements = List.map (fun s -> { s with snorm = ilapply_params params s.snorm } ) cls.cimplements;
  3161. }
  3162. let rec compatible_types t1 t2 = match t1,t2 with
  3163. | LManagedPointer(s1), LManagedPointer(s2) -> compatible_types s1 s2
  3164. | LManagedPointer(s1), s2 | s1, LManagedPointer(s2) ->
  3165. compatible_types s1 s2
  3166. | _ -> t1 = t2
  3167. let compatible_methods m1 m2 = match m1, m2 with
  3168. | LMethod(_,r1,a1), LMethod(_,r2,a2) -> (try
  3169. List.for_all2 (fun a1 a2 -> compatible_types a1 a2) a1 a2
  3170. with | Invalid_argument _ ->
  3171. false)
  3172. | _ -> false
  3173. let compatible_field f1 f2 = match f1, f2 with
  3174. | IlMethod { msig = { snorm = LMethod(_,_,a1) } },
  3175. IlMethod { msig = { snorm = LMethod(_,_,a2) } } ->
  3176. a1 = a2
  3177. | IlProp p1, IlProp p2 ->
  3178. (* p1.psig.snorm = p2.psig.snorm *)
  3179. true
  3180. | IlField f1, IlField f2 ->
  3181. (* f1.fsig.snorm = f2.fsig.snorm *)
  3182. true
  3183. | _ -> false
  3184. let get_all_fields cls =
  3185. let all_fields = List.map (fun f -> IlField f, cls.cpath, f.fname, List.mem CStatic f.fflags.ff_contract) cls.cfields in
  3186. let all_fields = all_fields @ List.map (fun m -> IlMethod m, cls.cpath, m.mname, List.mem CMStatic m.mflags.mf_contract) cls.cmethods in
  3187. let all_fields = all_fields @ List.map (function
  3188. | p ->
  3189. IlProp p, cls.cpath, p.pname, is_static (IlProp p)
  3190. ) cls.cprops in
  3191. all_fields
  3192. let normalize_ilcls ctx cls =
  3193. (* first filter out overloaded fields of same signature *)
  3194. let rec loop acc = function
  3195. | [] -> acc
  3196. | m :: cmeths ->
  3197. let static = List.mem CMStatic m.mflags.mf_contract in
  3198. if List.exists (fun m2 -> m.mname = m2.mname && List.mem CMStatic m2.mflags.mf_contract = static && compatible_methods m.msig.snorm m2.msig.snorm) cmeths then
  3199. loop acc cmeths
  3200. else
  3201. loop (m :: acc) cmeths
  3202. in
  3203. let meths = loop [] cls.cmethods in
  3204. (* fix overrides *)
  3205. (* get only the methods that aren't declared as override, but may be *)
  3206. let meths = List.map (fun v -> ref v) meths in
  3207. let no_overrides = List.filter (fun m ->
  3208. let m = !m in
  3209. not (List.mem CMStatic m.mflags.mf_contract)
  3210. ) meths in
  3211. let no_overrides = ref no_overrides in
  3212. let all_fields = ref [] in
  3213. let rec loop cls = try
  3214. match cls.csuper with
  3215. | Some { snorm = LClass((["System"],[],"Object"),_) }
  3216. | Some { snorm = LObject } | None -> ()
  3217. | Some s ->
  3218. let cls, params = ilcls_from_ilsig ctx s.snorm in
  3219. let cls = ilcls_with_params ctx cls params in
  3220. no_overrides := List.filter (fun v ->
  3221. let m = !v in
  3222. let is_override_here = List.exists (fun m2 ->
  3223. m2.mname = m.mname && not (List.mem CMStatic m2.mflags.mf_contract) && compatible_methods m.msig.snorm m2.msig.snorm
  3224. ) cls.cmethods in
  3225. if is_override_here then v := { m with moverride = Some(cls.cpath, m.mname) };
  3226. not is_override_here
  3227. ) !no_overrides;
  3228. all_fields := get_all_fields cls @ !all_fields;
  3229. loop cls
  3230. with | Not_found -> ()
  3231. in
  3232. loop cls;
  3233. List.iter (fun v -> v := { !v with moverride = None }) !no_overrides;
  3234. let added = ref [] in
  3235. let current_all = ref (get_all_fields cls @ !all_fields) in
  3236. (* look for interfaces and add missing implementations (some methods' implementation is optional) *)
  3237. let rec loop_interface cls iface = try
  3238. match iface.snorm with
  3239. | LClass((["System"],[],"Object"),_) | LObject -> ()
  3240. | LClass(path,_) when path = cls.cpath -> ()
  3241. | s ->
  3242. let cif, params = ilcls_from_ilsig ctx s in
  3243. let cif = ilcls_with_params ctx cif params in
  3244. List.iter (function
  3245. | (f,_,name,false) as ff ->
  3246. (* look for compatible fields *)
  3247. if not (List.exists (function
  3248. | (f2,_,name2,false) when name = name2 ->
  3249. compatible_field f f2
  3250. | _ -> false
  3251. ) !current_all) then begin
  3252. current_all := ff :: !current_all;
  3253. added := ff :: !added
  3254. end else
  3255. (* ensure it's public *)
  3256. List.iter (fun mref -> match !mref with
  3257. | m when m.mname = name && compatible_field f (IlMethod m) ->
  3258. mref := { m with mflags = { m.mflags with mf_access = FAPublic } }
  3259. | _ -> ()
  3260. ) meths
  3261. | _ -> ()
  3262. ) (get_all_fields cif);
  3263. List.iter (loop_interface cif) cif.cimplements
  3264. with | Not_found -> ()
  3265. in
  3266. List.iter (loop_interface cls) cls.cimplements;
  3267. let added = List.map (function
  3268. | (IlMethod m,a,name,b) ->
  3269. (IlMethod { m with mflags = { m.mflags with mf_access = FAPublic } },a,name,b)
  3270. | (IlField f,a,name,b) ->
  3271. (IlField { f with fflags = { f.fflags with ff_access = FAPublic } },a,name,b)
  3272. | s -> s
  3273. ) !added in
  3274. (* filter out properties that were already declared *)
  3275. let props = List.filter (function
  3276. | p ->
  3277. let static = is_static (IlProp p) in
  3278. let name = p.pname in
  3279. not (List.exists (function (IlProp _,_,n,s) -> s = static && name = n | _ -> false) !all_fields)
  3280. (* | _ -> false *)
  3281. ) cls.cprops in
  3282. let cls = { cls with cmethods = List.map (fun v -> !v) meths; cprops = props } in
  3283. let clsfields = added @ (get_all_fields cls) in
  3284. let super_fields = !all_fields in
  3285. all_fields := clsfields @ !all_fields;
  3286. let refclsfields = (List.map (fun v -> ref v) clsfields) in
  3287. (* search static / non-static name clash *)
  3288. (* change field name to not collide with haxe keywords *)
  3289. let iter_field v =
  3290. let f, p, name, is_static = !v in
  3291. let change = match name with
  3292. | "callback" | "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true
  3293. | _ ->
  3294. (is_static && List.exists (function | (f,_,n,false) -> name = n | _ -> false) !all_fields) ||
  3295. not is_static && match f with (* filter methods that have the same name as fields *)
  3296. | IlMethod _ ->
  3297. List.exists (function | ( (IlProp _ | IlField _),_,n,false) -> name = n | _ -> false) super_fields ||
  3298. List.exists (function | ( (IlProp _ | IlField _),_,n,s) -> name = n | _ -> false) clsfields
  3299. | _ -> false
  3300. in
  3301. if change then
  3302. let name = "%" ^ name in
  3303. v := change_name name f, p, name, is_static
  3304. in
  3305. List.iter iter_field refclsfields;
  3306. let clsfields = List.map (fun v -> !v) refclsfields in
  3307. let fields = List.filter (function | (IlField _,_,_,_) -> true | _ -> false) clsfields in
  3308. let methods = List.filter (function | (IlMethod _,_,_,_) -> true | _ -> false) clsfields in
  3309. let props = List.filter (function | (IlProp _,_,_,_) -> true | _ -> false) clsfields in
  3310. let methods = List.map (function | (IlMethod f,_,_,_) -> f | _ -> assert false) methods in
  3311. { cls with
  3312. cfields = List.map (function | (IlField f,_,_,_) -> f | _ -> assert false) fields;
  3313. cprops = List.map (function | (IlProp f,_,_,_) -> f | _ -> assert false) props;
  3314. cmethods = methods;
  3315. }
  3316. let add_net_std com file =
  3317. com.net_std <- file :: com.net_std
  3318. let add_net_lib com file std =
  3319. let ilctx = ref None in
  3320. let netpath_to_hx = netpath_to_hx std in
  3321. let real_file = ref file in
  3322. let get_ctx () =
  3323. match !ilctx with
  3324. | Some c ->
  3325. c
  3326. | None ->
  3327. let file = if Sys.file_exists file then
  3328. file
  3329. else try Common.find_file com file with
  3330. | Not_found -> try Common.find_file com (file ^ ".dll") with
  3331. | Not_found ->
  3332. failwith (".NET lib " ^ file ^ " not found")
  3333. in
  3334. real_file := file;
  3335. let r = PeReader.create_r (open_in_bin file) com.defines in
  3336. let ctx = PeReader.read r in
  3337. let clr_header = PeReader.read_clr_header ctx in
  3338. let cache = IlMetaReader.create_cache () in
  3339. let meta = IlMetaReader.read_meta_tables ctx clr_header cache in
  3340. close_in (r.PeReader.ch);
  3341. if PMap.mem "net_loader_debug" com.defines then
  3342. print_endline ("for lib " ^ file);
  3343. Hashtbl.iter (fun _ td ->
  3344. let path = IlMetaTools.get_path (TypeDef td) in
  3345. if PMap.mem "net_loader_debug" com.defines then
  3346. Printf.printf "found %s\n" (path_s (netpath_to_hx path));
  3347. Hashtbl.add com.net_path_map (netpath_to_hx path) path;
  3348. Hashtbl.replace meta.il_typedefs path td
  3349. ) meta.il_typedefs;
  3350. let meta = { nstd = std; ncom = com; nil = meta } in
  3351. ilctx := Some meta;
  3352. meta
  3353. in
  3354. let cache = Hashtbl.create 0 in
  3355. let lookup path =
  3356. try
  3357. Hashtbl.find cache path
  3358. with | Not_found -> try
  3359. let ctx = get_ctx() in
  3360. let ns, n, cl = hxpath_to_net ctx path in
  3361. let cls = IlMetaTools.convert_class ctx.nil (ns,n,cl) in
  3362. let cls = normalize_ilcls ctx cls in
  3363. Hashtbl.add cache path (Some cls);
  3364. Some cls
  3365. with | Not_found ->
  3366. Hashtbl.add cache path None;
  3367. None
  3368. in
  3369. let all_files () =
  3370. Hashtbl.fold (fun path _ acc -> match path with
  3371. | _,_ :: _, _ -> acc
  3372. | _ -> netpath_to_hx path :: acc) (get_ctx()).nil.il_typedefs []
  3373. in
  3374. let build path =
  3375. let p = { pfile = !real_file ^ " @ " ^ path_s path; pmin = 0; pmax = 0; } in
  3376. let pack = match fst path with | ["haxe";"root"] -> [] | p -> p in
  3377. let cp = ref [] in
  3378. let rec build path = try
  3379. if PMap.mem "net_loader_debug" com.defines then
  3380. Printf.printf "looking up %s\n" (path_s path);
  3381. match lookup path with
  3382. | Some({csuper = Some{snorm = LClass( (["System"],[],("Delegate"|"MulticastDelegate")),_)}} as cls)
  3383. when List.mem SSealed cls.cflags.tdf_semantics ->
  3384. let ctx = get_ctx() in
  3385. let hxcls = convert_ilclass ctx p ~delegate:true cls in
  3386. let delegate = convert_delegate ctx p cls in
  3387. cp := (hxcls,p) :: (delegate,p) :: !cp;
  3388. List.iter (fun ilpath ->
  3389. let path = netpath_to_hx ilpath in
  3390. build path
  3391. ) cls.cnested
  3392. | Some cls ->
  3393. let ctx = get_ctx() in
  3394. let hxcls = convert_ilclass ctx p cls in
  3395. cp := (hxcls,p) :: !cp;
  3396. List.iter (fun ilpath ->
  3397. let path = netpath_to_hx ilpath in
  3398. build path
  3399. ) cls.cnested
  3400. | _ -> ()
  3401. with | Not_found | Exit ->
  3402. ()
  3403. in
  3404. build path;
  3405. match !cp with
  3406. | [] -> None
  3407. | cp -> Some (!real_file, (pack,cp))
  3408. in
  3409. let build path p =
  3410. build path
  3411. in
  3412. com.load_extern_type <- com.load_extern_type @ [build];
  3413. com.net_libs <- (file, std, all_files, lookup) :: com.net_libs
  3414. let before_generate com =
  3415. (* net version *)
  3416. let net_ver = try
  3417. int_of_string (PMap.find "net_ver" com.defines)
  3418. with | Not_found ->
  3419. Common.define_value com Define.NetVer "20";
  3420. 20
  3421. in
  3422. if net_ver < 20 then
  3423. failwith (
  3424. ".NET version is defined to target .NET "
  3425. ^ string_of_int net_ver
  3426. ^ ", but the compiler can only output code to versions equal or superior to .NET 2.0 (defined as 20)"
  3427. );
  3428. let rec loop = function
  3429. | v :: acc when v <= net_ver ->
  3430. Common.raw_define com ("NET_" ^ string_of_int v);
  3431. loop acc
  3432. | _ -> ()
  3433. in
  3434. loop [20;21;30;35;40;45];
  3435. (* net target *)
  3436. let net_target = try
  3437. String.lowercase (PMap.find "net_target" com.defines)
  3438. with | Not_found ->
  3439. "net"
  3440. in
  3441. Common.define_value com Define.NetTarget net_target;
  3442. Common.raw_define com net_target;
  3443. (* std dirs *)
  3444. let stds = match com.net_std with
  3445. | [] -> ["netlib"]
  3446. | s -> s
  3447. in
  3448. (* look for all dirs that have the digraph NET_TARGET-NET_VER *)
  3449. let digraph = net_target ^ "-" ^ string_of_int net_ver in
  3450. let matched = ref [] in
  3451. List.iter (fun f -> try
  3452. let f = Common.find_file com (f ^ "/" ^ digraph) in
  3453. matched := (f, Unix.opendir f) :: !matched
  3454. with | _ -> ()) stds;
  3455. if !matched = [] then failwith (
  3456. "No .NET std lib directory with the pattern '" ^ digraph ^ "' was found in the -net-std search path. " ^
  3457. "Try updating the hxcs lib to the latest version, or specifying another -net-std path.");
  3458. List.iter (fun (path,f) ->
  3459. let rec loop () =
  3460. try
  3461. let f = Unix.readdir f in
  3462. let finsens = String.lowercase f in
  3463. if String.ends_with finsens ".dll" then
  3464. add_net_lib com (path ^ "/" ^ f) true;
  3465. loop()
  3466. with | End_of_file ->
  3467. Unix.closedir f
  3468. in
  3469. loop()
  3470. ) !matched;
  3471. (* now force all libraries to initialize *)
  3472. List.iter (function (_,_,_,lookup) -> ignore (lookup ([],""))) com.net_libs