genphp.ml 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339
  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 Ast
  23. open Type
  24. open Common
  25. type method_name = {
  26. mutable mpath : path;
  27. mutable mname : string;
  28. }
  29. type inline_method = {
  30. iname : string;
  31. iindex : int;
  32. iexpr : texpr;
  33. ihasthis : bool;
  34. iin_block : bool;
  35. iarguments : string list;
  36. ilocals : (string,string) PMap.t;
  37. iinv_locals : (string,string) PMap.t;
  38. }
  39. type context = {
  40. com : Common.context;
  41. ch : out_channel;
  42. buf : Buffer.t;
  43. path : path;
  44. stack : Codegen.stack_context;
  45. mutable nested_loops : int;
  46. mutable inline_index : int;
  47. mutable curclass : tclass;
  48. mutable curmethod : string;
  49. mutable tabs : string;
  50. mutable in_value : string option;
  51. mutable in_loop : bool;
  52. mutable in_block : bool;
  53. mutable in_instance_method : bool;
  54. mutable imports : (string,string list list) Hashtbl.t;
  55. mutable extern_required_paths : (string list * string) list;
  56. mutable extern_classes_with_init : path list;
  57. mutable locals : (string,string) PMap.t;
  58. mutable inv_locals : (string,string) PMap.t;
  59. mutable local_types : t list;
  60. mutable inits : texpr list;
  61. mutable constructor_block : bool;
  62. mutable all_dynamic_methods: method_name list;
  63. mutable dynamic_methods: tclass_field list;
  64. mutable is_call : bool;
  65. mutable cwd : string;
  66. mutable inline_methods : inline_method list;
  67. mutable lib_path : string;
  68. }
  69. let join_class_path path separator =
  70. let result = match fst path, snd path with
  71. | [], s -> s
  72. | el, s -> String.concat separator el ^ separator ^ s in
  73. if (String.contains result '+') then begin
  74. let idx = String.index result '+' in
  75. (String.sub result 0 idx) ^ (String.sub result (idx+1) ((String.length result) - idx -1 ) )
  76. end else
  77. result;;
  78. (* Get a string to represent a type.
  79. The "suffix" will be nothing or "_obj", depending if we want the name of the
  80. pointer class or the pointee (_obj class *)
  81. let rec class_string klass suffix params =
  82. (match klass.cl_path with
  83. (* Array class *)
  84. | ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "<" ^ (String.concat ","
  85. (List.map type_string params) ) ^ " >"
  86. | _ when (match klass.cl_kind with KTypeParameter _ -> true | _ -> false) -> "Dynamic"
  87. | ([],"#Int") -> "/* # */int"
  88. | (["haxe";"io"],"Unsigned_char__") -> "unsigned char"
  89. | ([],"Class") -> "Class"
  90. | ([],"Null") -> (match params with
  91. | [t] ->
  92. (match follow t with
  93. | TInst ({ cl_path = [],"Int" },_)
  94. | TInst ({ cl_path = [],"Float" },_)
  95. | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
  96. | _ -> "/*NULL*/" ^ (type_string t) )
  97. | _ -> assert false);
  98. (* Normal class *)
  99. | _ -> (join_class_path klass.cl_path "::") ^ suffix
  100. )
  101. and type_string_suff suffix haxe_type =
  102. (match haxe_type with
  103. | TMono r -> (match !r with None -> "Dynamic" | Some t -> type_string_suff suffix t)
  104. | TAbstract ({ a_path = [],"Int" },[]) -> "int"
  105. | TAbstract ({ a_path = [],"Float" },[]) -> "double"
  106. | TAbstract ({ a_path = [],"Bool" },[]) -> "bool"
  107. | TAbstract ({ a_path = [],"Void" },[]) -> "Void"
  108. | TEnum ({ e_path = ([],"Void") },[]) -> "Void"
  109. | TEnum ({ e_path = ([],"Bool") },[]) -> "bool"
  110. | TInst ({ cl_path = ([],"Float") },[]) -> "double"
  111. | TInst ({ cl_path = ([],"Int") },[]) -> "int"
  112. | TEnum (enum,params) -> (join_class_path enum.e_path "::") ^ suffix
  113. | TInst (klass,params) -> (class_string klass suffix params)
  114. | TAbstract (abs,params) -> (join_class_path abs.a_path "::") ^ suffix
  115. | TType (type_def,params) ->
  116. (match type_def.t_path with
  117. | [] , "Null" ->
  118. (match params with
  119. | [t] ->
  120. (match follow t with
  121. | TInst ({ cl_path = [],"Int" },_)
  122. | TInst ({ cl_path = [],"Float" },_)
  123. | TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
  124. | _ -> type_string_suff suffix t)
  125. | _ -> assert false);
  126. | [] , "Array" ->
  127. (match params with
  128. | [t] -> "Array<" ^ (type_string (follow t) ) ^ " >"
  129. | _ -> assert false)
  130. | _ -> type_string_suff suffix (apply_params type_def.t_types params type_def.t_type)
  131. )
  132. | TFun (args,haxe_type) -> "Dynamic"
  133. | TAnon anon -> "Dynamic"
  134. | TDynamic haxe_type -> "Dynamic"
  135. | TLazy func -> type_string_suff suffix ((!func)())
  136. )
  137. and type_string haxe_type =
  138. type_string_suff "" haxe_type;;
  139. let debug_expression expression type_too =
  140. "/* " ^ Type.s_expr_kind expression ^ (if (type_too) then " = " ^ (type_string (follow expression.etype)) else "") ^ " */";;
  141. let rec register_extern_required_path ctx path =
  142. if (List.exists(fun p -> p = path) ctx.extern_classes_with_init) && not (List.exists(fun p -> p = path) ctx.extern_required_paths) then
  143. ctx.extern_required_paths <- path :: ctx.extern_required_paths
  144. let s_expr_expr = Type.s_expr_kind
  145. let s_expr_name e =
  146. s_type (print_context()) (follow e.etype)
  147. let s_type_name t =
  148. s_type (print_context()) t
  149. and start_with s test =
  150. let len = String.length test in
  151. (String.length s > len && String.sub s 0 len = test)
  152. let rec is_uncertain_type t =
  153. match follow t with
  154. | TInst (c, _) -> c.cl_interface
  155. | TMono _ -> true
  156. | TAnon a ->
  157. (match !(a.a_status) with
  158. | Statics _
  159. | EnumStatics _ -> false
  160. | _ -> true)
  161. | TDynamic _ -> true
  162. | _ -> false
  163. let is_uncertain_expr e =
  164. is_uncertain_type e.etype
  165. let rec is_anonym_type t =
  166. match follow t with
  167. | TAnon a ->
  168. (match !(a.a_status) with
  169. | Statics _
  170. | EnumStatics _ -> false
  171. | _ -> true)
  172. | TDynamic _ -> true
  173. | _ -> false
  174. let is_anonym_expr e = is_anonym_type e.etype
  175. let rec is_unknown_type t =
  176. match follow t with
  177. | TMono r ->
  178. (match !r with
  179. | None -> true
  180. | Some t -> is_unknown_type t)
  181. | _ -> false
  182. let is_unknown_expr e = is_unknown_type e.etype
  183. let rec is_string_type t =
  184. match follow t with
  185. | TInst ({cl_path = ([], "String")}, _) -> true
  186. | TAnon a ->
  187. (match !(a.a_status) with
  188. | Statics ({cl_path = ([], "String")}) -> true
  189. | _ -> false)
  190. | TAbstract (a,pl) -> is_string_type (Codegen.Abstract.get_underlying_type a pl)
  191. | _ -> false
  192. let is_string_expr e = is_string_type e.etype
  193. let to_string ctx e =
  194. let v = alloc_var "__call__" t_dynamic in
  195. let f = mk (TLocal v) t_dynamic e.epos in
  196. mk (TCall (f, [ Codegen.string ctx.com "_hx_string_rec" e.epos; e; Codegen.string ctx.com "" e.epos])) ctx.com.basic.tstring e.epos
  197. let as_string_expr ctx e =
  198. match e.eexpr with
  199. | TConst (TNull) ->
  200. to_string ctx e
  201. | _ when not (is_string_expr e) ->
  202. to_string ctx e
  203. | _ -> e
  204. (* for known String type that could have null value *)
  205. let to_string_null ctx e =
  206. let v = alloc_var "__call__" t_dynamic in
  207. let f = mk (TLocal v) t_dynamic e.epos in
  208. mk (TCall (f, [ Codegen.string ctx.com "_hx_string_or_null" e.epos; e])) ctx.com.basic.tstring e.epos
  209. let as_string_expr ctx e = match e.eexpr with
  210. | TConst (TNull) -> to_string ctx e
  211. | TConst (TString s) -> e
  212. | TBinop (op,_,_) when (is_string_expr e)-> e
  213. | TCall ({eexpr = TField({eexpr = TTypeExpr(TClassDecl {cl_path = ([],"Std")})},FStatic(c,f) )}, [_]) when (f.cf_name="string") -> e
  214. | TCall ({eexpr = TLocal _}, [{eexpr = TConst (TString ("_hx_string_rec" | "_hx_str_or_null"))}]) -> e
  215. | _ when not (is_string_expr e) -> to_string ctx e
  216. | _ -> to_string_null ctx e
  217. let spr ctx s = Buffer.add_string ctx.buf s
  218. let print ctx = Printf.kprintf (fun s -> Buffer.add_string ctx.buf s)
  219. (*--php-prefix - added by skial bainn*)
  220. let prefix_class com name =
  221. match com.php_prefix with
  222. | Some prefix_class (* when not (String.length name <= 2 || String.sub name 0 2 = "__") *) ->
  223. prefix_class ^ name
  224. | _ ->
  225. name
  226. let prefix_init_replace com code =
  227. let r = Str.regexp "php_Boot" in
  228. Str.global_replace r ("php_" ^ (prefix_class com "Boot")) code
  229. let s_path ctx path isextern p =
  230. if isextern then begin
  231. register_extern_required_path ctx path;
  232. snd path
  233. end else begin
  234. (match path with
  235. (*--php-prefix*)
  236. | ([],"List") -> (prefix_class ctx.com "HList")
  237. (*--php-prefix*)
  238. | ([],name) -> (prefix_class ctx.com name)
  239. | (pack,name) ->
  240. (try
  241. (match Hashtbl.find ctx.imports name with
  242. | [p] when p = pack ->
  243. ()
  244. | packs ->
  245. if not (List.mem pack packs) then Hashtbl.replace ctx.imports name (pack :: packs))
  246. with Not_found ->
  247. Hashtbl.add ctx.imports name [pack]);
  248. (*--php-prefix*)
  249. String.concat "_" pack ^ "_" ^ (prefix_class ctx.com name))
  250. end
  251. let s_path_haxe path =
  252. match fst path, snd path with
  253. | [], s -> s
  254. | el, s -> String.concat "." el ^ "." ^ s
  255. let escape_bin s =
  256. let b = Buffer.create 0 in
  257. for i = 0 to String.length s - 1 do
  258. match Char.code (String.unsafe_get s i) with
  259. | c when c = Char.code('\\') or c = Char.code('"') or c = Char.code('$') ->
  260. Buffer.add_string b "\\";
  261. Buffer.add_char b (Char.chr c)
  262. | c when c < 32 ->
  263. Buffer.add_string b (Printf.sprintf "\\x%.2X" c)
  264. | c ->
  265. Buffer.add_char b (Char.chr c)
  266. done;
  267. Buffer.contents b
  268. (*
  269. haxe reserved words that match php ones: break, case, class, continue, default, do, else, extends, for, function, if, new, return, static, switch, var, while, interface, implements, public, private, try, catch, throw
  270. *)
  271. (* PHP only (for future use): cfunction, old_function *)
  272. let is_keyword n =
  273. match String.lowercase n with
  274. | "and" | "or" | "xor" | "__file__" | "exception" | "__line__" | "array"
  275. | "as" | "const" | "declare" | "die" | "echo"| "elseif" | "empty"
  276. | "enddeclare" | "endfor" | "endforeach" | "endif" | "endswitch"
  277. | "endwhile" | "eval" | "exit" | "foreach"| "global" | "include"
  278. | "include_once" | "isset" | "list" | "namespace" | "print" | "require" | "require_once"
  279. | "unset" | "use" | "__function__" | "__class__" | "__method__" | "final"
  280. | "php_user_filter" | "protected" | "abstract" | "__set" | "__get" | "__call"
  281. | "clone" | "instanceof" | "break" | "case" | "class" | "continue" | "default" | "do" | "else" | "extends" | "for" | "function" | "if" | "new" | "return" | "static" | "switch" | "var" | "while" | "interface" | "implements" | "public" | "private" | "try" | "catch" | "throw" -> true
  282. | "goto"
  283. | _ -> false
  284. let s_ident n =
  285. let suf = "h" in
  286. if (is_keyword n) then (suf ^ n) else n
  287. let s_ident_field n =
  288. if (is_keyword n) then ("{\"" ^ (escape_bin n) ^ "\"}") else n
  289. let s_ident_local n =
  290. let suf = "h" in
  291. match String.lowercase n with
  292. | "globals" | "_server" | "_get" | "_post" | "_cookie" | "_files"
  293. | "_env" | "_request" | "_session" -> suf ^ n
  294. | _ -> n
  295. let create_directory com ldir =
  296. let atm_path = ref (String.create 0) in
  297. atm_path := com.file;
  298. if not (Sys.file_exists com.file) then (Unix.mkdir com.file 0o755);
  299. (List.iter (fun p -> atm_path := !atm_path ^ "/" ^ p; if not (Sys.file_exists !atm_path) then (Unix.mkdir !atm_path 0o755);) ldir)
  300. let write_resource dir name data =
  301. let i = ref 0 in
  302. String.iter (fun c ->
  303. if c = '\\' || c = '/' || c = ':' || c = '*' || c = '?' || c = '"' || c = '<' || c = '>' || c = '|' then String.blit "_" 0 name !i 1;
  304. incr i
  305. ) name;
  306. let rdir = dir ^ "/res" in
  307. if not (Sys.file_exists dir) then Unix.mkdir dir 0o755;
  308. if not (Sys.file_exists rdir) then Unix.mkdir rdir 0o755;
  309. let ch = open_out_bin (rdir ^ "/" ^ name) in
  310. output_string ch data;
  311. close_out ch
  312. let stack_init com use_add =
  313. Codegen.stack_context_init com "GLOBALS['%s']" "GLOBALS['%e']" "__hx__spos" "tmp" use_add null_pos
  314. let init com cwd path def_type =
  315. let rec create acc = function
  316. | [] -> ()
  317. | d :: l ->
  318. let pdir = String.concat "/" (List.rev (d :: acc)) in
  319. if not (Sys.file_exists pdir) then Unix.mkdir pdir 0o755;
  320. create (d :: acc) l
  321. in
  322. let dir = if cwd <> "" then com.file :: (cwd :: fst path) else com.file :: fst path; in
  323. create [] dir;
  324. let filename path =
  325. prefix_class com (match path with
  326. | [], "List" -> "HList";
  327. | _, s -> s) in
  328. (*--php-prefix*)
  329. let ch = open_out (String.concat "/" dir ^ "/" ^ (filename path) ^ (if def_type = 0 then ".class" else if def_type = 1 then ".enum" else if def_type = 2 then ".interface" else ".extern") ^ ".php") in
  330. let imports = Hashtbl.create 0 in
  331. Hashtbl.add imports (snd path) [fst path];
  332. {
  333. com = com;
  334. stack = stack_init com false;
  335. tabs = "";
  336. ch = ch;
  337. path = path;
  338. buf = Buffer.create (1 lsl 14);
  339. in_value = None;
  340. in_loop = false;
  341. in_instance_method = false;
  342. imports = imports;
  343. extern_required_paths = [];
  344. extern_classes_with_init = [];
  345. curclass = null_class;
  346. curmethod = "";
  347. locals = PMap.empty;
  348. inv_locals = PMap.empty;
  349. local_types = [];
  350. inits = [];
  351. constructor_block = false;
  352. dynamic_methods = [];
  353. all_dynamic_methods = [];
  354. is_call = false;
  355. cwd = cwd;
  356. inline_methods = [];
  357. nested_loops = 0;
  358. inline_index = 0;
  359. in_block = false;
  360. lib_path = match com.php_lib with None -> "lib" | Some s -> s;
  361. }
  362. let unsupported msg p = error ("This expression cannot be generated to PHP: " ^ msg) p
  363. let newline ctx =
  364. match Buffer.nth ctx.buf (Buffer.length ctx.buf - 1) with
  365. | '{' | ':' | ' '
  366. | '}' when Buffer.nth ctx.buf (Buffer.length ctx.buf - 2) != '"' ->
  367. print ctx "\n%s" ctx.tabs
  368. | _ ->
  369. print ctx ";\n%s" ctx.tabs
  370. let rec concat ctx s f = function
  371. | [] -> ()
  372. | [x] -> f x
  373. | x :: l ->
  374. f x;
  375. spr ctx s;
  376. concat ctx s f l
  377. let open_block ctx =
  378. let oldt = ctx.tabs in
  379. ctx.tabs <- "\t" ^ ctx.tabs;
  380. (fun() -> ctx.tabs <- oldt)
  381. let parent e =
  382. match e.eexpr with
  383. | TParenthesis _ -> e
  384. | _ -> mk (TParenthesis e) e.etype e.epos
  385. let inc_extern_path ctx path =
  386. let rec slashes n =
  387. if n = 0 then "" else ("../" ^ slashes (n-1))
  388. in
  389. let pre = if ctx.cwd = "" then ctx.lib_path ^ "/" else "" in
  390. match path with
  391. | ([],name) ->
  392. pre ^ (slashes (List.length (fst ctx.path))) ^ (prefix_class ctx.com name) ^ ".extern.php"
  393. | (pack,name) ->
  394. pre ^ (slashes (List.length (fst ctx.path))) ^ String.concat "/" pack ^ "/" ^ (prefix_class ctx.com name) ^ ".extern.php"
  395. let close ctx =
  396. output_string ctx.ch "<?php\n";
  397. List.iter (fun path ->
  398. if path <> ctx.path then output_string ctx.ch ("require_once dirname(__FILE__).'/" ^ (inc_extern_path ctx path) ^ "';\n");
  399. ) (List.rev ctx.extern_required_paths);
  400. output_string ctx.ch "\n";
  401. output_string ctx.ch (Buffer.contents ctx.buf);
  402. close_out ctx.ch
  403. let save_locals ctx =
  404. let old = ctx.locals in
  405. let old_inv = ctx.inv_locals in
  406. (fun() -> ctx.locals <- old; ctx.inv_locals <- old_inv)
  407. let define_local ctx l =
  408. let rec loop n =
  409. let name = (if n = 1 then s_ident_local l else s_ident_local (l ^ string_of_int n)) in
  410. if PMap.mem name ctx.inv_locals then
  411. loop (n+1)
  412. else begin
  413. ctx.locals <- PMap.add l name ctx.locals;
  414. ctx.inv_locals <- PMap.add name l ctx.inv_locals;
  415. name
  416. end
  417. in
  418. loop 1
  419. let this ctx =
  420. if ctx.in_value <> None then "$__hx__this" else "$this"
  421. let gen_constant ctx p = function
  422. | TInt i -> print ctx "%ld" i
  423. | TFloat s -> spr ctx s
  424. | TString s ->
  425. print ctx "\"%s\"" (escape_bin s)
  426. | TBool b -> spr ctx (if b then "true" else "false")
  427. | TNull -> spr ctx "null"
  428. | TThis -> spr ctx (this ctx)
  429. | TSuper -> spr ctx "ERROR /* unexpected call to super in gen_constant */"
  430. let arg_is_opt c =
  431. match c with
  432. | Some _ -> true
  433. | None -> false
  434. let s_funarg ctx arg t p o =
  435. let byref = if (String.length arg > 7 && String.sub arg 0 7 = "byref__") then "&" else "" in
  436. print ctx "%s$%s" byref (s_ident_local arg);
  437. if o then spr ctx " = null"
  438. (*
  439. match c with
  440. | _, Some _ -> spr ctx " = null"
  441. | _, None -> ()
  442. *)
  443. let is_in_dynamic_methods ctx e s =
  444. List.exists (fun dm ->
  445. (* TODO: I agree, this is a mess ... but after hours of trials and errors I gave up; maybe in a calmer day *)
  446. ((String.concat "." ((fst dm.mpath) @ ["#" ^ (snd dm.mpath)])) ^ "." ^ dm.mname) = (s_type_name e.etype ^ "." ^ s)
  447. ) ctx.all_dynamic_methods
  448. let is_dynamic_method f =
  449. (match f.cf_kind with
  450. | Var _ -> true
  451. | Method MethDynamic -> true
  452. | _ -> false)
  453. let fun_block ctx f p =
  454. let e = (match f.tf_expr with { eexpr = TBlock [{ eexpr = TBlock _ } as e] } -> e | e -> e) in
  455. let e = List.fold_left (fun e (v,c) ->
  456. match c with
  457. | None | Some TNull -> e
  458. | Some c -> Codegen.concat (Codegen.set_default ctx.com v c p) e
  459. ) e f.tf_args in
  460. if ctx.com.debug then begin
  461. Codegen.stack_block ctx.stack ctx.curclass ctx.curmethod e
  462. end else
  463. mk_block e
  464. let rec gen_array_args ctx lst =
  465. match lst with
  466. | [] -> ()
  467. | h :: t ->
  468. spr ctx "[";
  469. gen_value ctx h;
  470. spr ctx "]";
  471. gen_array_args ctx t
  472. and gen_call ctx e el =
  473. let rec genargs lst =
  474. (match lst with
  475. | [] -> ()
  476. | h :: [] ->
  477. spr ctx " = ";
  478. gen_value ctx h;
  479. | h :: t ->
  480. spr ctx "[";
  481. gen_value ctx h;
  482. spr ctx "]";
  483. genargs t)
  484. in
  485. match e.eexpr , el with
  486. | TConst TSuper , params ->
  487. (match ctx.curclass.cl_super with
  488. | None -> assert false
  489. | Some (c,_) ->
  490. spr ctx "parent::__construct(";
  491. concat ctx "," (gen_value ctx) params;
  492. spr ctx ")";
  493. );
  494. | TField ({ eexpr = TConst TSuper },f) , params ->
  495. (match ctx.curclass.cl_super with
  496. | None -> assert false
  497. | Some (c,_) ->
  498. print ctx "parent::%s(" (s_ident (field_name f));
  499. concat ctx "," (gen_value ctx) params;
  500. spr ctx ")";
  501. );
  502. | TLocal { v_name = "__set__" }, { eexpr = TConst (TString code) } :: el ->
  503. print ctx "$%s" code;
  504. genargs el;
  505. | TLocal { v_name = "__set__" }, e :: el ->
  506. gen_value ctx e;
  507. genargs el;
  508. | TLocal { v_name = "__setfield__" }, e :: (f :: el) ->
  509. gen_value ctx e;
  510. spr ctx "->{";
  511. gen_value ctx f;
  512. spr ctx "}";
  513. genargs el;
  514. | TLocal { v_name = "__field__" }, e :: ({ eexpr = TConst (TString code) } :: el) ->
  515. gen_value ctx e;
  516. spr ctx "->";
  517. spr ctx code;
  518. gen_array_args ctx el;
  519. | TLocal { v_name = "__field__" }, e :: (f :: el) ->
  520. gen_value ctx e;
  521. spr ctx "->";
  522. gen_value ctx f;
  523. gen_array_args ctx el;
  524. | TLocal { v_name = "__prefix__" }, [] ->
  525. (match ctx.com.php_prefix with
  526. | Some prefix ->
  527. print ctx "\"%s\"" prefix
  528. | None ->
  529. spr ctx "null")
  530. | TLocal { v_name = "__var__" }, { eexpr = TConst (TString code) } :: el ->
  531. print ctx "$%s" code;
  532. gen_array_args ctx el;
  533. | TLocal { v_name = "__var__" }, e :: el ->
  534. gen_value ctx e;
  535. gen_array_args ctx el;
  536. | TLocal { v_name = "__call__" }, { eexpr = TConst (TString code) } :: el ->
  537. spr ctx code;
  538. spr ctx "(";
  539. concat ctx ", " (gen_value ctx) el;
  540. spr ctx ")";
  541. | TLocal { v_name = "__php__" }, [{ eexpr = TConst (TString code) }] ->
  542. (*--php-prefix*)
  543. spr ctx (prefix_init_replace ctx.com code)
  544. | TLocal { v_name = "__instanceof__" }, [e1;{ eexpr = TConst (TString t) }] ->
  545. gen_value ctx e1;
  546. print ctx " instanceof %s" t;
  547. | TLocal { v_name = "__physeq__" }, [e1;e2] ->
  548. spr ctx "(";
  549. gen_value ctx e1;
  550. spr ctx " === ";
  551. gen_value ctx e2;
  552. spr ctx ")"
  553. | TLocal _, []
  554. | TFunction _, []
  555. | TCall _, []
  556. | TParenthesis _, []
  557. | TMeta _, []
  558. | TBlock _, [] ->
  559. ctx.is_call <- true;
  560. spr ctx "call_user_func(";
  561. gen_value ctx e;
  562. ctx.is_call <- false;
  563. spr ctx ")";
  564. | TLocal _, el
  565. | TFunction _, el
  566. | TCall _, el
  567. | TParenthesis _, el
  568. | TMeta _, el
  569. | TBlock _, el ->
  570. ctx.is_call <- true;
  571. spr ctx "call_user_func_array(";
  572. gen_value ctx e;
  573. ctx.is_call <- false;
  574. spr ctx ", array(";
  575. concat ctx ", " (gen_value ctx) el;
  576. spr ctx "))"
  577. (*
  578. | TCall (x,_), el when (match x.eexpr with | TLocal _ -> false | _ -> true) ->
  579. ctx.is_call <- true;
  580. spr ctx "call_user_func_array(";
  581. gen_value ctx e;
  582. ctx.is_call <- false;
  583. spr ctx ", array(";
  584. concat ctx ", " (gen_value ctx) el;
  585. spr ctx "))"
  586. *)
  587. | _ ->
  588. ctx.is_call <- true;
  589. gen_value ctx e;
  590. ctx.is_call <- false;
  591. spr ctx "(";
  592. concat ctx ", " (gen_value ctx) el;
  593. spr ctx ")";
  594. and could_be_string_var s =
  595. s = "length"
  596. and gen_uncertain_string_var ctx s e =
  597. match s with
  598. | "length" ->
  599. spr ctx "_hx_len(";
  600. gen_value ctx e;
  601. spr ctx ")"
  602. | _ ->
  603. gen_field_access ctx true e s;
  604. and gen_string_var ctx s e =
  605. match s with
  606. | "length" ->
  607. spr ctx "strlen(";
  608. gen_value ctx e;
  609. spr ctx ")"
  610. | _ ->
  611. unsupported "gen_string_var " e.epos;
  612. and gen_string_static_call ctx s e el =
  613. match s with
  614. | "fromCharCode" ->
  615. spr ctx "chr(";
  616. concat ctx ", " (gen_value ctx) el;
  617. spr ctx ")";
  618. | _ -> unsupported "gen_string_static_call " e.epos;
  619. and could_be_string_call s =
  620. s = "substr" || s = "substring" || s = "charAt" || s = "charCodeAt" || s = "indexOf" ||
  621. s = "lastIndexOf" || s = "split" || s = "toLowerCase" || s = "toString" || s = "toUpperCase"
  622. and gen_string_call ctx s e el =
  623. match s with
  624. | "substr" ->
  625. spr ctx "_hx_substr(";
  626. gen_value ctx e;
  627. spr ctx ", ";
  628. concat ctx ", " (gen_value ctx) el;
  629. spr ctx ")"
  630. | "substring" ->
  631. spr ctx "_hx_substring(";
  632. gen_value ctx e;
  633. spr ctx ", ";
  634. concat ctx ", " (gen_value ctx) el;
  635. spr ctx ")"
  636. | "charAt" ->
  637. spr ctx "_hx_char_at(";
  638. gen_value ctx e;
  639. spr ctx ", ";
  640. concat ctx ", " (gen_value ctx) el;
  641. spr ctx ")"
  642. | "cca" ->
  643. spr ctx "ord(substr(";
  644. gen_value ctx e;
  645. spr ctx ",";
  646. concat ctx ", " (gen_value ctx) el;
  647. spr ctx ",1))"
  648. | "charCodeAt" ->
  649. spr ctx "_hx_char_code_at(";
  650. gen_value ctx e;
  651. spr ctx ", ";
  652. concat ctx ", " (gen_value ctx) el;
  653. spr ctx ")"
  654. | "indexOf" ->
  655. spr ctx "_hx_index_of(";
  656. gen_value ctx e;
  657. spr ctx ", ";
  658. concat ctx ", " (gen_value ctx) el;
  659. spr ctx ")"
  660. | "lastIndexOf" ->
  661. spr ctx "_hx_last_index_of(";
  662. gen_value ctx e;
  663. spr ctx ", ";
  664. concat ctx ", " (gen_value ctx) el;
  665. spr ctx ")"
  666. | "split" ->
  667. spr ctx "_hx_explode(";
  668. concat ctx ", " (gen_value ctx) el;
  669. spr ctx ", ";
  670. gen_value ctx e;
  671. spr ctx ")"
  672. | "toLowerCase" ->
  673. spr ctx "strtolower(";
  674. gen_value ctx e;
  675. spr ctx ")"
  676. | "toUpperCase" ->
  677. spr ctx "strtoupper(";
  678. gen_value ctx e;
  679. spr ctx ")"
  680. | "toString" ->
  681. gen_value ctx e;
  682. | _ ->
  683. unsupported "gen_string_call" e.epos;
  684. and gen_uncertain_string_call ctx s e el =
  685. spr ctx "_hx_string_call(";
  686. gen_value ctx e;
  687. print ctx ", \"%s\", array(" s;
  688. concat ctx ", " (gen_value ctx) el;
  689. spr ctx "))"
  690. and gen_field_op ctx e =
  691. match e.eexpr with
  692. | TField (f,s) ->
  693. (match follow e.etype with
  694. | TFun _ ->
  695. gen_field_access ctx true f (field_name s)
  696. | _ ->
  697. gen_value_op ctx e)
  698. | _ ->
  699. gen_value_op ctx e
  700. and gen_value_op ctx e =
  701. match e.eexpr with
  702. | TBinop (op,_,_) when op = Ast.OpAnd || op = Ast.OpOr || op = Ast.OpXor ->
  703. gen_value ctx e;
  704. | _ ->
  705. gen_value ctx e
  706. and is_static t =
  707. match follow t with
  708. | TAnon a -> (match !(a.a_status) with
  709. | Statics c -> true
  710. | _ -> false)
  711. | _ -> false
  712. and gen_member_access ctx isvar e s =
  713. match follow e.etype with
  714. | TAnon a ->
  715. (match !(a.a_status) with
  716. | EnumStatics _ ->
  717. print ctx "::%s%s" (if isvar then "$" else "") (s_ident s)
  718. | Statics _ ->
  719. print ctx "::%s%s" (if isvar then "$" else "") (s_ident s)
  720. | _ -> print ctx "->%s" (if isvar then s_ident_field s else s_ident s))
  721. | _ -> print ctx "->%s" (if isvar then s_ident_field s else s_ident s)
  722. and gen_field_access ctx isvar e s =
  723. match e.eexpr with
  724. | TTypeExpr t ->
  725. spr ctx (s_path ctx (t_path t) false e.epos);
  726. gen_member_access ctx isvar e s
  727. | TLocal _ ->
  728. gen_expr ctx e;
  729. print ctx "->%s" (if isvar then s_ident_field s else s_ident s)
  730. | TArray (e1,e2) ->
  731. spr ctx "_hx_array_get(";
  732. gen_value ctx e1;
  733. spr ctx ", ";
  734. gen_value ctx e2;
  735. spr ctx ")";
  736. gen_member_access ctx isvar e s
  737. | TBlock _
  738. | TParenthesis _
  739. | TMeta _
  740. | TObjectDecl _
  741. | TArrayDecl _
  742. | TNew _ ->
  743. spr ctx "_hx_deref(";
  744. ctx.is_call <- false;
  745. gen_value ctx e;
  746. spr ctx ")";
  747. gen_member_access ctx isvar e s
  748. | TCast (ec, _) when (match ec.eexpr with | TNew _ | TArrayDecl _ -> true | _ -> false) ->
  749. spr ctx "_hx_deref(";
  750. ctx.is_call <- false;
  751. gen_value ctx e;
  752. spr ctx ")";
  753. gen_member_access ctx isvar e s
  754. | _ ->
  755. gen_expr ctx e;
  756. gen_member_access ctx isvar e s
  757. and gen_dynamic_function ctx isstatic name f params p =
  758. let old = ctx.in_value in
  759. let old_l = ctx.locals in
  760. let old_li = ctx.inv_locals in
  761. let old_t = ctx.local_types in
  762. ctx.in_value <- None;
  763. ctx.local_types <- List.map snd params @ ctx.local_types;
  764. let byref = if (String.length name > 9 && String.sub name 0 9 = "__byref__") then "&" else "" in
  765. print ctx "function %s%s(" byref name;
  766. concat ctx ", " (fun (v,c) ->
  767. let arg = define_local ctx v.v_name in
  768. s_funarg ctx arg v.v_type p (arg_is_opt c);
  769. ) f.tf_args;
  770. spr ctx ") {";
  771. if (List.length f.tf_args) > 0 then begin
  772. if isstatic then
  773. print ctx " return call_user_func_array(self::$%s, array(" name
  774. else
  775. print ctx " return call_user_func_array($this->%s, array(" name;
  776. concat ctx ", " (fun (v,_) ->
  777. spr ctx ("$" ^ v.v_name)
  778. ) f.tf_args;
  779. print ctx ")); }";
  780. end else if isstatic then
  781. print ctx " return call_user_func(self::$%s); }" name
  782. else
  783. print ctx " return call_user_func($this->%s); }" name;
  784. newline ctx;
  785. if isstatic then
  786. print ctx "public static $%s = null" name
  787. else
  788. print ctx "public $%s = null" name;
  789. ctx.in_value <- old;
  790. ctx.locals <- old_l;
  791. ctx.inv_locals <- old_li;
  792. ctx.local_types <- old_t
  793. and gen_function ctx name f params p =
  794. let old = ctx.in_value in
  795. let old_l = ctx.locals in
  796. let old_li = ctx.inv_locals in
  797. let old_t = ctx.local_types in
  798. ctx.in_value <- None;
  799. ctx.local_types <- List.map snd params @ ctx.local_types;
  800. let byref = if (String.length name > 9 && String.sub name 0 9 = "__byref__") then "&" else "" in
  801. print ctx "function %s%s(" byref name;
  802. concat ctx ", " (fun (v,o) ->
  803. let arg = define_local ctx v.v_name in
  804. s_funarg ctx arg v.v_type p (arg_is_opt o);
  805. ) f.tf_args;
  806. print ctx ") ";
  807. gen_expr ctx (fun_block ctx f p);
  808. ctx.in_value <- old;
  809. ctx.locals <- old_l;
  810. ctx.inv_locals <- old_li;
  811. ctx.local_types <- old_t
  812. and gen_inline_function ctx f hasthis p =
  813. ctx.nested_loops <- ctx.nested_loops - 1;
  814. let old = ctx.in_value in
  815. let old_l = ctx.locals in
  816. let old_li = ctx.inv_locals in
  817. let old_t = ctx.local_types in
  818. ctx.in_value <- Some "closure";
  819. let args a = List.map (fun (v,_) -> v.v_name) a in
  820. let arguments = ref [] in
  821. if hasthis then begin arguments := "this" :: !arguments end;
  822. PMap.iter (fun n _ -> arguments := !arguments @ [n]) old_li;
  823. spr ctx "array(new _hx_lambda(array(";
  824. let c = ref 0 in
  825. List.iter (fun a ->
  826. if !c > 0 then spr ctx ", ";
  827. incr c;
  828. print ctx "&$%s" a;
  829. ) (remove_internals !arguments);
  830. spr ctx "), \"";
  831. spr ctx (inline_function ctx (args f.tf_args) hasthis (fun_block ctx f p));
  832. print ctx "\"), 'execute')";
  833. ctx.in_value <- old;
  834. ctx.locals <- old_l;
  835. ctx.inv_locals <- old_li;
  836. ctx.local_types <- old_t;
  837. ctx.nested_loops <- ctx.nested_loops + 1;
  838. and unset_locals ctx old_l =
  839. let lst = ref [] in
  840. PMap.iter (fun n _ ->
  841. if not (PMap.exists n old_l) then
  842. lst := ["$" ^ n] @ !lst;
  843. ) ctx.inv_locals;
  844. if (List.length !lst) > 0 then begin
  845. newline ctx;
  846. spr ctx "unset(";
  847. concat ctx "," (fun (s) -> spr ctx s; ) !lst;
  848. spr ctx ")"
  849. end
  850. and gen_while_expr ctx e =
  851. let old_loop = ctx.in_loop in
  852. ctx.in_loop <- true;
  853. let old_nested_loops = ctx.nested_loops in
  854. ctx.nested_loops <- 1;
  855. let old_l = ctx.inv_locals in
  856. let b = save_locals ctx in
  857. (match e.eexpr with
  858. | TBlock (el) ->
  859. List.iter (fun e -> newline ctx; gen_expr ctx e) el;
  860. | _ ->
  861. newline ctx;
  862. gen_expr ctx e);
  863. unset_locals ctx old_l;
  864. b();
  865. ctx.nested_loops <- old_nested_loops;
  866. ctx.in_loop <- old_loop
  867. and gen_tfield ctx e e1 s =
  868. match follow e.etype with
  869. | TFun (args, _) ->
  870. (if ctx.is_call then begin
  871. gen_field_access ctx false e1 s
  872. end else if is_in_dynamic_methods ctx e1 s then begin
  873. gen_field_access ctx true e1 s;
  874. end else begin
  875. let ob ex =
  876. (match ex with
  877. | TTypeExpr t ->
  878. print ctx "\"";
  879. spr ctx (s_path ctx (t_path t) false e1.epos);
  880. print ctx "\""
  881. | _ ->
  882. gen_expr ctx e1) in
  883. spr ctx "(isset(";
  884. gen_field_access ctx true e1 s;
  885. spr ctx ") ? ";
  886. gen_field_access ctx true e1 s;
  887. spr ctx ": array(";
  888. ob e1.eexpr;
  889. print ctx ", \"%s\"))" (s_ident s);
  890. end)
  891. | TMono _ ->
  892. if ctx.is_call then
  893. gen_field_access ctx false e1 s
  894. else
  895. gen_uncertain_string_var ctx s e1
  896. | _ ->
  897. if is_string_expr e1 then
  898. gen_string_var ctx s e1
  899. else if is_uncertain_expr e1 then
  900. gen_uncertain_string_var ctx s e1
  901. else
  902. gen_field_access ctx true e1 s
  903. and gen_expr ctx e =
  904. let in_block = ctx.in_block in
  905. ctx.in_block <- false;
  906. let restore_in_block ctx inb =
  907. if inb then ctx.in_block <- true
  908. in
  909. match e.eexpr with
  910. | TConst c ->
  911. gen_constant ctx e.epos c
  912. | TLocal v ->
  913. spr ctx ("$" ^ (try PMap.find v.v_name ctx.locals with Not_found -> (s_ident_local v.v_name)))
  914. | TArray (e1,e2) ->
  915. (match e1.eexpr with
  916. | TCall _
  917. | TBlock _
  918. | TParenthesis _
  919. | TMeta _
  920. | TArrayDecl _ ->
  921. spr ctx "_hx_array_get(";
  922. gen_value ctx e1;
  923. spr ctx ", ";
  924. gen_value ctx e2;
  925. spr ctx ")";
  926. | TCast (ec, _) when (match ec.eexpr with | TArrayDecl _ | TBlock _ -> true | _ -> false) ->
  927. spr ctx "_hx_array_get(";
  928. gen_value ctx e1;
  929. spr ctx ", ";
  930. gen_value ctx e2;
  931. spr ctx ")";
  932. | _ ->
  933. gen_value ctx e1;
  934. spr ctx "[";
  935. gen_value ctx e2;
  936. spr ctx "]");
  937. | TBinop (op,e1,e2) ->
  938. (* these operators are non-assoc in php, let let's make sure to separate them with parenthesises *)
  939. let non_assoc = function
  940. | (Ast.OpEq | Ast.OpNotEq | Ast.OpGt | Ast.OpGte | Ast.OpLt | Ast.OpLte) -> true
  941. | _ -> false
  942. in
  943. (match e1.eexpr with
  944. | TBinop (op2,_,_) when non_assoc op && non_assoc op2 ->
  945. gen_expr ctx { e with eexpr = TBinop (op,mk (TParenthesis e1) e1.etype e1.epos,e2) }
  946. | _ ->
  947. let leftside e =
  948. (match e.eexpr with
  949. | TArray(te1, te2) ->
  950. gen_value ctx te1;
  951. spr ctx "->a[";
  952. gen_value ctx te2;
  953. spr ctx "]";
  954. | _ ->
  955. gen_field_op ctx e1;) in
  956. let leftsidec e =
  957. (match e.eexpr with
  958. | TArray(te1, te2) ->
  959. gen_value ctx te1;
  960. spr ctx "->a[";
  961. gen_value ctx te2;
  962. spr ctx "]";
  963. | TField (e1,s) ->
  964. gen_field_access ctx true e1 (field_name s)
  965. | _ ->
  966. gen_field_op ctx e1;) in
  967. let leftsidef e =
  968. (match e.eexpr with
  969. | TField (e1,s) ->
  970. gen_field_access ctx true e1 (field_name s)
  971. | _ ->
  972. gen_field_op ctx e1;
  973. ) in
  974. (match op with
  975. | Ast.OpMod ->
  976. spr ctx "_hx_mod(";
  977. gen_value_op ctx e1;
  978. spr ctx ", ";
  979. gen_value_op ctx e2;
  980. spr ctx ")";
  981. | Ast.OpAssign ->
  982. (match e1.eexpr with
  983. | TArray(te1, te2) when (match te1.eexpr with | TCall _ | TParenthesis _ -> true | _ -> false) ->
  984. spr ctx "_hx_array_assign(";
  985. gen_value ctx te1;
  986. spr ctx ", ";
  987. gen_value ctx te2;
  988. spr ctx ", ";
  989. gen_value_op ctx e2;
  990. spr ctx ")";
  991. | _ ->
  992. leftsidef e1;
  993. spr ctx " = ";
  994. gen_value_op ctx e2;
  995. )
  996. | Ast.OpAssignOp(Ast.OpAdd) when (is_uncertain_expr e1 && is_uncertain_expr e2) ->
  997. (match e1.eexpr with
  998. | TArray(te1, te2) ->
  999. let t1 = define_local ctx "__hx__t1" in
  1000. let t2 = define_local ctx "__hx__t2" in
  1001. print ctx "_hx_array_assign($%s = " t1;
  1002. gen_value ctx te1;
  1003. print ctx ", $%s = " t2;
  1004. gen_value ctx te2;
  1005. print ctx ", $%s->a[$%s] + " t1 t2;
  1006. gen_value_op ctx e2;
  1007. spr ctx ")";
  1008. | _ ->
  1009. leftside e1;
  1010. spr ctx " = ";
  1011. spr ctx "_hx_add(";
  1012. gen_value_op ctx e1;
  1013. spr ctx ", ";
  1014. gen_value_op ctx e2;
  1015. spr ctx ")";
  1016. )
  1017. | Ast.OpAssignOp(Ast.OpAdd) when (is_string_expr e1 || is_string_expr e2) ->
  1018. leftside e1;
  1019. spr ctx " .= ";
  1020. gen_value_op ctx (as_string_expr ctx e2);
  1021. | Ast.OpAssignOp(Ast.OpShl) ->
  1022. leftside e1;
  1023. spr ctx " <<= ";
  1024. gen_value_op ctx e2;
  1025. | Ast.OpAssignOp(Ast.OpUShr) ->
  1026. leftside e1;
  1027. spr ctx " = ";
  1028. spr ctx "_hx_shift_right(";
  1029. gen_value_op ctx e1;
  1030. spr ctx ", ";
  1031. gen_value_op ctx e2;
  1032. spr ctx ")";
  1033. | Ast.OpAssignOp(Ast.OpMod) ->
  1034. leftside e1;
  1035. spr ctx " = ";
  1036. spr ctx "_hx_mod(";
  1037. gen_value_op ctx e1;
  1038. spr ctx ", ";
  1039. gen_value_op ctx e2;
  1040. spr ctx ")";
  1041. | Ast.OpAssignOp(_) ->
  1042. leftsidec e1;
  1043. print ctx " %s " (Ast.s_binop op);
  1044. gen_value_op ctx e2;
  1045. | Ast.OpAdd when (is_uncertain_expr e1 && is_uncertain_expr e2) ->
  1046. spr ctx "_hx_add(";
  1047. gen_value_op ctx e1;
  1048. spr ctx ", ";
  1049. gen_value_op ctx e2;
  1050. spr ctx ")";
  1051. | Ast.OpAdd when (is_string_expr e1 || is_string_expr e2) ->
  1052. gen_value_op ctx (as_string_expr ctx e1);
  1053. spr ctx " . ";
  1054. gen_value_op ctx (as_string_expr ctx e2);
  1055. | Ast.OpShl ->
  1056. gen_value_op ctx e1;
  1057. spr ctx " << ";
  1058. gen_value_op ctx e2;
  1059. | Ast.OpUShr ->
  1060. spr ctx "_hx_shift_right(";
  1061. gen_value_op ctx e1;
  1062. spr ctx ", ";
  1063. gen_value_op ctx e2;
  1064. spr ctx ")";
  1065. | Ast.OpNotEq
  1066. | Ast.OpEq ->
  1067. let s_op = if op = Ast.OpNotEq then " != " else " == " in
  1068. let s_phop = if op = Ast.OpNotEq then " !== " else " === " in
  1069. let se1 = s_expr_name e1 in
  1070. let se2 = s_expr_name e2 in
  1071. if
  1072. e1.eexpr = TConst (TNull)
  1073. || e2.eexpr = TConst (TNull)
  1074. then begin
  1075. (match e1.eexpr with
  1076. | TField (f, s) when is_anonym_expr e1 || is_unknown_expr e1 ->
  1077. spr ctx "_hx_field(";
  1078. gen_value ctx f;
  1079. print ctx ", \"%s\")" (field_name s);
  1080. | _ ->
  1081. gen_field_op ctx e1;
  1082. );
  1083. spr ctx s_phop;
  1084. (match e2.eexpr with
  1085. | TField (f, s) when is_anonym_expr e2 || is_unknown_expr e2 ->
  1086. spr ctx "_hx_field(";
  1087. gen_value ctx f;
  1088. print ctx ", \"%s\")" (field_name s);
  1089. | _ ->
  1090. gen_field_op ctx e2);
  1091. end else if
  1092. ((se1 = "Int" || se1 = "Null<Int>") && (se2 = "Int" || se2 = "Null<Int>"))
  1093. || ((se1 = "Float" || se1 = "Null<Float>") && (se2 = "Float" || se2 = "Null<Float>"))
  1094. then begin
  1095. gen_field_op ctx e1;
  1096. spr ctx s_phop;
  1097. gen_field_op ctx e2;
  1098. end else if
  1099. ((se1 = "Int" || se1 = "Float" || se1 = "Null<Int>" || se1 = "Null<Float>")
  1100. && (se1 = "Int" || se1 = "Float" || se1 = "Null<Int>" || se1 = "Null<Float>"))
  1101. || (is_unknown_expr e1 && is_unknown_expr e2)
  1102. || is_anonym_expr e1
  1103. || is_anonym_expr e2
  1104. then begin
  1105. if op = Ast.OpNotEq then spr ctx "!";
  1106. spr ctx "_hx_equal(";
  1107. gen_field_op ctx e1;
  1108. spr ctx ", ";
  1109. gen_field_op ctx e2;
  1110. spr ctx ")";
  1111. end else if
  1112. (
  1113. se1 == se2
  1114. || (match e1.eexpr with | TConst _ | TLocal _ | TArray _ | TNew _ -> true | _ -> false)
  1115. || (match e2.eexpr with | TConst _ | TLocal _ | TArray _ | TNew _ -> true | _ -> false)
  1116. || is_string_expr e1
  1117. || is_string_expr e2
  1118. || is_anonym_expr e1
  1119. || is_anonym_expr e2
  1120. || is_unknown_expr e1
  1121. || is_unknown_expr e2
  1122. )
  1123. && (type_string (follow e1.etype)) <> "Dynamic"
  1124. && (type_string (follow e2.etype)) <> "Dynamic"
  1125. then begin
  1126. gen_field_op ctx e1;
  1127. spr ctx s_phop;
  1128. gen_field_op ctx e2;
  1129. end else begin
  1130. let tmp = define_local ctx "_t" in
  1131. print ctx "(is_object($%s = " tmp;
  1132. gen_field_op ctx e1;
  1133. print ctx ") && !($%s instanceof Enum) ? $%s%s" tmp tmp s_phop;
  1134. gen_field_op ctx e2;
  1135. print ctx " : $%s%s" tmp s_op;
  1136. gen_field_op ctx e2;
  1137. spr ctx ")";
  1138. end
  1139. | _ ->
  1140. leftside e1;
  1141. print ctx " %s " (Ast.s_binop op);
  1142. gen_value_op ctx e2;
  1143. ));
  1144. | TEnumParameter(e1,_,i) ->
  1145. gen_value ctx e1;
  1146. print ctx "->params[%d]" i;
  1147. | TField (e1,s) ->
  1148. gen_tfield ctx e e1 (field_name s)
  1149. | TTypeExpr t ->
  1150. print ctx "_hx_qtype(\"%s\")" (s_path_haxe (t_path t))
  1151. | TParenthesis e ->
  1152. (match e.eexpr with
  1153. | TParenthesis _
  1154. | TReturn _ ->
  1155. gen_value ctx e;
  1156. | _ ->
  1157. spr ctx "(";
  1158. gen_value ctx e;
  1159. spr ctx ")"
  1160. );
  1161. | TMeta (_,e) ->
  1162. gen_expr ctx e
  1163. | TReturn eo ->
  1164. (match eo with
  1165. | None ->
  1166. spr ctx "return"
  1167. | Some e when (match follow e.etype with TEnum({ e_path = [],"Void" },[]) | TAbstract ({ a_path = [],"Void" },[]) -> true | _ -> false) ->
  1168. gen_value ctx e;
  1169. newline ctx;
  1170. spr ctx "return"
  1171. | Some e ->
  1172. (match e.eexpr with
  1173. | TThrow _ -> ()
  1174. | _ -> spr ctx "return ");
  1175. gen_value ctx e;
  1176. );
  1177. | TBreak ->
  1178. if ctx.in_loop then spr ctx "break" else print ctx "break %d" ctx.nested_loops
  1179. | TContinue ->
  1180. if ctx.in_loop then spr ctx "continue" else print ctx "continue %d" ctx.nested_loops
  1181. | TBlock [] ->
  1182. spr ctx ""
  1183. | TBlock el ->
  1184. let old_l = ctx.inv_locals in
  1185. let b = save_locals ctx in
  1186. print ctx "{";
  1187. let bend = open_block ctx in
  1188. let cb = (
  1189. if not ctx.constructor_block then
  1190. (fun () -> ())
  1191. else begin
  1192. ctx.constructor_block <- false;
  1193. if List.length ctx.dynamic_methods > 0 then newline ctx else spr ctx " ";
  1194. List.iter (fun (f) ->
  1195. let name = f.cf_name in
  1196. match f.cf_expr with
  1197. | Some { eexpr = TFunction fd } ->
  1198. print ctx "if(!isset($this->%s)) $this->%s = " name name;
  1199. gen_inline_function ctx fd true e.epos;
  1200. newline ctx;
  1201. | _ -> ()
  1202. ) ctx.dynamic_methods;
  1203. if Codegen.constructor_side_effects e then begin
  1204. print ctx "if(!%s::$skip_constructor) {" (s_path ctx (["php"],"Boot") false e.epos);
  1205. (fun() -> print ctx "}")
  1206. end else
  1207. (fun() -> ());
  1208. end) in
  1209. let remaining = ref (List.length el) in
  1210. let build e =
  1211. (match e.eexpr with
  1212. | TBlock [] -> ()
  1213. | _ -> newline ctx);
  1214. if (in_block && !remaining = 1) then begin
  1215. (match e.eexpr with
  1216. | TIf _
  1217. | TSwitch _
  1218. | TThrow _
  1219. | TWhile _
  1220. | TFor _
  1221. | TPatMatch _
  1222. | TTry _
  1223. | TBreak
  1224. | TBlock _ ->
  1225. restore_in_block ctx in_block;
  1226. gen_expr ctx e;
  1227. unset_locals ctx old_l;
  1228. | TReturn (Some e1) ->
  1229. (match e1.eexpr with
  1230. | TIf _
  1231. | TSwitch _
  1232. | TThrow _
  1233. | TWhile _
  1234. | TFor _
  1235. | TPatMatch _
  1236. | TTry _
  1237. | TBlock _ -> ()
  1238. | _ ->
  1239. spr ctx "return "
  1240. );
  1241. gen_expr ctx e1;
  1242. | _ ->
  1243. spr ctx "return ";
  1244. gen_value ctx e;
  1245. )
  1246. end else begin
  1247. gen_expr ctx e;
  1248. end;
  1249. decr remaining;
  1250. in
  1251. List.iter build el;
  1252. if ctx.in_loop then begin
  1253. unset_locals ctx old_l;
  1254. end;
  1255. bend();
  1256. newline ctx;
  1257. cb();
  1258. print ctx "}";
  1259. b();
  1260. | TFunction f ->
  1261. let old = ctx.in_value, ctx.in_loop in
  1262. let old_meth = ctx.curmethod in
  1263. ctx.in_value <- None;
  1264. ctx.in_loop <- false;
  1265. ctx.curmethod <- ctx.curmethod ^ "@" ^ string_of_int (Lexer.get_error_line e.epos);
  1266. gen_inline_function ctx f false e.epos;
  1267. ctx.curmethod <- old_meth;
  1268. ctx.in_value <- fst old;
  1269. ctx.in_loop <- snd old;
  1270. | TCall (ec,el) ->
  1271. (match ec.eexpr with
  1272. | TArray _ ->
  1273. spr ctx "call_user_func_array(";
  1274. gen_value ctx ec;
  1275. spr ctx ", array(";
  1276. concat ctx ", " (gen_value ctx) el;
  1277. spr ctx "))";
  1278. | TField (ef,s) when is_static ef.etype && is_string_expr ef ->
  1279. gen_string_static_call ctx (field_name s) ef el
  1280. | TField (ef,s) when is_string_expr ef ->
  1281. gen_string_call ctx (field_name s) ef el
  1282. | TField (ef,s) when is_anonym_expr ef && could_be_string_call (field_name s) ->
  1283. gen_uncertain_string_call ctx (field_name s) ef el
  1284. | _ ->
  1285. gen_call ctx ec el);
  1286. | TArrayDecl el ->
  1287. spr ctx "(new _hx_array(array(";
  1288. concat ctx ", " (gen_value ctx) el;
  1289. spr ctx ")))";
  1290. | TThrow e ->
  1291. spr ctx "throw new HException(";
  1292. gen_value ctx e;
  1293. spr ctx ")";
  1294. | TVars [] ->
  1295. ()
  1296. | TVars vl ->
  1297. spr ctx "$";
  1298. concat ctx ("; $") (fun (v,e) ->
  1299. let restore = save_locals ctx in
  1300. let n = define_local ctx v.v_name in
  1301. let restore2 = save_locals ctx in
  1302. restore();
  1303. (match e with
  1304. | None ->
  1305. print ctx "%s = null" (s_ident_local n)
  1306. | Some e ->
  1307. print ctx "%s = " (s_ident_local n);
  1308. gen_value ctx e);
  1309. restore2()
  1310. ) vl;
  1311. | TNew (c,_,el) ->
  1312. (match c.cl_path, el with
  1313. | ([], "String"), _ ->
  1314. concat ctx "" (gen_value ctx) el
  1315. | ([], "Array"), el ->
  1316. spr ctx "new _hx_array(array(";
  1317. concat ctx ", " (gen_value ctx) el;
  1318. spr ctx "))"
  1319. | (_, _), _ ->
  1320. print ctx "new %s(" (s_path ctx c.cl_path c.cl_extern e.epos);
  1321. let count = ref (-1) in
  1322. concat ctx ", " (fun e ->
  1323. incr count;
  1324. match c.cl_constructor with
  1325. | Some f ->
  1326. gen_value ctx e;
  1327. | _ -> ();
  1328. ) el;
  1329. spr ctx ")")
  1330. | TIf (cond,e,eelse) ->
  1331. spr ctx "if";
  1332. gen_value ctx (parent cond);
  1333. spr ctx " ";
  1334. restore_in_block ctx in_block;
  1335. gen_expr ctx (mk_block e);
  1336. (match eelse with
  1337. | None -> ()
  1338. | Some e when e.eexpr = TConst(TNull) -> ()
  1339. | Some e ->
  1340. spr ctx " else ";
  1341. restore_in_block ctx in_block;
  1342. gen_expr ctx (mk_block e));
  1343. | TUnop (op,Ast.Prefix,e) ->
  1344. (match e.eexpr with
  1345. | TArray(te1, te2) ->
  1346. (match op with
  1347. | Increment ->
  1348. spr ctx "_hx_array_increment(";
  1349. gen_value ctx te1;
  1350. spr ctx ",";
  1351. gen_value ctx te2;
  1352. spr ctx ")";
  1353. | Decrement ->
  1354. spr ctx "_hx_array_decrement(";
  1355. gen_value ctx te1;
  1356. spr ctx ",";
  1357. gen_value ctx te2;
  1358. spr ctx ")";
  1359. | _ ->
  1360. spr ctx (Ast.s_unop op);
  1361. gen_value ctx te1;
  1362. spr ctx "[";
  1363. gen_value ctx te2;
  1364. spr ctx "]";
  1365. );
  1366. | TField (e1,s) ->
  1367. spr ctx (Ast.s_unop op);
  1368. gen_field_access ctx true e1 (field_name s)
  1369. | _ ->
  1370. spr ctx (Ast.s_unop op);
  1371. gen_value ctx e)
  1372. | TUnop (op,Ast.Postfix,e) ->
  1373. (match e.eexpr with
  1374. | TArray(te1, te2) ->
  1375. gen_value ctx te1;
  1376. spr ctx "->a[";
  1377. gen_value ctx te2;
  1378. spr ctx "]";
  1379. | TField (e1,s) ->
  1380. gen_field_access ctx true e1 (field_name s)
  1381. | _ ->
  1382. gen_value ctx e);
  1383. spr ctx (Ast.s_unop op)
  1384. | TWhile (cond,e,Ast.NormalWhile) ->
  1385. let old = save_locals ctx in
  1386. spr ctx "while";
  1387. gen_value ctx (parent cond);
  1388. spr ctx " {";
  1389. let bend = open_block ctx in
  1390. gen_while_expr ctx e;
  1391. bend();
  1392. newline ctx;
  1393. spr ctx "}";
  1394. old()
  1395. | TWhile (cond,e,Ast.DoWhile) ->
  1396. let old = save_locals ctx in
  1397. spr ctx "do {";
  1398. let bend = open_block ctx in
  1399. gen_while_expr ctx e;
  1400. bend();
  1401. newline ctx;
  1402. spr ctx "} while";
  1403. gen_value ctx (parent cond);
  1404. old()
  1405. | TObjectDecl fields ->
  1406. spr ctx "_hx_anonymous(array(";
  1407. concat ctx ", " (fun (f,e) -> print ctx "\"%s\" => " (escape_bin f); gen_value ctx e) fields;
  1408. spr ctx "))"
  1409. | TFor (v,it,e) ->
  1410. let b = save_locals ctx in
  1411. let tmp = define_local ctx "__hx__it" in
  1412. let v = define_local ctx v.v_name in
  1413. (match it.eexpr with
  1414. | TCall (e,_) ->
  1415. (match e.eexpr with
  1416. | TField (e,f) ->
  1417. spr ctx "if(null == ";
  1418. gen_value ctx e;
  1419. spr ctx ") throw new HException('null iterable')";
  1420. newline ctx;
  1421. | _ ->
  1422. ());
  1423. | _ -> ()
  1424. );
  1425. print ctx "$%s = " tmp;
  1426. gen_value ctx it;
  1427. newline ctx;
  1428. print ctx "while($%s->hasNext()) {" tmp;
  1429. let bend = open_block ctx in
  1430. newline ctx;
  1431. print ctx "$%s = $%s->next()" v tmp;
  1432. gen_while_expr ctx e;
  1433. bend();
  1434. newline ctx;
  1435. spr ctx "}";
  1436. b();
  1437. | TTry (e,catchs) ->
  1438. spr ctx "try ";
  1439. restore_in_block ctx in_block;
  1440. gen_expr ctx (mk_block e);
  1441. let old = save_locals ctx in
  1442. let ex = define_local ctx "__hx__e" in
  1443. print ctx "catch(Exception $%s) {" ex;
  1444. let bend = open_block ctx in
  1445. let first = ref true in
  1446. let catchall = ref false in
  1447. let evar = define_local ctx "_ex_" in
  1448. newline ctx;
  1449. print ctx "$%s = ($%s instanceof HException) ? $%s->e : $%s" evar ex ex ex;
  1450. old();
  1451. List.iter (fun (v,e) ->
  1452. let ev = define_local ctx v.v_name in
  1453. newline ctx;
  1454. let b = save_locals ctx in
  1455. if not !first then spr ctx "else ";
  1456. (match follow v.v_type with
  1457. | TEnum (te,_) -> (match te.e_path with
  1458. | [], "Bool" -> print ctx "if(is_bool($%s = $%s))" ev evar
  1459. | _ -> print ctx "if(($%s = $%s) instanceof %s)" ev evar (s_path ctx te.e_path te.e_extern e.epos));
  1460. restore_in_block ctx in_block;
  1461. gen_expr ctx (mk_block e);
  1462. | TInst (tc,_) -> (match tc.cl_path with
  1463. | [], "Int" -> print ctx "if(is_int($%s = $%s))" ev evar
  1464. | [], "Float" -> print ctx "if(is_numeric($%s = $%s))" ev evar
  1465. | [], "String" -> print ctx "if(is_string($%s = $%s))" ev evar
  1466. | [], "Array" -> print ctx "if(($%s = $%s) instanceof _hx_array)" ev evar
  1467. | _ -> print ctx "if(($%s = $%s) instanceof %s)" ev evar (s_path ctx tc.cl_path tc.cl_extern e.epos));
  1468. restore_in_block ctx in_block;
  1469. gen_expr ctx (mk_block e);
  1470. | TAbstract (ta,_) -> (match ta.a_path with
  1471. | [], "Int" -> print ctx "if(is_int($%s = $%s))" ev evar
  1472. | [], "Float" -> print ctx "if(is_numeric($%s = $%s))" ev evar
  1473. | [], "Bool" -> print ctx "if(is_bool($%s = $%s))" ev evar
  1474. | _ -> print ctx "if(($%s = $%s) instanceof %s)" ev evar (s_path ctx ta.a_path false e.epos));
  1475. restore_in_block ctx in_block;
  1476. gen_expr ctx (mk_block e);
  1477. | TFun _
  1478. | TLazy _
  1479. | TType _
  1480. | TAnon _ ->
  1481. assert false
  1482. | TMono _
  1483. | TDynamic _ ->
  1484. catchall := true;
  1485. if not !first then spr ctx "{ ";
  1486. print ctx "$%s = $%s" ev evar;
  1487. newline ctx;
  1488. restore_in_block ctx in_block;
  1489. gen_expr ctx (mk_block e);
  1490. if not !first then spr ctx "}"
  1491. );
  1492. b();
  1493. first := false;
  1494. ) catchs;
  1495. if not !catchall then
  1496. print ctx " else throw $%s;" ex;
  1497. bend();
  1498. newline ctx;
  1499. spr ctx "}"
  1500. | TPatMatch dt -> assert false
  1501. | TSwitch (e,cases,def) ->
  1502. let old_loop = ctx.in_loop in
  1503. ctx.in_loop <- false;
  1504. ctx.nested_loops <- ctx.nested_loops + 1;
  1505. let old = save_locals ctx in
  1506. spr ctx "switch";
  1507. gen_value ctx (parent e);
  1508. spr ctx " {";
  1509. newline ctx;
  1510. List.iter (fun (el,e2) ->
  1511. List.iter (fun e ->
  1512. spr ctx "case ";
  1513. gen_value ctx e;
  1514. spr ctx ":";
  1515. ) el;
  1516. restore_in_block ctx in_block;
  1517. gen_expr ctx (mk_block e2);
  1518. print ctx "break";
  1519. newline ctx;
  1520. ) cases;
  1521. (match def with
  1522. | None -> ()
  1523. | Some e ->
  1524. spr ctx "default:";
  1525. restore_in_block ctx in_block;
  1526. gen_expr ctx (mk_block e);
  1527. print ctx "break";
  1528. newline ctx;
  1529. );
  1530. spr ctx "}";
  1531. ctx.nested_loops <- ctx.nested_loops - 1;
  1532. ctx.in_loop <- old_loop;
  1533. old()
  1534. | TCast (e,None) ->
  1535. gen_expr ctx e
  1536. | TCast (e1,Some t) ->
  1537. let mk_texpr = function
  1538. | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
  1539. | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
  1540. | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
  1541. | TTypeDecl _ -> assert false
  1542. in
  1543. spr ctx "_hx_cast(";
  1544. gen_expr ctx e1;
  1545. spr ctx ", ";
  1546. gen_expr ctx (mk (TTypeExpr t) (mk_texpr t) e1.epos);
  1547. spr ctx ")"
  1548. and argument_list_from_locals include_this in_var l =
  1549. let lst = ref [] in
  1550. if (include_this && in_var) then lst := "__hx__this" :: !lst
  1551. else if include_this then lst := "this" :: !lst;
  1552. PMap.iter (fun n _ ->
  1553. lst := !lst @ [n];
  1554. ) l;
  1555. !lst
  1556. and remove_internals args =
  1557. List.filter (fun a -> a = "__hx__this" || not (start_with a "__hx__")) args;
  1558. and inline_block ctx e =
  1559. let index = ctx.inline_index in
  1560. ctx.inline_index <- ctx.inline_index + 1;
  1561. let block = {
  1562. iname = (s_path ctx ctx.curclass.cl_path ctx.curclass.cl_extern ctx.curclass.cl_pos) ^ "_" ^ string_of_int index;
  1563. iindex = index;
  1564. ihasthis = ctx.in_instance_method; (* param this *)
  1565. iarguments = [];
  1566. iexpr = e;
  1567. ilocals = ctx.locals;
  1568. iin_block = true;
  1569. iinv_locals = ctx.inv_locals;
  1570. } in
  1571. print ctx "%s(" block.iname;
  1572. let in_value = (match ctx.in_value with Some _ -> true | _ -> false) in
  1573. (match remove_internals (argument_list_from_locals ctx.in_instance_method in_value ctx.locals) with
  1574. | [] -> ()
  1575. | l -> print ctx "$%s" (String.concat ", $" l)
  1576. );
  1577. spr ctx ")";
  1578. ctx.inline_methods <- ctx.inline_methods @ [block]
  1579. and inline_function ctx args hasthis e =
  1580. let index = ctx.inline_index in
  1581. ctx.inline_index <- ctx.inline_index + 1;
  1582. let block = {
  1583. iname = (s_path ctx ctx.curclass.cl_path ctx.curclass.cl_extern ctx.curclass.cl_pos) ^ "_" ^ string_of_int index;
  1584. iindex = index;
  1585. ihasthis = hasthis; (* param this *)
  1586. iarguments = args;
  1587. iexpr = e;
  1588. ilocals = ctx.locals;
  1589. iin_block = false;
  1590. iinv_locals = ctx.inv_locals;
  1591. } in
  1592. ctx.inline_methods <- ctx.inline_methods @ [block];
  1593. block.iname
  1594. and canbe_ternary_param e =
  1595. match e.eexpr with
  1596. | TTypeExpr _
  1597. | TConst _
  1598. | TLocal _
  1599. | TField (_,FEnum _)
  1600. | TParenthesis _
  1601. | TMeta _
  1602. | TObjectDecl _
  1603. | TArrayDecl _
  1604. | TCall _
  1605. | TUnop _
  1606. | TNew _
  1607. | TCast (_, _)
  1608. | TBlock [_] ->
  1609. true
  1610. | TIf (_,e,eelse) ->
  1611. cangen_ternary e eelse
  1612. | _ ->
  1613. false
  1614. and cangen_ternary e eelse =
  1615. match eelse with
  1616. | Some other ->
  1617. (canbe_ternary_param e) && (canbe_ternary_param other)
  1618. | _ ->
  1619. false
  1620. and gen_value ctx e =
  1621. match e.eexpr with
  1622. | TTypeExpr _
  1623. | TConst _
  1624. | TLocal _
  1625. | TArray _
  1626. | TBinop _
  1627. | TEnumParameter _
  1628. | TField _
  1629. | TParenthesis _
  1630. | TObjectDecl _
  1631. | TArrayDecl _
  1632. | TCall _
  1633. | TUnop _
  1634. | TNew _
  1635. | TFunction _ ->
  1636. gen_expr ctx e
  1637. | TMeta (_,e1) ->
  1638. gen_value ctx e1
  1639. | TBlock [] ->
  1640. ()
  1641. | TCast (e, _)
  1642. | TBlock [e] ->
  1643. gen_value ctx e
  1644. | TIf (cond,e,eelse) when (cangen_ternary e eelse) ->
  1645. spr ctx "(";
  1646. gen_value ctx cond;
  1647. spr ctx " ? ";
  1648. gen_value ctx e;
  1649. (match eelse with
  1650. | Some e ->
  1651. spr ctx " : ";
  1652. gen_value ctx e
  1653. | _ ->());
  1654. spr ctx ")";
  1655. (*
  1656. | TIf (cond,e,eelse) ->
  1657. spr ctx "if";
  1658. gen_value ctx (parent cond);
  1659. spr ctx " ";
  1660. restore_in_block ctx in_block;
  1661. gen_expr ctx (mk_block e);
  1662. (match eelse with
  1663. | None -> ()
  1664. | Some e when e.eexpr = TConst(TNull) -> ()
  1665. | Some e ->
  1666. spr ctx " else ";
  1667. restore_in_block ctx in_block;
  1668. gen_expr ctx (mk_block e));
  1669. *)
  1670. | TBlock _
  1671. | TBreak
  1672. | TContinue
  1673. | TVars _
  1674. | TReturn _
  1675. | TWhile _
  1676. | TThrow _
  1677. | TSwitch _
  1678. | TFor _
  1679. | TPatMatch _
  1680. | TIf _
  1681. | TTry _ ->
  1682. inline_block ctx e
  1683. let rec is_instance_method_defined cls m =
  1684. if PMap.exists m cls.cl_fields then
  1685. true
  1686. else
  1687. match cls.cl_super with
  1688. | Some (scls, _) ->
  1689. is_instance_method_defined scls m
  1690. | None ->
  1691. false
  1692. let is_method_defined ctx m static =
  1693. if static then
  1694. PMap.exists m ctx.curclass.cl_statics
  1695. else
  1696. is_instance_method_defined ctx.curclass m
  1697. let generate_self_method ctx rights m static setter =
  1698. if setter then (
  1699. if static then
  1700. print ctx "%s function %s($v) { return call_user_func(self::$%s, $v); }" rights (s_ident m) (s_ident m)
  1701. else
  1702. print ctx "%s function %s($v) { return call_user_func($this->%s, $v); }" rights (s_ident m) (s_ident m)
  1703. ) else (
  1704. if static then
  1705. print ctx "%s function %s() { return call_user_func(self::$%s); }" rights (s_ident m) (s_ident m)
  1706. else
  1707. print ctx "%s function %s() { return call_user_func($this->%s); }" rights (s_ident m) (s_ident m)
  1708. );
  1709. newline ctx
  1710. let gen_assigned_value ctx eo = match eo with
  1711. | Some ({eexpr = TConst _} as e) ->
  1712. print ctx " = ";
  1713. gen_value ctx e
  1714. | _ ->
  1715. ()
  1716. let generate_field ctx static f =
  1717. if not (is_extern_field f) then
  1718. newline ctx;
  1719. ctx.locals <- PMap.empty;
  1720. ctx.inv_locals <- PMap.empty;
  1721. ctx.in_instance_method <- not static;
  1722. let rights = if static then "static" else "public" in
  1723. let p = ctx.curclass.cl_pos in
  1724. match f.cf_expr with
  1725. | Some { eexpr = TFunction fd } ->
  1726. if f.cf_name = "__construct" then
  1727. ctx.curmethod <- "new"
  1728. else
  1729. ctx.curmethod <- f.cf_name;
  1730. spr ctx (rights ^ " ");
  1731. if is_dynamic_method f then
  1732. gen_dynamic_function ctx static (s_ident f.cf_name) fd f.cf_params p
  1733. else
  1734. gen_function ctx (s_ident f.cf_name) fd f.cf_params p
  1735. | _ ->
  1736. if (is_extern_field f) then
  1737. ()
  1738. else if ctx.curclass.cl_interface then
  1739. match follow f.cf_type, f.cf_kind with
  1740. | TFun (args,r), Method _ ->
  1741. print ctx "function %s(" (s_ident f.cf_name);
  1742. concat ctx ", " (fun (arg,o,t) ->
  1743. s_funarg ctx arg t p o;
  1744. ) args;
  1745. print ctx ")";
  1746. | _ -> spr ctx "//"; ()
  1747. else if
  1748. (match f.cf_kind with
  1749. | Var v ->
  1750. (match v.v_read, v.v_write with
  1751. | AccCall, AccCall ->
  1752. let m1 = "get_" ^ f.cf_name in
  1753. let m2 = "set_" ^ f.cf_name in
  1754. if not (is_method_defined ctx m1 static) then (
  1755. generate_self_method ctx rights m1 static false;
  1756. print ctx "%s $%s" rights (s_ident m1);
  1757. if not (is_method_defined ctx m2 static) then
  1758. newline ctx);
  1759. if not (is_method_defined ctx m2 static) then (
  1760. generate_self_method ctx rights m2 static true;
  1761. print ctx "%s $%s" rights (s_ident m2);
  1762. newline ctx);
  1763. false
  1764. | AccCall, _ ->
  1765. let m = "get_" ^ f.cf_name in
  1766. if not (is_method_defined ctx m static) then generate_self_method ctx rights m static false;
  1767. print ctx "%s $%s" rights (s_ident_field f.cf_name);
  1768. gen_assigned_value ctx f.cf_expr;
  1769. true
  1770. | _, AccCall ->
  1771. let m = "set_" ^ f.cf_name in
  1772. if not (is_method_defined ctx m static) then generate_self_method ctx rights m static true;
  1773. print ctx "%s $%s" rights (s_ident_field f.cf_name);
  1774. gen_assigned_value ctx f.cf_expr;
  1775. true
  1776. | _ ->
  1777. false)
  1778. | _ -> false) then
  1779. ()
  1780. else begin
  1781. let name = if static then s_ident f.cf_name else f.cf_name in
  1782. if static then
  1783. (match f.cf_kind with
  1784. | Var _ ->
  1785. (match follow f.cf_type with
  1786. | TFun _
  1787. | TDynamic _ ->
  1788. print ctx "static function %s() { $args = func_get_args(); return call_user_func_array(self::$%s, $args); }" name name;
  1789. newline ctx;
  1790. | _ ->
  1791. ()
  1792. )
  1793. | _ ->
  1794. ()
  1795. );
  1796. print ctx "%s $%s" rights name;
  1797. gen_assigned_value ctx f.cf_expr
  1798. end
  1799. let generate_static_field_assign ctx path f =
  1800. let p = ctx.curclass.cl_pos in
  1801. if not ctx.curclass.cl_interface then
  1802. (match f.cf_expr with
  1803. | None -> ()
  1804. | Some e ->
  1805. match e.eexpr with
  1806. | TConst _ -> ()
  1807. | TFunction fd ->
  1808. (match f.cf_kind with
  1809. | Var _ when
  1810. (match follow f.cf_type with
  1811. | TFun _
  1812. | TDynamic _ ->
  1813. true;
  1814. | _ ->
  1815. false) ->
  1816. newline ctx;
  1817. print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
  1818. gen_value ctx e
  1819. | Method MethDynamic ->
  1820. newline ctx;
  1821. print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
  1822. gen_value ctx e
  1823. | _ -> ())
  1824. | _ when is_extern_field f ->
  1825. ()
  1826. | _ ->
  1827. newline ctx;
  1828. print ctx "%s::$%s = " (s_path ctx path false p) (s_ident f.cf_name);
  1829. gen_value ctx e)
  1830. let rec super_has_dynamic c =
  1831. match c.cl_super with
  1832. | None -> false
  1833. | Some (csup, _) -> (match csup.cl_dynamic with
  1834. | Some _ -> true
  1835. | _ -> super_has_dynamic csup)
  1836. let generate_inline_method ctx c m =
  1837. (match ctx.inline_methods with
  1838. | [] -> ()
  1839. | h :: t -> ctx.inline_methods <- t
  1840. );
  1841. ctx.curclass <- c;
  1842. let old = save_locals ctx in
  1843. ctx.in_value <- Some m.iname;
  1844. ctx.in_block <- m.iin_block;
  1845. ctx.in_loop <- false;
  1846. ctx.locals <- m.ilocals;
  1847. ctx.inv_locals <- m.iinv_locals;
  1848. newline ctx;
  1849. print ctx "function %s(" m.iname;
  1850. (* arguments *)
  1851. let in_value = (match ctx.in_value with Some _ -> true | _ -> false) in
  1852. let arguments = remove_internals (argument_list_from_locals m.ihasthis in_value ctx.locals) in
  1853. let arguments = match arguments with
  1854. | [h] when h = "this" -> ["__hx__this"]
  1855. | h :: t when h = "this" -> "__hx__this" :: t
  1856. | _ -> arguments
  1857. in
  1858. let marguments = List.map (define_local ctx) m.iarguments in
  1859. let arguments = (List.map (fun a -> "&$" ^ a) arguments) @ (List.map (fun a -> "$" ^ a) marguments) in
  1860. (match arguments with
  1861. | [] -> ()
  1862. | l -> spr ctx (String.concat ", " arguments)
  1863. );
  1864. spr ctx ") {";
  1865. ctx.nested_loops <- ctx.nested_loops - 1;
  1866. let block = open_block ctx in
  1867. newline ctx;
  1868. gen_expr ctx m.iexpr;
  1869. block();
  1870. old();
  1871. ctx.nested_loops <- ctx.nested_loops + 1;
  1872. newline ctx;
  1873. spr ctx "}"
  1874. let generate_class ctx c =
  1875. let requires_constructor = ref true in
  1876. ctx.curclass <- c;
  1877. ctx.local_types <- List.map snd c.cl_types;
  1878. print ctx "%s %s " (if c.cl_interface then "interface" else "class") (s_path ctx c.cl_path c.cl_extern c.cl_pos);
  1879. (match c.cl_super with
  1880. | None -> ()
  1881. | Some (csup,_) ->
  1882. requires_constructor := false;
  1883. print ctx "extends %s " (s_path ctx csup.cl_path csup.cl_extern c.cl_pos));
  1884. let implements = ExtList.List.unique ~cmp:(fun a b -> (fst a).cl_path = (fst b).cl_path) c.cl_implements in
  1885. (match implements with
  1886. | [] -> ()
  1887. | l ->
  1888. spr ctx (if c.cl_interface then "extends " else "implements ");
  1889. concat ctx ", " (fun (i,_) ->
  1890. print ctx "%s" (s_path ctx i.cl_path i.cl_extern c.cl_pos)) l);
  1891. spr ctx "{";
  1892. let get_dynamic_methods = List.filter is_dynamic_method c.cl_ordered_fields in
  1893. if not ctx.curclass.cl_interface then ctx.dynamic_methods <- get_dynamic_methods;
  1894. let cl = open_block ctx in
  1895. (match c.cl_constructor with
  1896. | None ->
  1897. if !requires_constructor && not c.cl_interface then begin
  1898. newline ctx;
  1899. spr ctx "public function __construct(){}"
  1900. end;
  1901. | Some f ->
  1902. let f = { f with
  1903. cf_name = "__construct";
  1904. cf_public = true;
  1905. } in
  1906. ctx.constructor_block <- true;
  1907. generate_field ctx false f;
  1908. );
  1909. List.iter (generate_field ctx false) c.cl_ordered_fields;
  1910. (match c.cl_dynamic with
  1911. | Some _ when not c.cl_interface && not (super_has_dynamic c) ->
  1912. newline ctx;
  1913. spr ctx "public $__dynamics = array();\n\tpublic function __get($n) {\n\t\tif(isset($this->__dynamics[$n]))\n\t\t\treturn $this->__dynamics[$n];\n\t}\n\tpublic function __set($n, $v) {\n\t\t$this->__dynamics[$n] = $v;\n\t}\n\tpublic function __call($n, $a) {\n\t\tif(isset($this->__dynamics[$n]) && is_callable($this->__dynamics[$n]))\n\t\t\treturn call_user_func_array($this->__dynamics[$n], $a);\n\t\tif('toString' == $n)\n\t\t\treturn $this->__toString();\n\t\tthrow new HException(\"Unable to call <\".$n.\">\");\n\t}"
  1914. | Some _
  1915. | _ ->
  1916. if List.length ctx.dynamic_methods > 0 then begin
  1917. newline ctx;
  1918. spr ctx "public function __call($m, $a) {\n\t\tif(isset($this->$m) && is_callable($this->$m))\n\t\t\treturn call_user_func_array($this->$m, $a);\n\t\telse if(isset($this->__dynamics[$m]) && is_callable($this->__dynamics[$m]))\n\t\t\treturn call_user_func_array($this->__dynamics[$m], $a);\n\t\telse if('toString' == $m)\n\t\t\treturn $this->__toString();\n\t\telse\n\t\t\tthrow new HException('Unable to call <'.$m.'>');\n\t}";
  1919. end;
  1920. );
  1921. List.iter (generate_field ctx true) c.cl_ordered_statics;
  1922. let gen_props props =
  1923. String.concat "," (List.map (fun (p,v) -> "\"" ^ p ^ "\" => \"" ^ v ^ "\"") props)
  1924. in
  1925. let rec fields c =
  1926. let list = Codegen.get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
  1927. match c.cl_super with
  1928. | Some (csup, _) ->
  1929. list @ fields csup
  1930. | None ->
  1931. list
  1932. in
  1933. if not c.cl_interface then (match fields c with
  1934. | [] ->
  1935. ()
  1936. | props ->
  1937. newline ctx;
  1938. print ctx "static $__properties__ = array(%s)" (gen_props props);
  1939. );
  1940. cl();
  1941. newline ctx;
  1942. if PMap.exists "__toString" c.cl_fields then
  1943. ()
  1944. else if PMap.exists "toString" c.cl_fields && (not c.cl_interface) && (not c.cl_extern) then begin
  1945. print ctx "\tfunction __toString() { return $this->toString(); }";
  1946. newline ctx
  1947. end else if (not c.cl_interface) && (not c.cl_extern) then begin
  1948. print ctx "\tfunction __toString() { return '%s'; }" (s_path_haxe c.cl_path) ;
  1949. newline ctx
  1950. end;
  1951. print ctx "}"
  1952. let createmain com e =
  1953. let filename = match com.php_front with None -> "index.php" | Some n -> n in
  1954. let ctx = {
  1955. com = com;
  1956. stack = stack_init com false;
  1957. tabs = "";
  1958. ch = open_out (com.file ^ "/" ^ filename);
  1959. path = ([], "");
  1960. buf = Buffer.create (1 lsl 14);
  1961. in_value = None;
  1962. in_loop = false;
  1963. in_instance_method = false;
  1964. imports = Hashtbl.create 0;
  1965. extern_required_paths = [];
  1966. extern_classes_with_init = [];
  1967. curclass = null_class;
  1968. curmethod = "";
  1969. locals = PMap.empty;
  1970. inv_locals = PMap.empty;
  1971. local_types = [];
  1972. inits = [];
  1973. constructor_block = false;
  1974. dynamic_methods = [];
  1975. all_dynamic_methods = [];
  1976. is_call = false;
  1977. cwd = "";
  1978. inline_methods = [];
  1979. nested_loops = 0;
  1980. inline_index = 0;
  1981. in_block = false;
  1982. lib_path = match com.php_lib with None -> "lib" | Some s -> s;
  1983. } in
  1984. spr ctx "if(version_compare(PHP_VERSION, '5.1.0', '<')) {
  1985. exit('Your current PHP version is: ' . PHP_VERSION . '. Haxe/PHP generates code for version 5.1.0 or later');
  1986. }";
  1987. newline ctx;
  1988. newline ctx;
  1989. spr ctx ("require_once dirname(__FILE__).'/" ^ ctx.lib_path ^ "/php/" ^ (prefix_class com "Boot.class.php';\n\n"));
  1990. gen_value ctx e;
  1991. newline ctx;
  1992. spr ctx "\n?>";
  1993. close ctx
  1994. let generate_main ctx c =
  1995. (match c.cl_ordered_statics with
  1996. | [{ cf_expr = Some e }] ->
  1997. gen_value ctx e;
  1998. | _ -> assert false);
  1999. newline ctx
  2000. let generate_enum ctx e =
  2001. ctx.local_types <- List.map snd e.e_types;
  2002. let pack = open_block ctx in
  2003. let ename = s_path ctx e.e_path e.e_extern e.e_pos in
  2004. print ctx "class %s extends Enum {" ename;
  2005. PMap.iter (fun _ c ->
  2006. newline ctx;
  2007. match c.ef_type with
  2008. | TFun (args,_) ->
  2009. print ctx "public static function %s($" (s_ident c.ef_name);
  2010. concat ctx ", $" (fun (a,o,t) ->
  2011. spr ctx a;
  2012. if o then spr ctx " = null";
  2013. ) args;
  2014. spr ctx ") {";
  2015. print ctx " return new %s(\"%s\", %d, array($" ename (s_ident c.ef_name) c.ef_index;
  2016. concat ctx ", $" (fun (a,_,_) -> spr ctx a) args;
  2017. print ctx ")); }";
  2018. | _ ->
  2019. print ctx "public static $%s" (s_ident c.ef_name);
  2020. ) e.e_constrs;
  2021. newline ctx;
  2022. spr ctx "public static $__constructors = array(";
  2023. let first = ref true in
  2024. PMap.iter (fun _ c ->
  2025. if not !first then spr ctx ", ";
  2026. print ctx "%d => '%s'" c.ef_index (s_ident c.ef_name);
  2027. first := false;
  2028. ) e.e_constrs;
  2029. spr ctx ")";
  2030. newline ctx;
  2031. (match Codegen.build_metadata ctx.com (TEnumDecl e) with
  2032. | None -> ()
  2033. | Some _ ->
  2034. spr ctx "public static $__meta__";
  2035. newline ctx);
  2036. pack();
  2037. print ctx "}";
  2038. PMap.iter (fun _ c ->
  2039. match c.ef_type with
  2040. | TFun (args,_) ->
  2041. ();
  2042. | _ ->
  2043. newline ctx;
  2044. print ctx "%s::$%s = new %s(\"%s\", %d)" ename (s_ident c.ef_name) ename c.ef_name c.ef_index;
  2045. ) e.e_constrs;
  2046. newline ctx;
  2047. match Codegen.build_metadata ctx.com (TEnumDecl e) with
  2048. | None -> ()
  2049. | Some e ->
  2050. print ctx "%s::$__meta__ = " ename;
  2051. gen_expr ctx e;
  2052. newline ctx
  2053. let generate com =
  2054. let all_dynamic_methods = ref [] in
  2055. let extern_classes_with_init = ref [] in
  2056. let php_lib_path = (match com.php_lib with None -> "lib" | Some n -> n) in
  2057. create_directory com (Str.split (Str.regexp "/") php_lib_path);
  2058. (* check for methods with the same name but different case *)
  2059. let check_class_fields c =
  2060. let lc_names = ref [] in
  2061. let special_cases = ["toString"] in
  2062. let loop c lst static =
  2063. let in_special_cases name =
  2064. (List.exists (fun n -> String.lowercase n = name) (special_cases @ List.map (fun f -> f.cf_name) c.cl_overrides))
  2065. in
  2066. List.iter(fun cf ->
  2067. let name = String.lowercase cf.cf_name in
  2068. let prefixed_name s = (if s then "s_" else "i_") ^ name in
  2069. match cf.cf_kind, cf.cf_expr with
  2070. | (Method _, Some e) when not (in_special_cases name) ->
  2071. (try
  2072. let lc = List.find (fun n ->
  2073. let n = snd n in
  2074. if static then
  2075. (n = (prefixed_name false))
  2076. else
  2077. ((n = (prefixed_name false)) or (n = (prefixed_name true)))
  2078. ) !lc_names in
  2079. unsupported ("method '" ^ (s_type_path c.cl_path) ^ "." ^ cf.cf_name ^ "' already exists here '" ^ (fst lc) ^ "' (different case?)") c.cl_pos
  2080. with Not_found ->
  2081. lc_names := ((s_type_path c.cl_path) ^ "." ^ cf.cf_name, prefixed_name static) :: !lc_names)
  2082. | _ ->
  2083. ()
  2084. ) lst
  2085. in
  2086. let rec _check_class_fields cl =
  2087. (match cl.cl_super with
  2088. | Some (s,_) -> _check_class_fields s
  2089. | _ -> ());
  2090. loop cl cl.cl_ordered_statics true;
  2091. loop cl cl.cl_ordered_fields false
  2092. in
  2093. _check_class_fields c
  2094. in
  2095. List.iter (fun t ->
  2096. (match t with
  2097. | TClassDecl c ->
  2098. check_class_fields c
  2099. | TEnumDecl e ->
  2100. let e_names = ref [] in
  2101. List.iter(fun en -> (
  2102. if List.exists (fun n -> n = String.lowercase en) !e_names then
  2103. unsupported ("'" ^ en ^ "' constructor exists with different case") e.e_pos
  2104. else
  2105. e_names := (String.lowercase en) :: !e_names
  2106. )) (e.e_names)
  2107. | _ -> ())
  2108. ) com.types;
  2109. List.iter (fun t ->
  2110. (match t with
  2111. | TClassDecl c ->
  2112. let dynamic_methods_names lst =
  2113. List.map (fun fd -> {
  2114. mpath = c.cl_path;
  2115. mname = fd.cf_name;
  2116. }) (List.filter is_dynamic_method lst)
  2117. in
  2118. all_dynamic_methods := dynamic_methods_names c.cl_ordered_fields @ !all_dynamic_methods;
  2119. if c.cl_extern then
  2120. (match c.cl_init with
  2121. | Some _ ->
  2122. extern_classes_with_init := c.cl_path :: !extern_classes_with_init;
  2123. | _ ->
  2124. ())
  2125. else
  2126. all_dynamic_methods := dynamic_methods_names c.cl_ordered_statics @ !all_dynamic_methods;
  2127. | _ -> ())
  2128. ) com.types;
  2129. List.iter (Codegen.fix_abstract_inheritance com) com.types;
  2130. List.iter (fun t ->
  2131. (match t with
  2132. | TClassDecl c ->
  2133. if c.cl_extern then begin
  2134. (match c.cl_init with
  2135. | None -> ()
  2136. | Some e ->
  2137. let ctx = init com php_lib_path c.cl_path 3 in
  2138. gen_expr ctx e;
  2139. newline ctx;
  2140. close ctx;
  2141. );
  2142. end else
  2143. let ctx = init com php_lib_path c.cl_path (if c.cl_interface then 2 else 0) in
  2144. ctx.extern_classes_with_init <- !extern_classes_with_init;
  2145. ctx.all_dynamic_methods <- !all_dynamic_methods;
  2146. generate_class ctx c;
  2147. (match c.cl_init with
  2148. | None -> ()
  2149. | Some e ->
  2150. newline ctx;
  2151. gen_expr ctx e);
  2152. List.iter (generate_static_field_assign ctx c.cl_path) c.cl_ordered_statics;
  2153. if c.cl_path = (["php"], "Boot") & com.debug then begin
  2154. newline ctx;
  2155. print ctx "$%s = new _hx_array(array())" ctx.stack.Codegen.stack_var;
  2156. newline ctx;
  2157. print ctx "$%s = new _hx_array(array())" ctx.stack.Codegen.stack_exc_var;
  2158. end;
  2159. let rec loop l =
  2160. match l with
  2161. | [] -> ()
  2162. | h :: _ ->
  2163. generate_inline_method ctx c h;
  2164. loop ctx.inline_methods
  2165. in
  2166. loop ctx.inline_methods;
  2167. newline ctx;
  2168. close ctx
  2169. | TEnumDecl e ->
  2170. if e.e_extern then
  2171. ()
  2172. else
  2173. let ctx = init com php_lib_path e.e_path 1 in
  2174. generate_enum ctx e;
  2175. close ctx
  2176. | TTypeDecl _ | TAbstractDecl _ ->
  2177. ());
  2178. ) com.types;
  2179. (match com.main with
  2180. | None -> ()
  2181. | Some e -> createmain com e);
  2182. Hashtbl.iter (fun name data ->
  2183. write_resource com.file name data
  2184. ) com.resources;