Browse Source

Inital merge of cpp target

Hugh Sanderson 16 years ago
parent
commit
39580173cc
8 changed files with 2415 additions and 14 deletions
  1. 41 10
      codegen.ml
  2. 1 0
      common.ml
  3. 2235 0
      gencpp.ml
  4. 126 0
      gensource.ml
  5. 8 1
      main.ml
  6. 1 1
      optimizer.ml
  7. 1 1
      typeload.ml
  8. 2 1
      typer.ml

+ 41 - 10
codegen.ml

@@ -451,16 +451,19 @@ let block_vars ctx e =
 				else
 					v, o, vt
 			) f.tf_args in
-			let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in			
-			let args = List.map (fun (v,t) -> v, None, t) vars in
-			mk (TCall (
-				(mk (TFunction {
-					tf_args = args;
-					tf_type = e.etype;
-					tf_expr = mk (TReturn (Some e)) e.etype e.epos;
-				}) (TFun (fun_args args,e.etype)) e.epos),
-				List.map (fun (v,t) -> mk (TLocal v) t e.epos) vars)
-			) e.etype e.epos
+			let e = { e with eexpr = TFunction { f with tf_args = fargs; tf_expr = !fexpr } } in
+			(match ctx.platform with
+			| Cpp -> e
+			| _ ->
+				let args = List.map (fun (v,t) -> v, None, t) vars in
+				mk (TCall (
+					(mk (TFunction {
+						tf_args = args;
+						tf_type = e.etype;
+						tf_expr = mk (TReturn (Some e)) e.etype e.epos;
+					}) (TFun (fun_args args,e.etype)) e.epos),
+					List.map (fun (v,t) -> mk (TLocal v) t e.epos) vars)
+				) e.etype e.epos)
 		| _ ->
 			map_expr (wrap used) e
 
@@ -499,9 +502,37 @@ let block_vars ctx e =
 			if PMap.is_empty !used then e else wrap !used e
 		| _ ->
 			map_expr out_loop e
+	and all_vars e =
+		let vars = ref PMap.empty in
+		let used = ref PMap.empty in
+		let depth = ref 0 in
+		let rec collect_vars = function
+		| Block f ->
+			let old = !vars in
+			f collect_vars;
+			vars := old;
+		| Loop f ->
+			let old = !vars in
+			f collect_vars;
+			vars := old;
+		| Function f ->
+			incr depth;
+			f collect_vars;
+			decr depth;
+		| Declare (v,t) ->
+			vars := PMap.add v (!depth,t) !vars;
+		| Use v ->
+			try
+				let d, t = PMap.find v (!vars) in
+				if d <> !depth then used := PMap.add v t !used;
+			with Not_found -> ()
+		in
+	local_usage collect_vars e;
+	if PMap.is_empty !used then e else wrap !used e
 	in
 	match ctx.platform with
 	| Neko | Php | Cross -> e
+	| Cpp -> all_vars e
 	| _ -> out_loop e
 
 (* -------------------------------------------------------------------------- *)

+ 1 - 0
common.ml

@@ -30,6 +30,7 @@ type platform =
 	| Neko
 	| Flash9
 	| Php
+	| Cpp
 
 type pos = Ast.pos
 

+ 2235 - 0
gencpp.ml

@@ -0,0 +1,2235 @@
+(*
+ *  haXe/CPP Compiler
+ *  Copyright (c)2008 Hugh Sanderson
+ *  based on and including code by (c)2005-2008 Nicolas Cannasse
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+open Type
+open Common
+open Gensource
+
+
+type context =
+{
+	mutable ctx_output : string -> unit;
+	mutable ctx_writer : Gensource.source_writer;
+	mutable ctx_calling : bool;
+	mutable ctx_assigning : bool;
+	mutable ctx_return_from_block : bool;
+	(* This is for returning from the child nodes of TMatch, TSwitch && TTry *)
+	mutable ctx_return_from_internal_node : bool;
+	mutable ctx_debug : bool;
+	mutable ctx_debug_type : bool;
+	mutable ctx_real_this_ptr : bool;
+	mutable ctx_dynamic_this_ptr : bool;
+	mutable ctx_static_id_curr : int;
+	mutable ctx_static_id_used : int;
+	mutable ctx_switch_id : int;
+	mutable ctx_class_name : string;
+	mutable ctx_local_function_args : (string,string) Hashtbl.t;
+	mutable ctx_local_return_block_args : (string,string) Hashtbl.t;
+	mutable ctx_class_member_types : (string,string) Hashtbl.t;
+}
+
+let new_context writer debug = 
+	{
+	ctx_writer = writer;
+	ctx_output = (writer#write);
+	ctx_calling = false;
+	ctx_assigning = false;
+	ctx_debug = debug;
+	ctx_debug_type = debug;
+	ctx_return_from_block = false;
+	ctx_return_from_internal_node = false;
+	ctx_real_this_ptr = true;
+	ctx_dynamic_this_ptr = false;
+	ctx_static_id_curr = 0;
+	ctx_static_id_used = 0;
+	ctx_switch_id = 0;
+	ctx_class_name = "";
+	ctx_local_function_args = Hashtbl.create 0;
+	ctx_local_return_block_args = Hashtbl.create 0;
+	ctx_class_member_types =  Hashtbl.create 0;
+	}
+
+
+(* The internal classes are implemented by the core hxcpp system, so the cpp
+	 classes should not be generated *)
+let is_internal_class = function
+	|  ([],"Int") | ([],"Void") |  ([],"String") | ([], "Null") | ([], "Float")
+	|  ([],"Array") | ([], "Class") | ([], "Enum") | ([], "Bool")
+	|  ([], "Dynamic") | ([], "ArrayAccess") -> true
+	|  (["haxe"], "Int32") | ([],"Math") | (["haxe";"io"], "Unsigned_char__") -> true
+	| _ -> false
+
+
+(* The internal header files are also defined in the hxObject.h file, so you do
+	 #include them separately.  However, the Int32 and Math classes do have their
+	 own header files (these are under the hxcpp tree) so these should be included *)
+let is_internal_header path = match path with
+	|  (["haxe"], "Int32") | ([],"Math") -> false
+	| _ -> is_internal_class path
+
+(*
+  A class_path is made from a package (array of strings) and a class name.
+  Join these together, inclding a separator.  eg, "/" for includes : pack1/pack2/Name or "::"
+	for namespace "pack1::pack2::Name"
+*)
+let join_class_path path separator =
+	match fst path, snd path with
+	| [], s -> s
+	| el, s -> String.concat separator el ^ separator ^ s
+
+
+let rec cpp_follow t =
+	match t with
+	| TMono r -> (match !r with | Some t -> cpp_follow t | _ -> t)
+	| TLazy f -> cpp_follow (!f())
+	| TType (t,tl) -> cpp_follow (apply_params t.t_types tl t.t_type)
+	| _ -> t ;;
+
+let is_block exp = match exp.eexpr with | TBlock _ -> true | _ -> false ;;
+
+let to_block expression =
+	if is_block expression then expression else (mk_block expression);;
+
+(* todo - is this how it's done? *)
+let hash_keys hash =
+	let key_list = ref [] in
+	Hashtbl.iter (fun key value -> key_list :=  key :: !key_list ) hash;
+	!key_list
+
+
+
+(* The Hashtbl structure seems a little odd - but here is a helper function *)
+let hash_iterate hash visitor =
+	let result = ref [] in
+	Hashtbl.iter (fun key value -> result :=  (visitor key value) :: !result ) hash;
+	!result
+
+(* Convert function names that can't be written in c++ ... *)
+let keyword_remap = function
+	| "int" -> "toInt"
+	| "or" -> "_or" (*problem with gcc *)
+	| "and" -> "_and" (*problem with gcc *)
+	| "xor" -> "_xor" (*problem with gcc *)
+	| "typeof" -> "_typeof"
+	| "float" -> "_float"
+	| "union" -> "_union"
+	| "stdin" -> "Stdin"
+	| "stdout" -> "Stdout"
+	| "stderr" -> "Stderr"
+	| x -> x
+
+(*
+ While #include "Math.h" sould be different from "#include <math.h>", and it may be possible
+  to use include paths to get this right, I think it is easier just to chnage the name *)
+let include_remap = function | ([],"Math") -> ([],"hxMath") | x -> x;;
+
+
+(* Add include to source code *)
+let add_include writer class_path =
+	writer#add_include (include_remap class_path);;
+
+
+(* This gets the class include order correct.  In the header files, we forward declare
+	 the class types so the header file does not have any undefined variables.
+	 In the cpp files, we include all the required header files, providing the actual
+	 types for everything.  This way there is no problem with circular class references.
+*)
+let gen_forward_decl writer class_path =
+	if ( class_path = (["haxe"],"Int32")) then
+		writer#add_include class_path
+	else begin
+		let output = writer#write in
+		output ("DECLARE_CLASS" ^ (string_of_int (List.length (fst class_path) ) ) ^ "(");
+		List.iter (fun package_part -> output (package_part ^ ",") ) (fst class_path);
+		output ( (snd class_path) ^ ")\n")
+	end;;
+
+
+(* Output required code to place contents in required namespace *)
+let gen_open_namespace output class_path =
+		List.iter (fun namespace -> output ("namespace " ^ namespace ^ "{\n")) (fst class_path);;
+
+let gen_close_namespace output class_path =
+		List.iter
+			(fun namespace -> output ( "}" ^ " // end namespace " ^ namespace ^"\n"))
+			(fst class_path);;
+
+(* The basic types can have default values and are passesby value *)
+let is_basic_type = function
+	| "Int" | "Bool" | "Float" | "String" | "haxe::io::Unsigned_char__" -> true
+	| _ -> false
+
+(*  Get a string to represent a type.
+	 The "suffix" will be nothing or "_obj", depending if we want the name of the
+	 pointer class or the pointee (_obj class *)
+let rec class_string klass suffix params =
+	(match klass.cl_path with
+	(* Array class *)
+	|  ([],"Array") -> (snd klass.cl_path) ^ suffix ^ "<" ^ (String.concat ","
+					 (List.map type_string  params) ) ^ " >"
+	| _ when klass.cl_kind=KTypeParameter -> "Dynamic"
+	|  ([],"#Int") -> "/* # */int"
+	|  (["haxe";"io"],"Unsigned_char__") -> "unsigned char"
+	|  ([],"Class") -> "Class"
+	|  ([],"Null") -> (match params with
+			| [t] ->
+				(match follow t with
+				| TInst ({ cl_path = [],"Int" },_)
+				| TInst ({ cl_path = [],"Float" },_)
+				| TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
+				| _ -> "/*NULL*/" ^ (type_string t) )
+			| _ -> assert false); 
+	(* Normal class *)
+	| _ -> (join_class_path klass.cl_path "::") ^ suffix
+	)
+and type_string_suff suffix haxe_type =
+	(match haxe_type with
+	| TMono r -> (match !r with None -> "Dynamic" | Some t -> type_string_suff suffix t)
+	| TEnum ({ e_path = ([],"Void") },[]) -> "void"
+	| TEnum ({ e_path = ([],"Bool") },[]) -> "bool"
+	| TEnum (enum,params) ->  (join_class_path enum.e_path "::") ^ suffix
+	| TInst (klass,params) ->  (class_string klass suffix params)
+	| TType (type_def,params) ->
+		(match type_def.t_path with
+		| [] , "Null" ->
+			(match params with
+			| [t] ->
+				(match follow t with
+				| TInst ({ cl_path = [],"Int" },_)
+				| TInst ({ cl_path = [],"Float" },_)
+				| TEnum ({ e_path = [],"Bool" },_) -> "Dynamic"
+				| _ -> type_string_suff suffix t)
+			| _ -> assert false);
+		| [] , "Array" ->
+			(match params with
+			| [t] -> "Array<" ^ (type_string (follow t) ) ^ " >"
+			| _ -> assert false)
+		| _ ->  type_string_suff suffix (apply_params type_def.t_types params type_def.t_type)
+		)
+	| TFun (args,haxe_type) -> "Dynamic"
+	| TAnon anon -> "Dynamic"
+	| TDynamic haxe_type -> "Dynamic"
+	| TLazy func -> type_string_suff suffix ((!func)())
+	)
+and type_string haxe_type = 
+	type_string_suff "" haxe_type;;
+
+let is_array haxe_type =
+	match follow haxe_type with
+	| TInst (klass,params) -> 
+		(match klass.cl_path with
+		| [] , "Array" -> true
+		| _ -> false )
+	| TType (type_def,params) ->
+		(match type_def.t_path with
+		| [] , "Array" -> true
+		| _ -> false )
+	| _ -> false
+	;;
+ 
+
+let is_dynamic haxe_type = type_string haxe_type ="Dynamic";;
+
+(* Get the type and output it to the stream *)
+let gen_type ctx haxe_type =
+	ctx.ctx_output (type_string haxe_type);;
+
+let member_type ctx field_object member =
+	let name = (type_string field_object.etype) ^ "." ^ member in
+	try ( Hashtbl.find ctx.ctx_class_member_types name )
+	with Not_found -> "?";;
+
+(* Some fields of a dynamic object are internal and should be accessed directly,
+	rather than through the abstract interface.  In haxe code, these will be written
+	as "untyped" values.  *)
+let dynamic_access ctx field_object member =
+	match member with
+	| "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString"
+	| "__s" | "__GetPtr" | "__IsClass" | "__SetField" | "__length" | "__IsArray"
+	| "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "toString" | "__HasField"
+			-> false
+	| _ ->
+		(match field_object.eexpr with
+		| TConst TThis when ((not ctx.ctx_real_this_ptr) && ctx.ctx_dynamic_this_ptr) -> true
+		| _ -> (match follow field_object.etype with
+			| TMono mono -> true
+			| TAnon anon -> true
+			| TDynamic haxe_type -> true
+			| other -> (type_string other ) = "Dynamic") )
+
+let gen_arg_type_name name default_val arg_type prefix =
+	let type_str = (type_string arg_type) in
+	match default_val with
+	| Some constant when (is_basic_type type_str) -> ("Dynamic",prefix ^ name)
+	| _ -> (type_str,name);;
+
+
+(* Generate prototype text, including allowing default values to be null *)
+let gen_arg name default_val arg_type prefix =
+	let pair = gen_arg_type_name name default_val arg_type prefix in
+	(fst pair) ^ " " ^ (snd pair);;
+
+let rec gen_arg_list arg_list prefix =
+  String.concat "," (List.map (fun (name,o,arg_type) -> (gen_arg name o arg_type prefix) ) arg_list)
+
+
+let rec gen_tfun_arg_list arg_list =
+	match arg_list with
+	| [] -> ""
+	| [(name,o,arg_type)] -> gen_arg name None arg_type ""
+	| (name,o,arg_type) :: remaining  ->
+		(gen_arg name None arg_type "") ^ "," ^ (gen_tfun_arg_list remaining)
+
+
+
+(* Make string printable for c++ code *)
+(* Strings from the source files are in utf8 format. *)
+(* To use this, we construct a string from a char * and convert to a wchar_t in constructor *)
+let escape_string s =
+	let b = Buffer.create 0 in
+	Buffer.add_char b '"';
+	for i = 0 to String.length s - 1 do
+		match Char.code (String.unsafe_get s i) with
+		| c when c < 32 -> Buffer.add_string b (Printf.sprintf "\\x%.2X\"\"" c)
+		| c -> Buffer.add_char b (Char.chr c)
+	done;
+	Buffer.add_char b '"';
+	Buffer.contents b;;
+
+(* Here we know there are no utf8 characters, so use the L"" notation to avoid conversion *)
+let escape_stringw s =
+	let b = Buffer.create 0 in
+	Buffer.add_char b 'L';
+	Buffer.add_char b '"';
+	for i = 0 to String.length s - 1 do
+		match Char.code (String.unsafe_get s i) with
+		| c when c < 32 -> Buffer.add_string b (Printf.sprintf "\\x%.2X\"L\"" c)
+		| c -> Buffer.add_char b (Char.chr c)
+	done;
+	Buffer.add_char b '"';
+	Buffer.contents b;;
+
+
+let has_utf8_chars s = 
+	let result = ref false in
+	for i = 0 to String.length s - 1 do
+		!result <- !result || ( Char.code (String.unsafe_get s i) > 127 )
+	done;
+	!result;;
+
+
+let str s = "String(" ^ (
+	(if (has_utf8_chars s) then escape_string else escape_stringw) (Ast.s_escape s))
+		^ "," ^ (string_of_int (String.length s)) ^ ")"
+
+
+(* When we are in a "real" object, we refer to ourselves as "this", but
+	if we are in a local class that is used to generate return values,
+	we use the fake "__this" pointer. 
+	If we are in an "Anon" object, then the "this" refers to the anon object (eg List iterator) *)
+let clear_real_this_ptr ctx dynamic_this =
+	let old_flag = ctx.ctx_real_this_ptr in
+	let old_dynamic = ctx.ctx_dynamic_this_ptr in
+	ctx.ctx_real_this_ptr <- false;
+	ctx.ctx_dynamic_this_ptr <- dynamic_this;
+	fun () -> ( ctx.ctx_real_this_ptr <- old_flag; ctx.ctx_dynamic_this_ptr <- old_dynamic; );;
+
+
+(* Generate temp variable names *)
+let next_anon_function_name ctx =
+	ctx.ctx_static_id_curr <- ctx.ctx_static_id_curr + 1;
+	"_Function_" ^ (string_of_int ctx.ctx_static_id_curr)
+
+let use_anon_function_name ctx =
+	ctx.ctx_static_id_used <- ctx.ctx_static_id_used + 1;
+	"_Function_" ^ (string_of_int ctx.ctx_static_id_used)
+
+let get_switch_var ctx =
+	ctx.ctx_switch_id <- ctx.ctx_switch_id + 1;
+	"_switch_" ^ (string_of_int ctx.ctx_switch_id)
+
+
+(* If you put on the "-debug" flag, you get extra comments in the source code *)
+let debug_expression expression type_too =
+	"/* " ^
+	(match expression.eexpr with
+	| TConst _ -> "TConst"
+	| TLocal _ -> "TLocal"
+	| TEnumField _ -> "TEnumField"
+	| TArray (_,_) -> "TArray"
+	| TBinop (_,_,_) -> "TBinop"
+	| TField (_,_) -> "TField"
+	| TTypeExpr _ -> "TTypeExpr"
+	| TParenthesis _ -> "TParenthesis"
+	| TObjectDecl _ -> "TObjectDecl"
+	| TArrayDecl _ -> "TArrayDecl"
+	| TCall (_,_) -> "TCall"
+	| TNew (_,_,_) -> "TNew"
+	| TUnop (_,_,_) -> "TUnop"
+	| TFunction _ -> "TFunction"
+	| TVars _ -> "TVars"
+	| TBlock _ -> "TBlock"
+	| TFor (_,_,_,_) -> "TFor"
+	| TIf (_,_,_) -> "TIf"
+	| TWhile (_,_,_) -> "TWhile"
+	| TSwitch (_,_,_) -> "TSwitch"
+	| TMatch (_,_,_,_) -> "TMatch"
+	| TTry (_,_) -> "TTry"
+	| TReturn _ -> "TReturn"
+	| TBreak -> "TBreak"
+	| TContinue -> "TContinue"
+	| TThrow _ -> "TThrow" ) ^
+	(if (type_too) then " = " ^ (type_string expression.etype) else "") ^
+	" */";;
+
+
+
+(* This is like the Type.iter, but also keeps the "retval" flag up to date *)
+let rec iter_retval f retval e =
+	match e.eexpr with
+	| TConst _
+	| TLocal _
+	| TEnumField _
+	| TBreak
+	| TContinue
+	| TTypeExpr _ ->
+		()
+	| TArray (e1,e2)
+	| TBinop (_,e1,e2) ->
+		f true e1;
+		f true e2;
+	| TWhile (e1,e2,_) ->
+		f true e1;
+		f false e2;
+	| TFor (_,_,e1,e2) ->
+		f true e1;
+		f false e2;
+	| TThrow e
+	| TField (e,_)
+	| TUnop (_,_,e) ->
+		f true e
+	| TParenthesis e ->
+		f retval e
+	| TBlock expr_list when retval ->
+		let rec return_last = function
+			| [] -> ()
+			| expr :: [] -> f true expr
+			| expr :: exprs -> f false expr; return_last exprs in
+		return_last expr_list
+	| TArrayDecl el
+	| TNew (_,_,el)
+	| TBlock el ->
+		List.iter (f false ) el
+	| TObjectDecl fl ->
+		List.iter (fun (_,e) -> f true e) fl
+	| TCall (e,el) ->
+		f true e;
+		List.iter (f true) el
+	| TVars vl ->
+		List.iter (fun (_,_,e) -> match e with None -> () | Some e -> f true e) vl
+	| TFunction fu ->
+		f false fu.tf_expr
+	| TIf (e,e1,e2) ->
+		f retval e;
+		f retval e1;
+		(match e2 with None -> () | Some e -> f retval e)
+	| TSwitch (e,cases,def) ->
+		f true e;
+		List.iter (fun (el,e2) -> List.iter (f true) el; f retval e2) cases;
+		(match def with None -> () | Some e -> f retval e)
+	| TMatch (e,_,cases,def) ->
+		f true e;
+		List.iter (fun (_,_,e) -> f false e) cases;
+		(match def with None -> () | Some e -> f false e)
+	| TTry (e,catches) ->
+		f retval e;
+		List.iter (fun (_,_,e) -> f false e) catches
+	| TReturn eo ->
+		(match eo with None -> () | Some e -> f true e)
+;;
+
+
+(* Convert an array to a comma separated list of values *)
+let array_arg_list inList =
+	let i = ref (0-1) in
+	String.concat "," (List.map (fun _ -> incr i; "inArgs[" ^ (string_of_int !i) ^ "]"  ) inList)
+
+let list_num l = string_of_int (List.length l);;
+
+let generate_dynamic_call ctx func_def real_function=
+	let return = if (type_string func_def.tf_type ) = "void" then "" else "return" in
+	ctx.ctx_writer#write_i ( "DYNAMIC_CALL" ^ (list_num func_def.tf_args) ^ "(" ^ return ^ ","
+									^ real_function ^");\n" )
+	;;
+
+let only_int_cases cases =
+	not (List.exists (fun (cases,expression) -> 
+			List.exists (fun case -> match case.eexpr with TConst (TInt _) -> false | _ -> true ) cases
+				) cases );;
+
+(* Decide is we should look the field up by name *)
+let dynamic_internal = function | "__Is" -> true | _ -> false
+
+
+(* Get a list of variables to extract from a enum tmatch *)
+let tmatch_params_to_args params =
+	(match params with
+	| None | Some [] -> []
+	| Some l ->
+		let n = ref (-1) in
+		List.fold_left
+			(fun acc (v,t) -> incr n; match v with None -> acc | Some v -> (v,t,!n) :: acc) [] l)
+
+
+(*
+  This is the big one.
+  Once you get inside a function, all code is generated (recursively) as a "expression".
+  "retval" is tracked to determine whether the value on an expression is actually used.
+  eg, if the result of a block (ie, the last expression in the list) is used, then
+  we have to do some funky stuff to generate a local function.
+  Some things that change less often are stored in the context and are extracted
+	at the top for simplicity.
+*)
+let rec gen_expression ctx retval expression =
+	let output = ctx.ctx_output in
+	let writer = ctx.ctx_writer in
+	let output_i = writer#write_i in
+	let calling = ctx.ctx_calling in
+	ctx.ctx_calling <- false;
+	let assigning = ctx.ctx_assigning in
+	ctx.ctx_assigning <- false;
+	let return_from_block = ctx.ctx_return_from_block in
+	ctx.ctx_return_from_block <- false;
+	let return_from_internal_node = ctx.ctx_return_from_internal_node in
+	ctx.ctx_return_from_internal_node <- false;
+
+	(* Annotate source code with debug - can get a bit verbose.  Mainly for debugging code gen,
+		rather than the run time *)
+	if (ctx.ctx_debug) then begin
+		if calling then output "/* Call */";
+		output (debug_expression expression ctx.ctx_debug_type);
+	end;
+
+	(* Write comma separated list of variables - useful for function args. *)
+	let rec gen_expression_list expressions =
+		(match expressions with
+		| [] -> ()
+		| [single] -> gen_expression ctx true single
+		| first :: remaining ->
+			gen_expression ctx true first;
+			output ",";
+			gen_expression_list remaining
+		) in
+
+	let check_this = function | "this" when not ctx.ctx_real_this_ptr -> "__this" | x -> x in
+
+	let rec find_undeclared_variables undeclared declarations this_suffix expression =
+		(
+		match expression.eexpr with
+		| TVars var_list ->
+			List.iter (fun (var_name, var_type, optional_init) ->
+				Hashtbl.add declarations var_name ();
+				if (ctx.ctx_debug) then
+					output ("/* found var " ^ var_name ^ "*/ ");
+				match optional_init with
+				| Some expression -> find_undeclared_variables undeclared declarations this_suffix expression
+				| _ -> ()
+				) var_list
+		| TFunction func -> List.iter ( fun (arg_name, opt_val, arg_type) ->
+				if (ctx.ctx_debug) then
+					output ("/* found arg " ^ arg_name ^ " = " ^ (type_string arg_type) ^ " */ ");
+				Hashtbl.add declarations arg_name () ) func.tf_args;
+				find_undeclared_variables undeclared declarations this_suffix func.tf_expr
+		| TTry (try_block,catches) ->
+			find_undeclared_variables undeclared declarations this_suffix try_block;
+			List.iter (fun (name,t,catch_expt) ->
+				let old_decs = Hashtbl.copy declarations in
+				Hashtbl.add declarations name ();
+				find_undeclared_variables undeclared declarations this_suffix catch_expt;
+				Hashtbl.clear declarations;
+				Hashtbl.iter ( Hashtbl.add declarations ) old_decs
+				) catches;
+		| TLocal local_name ->
+			if  not (Hashtbl.mem declarations local_name) then
+				Hashtbl.replace undeclared local_name (type_string expression.etype)
+		| TFor (var_name, var_type, init, loop) ->
+			let old_decs = Hashtbl.copy declarations in
+			Hashtbl.add declarations var_name ();
+			find_undeclared_variables undeclared declarations this_suffix init;
+			find_undeclared_variables undeclared declarations this_suffix loop;
+			Hashtbl.clear declarations;
+			Hashtbl.iter ( Hashtbl.add declarations ) old_decs
+		| TConst TSuper
+		| TConst TThis ->
+			if  not (Hashtbl.mem declarations "this") then
+				Hashtbl.replace undeclared "this" (type_string_suff this_suffix expression.etype)
+		| TBlock expr_list ->
+			let old_decs = Hashtbl.copy declarations in
+			List.iter (find_undeclared_variables undeclared declarations this_suffix ) expr_list;
+			(* what is the best way for this ? *)
+			Hashtbl.clear declarations;
+			Hashtbl.iter ( Hashtbl.add declarations ) old_decs
+		| _ -> Type.iter (find_undeclared_variables undeclared declarations this_suffix) expression;
+		)
+	in
+
+	let remap_this = function | "this" -> "__this" | other -> other in
+	let reference = function | "this" -> " *__this" | name -> " &" ^name in
+
+	let rec define_local_function func_name func_def =
+		let declarations = Hashtbl.create 0 in
+		let undeclared = Hashtbl.create 0 in
+		(* Add args as defined variables *)
+		List.iter ( fun (arg_name, opt_val, arg_type) ->
+						if (ctx.ctx_debug) then
+							output ("/* found arg " ^ arg_name ^ " = " ^ (type_string arg_type) ^" */ ");
+						Hashtbl.add declarations arg_name () ) func_def.tf_args;
+		find_undeclared_variables undeclared declarations "" func_def.tf_expr;
+
+		let has_this = Hashtbl.mem undeclared "this" in
+		if (has_this) then Hashtbl.remove undeclared "this";
+		let typed_vars = hash_iterate undeclared (fun key value -> value ^ "," ^ key ) in
+		let func_name_sep = func_name ^ (if List.length typed_vars > 0 then "," else "") in
+		output_i ("BEGIN_LOCAL_FUNC" ^ (list_num typed_vars) ^ "(" ^ func_name_sep ^
+						(String.concat "," typed_vars) ^ ")\n" );
+
+		(* actual function, called "run" *)
+		let args_and_types = List.map
+				(fun (name,_,arg_type) -> (type_string arg_type) ^ " " ^ name ) func_def.tf_args in
+		let block = is_block func_def.tf_expr in
+		let func_type = type_string func_def.tf_type in
+		output_i (func_type ^ " run(" ^ (String.concat "," args_and_types) ^ ")");
+
+		let pop_real_this_ptr = clear_real_this_ptr ctx true in
+
+		if (block) then begin
+			gen_expression ctx false func_def.tf_expr;
+		end else begin
+			writer#begin_block;
+			(* Save old values, and equalize for new input ... *)
+			let old_used = ctx.ctx_static_id_used in
+			let old_curr = ctx.ctx_static_id_curr in
+			ctx.ctx_static_id_used <- old_curr;
+
+			find_local_functions func_def.tf_expr;
+
+			find_local_return_blocks false func_def.tf_expr;
+
+			(match func_def.tf_expr.eexpr with
+			| TReturn (Some return_expression) when (func_type = "void") ->
+				output_i "";
+				gen_expression ctx false return_expression
+			| _ ->
+				gen_expression ctx false func_def.tf_expr
+			);
+
+			ctx.ctx_static_id_used <- old_used;
+			ctx.ctx_static_id_curr <- old_curr;
+
+			output ";\n";
+			writer#end_block;
+		end;
+		pop_real_this_ptr();
+
+		if (has_this) then begin
+			output_i "Dynamic __this;\n";
+			output_i "void __SetThis(Dynamic inThis) { __this = inThis; }\n";
+		end;
+
+		let return = if (type_string func_def.tf_type ) = "void" then "(void)" else "return" in
+		output_i ("END_LOCAL_FUNC" ^ (list_num args_and_types) ^ "(" ^ return ^ ")\n\n");
+
+		Hashtbl.replace ctx.ctx_local_function_args func_name
+			(if (ctx.ctx_real_this_ptr) then
+				String.concat "," (hash_keys undeclared)
+			else
+				String.concat "," (List.map remap_this (hash_keys undeclared)) )
+	and
+	define_local_return_block expression  =
+		let declarations = Hashtbl.create 0 in
+		let undeclared = Hashtbl.create 0 in
+		find_undeclared_variables undeclared declarations "_obj" expression;
+		let name = next_anon_function_name ctx in
+
+		let vars = (hash_keys undeclared) in
+		let args = String.concat "," (List.map check_this (hash_keys undeclared)) in
+		Hashtbl.replace ctx.ctx_local_return_block_args name args;
+		output_i ("struct " ^ name);
+		writer#begin_block;
+		let ret_type = type_string expression.etype in
+		output_i ("static " ^ ret_type ^ " Block( ");
+		output (String.concat "," ( (List.map (fun var ->
+				(Hashtbl.find undeclared var) ^ (reference var)) ) vars));
+		output (")");
+
+		if (is_block expression) then begin
+			ctx.ctx_return_from_block <- true;
+			ctx.ctx_return_from_internal_node <- false;
+			output "/* DEF (ret block)(not intern) */";
+		end else begin
+			ctx.ctx_return_from_block <- false;
+			ctx.ctx_return_from_internal_node <- true;
+			output "/* DEF (not block)(ret intern) */";
+		end;
+		let pop_real_this_ptr = clear_real_this_ptr ctx false in
+		gen_expression ctx false (to_block expression);
+		pop_real_this_ptr();
+
+		(*
+		let block = is_block expression in
+		if (not block) then begin
+			writer#begin_block; output_i "";
+			iter_retval find_local_return_blocks false expression;
+		end;
+		ctx.ctx_return_from_block <- true;
+		let pop_real_this_ptr = clear_real_this_ptr ctx false in
+		gen_expression ctx false expression;
+		pop_real_this_ptr();
+		if (not block) then begin
+			output_i "return Dynamic();\n";
+			writer#end_block;
+		end;
+		*)
+		writer#end_block_line;
+		output ";\n";
+	and
+	find_local_functions expression =
+		match expression.eexpr with
+		| TBlock _ -> ()  (* stop at block - since that block will define the function *)
+		| TCall (e,el) -> (* visit the args first, then the function *)
+			List.iter find_local_functions  el;
+			find_local_functions e
+		| TFunction func ->
+			let func_name = next_anon_function_name ctx in
+			output "\n";
+			define_local_function func_name func
+		| _ -> Type.iter find_local_functions expression
+	and
+	find_local_return_blocks retval expression =
+		match expression.eexpr with
+		| TBlock _ ->
+			if (retval) then begin
+				define_local_return_block expression;
+			end  (* else we are done *)
+		| TFunction func -> ()
+		| TMatch (_, _, _, _)
+		| TTry (_, _)
+		| TSwitch (_, _, _) when retval ->
+				define_local_return_block expression;
+		| _ -> iter_retval find_local_return_blocks retval expression
+		in
+	let rec gen_bin_op_string expr1 op expr2 =
+		let cast = (match op with
+			| ">>" | "<<" | "&" | "|" | "^"  -> "int("
+			| "&&" | "||" -> "bool("
+			| "/" -> "double("
+			| _ -> "") in
+		if ( cast <> "") then output cast;
+		gen_expression ctx true expr1;
+		if ( cast <> "") then output ")";
+
+		output (" " ^ op ^ " ");
+
+		if ( cast <> "") then output cast;
+		gen_expression ctx true expr2;
+		if ( cast <> "") then output ")"
+	in
+	let rec gen_bin_op op expr1 expr2 =
+		match op with
+		| Ast.OpAssign -> ctx.ctx_assigning <- true;
+								gen_bin_op_string expr1 "=" expr2
+		| Ast.OpUShr ->
+			output "hxUShr(";
+			gen_expression ctx true expr1;
+			output ",";
+			gen_expression ctx true expr2;
+			output ")";
+		| Ast.OpMod ->
+			output "hxMod(";
+			gen_expression ctx true expr1;
+			output ",";
+			gen_expression ctx true expr2;
+			output ")";
+
+		| Ast.OpAssignOp bin_op ->
+			output (match bin_op with
+				| Ast.OpAdd -> "hxAddEq("
+				| Ast.OpMult -> "hxMultEq("
+				| Ast.OpDiv -> "hxDivEq("
+				| Ast.OpSub -> "hxSubEq("
+				| Ast.OpAnd -> "hxAndEq("
+				| Ast.OpOr  -> "hxOrEq("
+				| Ast.OpXor  -> "hxXorEq("
+				| Ast.OpShl  -> "hxShlEq("
+				| Ast.OpShr  -> "hxShrEq("
+				| Ast.OpUShr  -> "hxUShrEq("
+				| Ast.OpMod  -> "hxModEq("
+				| _ -> error "Unknown OpAssignOp" expression.epos );
+			ctx.ctx_assigning <- true;
+			gen_expression ctx true expr1;
+			output ",";
+			gen_expression ctx true expr2;
+			output ")"
+		| Ast.OpNotEq -> gen_bin_op_string expr1 "!=" expr2
+		| Ast.OpEq -> gen_bin_op_string expr1 "==" expr2
+		| _ ->  gen_bin_op_string expr1 (Ast.s_binop op) expr2
+		in
+	let gen_member_access field_object member is_function return_type =
+		begin
+		let check_dynamic_member_access member = begin
+			(match (dynamic_access ctx field_object member) with
+			| true when (not (dynamic_internal member)) ->
+					let access = (if assigning then ".FieldRef" else "->__Field") in
+					output ( access ^ "(" ^ (str member) ^ ")" );
+					if (not assigning) then begin
+						let return = type_string return_type in
+						if ( not (return="Dynamic") ) then
+							output (".Cast<" ^ return ^ " >()");
+					end
+			| _ ->
+			let member_name = (keyword_remap member) ^
+				( if ( (not calling) && is_function && (not assigning)) then "_dyn()" else "" ) in
+			if ( (type_string field_object.etype)="String") then
+				output ( "." ^ member_name)
+			else begin
+				output ( "->" ^ member_name);
+				(*
+				if (not assigning) then begin
+					let expr_type = type_string return_type in
+					let mem_type = member_type ctx field_object member in
+						output (".Cast<" ^ mem_type ^ "/* " ^ expr_type ^ " */" ^ ">()");
+				end;
+				*)
+			end )
+		end in
+
+		match field_object.eexpr with
+		(* static access ... *)
+		| TTypeExpr type_def ->
+			let class_name = (join_class_path (t_path type_def) "::" ) in
+			if (class_name="String") then
+				output ("String::" ^ (keyword_remap member))
+			else
+				output (class_name ^ "_obj::" ^ (keyword_remap member));
+			if ( (not calling) && is_function) then
+				output "_dyn()"
+		| TArray (e1,e2) ->
+			gen_expression ctx true e1;
+			output "[";
+			gen_expression ctx true e2;
+			output "]";
+			check_dynamic_member_access member
+		| TBlock _ -> print_endline "Unsupported contruct - block returning function"
+		| TParenthesis expr ->
+			output "(";
+			ctx.ctx_calling <- calling;
+			gen_expression ctx  true expr;
+			output ")";
+			check_dynamic_member_access member
+		| TNew (klass,params,expressions) ->
+			output ( ( class_string klass "_obj" params) ^ "::__new(" );
+			gen_expression_list expressions;
+			output ")";
+			output ( "->" ^ member )
+		| TLocal name when name = "__global__" ->
+			output ("::" ^ member )
+		| TConst TSuper -> output (if ctx.ctx_real_this_ptr then "this" else "__this");
+						output ("->super::" ^ member)
+		| _ -> 
+			gen_expression ctx true  field_object;
+			check_dynamic_member_access member
+	end in
+	(match expression.eexpr with
+	| TCall (func, arg_list) when (match func.eexpr with | TConst TSuper -> true | _ -> false ) ->
+		output "super::__construct(";
+		gen_expression_list arg_list;
+		output ")";
+	| TCall (func, arg_list) ->
+		ctx.ctx_calling <- true;
+		gen_expression ctx true func;
+		output "(";
+		gen_expression_list arg_list;
+		output ")";
+		(* This is a horrible hack - may need to prevent the strong typing of
+			the return value in the first place.
+			Eg.  haxe thinks List<X> first() is of type X, but cpp thinks it is Dynamic.
+		*)
+		let expr_type = type_string expression.etype in
+			if (not(expr_type="void")) then
+				(match func.eexpr with 
+				| TField(expr,name) ->
+					let mem_type = member_type ctx expr name in
+						if ( (mem_type="Dynamic") && (not(expr_type="Dynamic") ) ) then
+							 output (".Cast<" ^ expr_type ^ " >()");
+				| _ -> () )
+	| TBlock expr_list ->
+		if (retval) then begin
+			let func_name = use_anon_function_name ctx in
+			(
+			try
+			output ( func_name ^ "::Block(" ^
+				(Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" )
+			with Not_found ->
+			 (*error ("Block function " ^ func_name ^ " not found" ) expression.epos;*)
+			 output ("/* Block function " ^ func_name ^ " not found */" );
+			)
+		end else begin
+			writer#begin_block;
+			(* Save old values, and equalize for new input ... *)
+			let old_used = ctx.ctx_static_id_used in
+			let old_curr = ctx.ctx_static_id_curr in
+			let remaining = ref (List.length expr_list) in
+			ctx.ctx_static_id_used <- old_curr;
+			List.iter (fun expresion ->
+				find_local_functions expresion;
+				if (return_from_block && !remaining = 1) then begin
+					find_local_return_blocks true expresion;
+					output_i "";
+					ctx.ctx_return_from_internal_node <- return_from_internal_node;
+					output "return ";
+					gen_expression ctx true expresion;
+				end else begin
+					find_local_return_blocks false expresion;
+					output_i "";
+					ctx.ctx_return_from_internal_node <- return_from_internal_node;
+					gen_expression ctx false expresion;
+				end;
+				decr remaining;
+				writer#terminate_line
+				) expr_list;
+			writer#end_block;
+			ctx.ctx_static_id_used <- old_used;
+			ctx.ctx_static_id_curr <- old_curr
+		end
+	| TTypeExpr type_expr ->
+		let klass = (join_class_path (t_path type_expr) "::" ) in
+		let klass1 = if klass="Array" then "Array<int>" else klass in
+		output ("hxClassOf<" ^ klass1 ^ " >()")
+	| TReturn optional_expr ->
+		output "";
+		( match optional_expr with
+		| Some expression ->
+			output "return ";
+			gen_expression ctx true expression
+		| _ -> output "return"
+		)
+
+	| TConst const ->
+		(match const with
+		| TInt i -> output (Printf.sprintf "%ld" i)
+		| TFloat float_as_string -> output float_as_string
+		| TString s -> output (str s)
+		| TBool b -> output (if b then "true" else "false")
+		| TNull -> output "null()"
+		| TThis -> output (if ctx.ctx_real_this_ptr then "this" else "__this")
+		| TSuper -> output (if ctx.ctx_real_this_ptr then "((super *)this)" else "((super*)__this)")
+		)
+
+
+	| TLocal local_name -> output local_name;
+	| TEnumField (enum, name) ->
+			output ((join_class_path enum.e_path "::") ^ "_obj::" ^ name)
+	| TArray (array_expr,index) ->
+		if ( (assigning && (is_array array_expr.etype)) || (is_dynamic array_expr.etype) ) then begin
+			gen_expression ctx true array_expr;
+			output "[";
+			gen_expression ctx true index;
+			output "]";
+		end else if (assigning) then begin
+			(* output (" /*" ^ (type_string array_expr.etype) ^ " */ "); *)
+			output "hxIndexRefNew(";
+			gen_expression ctx true array_expr;
+			output ",";
+			gen_expression ctx true index;
+			output ")";
+		end else begin
+			gen_expression ctx true array_expr;
+			output "->__get(";
+			gen_expression ctx true index;
+			output ")";
+		end
+	(* Get precidence matching haxe ? *)
+	| TBinop (op,expr1,expr2) -> gen_bin_op op expr1 expr2
+	| TField (expr,name) ->
+		let is_function = match (follow expression.etype) with | TFun (_,_) -> true | _ -> false in
+		gen_member_access expr name is_function expression.etype
+	| TParenthesis expr -> output "("; gen_expression ctx true expr; output ")"
+	| TObjectDecl decl_list ->
+		let declare_field name value =
+			output ("->Add( " ^ (str name) ^ " , ");
+			gen_expression ctx true value;
+			output (")")
+		in
+		let rec declare_fields fields =
+		match fields with
+		| [] -> ()
+		| (name,value) :: remaining->
+			declare_field name value;
+			declare_fields remaining
+		in
+		output "hxAnon_obj::Create()";
+		declare_fields decl_list
+
+	| TArrayDecl decl_list ->
+		(* gen_type output expression.etype; *)
+		output ( (type_string_suff "_obj" expression.etype) ^ "::__new()");
+		List.iter ( fun elem -> output ".Add(";
+							gen_expression ctx true elem;
+							output ")" ) decl_list;
+	| TNew (klass,params,expressions) ->
+		if (klass.cl_path = ([],"String")) then
+			output "String("
+		else
+			output ( ( class_string klass "_obj" params) ^ "::__new(" );
+		gen_expression_list expressions;
+		output ")"
+	| TUnop (op,Ast.Prefix,expr) ->
+		ctx.ctx_assigning <- true;
+		output (Ast.s_unop op);
+		gen_expression ctx true expr
+	| TUnop (op,Ast.Postfix,expr) ->
+		ctx.ctx_assigning <- true;
+		gen_expression ctx true expr;
+		output (Ast.s_unop op)
+	| TFunction func ->
+		let func_name = use_anon_function_name ctx in
+		(
+		try
+			output ( " Dynamic(new " ^ func_name ^ "(" ^
+				(Hashtbl.find ctx.ctx_local_function_args func_name) ^ "))" )
+		with Not_found ->
+			error ("function " ^ func_name ^ " not found.") expression.epos;
+		)
+
+	| TVars var_list ->
+		let count = ref (List.length var_list) in
+		List.iter (fun (var_name, var_type, optional_init) ->
+			gen_type ctx var_type;
+			output (" " ^ var_name);
+			(match optional_init with
+			| None -> ()
+			| Some expression -> output " = "; gen_expression ctx true expression);
+			count := !count -1;
+			if (!count > 0) then begin output ";\n"; output_i "" end
+		) var_list
+	| TFor (var_name, var_type, init, loop) ->
+		output ("for(Dynamic __it = ");
+		gen_expression ctx true init;
+		output (";  __it->__Field(" ^ (str "hasNext") ^ ")(); )");
+		ctx.ctx_writer#begin_block;
+		output ( (type_string var_type) ^ " " ^ var_name ^ " = __it->__Field(" ^ (str "next") ^ ")();\n" );
+		output_i "";
+		gen_expression ctx false loop;
+		output ";\n";
+		ctx.ctx_writer#end_block;
+	| TIf (condition, if_expr, optional_else_expr)  ->
+		let output_if_expr expr terminate =
+			(match expr.eexpr with
+			| TBlock _ -> gen_expression ctx false expr
+			| _ ->  output "\n";
+				output_i "";
+				writer#indent_one;
+				gen_expression ctx false expr;
+				if (terminate) then output ";\n"
+			) in
+
+		(match optional_else_expr with
+		| Some else_expr -> 
+			if (retval) then begin
+				gen_expression ctx true condition;
+				output " ? ";
+				let type_str = (type_string expression.etype) in
+				if ( true (*(type_string if_expr.etype) <> type_str*) ) then begin
+					output (type_str ^ "( ");
+					gen_expression ctx true if_expr;
+					output " )";
+				end else
+					gen_expression ctx true if_expr;
+
+				output " : ";
+
+				if ( true (*(type_string else_expr.etype) <> type_str*) ) then begin
+					output (type_str ^ "( ");
+					gen_expression ctx true else_expr;
+					output " )";
+				end else
+					gen_expression ctx true else_expr;
+			end else begin
+				output "if (";
+				gen_expression ctx true condition;
+				output ")";
+				output_if_expr if_expr true;
+				output_i "else";
+				output_if_expr else_expr true
+			end
+		| _ -> output "if (";
+			gen_expression ctx true condition;
+			output ")";
+			output_if_expr if_expr false
+		)
+	| TWhile (condition, repeat, Ast.NormalWhile ) ->
+			output  "while(";
+			gen_expression ctx true condition;
+			output ")";
+			gen_expression ctx false repeat
+	| TWhile (condition, repeat, Ast.DoWhile ) ->
+			output "do";
+			gen_expression ctx false repeat;
+			output "while(";
+			gen_expression ctx true condition;
+			output ")"
+
+	(* These have already been defined in find_local_return_blocks ... *)
+	| TTry (_,_)
+	| TSwitch (_,_,_)
+	| TMatch (_, _, _, _) when (retval && (not return_from_internal_node) )->
+		let func_name = use_anon_function_name ctx in
+		(try output ( func_name ^ "::Block(" ^
+					(Hashtbl.find ctx.ctx_local_return_block_args func_name) ^ ")" )
+		with Not_found ->
+			output ("/* return block " ^ func_name ^ " not found */" ); )
+				(*error ("return block " ^ func_name ^ " not found" ) expression.epos;*)
+
+	| TSwitch (condition,cases,optional_default)  ->
+		let switch_on_int_constants = only_int_cases cases in
+		if (switch_on_int_constants) then begin
+			output "switch( (int)";
+			gen_expression ctx true condition;
+			output ")";
+			ctx.ctx_writer#begin_block;
+			List.iter (fun (cases_list,expression) ->
+				output_i "";
+				List.iter (fun value -> output "case ";
+								gen_expression ctx true value;
+								output ": " ) cases_list;
+				ctx.ctx_return_from_block <- return_from_internal_node;
+				gen_expression ctx false expression;
+				output_i "break;\n";
+				) cases;
+			(match optional_default with | None -> ()
+			| Some default ->
+				output_i "default: ";
+				ctx.ctx_return_from_block <- return_from_internal_node;
+				gen_expression ctx false (to_block default);
+			);
+			ctx.ctx_writer#end_block;
+		end else begin
+			let tmp_name = get_switch_var ctx in
+			output ( (type_string condition.etype) ^ " " ^ tmp_name ^ " = " );
+			gen_expression ctx true condition;
+			output ";\n";
+			let else_str = ref "" in
+			if (List.length cases > 0) then
+				List.iter (fun (cases,expression) ->
+					output_i ( !else_str ^ "if ( ");
+					!else_str <- "else ";
+					let or_str = ref "" in
+					List.iter (fun value ->
+						output (!or_str ^ " ( " ^ tmp_name ^ "==");
+						gen_expression ctx true value;
+						output ")";
+						!or_str <- " || ";
+						) cases;
+					output (")");
+					ctx.ctx_return_from_block <- return_from_internal_node;
+					gen_expression ctx false expression;
+					) cases;
+			(match optional_default with | None -> ()
+			| Some default ->
+				output_i ( !else_str ^ " ");
+				ctx.ctx_return_from_block <- return_from_internal_node;
+				gen_expression ctx false (to_block default);
+				output ";\n";
+			);
+		end
+	| TMatch (condition, enum, cases, default) ->
+	let tmp_var = get_switch_var ctx in
+	output ( (type_string condition.etype) ^ " " ^ tmp_var ^ " = " );
+	gen_expression ctx true condition;
+	output ";\n";
+
+	output_i ("switch((" ^ tmp_var ^ ")->GetIndex())");
+	writer#begin_block;
+	List.iter (fun (case_ids,params,expression) ->
+		output_i "";
+		List.iter (fun id -> output ("case " ^ (string_of_int id) ^ ": ") ) case_ids;
+		let has_params = match params with | Some _ -> true | _ -> false in
+		if (has_params) then begin
+			writer#begin_block;
+			List.iter (fun (name,vtype,id) -> output_i
+			((type_string vtype) ^ " " ^ name ^
+				" = " ^ tmp_var ^ "->__Param(" ^ (string_of_int id) ^ ");\n"))
+					(tmatch_params_to_args params);
+		end;
+		ctx.ctx_return_from_block <- return_from_internal_node;
+		gen_expression ctx false expression;
+		if (has_params) then writer#end_block;
+		output_i "break;\n";
+	) cases;
+	(match default with
+	| None -> ()
+	|  Some e ->
+		output_i "default: ";
+		ctx.ctx_return_from_block <- return_from_internal_node;
+		gen_expression ctx false (to_block e);
+	);
+	writer#end_block
+	| TTry (expression, catch_list) ->
+		output "try";
+		(* Move this "inside" the try call ... *)
+		ctx.ctx_return_from_block <-return_from_internal_node;
+		gen_expression ctx false (to_block expression);
+		if (List.length catch_list > 0 ) then begin
+			output_i "catch(Dynamic __e)";
+			ctx.ctx_writer#begin_block;
+			let seen_dynamic = ref false in
+			let else_str = ref "" in
+			List.iter (fun (name,t,expression) ->
+				let type_name = type_string t in
+				if (type_name="Dynamic") then begin
+					!seen_dynamic <- true;
+					output_i !else_str;
+				end else
+					output_i (!else_str ^ "if (__e->__IsClass(hxClassOf<" ^ type_name ^ " >()))");
+				ctx.ctx_writer#begin_block;
+				output_i (type_name ^ " " ^ name ^ " = __e;");
+				(* Move this "inside" the catch call too ... *)
+				ctx.ctx_return_from_block <-return_from_internal_node;
+				gen_expression ctx false (to_block expression);
+				ctx.ctx_writer#end_block;
+				!else_str <- "else ";
+				) catch_list;
+			if (not !seen_dynamic) then begin
+				output_i "else throw(__e);\n";
+			end;
+			ctx.ctx_writer#end_block;
+		end;
+	| TBreak -> output "break"
+	| TContinue -> output "continue"
+	| TThrow expression -> output "hxThrow (";
+			gen_expression ctx true expression;
+			output ")"
+	);;
+
+
+let is_dynamic_method f =
+	match follow f.cf_type with
+	| TFun _ when f.cf_expr = None -> true
+	| _ ->
+		(match f.cf_expr with
+		| Some { eexpr = TFunction fd } -> f.cf_set = NormalAccess
+		| _ -> false)
+
+
+let default_value_string = function
+	| TInt i -> Printf.sprintf "%ld" i
+	| TFloat float_as_string -> float_as_string
+	| TString s -> str s
+	| TBool b -> (if b then "true" else "false")
+	| TNull -> "null()"
+	| _ -> "/* Hmmm */"
+
+
+let generate_default_values ctx args prefix =
+  List.iter ( fun (name,o,arg_type) -> let type_str = type_string arg_type in
+	match o with
+	| Some const when (is_basic_type type_str) ->
+		ctx.ctx_output (type_str ^ " " ^ name ^ " = " ^ prefix ^ name ^ ".Default(" ^ 
+			(default_value_string const) ^ ");\n")
+	| _ -> () ) args;;
+
+
+let has_default_values args =
+	List.exists ( fun (name,o,arg_type) -> let type_str = type_string arg_type in
+	match o with | Some const when (is_basic_type type_str) -> true | _ -> false ) args;;
+
+
+let gen_field ctx class_name ptr_name is_static is_external is_interface field =
+	let output = ctx.ctx_output in
+	ctx.ctx_real_this_ptr <- not is_static;
+	let remap_name = keyword_remap field.cf_name in
+	if (is_external || is_interface) then begin
+		(* Just the dynamic glue ... *)
+		match follow field.cf_type with
+		| TFun (args,result) ->
+			if (is_static) then output "STATIC_";
+			let ret = if ((type_string result ) = "void" ) then "" else "return " in
+			output ("DEFINE_DYNAMIC_FUNC" ^ (string_of_int (List.length args)) ^
+				 "(" ^ class_name ^ "," ^ remap_name ^ "," ^ ret ^ ")\n\n");
+		| _ -> ()
+	end else (match  field.cf_expr with
+	(* Function field *)
+	| Some { eexpr = TFunction function_def } ->
+		let return_type = (type_string function_def.tf_type) in
+		let nargs = string_of_int (List.length function_def.tf_args) in
+		let ret = if ((type_string function_def.tf_type ) = "void" ) then "(void)" else "return " in
+
+		if (not (is_dynamic_method field)) then begin
+			(* The actual function definition *)
+			output return_type;
+			output (" " ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ "( " );
+			output (gen_arg_list function_def.tf_args "__o_");
+			output ")";
+
+			if (has_default_values function_def.tf_args) then begin
+				ctx.ctx_writer#begin_block;
+				generate_default_values ctx function_def.tf_args "__o_";
+				gen_expression ctx false function_def.tf_expr;
+				ctx.ctx_writer#end_block;
+			end else
+				gen_expression ctx false function_def.tf_expr;
+
+			output "\n\n";
+			(* generate dynamic version too ... *)
+			if (is_static) then output "STATIC_";
+			output ("DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^
+							 remap_name ^ "," ^ ret ^ ")\n\n");
+
+		end else begin
+			ctx.ctx_real_this_ptr <- false;
+			ctx.ctx_dynamic_this_ptr <- false;
+			let func_name = "__default_" ^ (remap_name) in
+			output ("BEGIN_DEFAULT_FUNC(" ^ func_name ^ "," ^ class_name ^ ")\n");
+			output return_type;
+			output (" run(" ^ (gen_arg_list function_def.tf_args "") ^ ")");
+			(*ctx.ctx_writer#begin_block;*)
+			gen_expression ctx false function_def.tf_expr;
+			(*ctx.ctx_writer#end_block;*)
+			output ("END_LOCAL_FUNC" ^ nargs ^ "(" ^ ret ^ ")\n\n");
+
+			if (is_static) then
+				output ( "Dynamic " ^ class_name ^ "::" ^ (keyword_remap field.cf_name) ^ ";\n\n");
+		end
+
+	(* Data field *)
+	| _ ->
+		if is_static then begin
+			gen_type ctx field.cf_type;
+			output ( " " ^ class_name ^ "::" ^ field.cf_name ^ ";\n\n");
+		end
+	)
+
+
+
+
+
+let gen_field_init ctx field =
+	let output = ctx.ctx_output in
+	let remap_name = keyword_remap field.cf_name in
+	(match  field.cf_expr with
+	(* Function field *)
+	| Some { eexpr = TFunction function_def } ->
+
+		if (is_dynamic_method field) then begin
+			let func_name = "__default_" ^ (remap_name) in
+			output ( "	Static(" ^ (keyword_remap field.cf_name) ^ ") = new " ^ func_name ^ ";\n\n" );
+		end
+
+	(* Data field *)
+	| _ -> (match field.cf_expr with
+		| Some expr ->
+			output ( "	Static(" ^ field.cf_name ^ ") = ");
+			gen_expression ctx true expr;
+			output ";\n"
+		| _ ->
+			output ( "	Static(" ^ field.cf_name ^ ");\n");
+		);
+	)
+
+
+
+let declare_typedef ctx output type_def = 
+	let name =  snd type_def.t_path in
+	if ( not (name = "Null") ) then begin
+		List.iter (fun namespace -> output ("namespace " ^ namespace ^ "{ ") ) (fst type_def.t_path);
+		output ("typedef " ^ (type_string type_def.t_type) ^ " " ^ name ^ "; "); 
+		List.iter (fun _ -> output ("} ") ) (fst type_def.t_path);
+		output "\n\n"
+	end
+
+let gen_member_def ctx is_static is_extern is_interface field =
+	let output = ctx.ctx_output in
+	let remap_name = keyword_remap field.cf_name in
+
+	output (if is_static then "		static " else "		");
+	if (is_extern || is_interface) then begin
+		match follow field.cf_type with
+		| TFun (args,return_type) ->
+			output ( (if (not is_static) then "virtual " else "" ) ^ type_string return_type);
+			output (" " ^ remap_name ^ "( " );
+			output (String.concat "," (List.map (fun (name,opt,typ) ->
+				(type_string typ) ^ " " ^ name ^ (if opt then "=null()" else "")) args));
+			output (if (not is_static) then ")=0;\n" else ");\n");
+			(*if (not is_interface) then begin*)
+				output (if is_static then "		static " else "		");
+				output ("Dynamic " ^ remap_name ^ "_dyn();\n" );
+			(*end else
+				output ("		virtual Dynamic " ^ remap_name ^ "_dyn() = 0;\n\n" );*)
+		| _ -> 
+			gen_type ctx field.cf_type;
+			output (" " ^ remap_name ^ ";\n" )
+	end else (match  field.cf_expr with
+	| Some { eexpr = TFunction function_def } ->
+		if ( is_dynamic_method field ) then begin
+			output ("Dynamic " ^ field.cf_name ^ ";\n");
+			output (if is_static then "		static " else "		");
+			output ("inline Dynamic &" ^ field.cf_name ^ "_dyn() " ^
+									 "{return " ^ field.cf_name^ "; }\n") 
+		end else begin
+			let return_type = (type_string function_def.tf_type) in
+			if (not is_static) then output "virtual ";
+			output return_type;
+			output (" " ^ remap_name ^ "( " );
+			output (gen_arg_list function_def.tf_args "" );
+			output ");\n";
+			output (if is_static then "		static " else "		");
+			output ("Dynamic " ^ remap_name ^ "_dyn();\n" )
+			end;
+		output "\n";
+	| _ ->
+		(* Variable access *)
+		gen_type ctx field.cf_type;
+		output (" " ^ remap_name ^ ";\n" );
+		(* Add a "dyn" function for variable to unify variable/function access *)
+		(match follow field.cf_type with
+		| TFun (_,_) ->
+			output "	";
+			gen_type ctx field.cf_type;
+			output (" &" ^ remap_name ^ "_dyn() { return " ^ remap_name ^ ";}\n" )
+		| _ -> () )
+	)
+
+
+
+(*
+  Get a list of all classes referred to by the class/enum definition
+  These are used for "#include"ing the appropriate header files.
+*)
+let find_referenced_types obj =
+	let types = Hashtbl.create 0 in
+	(* When a class or function is templated on type T, variables of that type show
+		up as being in a package "class-name.T" or "function-name.T"  in these cases
+		we just use "Dynamic" - TODO: Use cl_kind *)
+	let ignore_class_name = ref "?" in
+	let ignore_function_name = ref "?" in
+	let add_type in_path =
+		let package = (String.concat "." (fst in_path)) in
+		if ( not ((package=(!ignore_function_name)) || (package=(!ignore_class_name))) ) then
+			try ( Hashtbl.find types in_path; () ) with Not_found -> Hashtbl.add types in_path ()
+	in
+	let rec visit_type in_type =
+		match (follow in_type) with
+		| TMono r -> (match !r with None -> () | Some t -> visit_type t)
+		(*| TEnum ({ e_path = ([],"Void") },[]) -> ()
+		| TEnum ({ e_path = ([],"Bool") },[]) -> () *)
+		| TEnum (enum,params) -> add_type enum.e_path
+		(* If a class has a template parameter, then we treat it as dynamic - except
+			for the Array or Class class, for which we do a fully typed object *)
+		| TInst (klass,params) -> add_type klass.cl_path;
+			(match klass.cl_path with
+				| ([],"Array") | ([],"Class") -> List.iter visit_type params
+			| _ -> () )
+		| TFun (args,haxe_type) -> visit_type haxe_type;
+				List.iter (fun (_,_,t) -> visit_type t; ) args;
+		| _ -> ()
+	in
+	let rec visit_types expression =
+		begin
+		let rec visit_expression = fun expression ->
+			(* Expand out TTypeExpr ... *)
+			(match expression.eexpr with
+				| TTypeExpr type_def -> add_type (t_path type_def)
+				(* Must visit the types, Type.iter will visit the expressions ... *)
+				| TTry (e,catches) ->
+					List.iter (fun (_,catch_type,_) -> visit_type catch_type) catches
+				(* Must visit the enum param types, Type.iter will visit the rest ... *)
+				| TMatch (_,_,cases,_) ->
+					List.iter (fun (case_ids,params,expression) ->
+						(match params with
+						| None -> ()
+						| Some l -> List.iter (fun (v,t) -> visit_type t) l  ) ) cases;
+
+				(* Must visit args too, Type.iter will visit the expressions ... *)
+				| TFunction func_def ->
+					List.iter (fun (_,_,arg_type) -> visit_type arg_type) func_def.tf_args;
+				| _ -> ()
+			);
+			Type.iter visit_expression expression;
+			visit_type (follow expression.etype)
+		in
+		visit_expression expression
+		end
+	in
+	let visit_field field =
+		!ignore_function_name <- field.cf_name;
+		(* Add the type of the expression ... *)
+		visit_type field.cf_type;
+		(match field.cf_expr with
+			| Some expression -> visit_types expression | _ -> ());
+		!ignore_function_name <- "?"
+	in
+	let visit_class class_def =
+		!ignore_class_name <- join_class_path class_def.cl_path ".";
+		let fields = List.append class_def.cl_ordered_fields class_def.cl_ordered_statics in
+		let fields_and_constructor = List.append fields
+			(match class_def.cl_constructor with | Some expr -> [expr] | _ -> [] ) in
+		List.iter visit_field fields_and_constructor;
+		!ignore_class_name <- "?"
+	in
+	let visit_enum enum_def =
+		add_type enum_def.e_path;
+		PMap.iter (fun _ constructor ->
+			(match constructor.ef_type with
+			| TFun (args,_) ->
+				List.iter (fun (_,_,t) -> visit_type t; ) args;
+			| _ -> () );
+			) enum_def.e_constrs
+	in
+
+	(* Body of main function *)
+	(match obj with
+	| TClassDecl class_def -> visit_class class_def
+	| TEnumDecl enum_def -> visit_enum enum_def
+	| TTypeDecl _ -> (* These are expanded *) ());
+
+	List.filter (fun path -> not (is_internal_header path) ) (hash_keys types)
+	;;
+
+
+
+
+
+
+let generate_main common_ctx member_types class_def boot_classes init_classes =
+	let base_dir = common_ctx.file in
+	(*make_class_directories base_dir ( "src" :: []);*)
+	let cpp_file = Gensource.new_cpp_file common_ctx.file ([],"__main__") in
+	let output_main = (cpp_file#write) in
+	let ctx = new_context cpp_file common_ctx.debug in
+	ctx.ctx_class_name <- "?";
+	ctx.ctx_class_member_types <- member_types;
+
+	(* main routine should be a single static function *)
+	let main_expression = 
+		(match class_def.cl_ordered_statics with
+		| [{ cf_expr = Some expression }] -> expression;
+		| _ -> assert false ) in
+	output_main "#include <hxObject.h>\n\n";
+	output_main "#include <stdio.h>\n\n";
+	(*output_main "#include <hxLoadDLL.cpp>\n\n";*)
+
+	let referenced = find_referenced_types (TClassDecl class_def) in
+	List.iter ( add_include cpp_file ) referenced;
+
+	output_main "\n\n";
+	output_main "int main(int argc,char **argv)";
+	cpp_file#begin_block;
+	(*cpp_file#write_i "hxLoadDLL();\n";*)
+	cpp_file#write_i "__boot_hxcpp();\n";
+	cpp_file#write_i "try";
+	cpp_file#begin_block;
+	cpp_file#write_i "__boot_all();\n";
+	cpp_file#write_i "";
+	gen_expression (new_context cpp_file common_ctx.debug) false main_expression;
+	output_main ";\n";
+	cpp_file#end_block;
+	cpp_file#write_i "catch (Dynamic e)";
+	cpp_file#begin_block;
+	cpp_file#write_i "printf(\"Error : %s\\n\",e->__ToString().__CStr());\n";
+	cpp_file#end_block;
+	cpp_file#write_i "return 0;\n";
+	cpp_file#end_block;
+	cpp_file#close;
+
+	(* Write boot class too ... *)
+	let boot_file = Gensource.new_cpp_file base_dir ([],"__boot__") in
+	let output_boot = (boot_file#write) in
+	output_boot "#include <hxObject.h>\n\n";
+	List.iter ( fun class_path ->
+		output_boot ("#include <" ^
+			( join_class_path (include_remap class_path) "/" ) ^ ".h>\n")
+			) boot_classes;
+
+	output_boot "\nvoid __boot_all()\n{\n";
+	output_boot "RegisterResources( GetResources() );\n";
+	List.iter ( fun class_path ->
+		output_boot (( join_class_path class_path "::" ) ^ "_obj::__register();\n") ) boot_classes;
+	List.iter ( fun class_path ->
+		output_boot (( join_class_path class_path "::" ) ^ "_obj::__init__();\n") ) (List.rev init_classes);
+	List.iter ( fun class_path ->
+		output_boot (( join_class_path class_path "::" ) ^ "_obj::__boot();\n") ) (List.rev boot_classes);
+	output_boot "}\n\n";
+	boot_file#close;;
+
+
+let begin_header_file output_h def_string =
+	output_h ("#ifndef INCLUDED_" ^ def_string ^ "\n");
+	output_h ("#define INCLUDED_" ^ def_string ^ "\n\n");
+	output_h "#include <hxObject.h>\n\n"
+	(*output_h "#include <Typedefs.h>\n\n" *)
+
+let end_header_file output_h def_string = 
+	output_h ("\n#endif /* INCLUDED_" ^ def_string ^ " */ \n")
+
+
+let generate_enum_files common_ctx enum_def =
+	let class_path = enum_def.e_path in
+	let class_name = (snd class_path) ^ "_obj" in
+	let smart_class_name =  (snd class_path)  in
+	(*let cpp_file = new_cpp_file common_ctx.file class_path in*)
+	let cpp_file = Gensource.new_cpp_file common_ctx.file class_path in
+	let output_cpp = (cpp_file#write) in
+	let ctx = new_context cpp_file common_ctx.debug in
+
+	if (common_ctx.debug) then
+		print_endline ("Found enum definition:" ^ (join_class_path  class_path "::" ));
+
+	output_cpp "#include <hxObject.h>\n\n";
+	add_include cpp_file class_path;
+
+	let referenced = find_referenced_types (TEnumDecl enum_def) in
+	List.iter (add_include cpp_file) referenced;
+
+	gen_open_namespace output_cpp class_path;
+	output_cpp "\n";
+
+	PMap.iter (fun _ constructor ->
+		let name = constructor.ef_name in
+		match constructor.ef_type with
+		| TFun (args,_) -> 
+			output_cpp (smart_class_name ^ "  " ^ class_name ^ "::" ^ name ^ "(" ^
+				(gen_tfun_arg_list args) ^")\n");
+			output_cpp ("	{ return CreateEnum<" ^ class_name ^ " >(" ^ (str name) ^ "," ^
+				(string_of_int constructor.ef_index) ^ ",DynamicArray(0," ^
+				(string_of_int (List.length args)) ^  ")" );
+			List.iter (fun (arg,_,_) -> output_cpp (".Add(" ^ arg ^ ")")) args;
+			output_cpp "); }\n\n"
+
+		| _ ->
+			output_cpp ( smart_class_name ^ " " ^ class_name ^ "::" ^ name ^ ";\n\n" )
+	) enum_def.e_constrs;
+
+
+
+
+	output_cpp ("DEFINE_CREATE_ENUM(" ^ class_name ^ ")\n\n");
+	output_cpp ("int " ^ class_name ^ "::__FindIndex(String inName)\n{\n");
+	PMap.iter (fun _ constructor ->
+		let name = constructor.ef_name in
+		let idx = string_of_int constructor.ef_index in
+		output_cpp ("	if (inName==" ^ (str name) ^ ") return " ^ idx ^ ";\n") ) enum_def.e_constrs;
+	output_cpp ("	return super::__FindIndex(inName);\n");
+	output_cpp ("}\n\n");
+
+	let constructor_arg_count constructor =
+		(match constructor.ef_type with | TFun(args,_) -> List.length args | _ -> 0 )
+	in
+
+
+	(* Dynamic versions of constructors *)
+	let dump_dynamic_constructor _ constr =
+		let count = constructor_arg_count constr in
+		if (count>0) then begin
+			let nargs = string_of_int count in
+			output_cpp ("STATIC_DEFINE_DYNAMIC_FUNC" ^ nargs ^ "(" ^ class_name ^ "," ^
+						 constr.ef_name ^ ",return)\n\n");
+		end
+	in
+	PMap.iter dump_dynamic_constructor enum_def.e_constrs;
+
+
+	output_cpp ("int " ^ class_name ^ "::__FindArgCount(String inName)\n{\n");
+	PMap.iter (fun _ constructor ->
+		let name = constructor.ef_name in
+		let count = string_of_int (constructor_arg_count constructor) in
+		output_cpp ("	if (inName==" ^ (str name) ^ ") return " ^ count ^ ";\n") ) enum_def.e_constrs;
+		output_cpp ("	return super::__FindArgCount(inName);\n");
+		output_cpp ("}\n\n");
+
+	(* Dynamic "Get" Field function - string version *)
+	output_cpp ("Dynamic " ^ class_name ^ "::__Field(const String &inName)\n{\n");
+	let dump_constructor_test _ constr =
+		output_cpp ("	if (inName==" ^ (str constr.ef_name) ^ ") return " ^ constr.ef_name );
+		if ( (constructor_arg_count constr) > 0 ) then output_cpp "_dyn()";
+		output_cpp (";\n")
+	in
+	PMap.iter dump_constructor_test enum_def.e_constrs;
+	output_cpp ("	return super::__Field(inName);\n}\n\n");
+
+
+	output_cpp "static wchar_t *sStaticFields[] = {\n";
+	PMap.iter
+		(fun _ constructor -> output_cpp ("	L\"" ^ constructor.ef_name ^ "\",\n") )
+		enum_def.e_constrs;
+	output_cpp "	0 };\n\n";
+
+	output_cpp "static wchar_t *sMemberFields[] = { 0 };\n";
+
+	output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n");
+
+	output_cpp ("Dynamic __Create_" ^ class_name ^ "() { return new " ^ class_name ^ "; }\n\n");
+
+	output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
+	output_cpp ("\nStatic(__mClass) = RegisterClass(" ^ 
+					(str (join_class_path class_path ".") ) ^ ",sStaticFields,sMemberFields,\n");
+	output_cpp ("	&__Create_" ^ class_name ^ ", &__Create,\n");
+	output_cpp ("	&super::__SGetClass(), &Create" ^ class_name ^ ");\n");
+	output_cpp ("}\n\n");
+
+	output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
+	PMap.iter (fun _ constructor ->
+		let name = constructor.ef_name in
+		match constructor.ef_type with
+		| TFun (_,_) -> ()
+		| _ ->
+			output_cpp ( "Static(" ^ name ^ ") = CreateEnum<" ^ class_name ^ " >(" ^ (str name) ^  "," ^
+				(string_of_int constructor.ef_index) ^ ");\n" )
+	) enum_def.e_constrs;
+	output_cpp ("}\n\n");
+
+
+
+
+	output_cpp "\n";
+	gen_close_namespace output_cpp class_path;
+	cpp_file#close;
+
+	let h_file = Gensource.new_header_file common_ctx.file class_path in
+	let super = "hxEnumBase_obj" in
+	let output_h = (h_file#write) in
+	let def_string = join_class_path class_path "_"  in
+	ctx.ctx_output <- output_h;
+
+	begin_header_file output_h def_string;
+
+	List.iter (gen_forward_decl h_file ) referenced;
+
+	gen_open_namespace output_h class_path;
+
+	output_h "\n\n";
+	output_h ("class " ^ class_name ^ " : public " ^ super ^ "\n");
+	output_h ("{\n	typedef " ^ super ^ " super;\n");
+	output_h ("		typedef " ^ class_name ^ " OBJ_;\n");
+	output_h "\n	public:\n";
+	output_h ("		" ^ class_name ^ "() {};\n");
+	output_h ("		DO_ENUM_RTTI;\n");
+	output_h ("		static void __boot();\n");
+	output_h ("		static void __register();\n");
+		output_h ("		String GetEnumName( ) const { return " ^
+									(str (join_class_path class_path "."))  ^ "; }\n" );
+	output_h ("		String __ToString() const { return " ^
+									(str (smart_class_name ^ ".") )^ " + tag; }\n\n");
+
+	PMap.iter (fun _ constructor ->
+		let name = constructor.ef_name in
+		output_h ( "		static " ^  smart_class_name ^ " " ^ name );
+		match constructor.ef_type with
+		| TFun (args,_) -> 
+			output_h ( "(" ^ (gen_tfun_arg_list args) ^");\n");
+			output_h ( "		static Dynamic " ^ name ^ "_dyn();\n");
+		| _ ->
+			output_h ";\n"
+	) enum_def.e_constrs;
+
+	output_h "};\n\n";
+
+	gen_close_namespace output_h class_path;
+
+	end_header_file output_h def_string;
+	h_file#close;
+	referenced;;
+
+let has_init_field class_def = match class_def.cl_init with Some _ -> true | _ -> false;;
+
+
+
+
+
+let generate_class_files common_ctx member_types class_def =
+	let is_extern = class_def.cl_extern in
+	let class_path = class_def.cl_path in
+	let class_name = (snd class_def.cl_path) ^ "_obj" in
+	let smart_class_name =  (snd class_def.cl_path)  in
+	(*let cpp_file = new_cpp_file common_ctx.file class_path in*)
+	let cpp_file = Gensource.new_cpp_file common_ctx.file class_path in
+	let output_cpp = (cpp_file#write) in
+	let debug = common_ctx.debug in
+	let ctx = new_context cpp_file debug in
+	ctx.ctx_class_name <- join_class_path class_path "::";
+	ctx.ctx_class_member_types <- member_types;
+	if debug then print_endline ("Found class definition:" ^ ctx.ctx_class_name);
+
+	let ptr_name = "hxObjectPtr<" ^ class_name ^ " >" in
+	let constructor_type_var_list =
+		match class_def.cl_constructor with
+		| Some definition ->
+				(match  definition.cf_type with
+					| TFun (args,_) -> List.map (fun (a,_,t) -> (type_string t,a) )  args
+					| _ ->  (match definition.cf_expr with
+						| Some { eexpr = TFunction function_def } ->
+							List.map (fun (name,o,arg_type) -> gen_arg_type_name name o arg_type "__o_")
+									function_def.tf_args;
+						| _ -> [] )
+					)
+		| _ -> [] in
+	let constructor_var_list = List.map snd constructor_type_var_list in
+	let constructor_type_args = String.concat ","
+				(List.map (fun (t,a) -> t ^ " " ^ a) constructor_type_var_list) in
+	let constructor_args = String.concat "," constructor_var_list in
+
+
+	output_cpp "#include <hxObject.h>\n\n";
+	add_include cpp_file class_path;
+
+	let referenced = find_referenced_types (TClassDecl class_def) in
+	List.iter ( add_include cpp_file  ) referenced;
+
+	gen_open_namespace output_cpp class_path;
+	output_cpp "\n";
+
+	if (not class_def.cl_interface) then begin
+		if (not is_extern) then begin
+			output_cpp ("void " ^ class_name ^ "::__construct(" ^ constructor_type_args ^ ")\n{\n");
+			(match class_def.cl_constructor with
+				| Some definition ->
+						(match  definition.cf_expr with
+						| Some { eexpr = TFunction function_def } ->
+							if (has_default_values function_def.tf_args) then begin
+								ctx.ctx_writer#begin_block;
+								generate_default_values ctx function_def.tf_args "__o_";
+								gen_expression ctx false function_def.tf_expr;
+								ctx.ctx_writer#end_block;
+							end else
+								gen_expression ctx false function_def.tf_expr;
+								(*gen_expression (new_context cpp_file debug ) false function_def.tf_expr;*)
+							output_cpp ";\n";
+						| _ -> ()
+						)
+				| _ -> ());
+			output_cpp "}\n\n";
+		end;
+
+		(* Destructor goes in the cpp file so we can "see" the full definition of the member vars *)
+		output_cpp ( class_name ^ "::~" ^ class_name ^ "() { }\n\n");
+		if (not is_extern) then
+			output_cpp ("Dynamic " ^ class_name ^ "::__CreateEmpty() { return  new " ^ class_name ^ "; }\n");
+
+		output_cpp (ptr_name ^ " " ^ class_name ^ "::__new(" ^constructor_type_args ^")\n");
+
+		let create_result ext = 
+			if (ext) then
+				output_cpp ("{  " ^ ptr_name ^ " result = __CreateEmpty();\n")
+			else
+				output_cpp ("{  " ^ ptr_name ^ " result = new " ^ class_name ^ "();\n");
+			in
+		create_result is_extern;
+		output_cpp ("	result->__construct(" ^ constructor_args ^ ");\n");
+		output_cpp ("	return result;}\n\n");
+
+		output_cpp ("Dynamic " ^ class_name ^ "::__Create(DynamicArray inArgs)\n");
+		create_result is_extern;
+		output_cpp ("	result->__construct(" ^ (array_arg_list constructor_var_list) ^ ");\n");
+		output_cpp ("	return result;}\n\n");
+
+	end;
+
+	(match class_def.cl_init with
+	| Some expression -> 
+		output_cpp ("void " ^ class_name^ "::__init__()");
+		gen_expression (new_context cpp_file debug) false expression;
+		output_cpp "\n\n";
+	| _ -> ());
+
+	List.iter
+		(gen_field ctx class_name smart_class_name false is_extern class_def.cl_interface)
+		class_def.cl_ordered_fields;
+	List.iter
+		(gen_field ctx class_name smart_class_name true is_extern class_def.cl_interface)
+		class_def.cl_ordered_statics;
+	output_cpp "\n";
+
+
+	(* Initialise non-static variables *)
+	if (not class_def.cl_interface) then begin
+		output_cpp (class_name ^ "::" ^ class_name ^  "()\n{\n");
+		List.iter
+			(fun field -> match field.cf_expr with
+				| Some { eexpr = TFunction function_def } ->
+						if (is_dynamic_method field) then
+							output_cpp ("	" ^ field.cf_name ^ " = new __default_"
+								^ field.cf_name ^ "(this);\n")
+				| _ -> (match follow field.cf_type with
+					| TFun _ -> ()
+					| _ -> output_cpp ("	InitMember(" ^ field.cf_name ^ ");\n"));
+			)
+			class_def.cl_ordered_fields;
+		output_cpp "}\n\n";
+
+		let variable_field field =
+			(match field.cf_expr with
+			| Some { eexpr = TFunction function_def } -> is_dynamic_method field
+			| _ -> (not is_extern) ||
+							  (match follow field.cf_type with | TFun _ -> false | _ -> true) ) in
+
+		(* Dynamic "Get" Field function - string version *)
+		output_cpp ("Dynamic " ^ class_name ^ "::__Field(const String &inName)\n{\n");
+		let dump_field_test = (fun field ->
+			let remap_name = keyword_remap field.cf_name in
+			output_cpp ("	if (inName==" ^ (str field.cf_name) ^ ") return " ^ remap_name );
+			if (not (variable_field field) ) then output_cpp "_dyn()";
+			output_cpp (";\n")) in
+		List.iter dump_field_test  class_def.cl_ordered_statics;
+		List.iter dump_field_test  class_def.cl_ordered_fields;
+		output_cpp ("	return super::__Field(inName);\n}\n\n");
+
+		(* Dynamic "Get" Field function - int version *)
+
+		let dump_static_ids = (fun field ->
+			let remap_name = keyword_remap field.cf_name in
+			output_cpp ("static int __id_" ^ remap_name ^ " = __hxcpp_field_to_id(\"" ^
+								  (field.cf_name) ^ "\");\n");
+			) in
+		List.iter dump_static_ids  class_def.cl_ordered_statics;
+		List.iter dump_static_ids  class_def.cl_ordered_fields;
+		output_cpp "\n\n";
+
+		output_cpp ("Dynamic " ^ class_name ^ "::__IField(int inFieldID)\n{\n");
+		let dump_field_test = (fun field ->
+			let remap_name = keyword_remap field.cf_name in
+			output_cpp ("	if (inFieldID==__id_" ^ remap_name ^ ") return " ^ remap_name );
+			if (not (variable_field field) ) then output_cpp "_dyn()";
+			output_cpp (";\n")) in
+		List.iter dump_field_test  class_def.cl_ordered_statics;
+		List.iter dump_field_test  class_def.cl_ordered_fields;
+		output_cpp ("	return super::__IField(inFieldID);\n}\n\n");
+
+
+		(* Dynamic "Set" Field function *)
+		output_cpp ("Dynamic " ^ class_name ^ "::__SetField(const String &inName," ^
+						"const Dynamic &inValue)\n{\n");
+
+		let dump_field_set = (fun field ->
+			let n = keyword_remap field.cf_name in
+			if (variable_field field ) then
+				output_cpp ("	if (inName==" ^ (str field.cf_name) ^ ") " ^
+						"return "^n^"=inValue.Cast<" ^ (type_string field.cf_type) ^ " >();\n" );
+			) in
+		List.iter dump_field_set  class_def.cl_ordered_statics;
+		List.iter dump_field_set  class_def.cl_ordered_fields;
+		output_cpp ("	return super::__SetField(inName,inValue);\n}\n\n");
+
+		(* For getting a list of data members (eg, for serialization) *)
+		let append_field =
+			(fun field -> output_cpp ("	outFields->push(" ^( str field.cf_name )^ ");\n")) in
+		let is_data_field field = (match follow field.cf_type with | TFun _ -> false | _ -> true) in
+
+		output_cpp ("void " ^ class_name ^ "::__GetFields(Array<String> &outFields)\n{\n");
+		List.iter append_field (List.filter is_data_field class_def.cl_ordered_fields);
+		output_cpp "	super::__GetFields(outFields);\n";
+		output_cpp "};\n\n";
+
+
+		let dump_field_name = (fun field -> output_cpp ("	L\"" ^  field.cf_name ^ "\",\n")) in
+		output_cpp "static wchar_t *sStaticFields[] = {\n";
+		List.iter dump_field_name  class_def.cl_ordered_statics;
+		output_cpp "	0 };\n\n";
+
+		output_cpp "static wchar_t *sMemberFields[] = {\n";
+		List.iter dump_field_name  class_def.cl_ordered_fields;
+		output_cpp "	0 };\n\n";
+	end;
+
+
+
+	(* Initialise static in boot function ... *)
+	if (not class_def.cl_interface) then begin
+		output_cpp ("Class " ^ class_name ^ "::__mClass;\n\n");
+
+		output_cpp ("void " ^ class_name ^ "::__register()\n{\n");
+		output_cpp ("	Static(__mClass) = RegisterClass(" ^ 
+							(str (join_class_path class_path "."))  ^ ",sStaticFields,sMemberFields,\n");
+		output_cpp ("	&__CreateEmpty, &__Create,\n");
+		output_cpp ("	&super::__SGetClass(), 0);\n");
+		output_cpp ("}\n\n");
+
+		if (not is_extern) then begin
+			output_cpp ("void " ^ class_name ^ "::__boot()\n{\n");
+			List.iter (gen_field_init ctx ) class_def.cl_ordered_statics;
+			output_cpp ("}\n\n");
+		end;
+	end;
+
+	gen_close_namespace output_cpp class_path;
+
+	if (is_extern) then begin
+		output_cpp ("\n\n#include<extern/" ^ (join_class_path class_path  "/") ^ ".cpp>\n\n");
+	end;
+	cpp_file#close;
+
+
+	let h_file = Gensource.new_header_file common_ctx.file class_path in
+	let super = match class_def.cl_super with
+		| Some (klass,params) -> (class_string klass "_obj" params)
+		| _ -> "hxObject"
+		in
+	let output_h = (h_file#write) in
+	let def_string = join_class_path class_path "_"  in
+	ctx.ctx_output <- output_h;
+
+	begin_header_file output_h def_string;
+
+	(* Include the real header file for the super class *)
+	(match class_def.cl_super with
+	| Some super ->
+		let super_path = (fst super).cl_path in
+		output_h ("#include <" ^ ( join_class_path super_path "/" ) ^ ".h>\n")
+	| _ -> () );
+	(* And any interfaces ... *)
+	List.iter (fun imp->
+		let imp_path = (fst imp).cl_path in
+		output_h ("#include <" ^ ( join_class_path imp_path "/" ) ^ ".h>\n") )
+	class_def.cl_implements;
+
+	List.iter ( gen_forward_decl h_file ) referenced;
+
+	gen_open_namespace output_h class_path;
+	output_h "\n\n";
+
+	if (class_def.cl_interface) then begin
+		output_h ("class " ^ class_name ^ " : public virtual hxObject\n");
+		output_h "{\n	public:\n";
+		output_h "	INTERFACE_DEF\n";
+	end else begin
+		output_h ("class " ^ class_name ^ " : public " ^
+			(if super="hxObject" then "virtual hxObject" else super ) );
+		List.iter (fun imp ->
+			let imp_path = (fst imp).cl_path in
+			let interface_name = (join_class_path imp_path "::" ) ^ "_obj" in
+			output_h (", public " ^ interface_name ) ) class_def.cl_implements;
+		output_h "\n{\n	public:\n";
+		output_h ("		typedef " ^ super ^ " super;\n");
+		output_h ("		typedef " ^ class_name ^ " OBJ_;\n");
+		output_h "\n	protected:\n";
+		output_h ("		" ^ class_name ^  "();\n");
+		if (is_extern) then
+			output_h ("		virtual void __construct(" ^ constructor_type_args ^ ")=0;\n")
+		else
+			output_h ("		void __construct(" ^ constructor_type_args ^ ");\n");
+		output_h "\n	public:\n";
+		output_h ("	  static " ^ptr_name^ " __new(" ^constructor_type_args ^");\n");
+		output_h ("	  static Dynamic __CreateEmpty();\n");
+		output_h ("	  static Dynamic __Create(DynamicArray inArgs);\n");
+		output_h ("		~" ^ class_name ^ "();\n\n");
+		output_h ("	  DO_RTTI;\n");
+		output_h ("	  static void __boot();\n");
+		output_h ("	  static void __register();\n");
+
+		if (has_init_field class_def) then
+			output_h "		static void __init__();\n\n";
+		output_h ("	  String __ToString() const { return " ^ (str smart_class_name) ^ "; }\n\n");
+	end;
+
+
+	(match class_def.cl_array_access with
+	| Some t -> output_h ("		typedef " ^ (type_string t) ^ " __array_access;\n")
+	| _ -> ());
+
+
+	let interface = class_def.cl_interface in
+	List.iter (gen_member_def ctx false is_extern interface) class_def.cl_ordered_fields;
+	List.iter (gen_member_def ctx true is_extern interface)  class_def.cl_ordered_statics;
+
+	output_h "};\n\n";
+	gen_close_namespace output_h class_path;
+
+	end_header_file output_h def_string;
+	h_file#close;
+	referenced;;
+
+
+let gen_deps deps =
+	let project_deps = List.filter (fun path -> not (is_internal_class path) ) deps in
+	String.concat " " (List.map (fun class_path ->
+		"include/" ^ (join_class_path class_path "/") ^ ".h") project_deps );;
+
+let add_class_to_makefile makefile add_obj class_def =
+	let class_path = fst class_def in
+	let deps = snd class_def in
+	let obj_file =  "obj/" ^ (join_class_path class_path "-") ^ "$(OBJ)" in
+	let cpp = (join_class_path class_path "/") ^ ".cpp" in
+	output_string makefile ( obj_file ^ " : src/" ^ cpp ^ " " ^ (gen_deps deps) ^ "\n");
+	output_string makefile ("\t$(COMPILE) src/" ^ cpp ^ " $(OUT_FLAGS)$@\n\n");
+	output_string makefile (add_obj ^ " " ^ obj_file ^ "\n\n" );;
+	
+
+let kind_string = function
+	| KNormal -> "KNormal"
+	| KTypeParameter -> "KTypeParameter"
+	| KExtension _ -> "KExtension"
+	| KConstant _ -> "KConstant"
+	| KGeneric -> "KGeneric"
+	| KGenericInstance _ -> "KGenericInstance";;
+
+
+let write_resources common_ctx =
+	let resource_file = Gensource.new_cpp_file common_ctx.file ([],"__resources__") in
+	resource_file#write "#include <hxObject.h>\n\n";
+
+	let idx = ref 0 in
+	Hashtbl.iter (fun _ data ->
+		resource_file#write_i ("static unsigned char __res_" ^ (string_of_int !idx) ^ "[] = {\n");
+		for i = 0 to String.length data - 1 do
+		let code = Char.code (String.unsafe_get data i) in
+			resource_file#write  (Printf.sprintf "0x%.2x, " code);
+			if ( (i mod 10) = 9) then resource_file#write "\n";
+		done;
+		resource_file#write ("};\n");
+		incr idx;
+	) common_ctx.resources;
+
+	!idx <- 0;
+	resource_file#write "hxResource __Resources[] =";
+	resource_file#begin_block;
+	Hashtbl.iter (fun name data ->
+		resource_file#write_i
+			("{ " ^ (str name) ^ "," ^ (string_of_int (String.length data)) ^ "," ^
+				"__res_" ^ (string_of_int !idx) ^ " },\n");
+		incr idx;
+	) common_ctx.resources;
+
+	resource_file#write_i "{0,0,0}";
+	resource_file#end_block_line;
+	resource_file#write ";\n\n";
+	resource_file#write "hxResource *GetResources() { return __Resources; }\n\n";
+	resource_file#close;;
+
+
+let write_makefile is_nmake filename classes add_obj exe_name =
+	let makefile = open_out filename in
+	if (is_nmake) then begin
+		output_string makefile ("!ifndef HXCPP\n");
+		output_string makefile ("!error Please define HXCPP\n");
+		output_string makefile ("!endif\n");
+		output_string makefile ("!include $(HXCPP)/make/nmake.setup\n\n");
+	end else begin
+		output_string makefile ("ifeq (\"x$(HXCPP)\",\"x\")\n");
+		output_string makefile (" HXCPP := `haxelib path hxcpp`\n");
+		output_string makefile ("endif\n");
+		output_string makefile ("include $(HXCPP)/make/make.setup\n\n");
+	end;
+
+	(* TODO : resource deps *)
+	List.iter (add_class_to_makefile makefile add_obj ) classes;
+
+	output_string makefile ("\n\nOUT_FILE = " ^ exe_name ^ "$(EXE_EXT)\n");
+	output_string makefile "\n\n$(OUT_FILE) : $(OBJ_FILES)\n";
+	output_string makefile "\n\nexe : $(OUT_FILE)\n";
+	output_string makefile "\t$(LINK) $(OBJ_FILES) $(LINK_OUT)$(OUT_FILE)\n\n";
+	output_string makefile "\nclean:\n";
+	output_string makefile "\t$(CLEAN_CMD) $(OBJ_FILES) $(OUT_FILE)";
+	close_out makefile;;
+
+let create_member_types common_ctx = 
+	let result = Hashtbl.create 0 in
+	let add_member class_path member =
+		match follow member.cf_type with
+		| TFun (_,ret) ->
+			(* print_endline (((join_class_path class_path "::") ^ "." ^ member.cf_name) ^ "=" ^
+						(type_string ret)); *)
+			Hashtbl.add result ((join_class_path class_path "::") ^ "." ^ member.cf_name)
+						(type_string ret)
+		| _ -> ()
+		in
+	List.iter (fun object_def ->
+		(match object_def with
+		| TClassDecl class_def when (match class_def.cl_kind with | KGeneric -> false | _ ->true) ->
+			List.iter (add_member class_def.cl_path) class_def.cl_ordered_fields;
+			List.iter (add_member class_def.cl_path) class_def.cl_ordered_statics
+		| _ -> ()
+		) ) common_ctx.types;
+	result;;
+
+
+(* The common_ctx contains the haxe AST in the "types" field and the resources *)
+let generate common_ctx =
+	Gensource.make_base_directory common_ctx.file;
+
+	let debug = common_ctx.debug in
+	let exe_classes = ref [] in
+	let boot_classes = ref [] in
+	let init_classes = ref [] in
+	let class_text path = join_class_path path "::" in
+	let member_types = create_member_types common_ctx in
+
+	List.iter (fun object_def ->
+		(match object_def with
+		| TClassDecl class_def when (match class_def.cl_kind with | KGeneric -> true | _ ->false) ->
+			let name =  class_text class_def.cl_path in
+			(if debug then print_endline ("	ignore generic class " ^ name))
+		| TClassDecl class_def ->
+			(match class_def.cl_path with
+			| [], "@Main" ->
+				generate_main common_ctx member_types class_def !boot_classes !init_classes;
+			| _ ->
+				let name =  class_text class_def.cl_path in
+				let is_internal = is_internal_class class_def.cl_path in
+				if (is_internal) then
+					( if debug then print_endline (" internal class " ^ name ))
+				else begin
+					if (not class_def.cl_interface) then
+						!boot_classes <- class_def.cl_path ::  !boot_classes;
+					if (has_init_field class_def) then
+						!init_classes <- class_def.cl_path ::  !init_classes;
+					let deps = generate_class_files common_ctx member_types class_def in
+					!exe_classes <- (class_def.cl_path, deps)  ::  !exe_classes;
+				end
+			)
+		| TEnumDecl enum_def ->
+			let name =  class_text enum_def.e_path in
+			let is_internal = is_internal_class enum_def.e_path in
+			if (is_internal) then
+				(if debug then print_endline (" internal enum " ^ name ))
+			else begin
+				if (enum_def.e_extern) then
+					(if debug then print_endline ("external enum " ^ name ));
+				!boot_classes <- enum_def.e_path :: !boot_classes;
+				let deps = generate_enum_files common_ctx enum_def in
+				!exe_classes <- (enum_def.e_path, deps) :: !exe_classes;
+			end
+		| TTypeDecl _ -> (* already done *) ()
+		);
+	) common_ctx.types;
+
+	write_resources common_ctx;
+
+
+	let output_name = match  common_ctx.main_class with
+	| Some path -> (snd path)
+	| _ -> "output" in
+
+	if ( (Sys.os_type = "Win32") && not (Common.defined common_ctx "gmake" ) ) then
+		write_makefile true (common_ctx.file ^ "/makefile") !exe_classes
+			"OBJ_FILES = $(OBJ_FILES)" output_name
+	else
+		write_makefile false (common_ctx.file ^ "/makefile") !exe_classes
+			"OBJ_FILES += " output_name
+	;;
+
+
+

+ 126 - 0
gensource.ml

@@ -0,0 +1,126 @@
+(*
+ *  haXe/CPP Compiler
+ *  Copyright (c)2008 Hugh Sanderson
+ *  based on and including code by (c)2005-2008 Nicolas Cannasse
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+
+let join_path path separator =
+   match fst path, snd path with
+   | [], s -> s
+   | el, s -> String.concat separator el ^ separator ^ s;;
+
+
+class source_writer write_func close_func=
+	object(this)
+	val indent_str = "\t"
+	val mutable indent = ""
+	val mutable indents = []
+	val mutable just_finished_block = false
+	method close = close_func(); ()
+	method write x = write_func x; just_finished_block <- false
+	method indent_one = this#write indent_str
+
+	method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents
+	method pop_indent = match indents with
+							| h::tail -> indents <- tail; indent <- String.concat "" indents
+							| [] -> indent <- "/*?*/";
+	method write_i x = this#write (indent ^ x)
+	method get_indent = indent
+	method begin_block = this#write ("{\n"); this#push_indent
+	method end_block = this#pop_indent; this#write_i "}\n"; just_finished_block <- true
+	method end_block_line = this#pop_indent; this#write_i "}"; just_finished_block <- true
+	method terminate_line = this#write (if just_finished_block then "" else ";\n")
+
+
+	method add_include class_path =
+		this#write ("#include <" ^ (join_path class_path "/") ^ ".h>\n")
+end;;
+
+let file_source_writer filename =
+	let out_file = open_out filename in
+	new source_writer (output_string out_file) (fun ()-> close_out out_file);;
+
+
+let read_whole_file chan =
+	let fileRead = ref "" in 
+	(*we'll store results here before the EOF exception is thrown*)
+	let bufSize = 4096 in
+	let buf = String.create bufSize in (*rewritable buffer*)
+	let rec reader accumString =
+	let chunkLen = input chan buf 0 bufSize in (*input up to bufSize chars to buf*)
+	if (chunkLen > 0) then (*more than 0 chars read*)
+	let lastChunk = String.sub buf 0 chunkLen (*getting n chars read*) in
+		reader (accumString^lastChunk) 
+	else 
+		accumString (*this case will occur before EOF*)
+	in
+	try
+		let () = (fileRead := (reader "")) in (*reader stops and returns at 0 chars read*)
+		!fileRead (*this will never be reached, EOF comes before*)
+	with
+		End_of_file -> !fileRead;; (*so we go and retrieve the string read*)
+
+
+
+(* The cached_source_writer will not write to the file if it has not changed,
+	thus allowing the makefile dependencies to work correctly *)
+let cached_source_writer filename =
+	try
+		let in_file = open_in filename in
+		let old_contents = read_whole_file in_file in
+		close_in in_file;
+		let buffer = Buffer.create 0 in
+		let add_buf str = Buffer.add_string buffer str in
+		let close = fun () ->
+			let contents = Buffer.contents buffer in
+			if (not (contents=old_contents) ) then begin
+				let out_file = open_out filename in
+				output_string out_file contents;
+				close_out out_file;
+			end;
+		in
+		new source_writer (add_buf) (close);
+	with _ ->
+		file_source_writer filename;;
+
+let rec make_class_directories base dir_list =
+	( match dir_list with
+	| [] -> ()
+	| dir :: remaining ->
+		let path = base ^ "/" ^ dir  in
+		if not (Sys.file_exists path) then
+			Unix.mkdir path 0o755;
+		make_class_directories path remaining
+	);;
+
+
+let new_source_file base_dir sub_dir extension class_path =
+	make_class_directories base_dir ( sub_dir :: (fst class_path));
+	cached_source_writer ( base_dir ^ "/" ^ sub_dir ^ "/" ^
+							  ( String.concat "/" (fst class_path) ) ^ "/" ^
+							  (snd class_path) ^ extension);;
+
+
+let new_cpp_file base_dir = new_source_file base_dir "src" ".cpp";;
+
+let new_header_file base_dir = new_source_file base_dir "include" ".h";;
+
+let make_base_directory file =
+	make_class_directories "." (file :: []);;
+
+ 

+ 8 - 1
main.ml

@@ -186,7 +186,7 @@ try
 	let gen_as3 = ref false in
 	let no_output = ref false in
 	let did_something = ref false in
-	let root_packages = ["neko"; "flash"; "flash9"; "js"; "php"] in
+	let root_packages = ["neko"; "flash"; "flash9"; "js"; "php"; "cpp"] in
 	Common.define com ("haxe_" ^ string_of_int version);
 	com.warning <- message;
 	com.error <- (fun msg p ->
@@ -256,6 +256,9 @@ try
 			classes := (["php"],"PhpMath__") :: !classes;
 			set_platform Php "php" dir;
 		),"<directory> : generate PHP code into target directory");
+		("-cpp",Arg.String (fun dir ->
+			set_platform Cpp "cpp" dir;
+		),"<directory> : generate C++ code into target directory");
 		("-xml",Arg.String (fun file ->
 			Parser.use_doc := true;
 			xml_out := Some file
@@ -424,6 +427,7 @@ try
 		| Neko -> "n"
 		| Js -> "js"
 		| Php -> "php"
+		| Cpp -> "cpp"
 	) in
 	(* check file extension. In case of wrong commandline, we don't want
 		to accidentaly delete a source file. *)
@@ -468,6 +472,9 @@ try
 		| Php ->
 			if com.verbose then print_endline ("Generating PHP in : " ^ com.file);
 			Genphp.generate com;
+		| Cpp ->
+			if com.verbose then print_endline ("Generating Cpp in : " ^ com.file);
+			Gencpp.generate com;
 		);
 		(match !xml_out with
 		| None -> ()

+ 1 - 1
optimizer.ml

@@ -280,7 +280,7 @@ let rec reduce_loop com is_sub e =
 	let is_text_platform() =
 		match com.platform with
 		| Js | Php -> true 
-		| Neko | Flash | Flash9 | Cross -> false
+		| Neko | Flash | Flash9 | Cross | Cpp -> false
 	in
 	let e = Type.map_expr (reduce_loop com (match e.eexpr with TBlock _ -> false | _ -> true)) e in
 	match e.eexpr with

+ 1 - 1
typeload.ml

@@ -401,7 +401,7 @@ let set_heritance ctx c herits p =
 			| TInst ({ cl_path = [],"Array" },_)
 			| TInst ({ cl_path = [],"String" },_)
 			| TInst ({ cl_path = [],"Date" },_)
-			| TInst ({ cl_path = [],"Xml" },_) when (match c.cl_path with "mt" :: _ , _ -> false | _ -> true) ->
+			| TInst ({ cl_path = [],"Xml" },_) when ((not (platform ctx.com Cpp)) && (match c.cl_path with "mt" :: _ , _ -> false | _ -> true)) ->
 				error "Cannot extend basic class" p;
 			| TInst (cl,params) ->
 				if is_parent c cl then error "Recursive class" p;

+ 2 - 1
typer.ml

@@ -1750,7 +1750,8 @@ let create com =
 			(match snd td.t_path with
 			| "Null" ->
 				let f9 = platform com Flash9 in
-				ctx.api.tnull <- if not f9 then (fun t -> t) else (fun t -> if is_nullable t then TType (td,[t]) else t);
+				let cpp = platform com Cpp in
+				ctx.api.tnull <- if not (f9 || cpp) then (fun t -> t) else (fun t -> if is_nullable t then TType (td,[t]) else t);
 			| _ -> ());
 	) ctx.std.mtypes;
 	let m = Typeload.load_module ctx ([],"String") null_pos in