gencs.ml 151 KB

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