gencs.ml 157 KB

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