genphp.ml 57 KB

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