Browse Source

Merge branch 'development' into hl

Conflicts:
	.travis.yml
Simon Krajewski 9 years ago
parent
commit
2a0ecd2603
23 changed files with 306 additions and 113 deletions
  1. 1 0
      .gitignore
  2. 5 0
      Makefile
  3. 1 0
      ast.ml
  4. 7 5
      common.ml
  5. BIN
      extra/deploy_key.enc
  6. 49 17
      gencpp.ml
  7. 2 1
      genswf.ml
  8. 1 1
      genxml.ml
  9. 11 0
      interp.ml
  10. 5 0
      main.ml
  11. 5 5
      std/UInt.hx
  12. 7 7
      std/Xml.hx
  13. 5 0
      std/cpp/cppia/HostClasses.hx
  14. 1 1
      std/haxe/crypto/BaseCode.hx
  15. 13 10
      std/haxe/macro/Compiler.hx
  16. 1 1
      std/haxe/macro/ComplexTypeTools.hx
  17. 12 0
      std/haxe/macro/Context.hx
  18. 1 1
      std/js/Lib.hx
  19. 19 4
      tests/RunCi.hx
  20. 16 0
      type.ml
  21. 11 0
      typecore.ml
  22. 3 1
      typeload.ml
  23. 130 59
      typer.ml

+ 1 - 0
.gitignore

@@ -13,6 +13,7 @@
 /extra/*.swc
 /extra/*.swc
 /extra/bintray.json
 /extra/bintray.json
 /extra/git-archive-all
 /extra/git-archive-all
+/extra/deploy_key
 
 
 /version.ml
 /version.ml
 /haxe
 /haxe

+ 5 - 0
Makefile

@@ -220,9 +220,14 @@ install_dox:
 	haxelib git dox https://github.com/dpeek/dox
 	haxelib git dox https://github.com/dpeek/dox
 
 
 package_doc:
 package_doc:
+	mkdir -p $(PACKAGE_OUT_DIR)
 	cd $$(haxelib path dox | head -n 1) && haxe run.hxml && haxe gen.hxml
 	cd $$(haxelib path dox | head -n 1) && haxe run.hxml && haxe gen.hxml
 	haxelib run dox --title "Haxe API" -o $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip -D version "$$(haxe -version 2>&1)" -i $$(haxelib path dox | head -n 1)bin/xml -ex microsoft -ex javax -ex cs.internal -D source-path https://github.com/HaxeFoundation/haxe/blob/$(BRANCH)/std/
 	haxelib run dox --title "Haxe API" -o $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip -D version "$$(haxe -version 2>&1)" -i $$(haxelib path dox | head -n 1)bin/xml -ex microsoft -ex javax -ex cs.internal -D source-path https://github.com/HaxeFoundation/haxe/blob/$(BRANCH)/std/
 
 
+deploy_doc:
+	scp $(PACKAGE_OUT_DIR)/$(PACKAGE_FILE_NAME)_doc.zip [email protected]:/data/haxeapi/www/v/dev/api-latest.zip
+	ssh [email protected] "cd /data/haxeapi/www/v/dev && find . ! -name 'api-latest.zip' -maxdepth 1 -mindepth 1 -exec rm -rf {} + && unzip -q -o api-latest.zip"
+
 # Clean
 # Clean
 
 
 clean: clean_libs clean_haxe clean_tools clean_package
 clean: clean_libs clean_haxe clean_tools clean_package

+ 1 - 0
ast.ml

@@ -160,6 +160,7 @@ module Meta = struct
 		| Strict
 		| Strict
 		| Struct
 		| Struct
 		| StructAccess
 		| StructAccess
+		| StructInit
 		| SuppressWarnings
 		| SuppressWarnings
 		| This
 		| This
 		| Throws
 		| Throws

+ 7 - 5
common.ml

@@ -494,6 +494,7 @@ module MetaInfo = struct
 		| Strict -> ":strict",("Used to declare a native C# attribute or a native Java metadata. Is type checked",[Platforms [Java;Cs]])
 		| Strict -> ":strict",("Used to declare a native C# attribute or a native Java metadata. Is type checked",[Platforms [Java;Cs]])
 		| Struct -> ":struct",("Marks a class definition as a struct",[Platform Cs; UsedOn TClass])
 		| Struct -> ":struct",("Marks a class definition as a struct",[Platform Cs; UsedOn TClass])
 		| StructAccess -> ":structAccess",("Marks an extern class as using struct access('.') not pointer('->')",[Platform Cpp; UsedOn TClass])
 		| StructAccess -> ":structAccess",("Marks an extern class as using struct access('.') not pointer('->')",[Platform Cpp; UsedOn TClass])
+		| StructInit -> ":structInit",("Allows to initialize the class with a structure that matches constructor parameters",[UsedOn TClass])
 		| SuppressWarnings -> ":suppressWarnings",("Adds a SuppressWarnings annotation for the generated Java class",[Platform Java; UsedOn TClass])
 		| SuppressWarnings -> ":suppressWarnings",("Adds a SuppressWarnings annotation for the generated Java class",[Platform Java; UsedOn TClass])
 		| Throws -> ":throws",("Adds a 'throws' declaration to the generated function",[HasParam "Type as String"; Platform Java; UsedOn TClassField])
 		| Throws -> ":throws",("Adds a 'throws' declaration to the generated function",[HasParam "Type as String"; Platform Java; UsedOn TClassField])
 		| This -> ":this",("Internally used to pass a 'this' expression to macros",[Internal; UsedOn TExpr])
 		| This -> ":this",("Internally used to pass a 'this' expression to macros",[Internal; UsedOn TExpr])
@@ -805,12 +806,13 @@ let get_signature com =
 	match com.defines_signature with
 	match com.defines_signature with
 	| Some s -> s
 	| Some s -> s
 	| None ->
 	| None ->
-		let str = String.concat "@" (PMap.foldi (fun k v acc ->
+		let defines = PMap.foldi (fun k v acc ->
 			(* don't make much difference between these special compilation flags *)
 			(* don't make much difference between these special compilation flags *)
-			match k with
-			| "display" | "use_rtti_doc" | "macrotimes" -> acc
-			| _ -> k :: v :: acc
-		) com.defines []) in
+			match String.concat "_" (ExtString.String.nsplit k "-") with
+			| "display" | "use_rtti_doc" | "macro_times" | "display_details" | "no_copt" -> acc
+			| _ -> (k ^ "=" ^ v) :: acc
+		) com.defines [] in
+		let str = String.concat "@" (List.sort compare defines) in
 		let s = Digest.string str in
 		let s = Digest.string str in
 		com.defines_signature <- Some s;
 		com.defines_signature <- Some s;
 		s
 		s

BIN
extra/deploy_key.enc


+ 49 - 17
gencpp.ml

@@ -304,12 +304,53 @@ let hash_iterate hash visitor =
    Hashtbl.iter (fun key value -> result :=  (visitor key value) :: !result ) hash;
    Hashtbl.iter (fun key value -> result :=  (visitor key value) :: !result ) hash;
    !result
    !result
 
 
+
+
+
+
+let is_internal_member member =
+   member = "toString" || (
+      (String.length member > 1) && (String.sub member 0 2 = "__") &&
+         (match member with
+         | "__ArgCount" | "__ArrayImplRef" | "__CStr" | "__Compare" | "__Create"
+         | "__CreateEmpty" | "__FieldRef" | "__FindArgCount"
+         | "__GetFieldMap" | "__GetHandle" | "__GetItem"
+         | "__GetScriptCallable" | "__GetScriptVTable"
+         | "__Param" | "__Remove" | "__SGetClass"
+         | "__Set" | "__SetItem" | "__TArrayImplRef"
+         | "__ToDouble" | "__ToInt" | "__ToInterface" | "__ToObject"
+         | "__Visit" | "__WCStr" | "__a" | "__blit" | "__boot"
+         | "__boot_all" | "__compare" | "__concat" | "__construct" | "__copy"
+         | "__filter" | "__get_args" | "__hx_dump_stack" | "__hx_field_iter" | "__hxt_gc_new"
+         | "__indexOf" | "__insert" | "__instanceof" | "__int" | "__iterator"
+         | "__join" | "__lastIndexOf" | "__loadprim" | "__mClass" | "__mDynamicFields"
+         | "__map" | "__memcmp" | "__new" | "__pop" | "__prime"
+         | "__push" | "__qsort" | "__unshift" | "__unsafeStringReference" | "__time_stamp"
+         | "__superString" | "__splice" | "__shift" | "__slice" | "__sort"
+         | "__s_id" | "__run" | "__root" | "__register" | "__remove"
+         | "__removeAt" | "__reverse" | "__zero" 
+         | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString"
+         | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal"
+         | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "__HasField"
+         | "__get" | "__set" | "__unsafe_get" | "__unsafe_set" | "__global__"
+         | "__SetSize" | "__trace" | "__GetRealObject" | "__SetSizeExact" | "__cpp__"
+         | "__URLEncode" | "__URLDecode" | "__IsEnum"
+               -> true
+         | _ -> false) );;
+      
+let is_known_member member =
+   match member with
+   | "__meta__" | "__rtti" | "_Compare"
+         -> true
+   | _ -> false;;
+
 (* Convert function names that can't be written in c++ ... *)
 (* Convert function names that can't be written in c++ ... *)
 let keyword_remap name =
 let keyword_remap name =
-   match name with
-   | "__get" | "__set" | "__unsafe_get" | "__unsafe_set" | "__global__"
-   |   "__SetSize" | "__s" | "__trace" -> name
-   (* | _ when (String.length name > 1) && (String.sub name 0 2 = "__") -> "_hx" ^ name *)
+   if (is_internal_member name) || (is_known_member name) then
+      name
+   else if (String.length name > 1) && (String.sub name 0 2 = "__") then
+      "_hx_" ^ name 
+   else match name with
    | "int"
    | "int"
    | "auto" | "char" | "const" | "delete" | "double" | "Float" | "enum"
    | "auto" | "char" | "const" | "delete" | "double" | "Float" | "enum"
    | "extern" | "float" | "friend" | "goto" | "long" | "operator" | "protected"
    | "extern" | "float" | "friend" | "goto" | "long" | "operator" | "protected"
@@ -890,16 +931,6 @@ let should_implement_field x = not (is_extern_field x);;
 let is_function_member expression =
 let is_function_member expression =
    match (follow expression.etype) with | TFun (_,_) -> true | _ -> false;;
    match (follow expression.etype) with | TFun (_,_) -> true | _ -> false;;
 
 
-let is_internal_member member =
-   match member with
-   | "__Field" | "__IField" | "__Run" | "__Is" | "__GetClass" | "__GetType" | "__ToString"
-   | "__s" | "__GetPtr" | "__SetField" | "__length" | "__IsArray" | "__SetThis" | "__Internal"
-   | "__EnumParams" | "__Index" | "__Tag" | "__GetFields" | "toString" | "__HasField"
-   | "__GetRealObject"
-         -> true
-   | _ -> false;;
-
-
 let is_extern_class class_def =
 let is_extern_class class_def =
    class_def.cl_extern || (has_meta_key class_def.cl_meta Meta.Extern) ||
    class_def.cl_extern || (has_meta_key class_def.cl_meta Meta.Extern) ||
       (match class_def.cl_kind with
       (match class_def.cl_kind with
@@ -1400,7 +1431,7 @@ and is_dynamic_member_return_in_cpp ctx field_object field =
    if (is_internal_member member) then false else
    if (is_internal_member member) then false else
    match field_object.eexpr with
    match field_object.eexpr with
    | TTypeExpr t ->
    | TTypeExpr t ->
-         let full_name = "::" ^ (join_class_path (t_path t) "::" ) ^ "." ^ member in
+         let full_name = "::" ^ (join_class_path_remap (t_path t) "::" ) ^ "." ^ member in
          ctx.ctx_dbgout ("/*static:"^ full_name^"*/");
          ctx.ctx_dbgout ("/*static:"^ full_name^"*/");
          ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in
          ( try ( let mem_type = (Hashtbl.find ctx.ctx_class_member_types full_name) in
              mem_type="Dynamic" || mem_type="cpp::ArrayBase" || mem_type="cpp::VirtualArray" )
              mem_type="Dynamic" || mem_type="cpp::ArrayBase" || mem_type="cpp::VirtualArray" )
@@ -1574,6 +1605,7 @@ let gen_expression_tree ctx retval expression_tree set_var tail_code =
 
 
 
 
       let pop_real_this_ptr = clear_real_this_ptr ctx true in
       let pop_real_this_ptr = clear_real_this_ptr ctx true in
+      ctx.ctx_real_void <- false;
 
 
       writer#begin_block;
       writer#begin_block;
       if (ctx.ctx_debug_level>0) then begin
       if (ctx.ctx_debug_level>0) then begin
@@ -5305,7 +5337,7 @@ class script_writer common_ctx ctx filename asciiOut =
          | TField (obj,FInstance (_,_,field) ) when is_super obj ->
          | TField (obj,FInstance (_,_,field) ) when is_super obj ->
                   this#write ( (this#op IaCallSuper) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^
                   this#write ( (this#op IaCallSuper) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^
                      argN ^ "\n");
                      argN ^ "\n");
-         | TField (obj,FInstance (_,_,field) ) when is_real_function field ->
+         | TField (obj,FInstance (_,_,field) ) when not (is_dynamic_in_cppia ctx obj) && is_real_function field ->
                   this#write ( (this#op IaCallMember) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^
                   this#write ( (this#op IaCallMember) ^ (this#typeText obj.etype) ^ " " ^ (this#stringText field.cf_name) ^
                      argN ^ "\n");
                      argN ^ "\n");
                   this#gen_expression obj;
                   this#gen_expression obj;
@@ -5349,7 +5381,7 @@ class script_writer common_ctx ctx filename asciiOut =
          | _ -> gen_call();
          | _ -> gen_call();
       );
       );
    | TField (obj, acc) ->
    | TField (obj, acc) ->
-      let typeText = this#typeText obj.etype in
+      let typeText = if is_dynamic_in_cppia ctx obj then this#typeTextString "Dynamic" else this#typeText obj.etype in
       (match acc with
       (match acc with
       | FDynamic name -> this#write ( (this#op IaFName) ^ typeText ^ " " ^ (this#stringText name) ^ "\n");
       | FDynamic name -> this#write ( (this#op IaFName) ^ typeText ^ " " ^ (this#stringText name) ^ "\n");
             this#gen_expression obj;
             this#gen_expression obj;

+ 2 - 1
genswf.ml

@@ -1111,6 +1111,7 @@ let generate swf_header com =
 	let tags = build_swf9 com file swc in
 	let tags = build_swf9 com file swc in
 	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
 	let header, bg = (match swf_header with None -> default_header com | Some h -> convert_header com h) in
 	let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in
 	let bg = tag (TSetBgColor { cr = bg lsr 16; cg = (bg lsr 8) land 0xFF; cb = bg land 0xFF }) in
+	let scene = tag ~ext:true (TScenes ([(0,"Scene1")],[])) in
 	let swf_debug_password = try
 	let swf_debug_password = try
 		Digest.to_hex(Digest.string (Common.defined_value com Define.SwfDebugPassword))
 		Digest.to_hex(Digest.string (Common.defined_value com Define.SwfDebugPassword))
 	with Not_found ->
 	with Not_found ->
@@ -1143,7 +1144,7 @@ let generate swf_header com =
 	with Not_found ->
 	with Not_found ->
 		[]
 		[]
 	in
 	in
-	let swf = header, fattr @ meta_data @ bg :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in
+	let swf = header, fattr @ meta_data @ bg :: scene :: debug @ swf_script_limits @ tags @ [tag TShowFrame] in
 	(* merge swf libraries *)
 	(* merge swf libraries *)
 	let priority = ref (swf_header = None) in
 	let priority = ref (swf_header = None) in
 	let swf = List.fold_left (fun swf (file,lib,cl) ->
 	let swf = List.fold_left (fun swf (file,lib,cl) ->

+ 1 - 1
genxml.ml

@@ -502,7 +502,7 @@ let generate_type com t =
 		) in
 		) in
 		let ext = (match c.cl_path with
 		let ext = (match c.cl_path with
 			| ["flash";"utils"], "ByteArray" -> " implements ArrayAccess<Int>" :: ext
 			| ["flash";"utils"], "ByteArray" -> " implements ArrayAccess<Int>" :: ext
-			| ["flash";"utils"], "Dictionnary" -> [" implements ArrayAccess<Dynamic>"]
+			| ["flash";"utils"], "Dictionary" -> [" implements ArrayAccess<Dynamic>"]
 			| ["flash";"xml"], "XML" -> [" implements Dynamic<XMLList>"]
 			| ["flash";"xml"], "XML" -> [" implements Dynamic<XMLList>"]
 			| ["flash";"xml"], "XMLList" -> [" implements ArrayAccess<XML>"]
 			| ["flash";"xml"], "XMLList" -> [" implements ArrayAccess<XML>"]
 			| ["flash";"display"],"MovieClip" -> [" extends Sprite #if !flash_strict implements Dynamic #end"]
 			| ["flash";"display"],"MovieClip" -> [" extends Sprite #if !flash_strict implements Dynamic #end"]

+ 11 - 0
interp.ml

@@ -103,6 +103,7 @@ type extern_api = {
 	on_type_not_found : (string -> value) -> unit;
 	on_type_not_found : (string -> value) -> unit;
 	parse_string : string -> Ast.pos -> bool -> Ast.expr;
 	parse_string : string -> Ast.pos -> bool -> Ast.expr;
 	type_expr : Ast.expr -> Type.texpr;
 	type_expr : Ast.expr -> Type.texpr;
+	resolve_type  : Ast.complex_type -> Ast.pos -> t;
 	type_macro_expr : Ast.expr -> Type.texpr;
 	type_macro_expr : Ast.expr -> Type.texpr;
 	store_typed_expr : Type.texpr -> Ast.expr;
 	store_typed_expr : Type.texpr -> Ast.expr;
 	get_display : string -> string;
 	get_display : string -> string;
@@ -196,6 +197,8 @@ exception Sys_exit of int
 
 
 let get_ctx_ref = ref (fun() -> assert false)
 let get_ctx_ref = ref (fun() -> assert false)
 let encode_complex_type_ref = ref (fun t -> assert false)
 let encode_complex_type_ref = ref (fun t -> assert false)
+let decode_complex_type_ref = ref (fun t -> assert false)
+let decode_pos_ref = ref (fun v -> assert false)
 let encode_type_ref = ref (fun t -> assert false)
 let encode_type_ref = ref (fun t -> assert false)
 let decode_type_ref = ref (fun t -> assert false)
 let decode_type_ref = ref (fun t -> assert false)
 let encode_expr_ref = ref (fun e -> assert false)
 let encode_expr_ref = ref (fun e -> assert false)
@@ -215,7 +218,10 @@ let eval_expr_ref : (context -> texpr -> value option) ref = ref (fun _ _ -> ass
 let get_ctx() = (!get_ctx_ref)()
 let get_ctx() = (!get_ctx_ref)()
 let enc_array (l:value list) : value = (!enc_array_ref) l
 let enc_array (l:value list) : value = (!enc_array_ref) l
 let dec_array (l:value) : value list = (!dec_array_ref) l
 let dec_array (l:value) : value list = (!dec_array_ref) l
+
+let decode_complex_type (v:value) : Ast.complex_type = (!decode_complex_type_ref) v
 let encode_complex_type (t:Ast.complex_type) : value = (!encode_complex_type_ref) t
 let encode_complex_type (t:Ast.complex_type) : value = (!encode_complex_type_ref) t
+let decode_pos (v:value) : Ast.pos = (!decode_pos_ref) v
 let encode_type (t:Type.t) : value = (!encode_type_ref) t
 let encode_type (t:Type.t) : value = (!encode_type_ref) t
 let decode_type (v:value) : Type.t = (!decode_type_ref) v
 let decode_type (v:value) : Type.t = (!decode_type_ref) v
 let encode_expr (e:Ast.expr) : value = (!encode_expr_ref) e
 let encode_expr (e:Ast.expr) : value = (!encode_expr_ref) e
@@ -2428,6 +2434,9 @@ let macro_lib =
 		"type_expr", Fun1 (fun v ->
 		"type_expr", Fun1 (fun v ->
 			encode_texpr ((get_ctx()).curapi.type_expr (decode_expr v))
 			encode_texpr ((get_ctx()).curapi.type_expr (decode_expr v))
 		);
 		);
+		"resolve_type", Fun2 (fun t p ->
+			encode_type ((get_ctx()).curapi.resolve_type (decode_complex_type t) (decode_pos p));
+		);
 		"s_type", Fun1 (fun v ->
 		"s_type", Fun1 (fun v ->
 			VString (Type.s_type (print_context()) (decode_type v))
 			VString (Type.s_type (print_context()) (decode_type v))
 		);
 		);
@@ -5036,6 +5045,8 @@ let rec make_const e =
 
 
 ;;
 ;;
 encode_complex_type_ref := encode_ctype;
 encode_complex_type_ref := encode_ctype;
+decode_complex_type_ref := decode_ctype;
+decode_pos_ref := decode_pos;
 enc_array_ref := enc_array;
 enc_array_ref := enc_array;
 dec_array_ref := dec_array;
 dec_array_ref := dec_array;
 encode_type_ref := encode_type;
 encode_type_ref := encode_type;

+ 5 - 0
main.ml

@@ -875,6 +875,11 @@ and wait_loop boot_com host port =
 				if ctx.has_error then ssend sin "\x02\n" else cache_context ctx.com;
 				if ctx.has_error then ssend sin "\x02\n" else cache_context ctx.com;
 			);
 			);
 			ctx.setup <- (fun() ->
 			ctx.setup <- (fun() ->
+				if verbose then begin
+					let defines = PMap.foldi (fun k v acc -> (k ^ "=" ^ v) :: acc) ctx.com.defines [] in
+					print_endline ("Defines " ^ (String.concat "," (List.sort compare defines)));
+					print_endline ("Using signature " ^ Digest.to_hex (get_signature ctx.com));
+				end;
 				Parser.display_error := (fun e p -> has_parse_error := true; ctx.com.error (Parser.error_msg e) p);
 				Parser.display_error := (fun e p -> has_parse_error := true; ctx.com.error (Parser.error_msg e) p);
 				if ctx.com.display <> DMNone then begin
 				if ctx.com.display <> DMNone then begin
 					let file = (!Parser.resume_display).Ast.pfile in
 					let file = (!Parser.resume_display).Ast.pfile in

+ 5 - 5
std/UInt.hx

@@ -202,12 +202,12 @@ abstract UInt(Int) from Int to Int {
 	}
 	}
 
 
 	@:commutative @:op(A == B) private static inline function equalsFloat<T:Float>(a:UInt, b:T):Bool {
 	@:commutative @:op(A == B) private static inline function equalsFloat<T:Float>(a:UInt, b:T):Bool {
-        return a.toFloat() == b;
-    }
+		return a.toFloat() == b;
+	}
 
 
-    @:commutative @:op(A != B) private static inline function notEqualsFloat<T:Float>(a:UInt, b:T):Bool {
-        return a.toFloat() != b;
-    }
+	@:commutative @:op(A != B) private static inline function notEqualsFloat<T:Float>(a:UInt, b:T):Bool {
+		return a.toFloat() != b;
+	}
 
 
 	@:op(A >= B) private static inline function gteFloat(a:UInt, b:Float):Bool {
 	@:op(A >= B) private static inline function gteFloat(a:UInt, b:Float):Bool {
 		return a.toFloat() >= b;
 		return a.toFloat() >= b;

+ 7 - 7
std/Xml.hx

@@ -122,28 +122,28 @@ class Xml {
 	var children:Array<Xml>;
 	var children:Array<Xml>;
 	var attributeMap:Map<String, String>;
 	var attributeMap:Map<String, String>;
 
 
-	inline function get_nodeName() {
+	#if !cppia inline #end function get_nodeName() {
 		if (nodeType != Element) {
 		if (nodeType != Element) {
 			throw 'Bad node type, expected Element but found $nodeType';
 			throw 'Bad node type, expected Element but found $nodeType';
 		}
 		}
 		return nodeName;
 		return nodeName;
 	}
 	}
 
 
-	inline function set_nodeName(v) {
+	#if !cppia inline #end function set_nodeName(v) {
 		if (nodeType != Element) {
 		if (nodeType != Element) {
 			throw 'Bad node type, expected Element but found $nodeType';
 			throw 'Bad node type, expected Element but found $nodeType';
 		}
 		}
 		return this.nodeName = v;
 		return this.nodeName = v;
 	}
 	}
 
 
-	inline function get_nodeValue() {
+	#if !cppia inline #end function get_nodeValue() {
 		if (nodeType == Document || nodeType == Element) {
 		if (nodeType == Document || nodeType == Element) {
 			throw 'Bad node type, unexpected $nodeType';
 			throw 'Bad node type, unexpected $nodeType';
 		}
 		}
 		return nodeValue;
 		return nodeValue;
 	}
 	}
 
 
-	inline function set_nodeValue(v) {
+	#if !cppia inline #end function set_nodeValue(v) {
 		if (nodeType == Document || nodeType == Element) {
 		if (nodeType == Document || nodeType == Element) {
 			throw 'Bad node type, unexpected $nodeType';
 			throw 'Bad node type, unexpected $nodeType';
 		}
 		}
@@ -269,7 +269,7 @@ class Xml {
 		Returns an iterator of all child nodes.
 		Returns an iterator of all child nodes.
 		Only works if the current node is an Element or a Document.
 		Only works if the current node is an Element or a Document.
 	**/
 	**/
-	public inline function iterator() : Iterator<Xml> {
+	public #if !cppia inline #end function iterator() : Iterator<Xml> {
 		ensureElementType();
 		ensureElementType();
 		return children.iterator();
 		return children.iterator();
 	}
 	}
@@ -297,7 +297,7 @@ class Xml {
 	/**
 	/**
 		Returns the first child node.
 		Returns the first child node.
 	**/
 	**/
-	public inline function firstChild() : Xml {
+	public #if !cppia inline #end function firstChild() : Xml {
 		ensureElementType();
 		ensureElementType();
 		return children[0];
 		return children[0];
 	}
 	}
@@ -361,7 +361,7 @@ class Xml {
 	/**
 	/**
 		Returns a String representation of the Xml node.
 		Returns a String representation of the Xml node.
 	**/
 	**/
-	public inline function toString() : String {
+	public #if !cppia inline #end function toString() : String {
 		return haxe.xml.Printer.print(this);
 		return haxe.xml.Printer.print(this);
 	}
 	}
 
 

+ 5 - 0
std/cpp/cppia/HostClasses.hx

@@ -72,6 +72,7 @@ class HostClasses
    "Type",
    "Type",
    "Xml",
    "Xml",
    "Date",
    "Date",
+   "Lambda",
    "DateTools",
    "DateTools",
    "List",
    "List",
    "Math",
    "Math",
@@ -82,6 +83,7 @@ class HostClasses
    "haxe.ds.IntMap",
    "haxe.ds.IntMap",
    "haxe.ds.ObjectMap",
    "haxe.ds.ObjectMap",
    "haxe.ds.StringMap",
    "haxe.ds.StringMap",
+   "haxe.ds.BalancedTree",
    "haxe.CallStack",
    "haxe.CallStack",
    "haxe.Serializer",
    "haxe.Serializer",
    "haxe.Unserializer",
    "haxe.Unserializer",
@@ -184,6 +186,9 @@ class HostClasses
       externs.set("haxe._Int64.___Int64",true);
       externs.set("haxe._Int64.___Int64",true);
       externs.set("haxe._Int32.Int32_Impl_",true);
       externs.set("haxe._Int32.Int32_Impl_",true);
       externs.set("haxe._Int32.___Int32",true);
       externs.set("haxe._Int32.___Int32",true);
+      // Hidded in implementation classes
+      externs.set("haxe.ds.TreeNode",true);
+      externs.set("haxe.xml.XmlParserException",true);
       for(e in classes)
       for(e in classes)
          externs.set(e,true);
          externs.set(e,true);
 
 

+ 1 - 1
std/haxe/crypto/BaseCode.hx

@@ -22,7 +22,7 @@
 package haxe.crypto;
 package haxe.crypto;
 
 
 /**
 /**
-	Allows to encode/decode String and bytes using a power of two base dictionnary.
+	Allows to encode/decode String and bytes using a power of two base dictionary.
 **/
 **/
 class BaseCode {
 class BaseCode {
 
 

+ 13 - 10
std/haxe/macro/Compiler.hx

@@ -63,7 +63,7 @@ class Compiler {
 
 
 	/**
 	/**
 		Removes a (static) field from a given class by name.
 		Removes a (static) field from a given class by name.
-		An error is thrown when className or field is invalid.
+		An error is thrown when `className` or `field` is invalid.
 	**/
 	**/
 	public static function removeField( className : String, field : String, ?isStatic : Bool ) {
 	public static function removeField( className : String, field : String, ?isStatic : Bool ) {
 		if( !path.match(className) ) throw "Invalid "+className;
 		if( !path.match(className) ) throw "Invalid "+className;
@@ -73,7 +73,7 @@ class Compiler {
 
 
 	/**
 	/**
 		Set the type of a (static) field at a given class by name.
 		Set the type of a (static) field at a given class by name.
-		An error is thrown when className or field is invalid.
+		An error is thrown when `className` or `field` is invalid.
 	**/
 	**/
 	public static function setFieldType( className : String, field : String, type : String, ?isStatic : Bool ) {
 	public static function setFieldType( className : String, field : String, type : String, ?isStatic : Bool ) {
 		if( !path.match(className) ) throw "Invalid "+className;
 		if( !path.match(className) ) throw "Invalid "+className;
@@ -83,7 +83,7 @@ class Compiler {
 
 
 	/**
 	/**
 		Add metadata to a (static) field or class by name.
 		Add metadata to a (static) field or class by name.
-		An error is thrown when className or field is invalid.
+		An error is thrown when `className` or `field` is invalid.
 	**/
 	**/
 	public static function addMetadata( meta : String, className : String, ?field : String, ?isStatic : Bool ) {
 	public static function addMetadata( meta : String, className : String, ?field : String, ?isStatic : Bool ) {
 		if( !path.match(className) ) throw "Invalid "+className;
 		if( !path.match(className) ) throw "Invalid "+className;
@@ -111,14 +111,14 @@ class Compiler {
 	}
 	}
 
 
 	/**
 	/**
-		Adds a native library depending on the platform (e.g. `-swf-lib` for Flash)
+		Adds a native library depending on the platform (e.g. `-swf-lib` for Flash).
 	**/
 	**/
 	public static function addNativeLib( name : String ) {
 	public static function addNativeLib( name : String ) {
 		untyped load("add_native_lib",1)(name.__s);
 		untyped load("add_native_lib",1)(name.__s);
 	}
 	}
 
 
 	/**
 	/**
-		Adds an argument to be passed to the native compiler (e.g. `-javac-arg` for Java)
+		Adds an argument to be passed to the native compiler (e.g. `-javac-arg` for Java).
 	 **/
 	 **/
 	public static function addNativeArg( argument : String )
 	public static function addNativeArg( argument : String )
 	{
 	{
@@ -183,7 +183,7 @@ class Compiler {
 	}
 	}
 
 
 	/**
 	/**
-		Exclude a class or a enum without changing it to @:nativeGen.
+		Exclude a class or an enum without changing it to `@:nativeGen`.
 	**/
 	**/
 	static function excludeBaseType( baseType : Type.BaseType ) : Void {
 	static function excludeBaseType( baseType : Type.BaseType ) : Void {
 		if (!baseType.isExtern) {
 		if (!baseType.isExtern) {
@@ -196,7 +196,10 @@ class Compiler {
 	}
 	}
 
 
 	/**
 	/**
-		Exclude a given class or a complete package from being generated.
+		Exclude a specific class, enum, or all classes and enums in a
+		package from being generated. Excluded types become `extern`.
+		
+		@param rec If true, recursively excludes all sub-packages.
 	**/
 	**/
 	public static function exclude( pack : String, ?rec = true ) {
 	public static function exclude( pack : String, ?rec = true ) {
 		Context.onGenerate(function(types) {
 		Context.onGenerate(function(types) {
@@ -219,7 +222,7 @@ class Compiler {
 	}
 	}
 
 
 	/**
 	/**
-		Exclude classes listed in an extern file (one per line) from being generated.
+		Exclude classes and enums listed in an extern file (one per line) from being generated.
 	**/
 	**/
 	public static function excludeFile( fileName : String ) {
 	public static function excludeFile( fileName : String ) {
 		fileName = Context.resolvePath(fileName);
 		fileName = Context.resolvePath(fileName);
@@ -246,7 +249,7 @@ class Compiler {
 	}
 	}
 
 
 	/**
 	/**
-		Load a type patch file that can modify declared classes fields types
+		Load a type patch file that can modify the field types within declared classes and enums.
 	**/
 	**/
 	public static function patchTypes( file : String ) : Void {
 	public static function patchTypes( file : String ) : Void {
 		var file = Context.resolvePath(file);
 		var file = Context.resolvePath(file);
@@ -303,7 +306,7 @@ class Compiler {
 
 
 		In order to include module sub-types directly, their full dot path
 		In order to include module sub-types directly, their full dot path
 		including the containing module has to be used
 		including the containing module has to be used
-		(e.g. msignal.Signal.Signal0).
+		(e.g. `msignal.Signal.Signal0`).
 
 
 		This operation has no effect if the type has already been loaded, e.g.
 		This operation has no effect if the type has already been loaded, e.g.
 		through `Context.getType`.
 		through `Context.getType`.

+ 1 - 1
std/haxe/macro/ComplexTypeTools.hx

@@ -48,7 +48,7 @@ class ComplexTypeTools {
 		If [c] is null, the result is null.
 		If [c] is null, the result is null.
 	**/
 	**/
 	static public function toType( c : ComplexType ) : Null<Type>
 	static public function toType( c : ComplexType ) : Null<Type>
-		return c == null ? null : haxe.macro.Context.typeof( { expr: ECheckType(macro null, c), pos: Context.currentPos() } );
+		return c == null ? null : Context.resolveType(c,Context.currentPos());
 
 
 	#end
 	#end
 }
 }

+ 12 - 0
std/haxe/macro/Context.hx

@@ -368,6 +368,18 @@ class Context {
 		return load("type_expr", 1)(e);
 		return load("type_expr", 1)(e);
 	}
 	}
 
 
+	/**
+		Resolve type `t` and returns the corresponding `Type`.
+
+		Resolving the type may result in a compiler error which can be
+		caught using `try ... catch`.
+		Resolution is performed based on the current context in which the macro is called.
+	**/
+	@:require(haxe_ver >= 3.3)
+	public static function resolveType( t : ComplexType, p : Position ) : Type {
+		return load("resolve_type", 2)(t,p);
+	}
+	
 	/**
 	/**
 		Returns the `ComplexType` corresponding to the given `Type` `t`.
 		Returns the `ComplexType` corresponding to the given `Type` `t`.
 
 

+ 1 - 1
std/js/Lib.hx

@@ -50,7 +50,7 @@ class Lib {
 		This is only supported in environments where `require` function
 		This is only supported in environments where `require` function
 		is available, such as Node.js or RequireJS.
 		is available, such as Node.js or RequireJS.
 	**/
 	**/
-	public static inline function require( module:String ) : Dynamic {
+	@:extern public static inline function require( module:String ) : Dynamic {
 		return untyped __js__("require")(module);
 		return untyped __js__("require")(module);
 	}
 	}
 
 

+ 19 - 4
tests/RunCi.hx

@@ -64,21 +64,22 @@ class RunCi {
 		If `useRetry` is `true`, the command will be re-run if it exits with non-zero code (3 trials).
 		If `useRetry` is `true`, the command will be re-run if it exits with non-zero code (3 trials).
 		It is useful for running network-dependent commands.
 		It is useful for running network-dependent commands.
 	*/
 	*/
-	static function runCommand(cmd:String, args:Array<String>, useRetry:Bool = false):Void {
+	static function runCommand(cmd:String, ?args:Array<String>, useRetry:Bool = false):Void {
 		var trials = useRetry ? 3 : 1;
 		var trials = useRetry ? 3 : 1;
 		var exitCode:Int = 1;
 		var exitCode:Int = 1;
+		var cmdStr = cmd + (args == null ? '' : ' $args');
 
 
 		while (trials-->0) {
 		while (trials-->0) {
-			Sys.println('Command: $cmd $args');
+			Sys.println('Command: $cmdStr');
 
 
 			var t = Timer.stamp();
 			var t = Timer.stamp();
 			exitCode = Sys.command(cmd, args);
 			exitCode = Sys.command(cmd, args);
 			var dt = Math.round(Timer.stamp() - t);
 			var dt = Math.round(Timer.stamp() - t);
 
 
 			if (exitCode == 0)
 			if (exitCode == 0)
-				successMsg('Command exited with $exitCode in ${dt}s: $cmd $args');
+				successMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
 			else
 			else
-				failMsg('Command exited with $exitCode in ${dt}s: $cmd $args');
+				failMsg('Command exited with $exitCode in ${dt}s: $cmdStr');
 
 
 			if (exitCode == 0) {
 			if (exitCode == 0) {
 				return;
 				return;
@@ -627,6 +628,20 @@ class RunCi {
 			// generate doc
 			// generate doc
 			runCommand("make", ["-s", "install_dox"]);
 			runCommand("make", ["-s", "install_dox"]);
 			runCommand("make", ["-s", "package_doc"]);
 			runCommand("make", ["-s", "package_doc"]);
+
+			// deploy doc to api.haxe.org
+			if (
+				gitInfo.branch == "development" && 
+				Sys.getEnv("DEPLOY") != null && 
+				Sys.getEnv("deploy_key_decrypt") != null
+			) {
+				//setup deploy_key
+				runCommand("openssl aes-256-cbc -k \"$deploy_key_decrypt\" -in extra/deploy_key.enc -out extra/deploy_key -d");
+				runCommand("chmod 600 extra/deploy_key");
+				runCommand("ssh-add extra/deploy_key");
+
+				runCommand("make", ["-s", "deploy_doc"]);
+			}
 		}
 		}
 	}
 	}
 
 

+ 16 - 0
type.ml

@@ -500,6 +500,22 @@ let map loop t =
 	| TDynamic t2 ->
 	| TDynamic t2 ->
 		if t == t2 then	t else TDynamic (loop t2)
 		if t == t2 then	t else TDynamic (loop t2)
 
 
+let dup t =
+	let monos = ref [] in
+	let rec loop t =
+		match t with
+		| TMono { contents = None } ->
+			(try
+				List.assq t !monos
+			with Not_found ->
+				let m = mk_mono() in
+				monos := (t,m) :: !monos;
+				m)
+		| _ ->
+			map loop t
+	in
+	loop t
+
 (* substitute parameters with other types *)
 (* substitute parameters with other types *)
 let apply_params cparams params t =
 let apply_params cparams params t =
 	match cparams with
 	match cparams with

+ 11 - 0
typecore.ml

@@ -365,6 +365,17 @@ let delay ctx p f =
 	in
 	in
 	ctx.g.delayed <- loop ctx.g.delayed
 	ctx.g.delayed <- loop ctx.g.delayed
 
 
+let delay_late ctx p f =
+	let rec loop = function
+		| [] -> [p,[f]]
+		| (p2,l) :: rest ->
+			if p2 <= p then
+				(p2,l) :: loop rest
+			else
+				(p,[f]) :: (p2,l) :: rest
+	in
+	ctx.g.delayed <- loop ctx.g.delayed
+
 let rec flush_pass ctx p (where:string) =
 let rec flush_pass ctx p (where:string) =
 	match ctx.g.delayed with
 	match ctx.g.delayed with
 	| (p2,l) :: rest when p2 <= p ->
 	| (p2,l) :: rest when p2 <= p ->

+ 3 - 1
typeload.ml

@@ -91,6 +91,8 @@ let module_pass_1 com m tdecls loadp =
 			let priv = List.mem HPrivate d.d_flags in
 			let priv = List.mem HPrivate d.d_flags in
 			let path = make_path d.d_name priv in
 			let path = make_path d.d_name priv in
 			let c = mk_class m path p in
 			let c = mk_class m path p in
+			(* we shouldn't load any other type until we propertly set cl_build *)
+			c.cl_build <- (fun() -> assert false);
 			c.cl_module <- m;
 			c.cl_module <- m;
 			c.cl_private <- priv;
 			c.cl_private <- priv;
 			c.cl_doc <- d.d_doc;
 			c.cl_doc <- d.d_doc;
@@ -2957,7 +2959,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 				true;
 				true;
 			with Exit ->
 			with Exit ->
 				c.cl_build <- make_pass ctx build;
 				c.cl_build <- make_pass ctx build;
-				delay ctx PTypeField (fun() -> ignore(c.cl_build())); (* delay after PBuildClass, not very good but better than forgotten *)
+				delay_late ctx PBuildClass (fun() -> ignore(c.cl_build()));
 				false
 				false
 			| exn ->
 			| exn ->
 				c.cl_build <- (fun()-> true);
 				c.cl_build <- (fun()-> true);

+ 130 - 59
typer.ml

@@ -62,6 +62,11 @@ type access_kind =
 	| AKUsing of texpr * tclass * tclass_field * texpr
 	| AKUsing of texpr * tclass * tclass_field * texpr
 	| AKAccess of tabstract * tparams * tclass * texpr * texpr
 	| AKAccess of tabstract * tparams * tclass * texpr * texpr
 
 
+type object_decl_kind =
+	| ODKWithStructure of tanon
+	| ODKWithClass of tclass * tparams
+	| ODKPlain
+
 let build_call_ref : (typer -> access_kind -> expr list -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
 let build_call_ref : (typer -> access_kind -> expr list -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
 
 
 let mk_infos ctx p params =
 let mk_infos ctx p params =
@@ -133,6 +138,20 @@ let get_iterable_param t =
 			raise Not_found)
 			raise Not_found)
 	| _ -> raise Not_found
 	| _ -> raise Not_found
 
 
+let get_abstract_froms a pl =
+	let l = List.map (apply_params a.a_params pl) a.a_from in
+	List.fold_left (fun acc (t,f) ->
+		match follow (field_type f) with
+		| TFun ([_,_,v],t) ->
+			(try
+				ignore(type_eq EqStrict t (TAbstract(a,List.map dup pl))); (* unify fields monomorphs *)
+				v :: acc
+			with Unify_error _ ->
+				acc)
+		| _ ->
+			acc
+	) l a.a_from_field
+
 (*
 (*
 	temporally remove the constant flag from structures to allow larger unification
 	temporally remove the constant flag from structures to allow larger unification
 *)
 *)
@@ -3026,52 +3045,39 @@ and type_expr ctx (e,p) (with_type:with_type) =
 		let dynamic_parameter = ref None in
 		let dynamic_parameter = ref None in
 		let a = (match with_type with
 		let a = (match with_type with
 		| WithType t ->
 		| WithType t ->
-			(match follow t with
-			| TAnon a when not (PMap.is_empty a.a_fields) -> Some a
-			(* issues with https://github.com/HaxeFoundation/haxe/issues/3437 *)
-(* 			| TAbstract (a,tl) when not (Meta.has Meta.CoreType a.a_meta) && a.a_from <> [] ->
-				begin match follow (Abstract.get_underlying_type a tl) with
-					| TAnon a when not (PMap.is_empty a.a_fields) -> Some a
-					| _ -> None
-				end *)
-			| TDynamic t when (follow t != t_dynamic) ->
-				dynamic_parameter := Some t;
-				Some {
-					a_status = ref Closed;
-					a_fields = PMap.empty;
-				}
-			| _ -> None)
-		| _ -> None
+			let rec loop t =
+				match follow t with
+				| TAnon a when not (PMap.is_empty a.a_fields) -> ODKWithStructure a
+				| TAbstract (a,pl) when not (Meta.has Meta.CoreType a.a_meta) ->
+					(match List.fold_left (fun acc t -> match loop t with ODKPlain -> acc | t -> t :: acc) [] (get_abstract_froms a pl) with
+					| [t] -> t
+					| _ -> ODKPlain)
+				| TDynamic t when (follow t != t_dynamic) ->
+					dynamic_parameter := Some t;
+					ODKWithStructure {
+						a_status = ref Closed;
+						a_fields = PMap.empty;
+					}
+				| TInst(c,tl) when Meta.has Meta.StructInit c.cl_meta ->
+					ODKWithClass(c,tl)
+				| _ ->
+					ODKPlain
+			in
+			loop t
+		| _ ->
+			ODKPlain
 		) in
 		) in
 		let wrap_quoted_meta e =
 		let wrap_quoted_meta e =
 			mk (TMeta((Meta.QuotedField,[],e.epos),e)) e.etype e.epos
 			mk (TMeta((Meta.QuotedField,[],e.epos),e)) e.etype e.epos
 		in
 		in
-		(match a with
-		| None ->
-			let rec loop (l,acc) (f,e) =
-				let f,is_quoted,is_valid = Parser.unquote_ident f in
-				if PMap.mem f acc then error ("Duplicate field in object declaration : " ^ f) p;
-				let e = type_expr ctx e Value in
-				(match follow e.etype with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
-				let cf = mk_field f e.etype e.epos in
-				let e = if is_quoted then wrap_quoted_meta e else e in
-				((f,e) :: l, if is_valid then begin
-					if String.length f > 0 && f.[0] = '$' then error "Field names starting with a dollar are not allowed" p;
-					PMap.add f cf acc
-				end else acc)
-			in
-			let fields , types = List.fold_left loop ([],PMap.empty) fl in
-			let x = ref Const in
-			ctx.opened <- x :: ctx.opened;
-			mk (TObjectDecl (List.rev fields)) (TAnon { a_fields = types; a_status = x }) p
-		| Some a ->
+		let type_fields field_map =
 			let fields = ref PMap.empty in
 			let fields = ref PMap.empty in
 			let extra_fields = ref [] in
 			let extra_fields = ref [] in
 			let fl = List.map (fun (n, e) ->
 			let fl = List.map (fun (n, e) ->
 				let n,is_quoted,is_valid = Parser.unquote_ident n in
 				let n,is_quoted,is_valid = Parser.unquote_ident n in
 				if PMap.mem n !fields then error ("Duplicate field in object declaration : " ^ n) p;
 				if PMap.mem n !fields then error ("Duplicate field in object declaration : " ^ n) p;
 				let e = try
 				let e = try
-					let t = (match !dynamic_parameter with Some t -> t | None -> (PMap.find n a.a_fields).cf_type) in
+					let t = (match !dynamic_parameter with Some t -> t | None -> (PMap.find n field_map).cf_type) in
 					let e = type_expr ctx e (WithType t) in
 					let e = type_expr ctx e (WithType t) in
 					let e = Codegen.AbstractCast.cast_or_unify ctx t e p in
 					let e = Codegen.AbstractCast.cast_or_unify ctx t e p in
 					(try type_eq EqStrict e.etype t; e with Unify_error _ -> mk (TCast (e,None)) t e.epos)
 					(try type_eq EqStrict e.etype t; e with Unify_error _ -> mk (TCast (e,None)) t e.epos)
@@ -3090,7 +3096,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 			) fl in
 			) fl in
 			let t = (TAnon { a_fields = !fields; a_status = ref Const }) in
 			let t = (TAnon { a_fields = !fields; a_status = ref Const }) in
 			if not ctx.untyped then begin
 			if not ctx.untyped then begin
-				(match PMap.foldi (fun n cf acc -> if not (Meta.has Meta.Optional cf.cf_meta) && not (PMap.mem n !fields) then n :: acc else acc) a.a_fields [] with
+				(match PMap.foldi (fun n cf acc -> if not (Meta.has Meta.Optional cf.cf_meta) && not (PMap.mem n !fields) then n :: acc else acc) field_map [] with
 					| [] -> ()
 					| [] -> ()
 					| [n] -> raise_or_display ctx [Unify_custom ("Object requires field " ^ n)] p
 					| [n] -> raise_or_display ctx [Unify_custom ("Object requires field " ^ n)] p
 					| nl -> raise_or_display ctx [Unify_custom ("Object requires fields: " ^ (String.concat ", " nl))] p);
 					| nl -> raise_or_display ctx [Unify_custom ("Object requires fields: " ^ (String.concat ", " nl))] p);
@@ -3098,8 +3104,63 @@ and type_expr ctx (e,p) (with_type:with_type) =
 				| [] -> ()
 				| [] -> ()
 				| _ -> raise_or_display ctx (List.map (fun n -> has_extra_field t n) !extra_fields) p);
 				| _ -> raise_or_display ctx (List.map (fun n -> has_extra_field t n) !extra_fields) p);
 			end;
 			end;
+			t, fl
+		in
+		(match a with
+		| ODKPlain ->
+			let rec loop (l,acc) (f,e) =
+				let f,is_quoted,is_valid = Parser.unquote_ident f in
+				if PMap.mem f acc then error ("Duplicate field in object declaration : " ^ f) p;
+				let e = type_expr ctx e Value in
+				(match follow e.etype with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
+				let cf = mk_field f e.etype e.epos in
+				let e = if is_quoted then wrap_quoted_meta e else e in
+				((f,e) :: l, if is_valid then begin
+					if String.length f > 0 && f.[0] = '$' then error "Field names starting with a dollar are not allowed" p;
+					PMap.add f cf acc
+				end else acc)
+			in
+			let fields , types = List.fold_left loop ([],PMap.empty) fl in
+			let x = ref Const in
+			ctx.opened <- x :: ctx.opened;
+			mk (TObjectDecl (List.rev fields)) (TAnon { a_fields = types; a_status = x }) p
+		| ODKWithStructure a ->
+			let t, fl = type_fields a.a_fields in
 			if !(a.a_status) <> Const then a.a_status := Closed;
 			if !(a.a_status) <> Const then a.a_status := Closed;
-			mk (TObjectDecl fl) t p)
+			mk (TObjectDecl fl) t p
+		| ODKWithClass (c,tl) ->
+			let _,ctor = get_constructor ctx c tl p in
+			let args = match follow ctor.cf_type with
+				| TFun(args,_) -> args
+				| _ -> assert false
+			in
+			let fields = List.fold_left (fun acc (n,opt,t) ->
+				let f = mk_field n t ctor.cf_pos in
+				if opt then f.cf_meta <- [(Meta.Optional,[],ctor.cf_pos)];
+				PMap.add n f acc
+			) PMap.empty args in
+			let t,fl = type_fields fields in
+			let evars,fl,_ = List.fold_left (fun (evars,elocs,had_side_effect) (s,e) ->
+				begin match e.eexpr with
+				| TConst _ | TTypeExpr _ | TFunction _ ->
+					evars,(s,e) :: elocs,had_side_effect
+				| _ ->
+					if had_side_effect then begin
+						let v = gen_local ctx e.etype in
+						let ev = mk (TVar(v,Some e)) e.etype e.epos in
+						let eloc = mk (TLocal v) v.v_type e.epos in
+						(ev :: evars),((s,eloc) :: elocs),had_side_effect
+					end else
+						evars,(s,e) :: elocs,Optimizer.has_side_effect e
+				end
+			) ([],[],false) (List.rev fl) in
+			let el = List.map (fun (n,_,t) ->
+				try List.assoc n fl
+				with Not_found -> mk (TConst TNull) t p
+			) args in
+			let e = mk (TNew(c,tl,el)) (TInst(c,tl)) p in
+			mk (TBlock (List.rev (e :: (List.rev evars)))) e.etype e.epos
+		)
 	| EArrayDecl [(EFor _,_) | (EWhile _,_) as e] ->
 	| EArrayDecl [(EFor _,_) | (EWhile _,_) as e] ->
 		let v = gen_local ctx (mk_mono()) in
 		let v = gen_local ctx (mk_mono()) in
 		let et = ref (EConst(Ident "null"),p) in
 		let et = ref (EConst(Ident "null"),p) in
@@ -3197,18 +3258,25 @@ and type_expr ctx (e,p) (with_type:with_type) =
 	| EArrayDecl el ->
 	| EArrayDecl el ->
 		let tp = (match with_type with
 		let tp = (match with_type with
 		| WithType t ->
 		| WithType t ->
-			(match follow t with
-			| TInst ({ cl_path = [],"Array" },[tp]) ->
-				(match follow tp with
-				| TMono _ -> None
-				| _ -> Some tp)
-			| TAnon _ ->
-				(try
-					Some (get_iterable_param t)
-				with Not_found ->
-					None)
-			| t ->
-				if t == t_dynamic then Some t else None)
+			let rec loop t =
+				(match follow t with
+				| TInst ({ cl_path = [],"Array" },[tp]) ->
+					(match follow tp with
+					| TMono _ -> None
+					| _ -> Some tp)
+				| TAnon _ ->
+					(try
+						Some (get_iterable_param t)
+					with Not_found ->
+						None)
+				| TAbstract (a,pl) ->
+					(match List.fold_left (fun acc t -> match loop t with None -> acc | Some t -> t :: acc) [] (get_abstract_froms a pl) with
+					| [t] -> Some t
+					| _ -> None)
+				| t ->
+					if t == t_dynamic then Some t else None)
+			in
+			loop t
 		| _ ->
 		| _ ->
 			None
 			None
 		) in
 		) in
@@ -4410,14 +4478,14 @@ let get_type_patch ctx t sub =
 let macro_timer ctx path =
 let macro_timer ctx path =
 	Common.timer (if Common.defined ctx.com Define.MacroTimes then "macro " ^ path else "macro execution")
 	Common.timer (if Common.defined ctx.com Define.MacroTimes then "macro " ^ path else "macro execution")
 
 
-let typing_timer ctx f =
+let typing_timer ctx need_type f =
 	let t = Common.timer "typing" in
 	let t = Common.timer "typing" in
 	let old = ctx.com.error and oldp = ctx.pass in
 	let old = ctx.com.error and oldp = ctx.pass in
 	(*
 	(*
 		disable resumable errors... unless we are in display mode (we want to reach point of completion)
 		disable resumable errors... unless we are in display mode (we want to reach point of completion)
 	*)
 	*)
 	if ctx.com.display = DMNone then ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));
 	if ctx.com.display = DMNone then ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));
-	if ctx.pass < PTypeField then ctx.pass <- PTypeField;
+	if need_type && ctx.pass < PTypeField then ctx.pass <- PTypeField;
 	let exit() =
 	let exit() =
 		t();
 		t();
 		ctx.com.error <- old;
 		ctx.com.error <- old;
@@ -4441,13 +4509,13 @@ let load_macro_ref : (typer -> path -> string -> pos -> (typer * ((string * bool
 
 
 let make_macro_api ctx p =
 let make_macro_api ctx p =
 	let parse_expr_string s p inl =
 	let parse_expr_string s p inl =
-		typing_timer ctx (fun() -> parse_expr_string ctx s p inl)
+		typing_timer ctx false (fun() -> parse_expr_string ctx s p inl)
 	in
 	in
 	{
 	{
 		Interp.pos = p;
 		Interp.pos = p;
 		Interp.get_com = (fun() -> ctx.com);
 		Interp.get_com = (fun() -> ctx.com);
 		Interp.get_type = (fun s ->
 		Interp.get_type = (fun s ->
-			typing_timer ctx (fun() ->
+			typing_timer ctx false (fun() ->
 				let path = parse_path s in
 				let path = parse_path s in
 				let tp = match List.rev (fst path) with
 				let tp = match List.rev (fst path) with
 					| s :: sl when String.length s > 0 && (match s.[0] with 'A'..'Z' -> true | _ -> false) ->
 					| s :: sl when String.length s > 0 && (match s.[0] with 'A'..'Z' -> true | _ -> false) ->
@@ -4462,8 +4530,11 @@ let make_macro_api ctx p =
 					None
 					None
 			)
 			)
 		);
 		);
+		Interp.resolve_type = (fun t p ->
+			typing_timer ctx false (fun() -> Typeload.load_complex_type ctx p t)
+		);
 		Interp.get_module = (fun s ->
 		Interp.get_module = (fun s ->
-			typing_timer ctx (fun() ->
+			typing_timer ctx false (fun() ->
 				let path = parse_path s in
 				let path = parse_path s in
 				let m = List.map type_of_module_type (Typeload.load_module ctx path p).m_types in
 				let m = List.map type_of_module_type (Typeload.load_module ctx path p).m_types in
 				m
 				m
@@ -4494,10 +4565,10 @@ let make_macro_api ctx p =
 		);
 		);
 		Interp.parse_string = parse_expr_string;
 		Interp.parse_string = parse_expr_string;
 		Interp.type_expr = (fun e ->
 		Interp.type_expr = (fun e ->
-			typing_timer ctx (fun() -> (type_expr ctx e Value))
+			typing_timer ctx true (fun() -> type_expr ctx e Value)
 		);
 		);
 		Interp.type_macro_expr = (fun e ->
 		Interp.type_macro_expr = (fun e ->
-			let e = typing_timer ctx (fun() -> (type_expr ctx e Value)) in
+			let e = typing_timer ctx true (fun() -> type_expr ctx e Value) in
 			let rec loop e = match e.eexpr with
 			let rec loop e = match e.eexpr with
 				| TField(_,FStatic(c,({cf_kind = Method _} as cf))) -> ignore(!load_macro_ref ctx c.cl_path cf.cf_name e.epos)
 				| TField(_,FStatic(c,({cf_kind = Method _} as cf))) -> ignore(!load_macro_ref ctx c.cl_path cf.cf_name e.epos)
 				| _ -> Type.iter loop e
 				| _ -> Type.iter loop e
@@ -4560,7 +4631,7 @@ let make_macro_api ctx p =
 		);
 		);
 		Interp.allow_package = (fun v -> Common.allow_package ctx.com v);
 		Interp.allow_package = (fun v -> Common.allow_package ctx.com v);
 		Interp.type_patch = (fun t f s v ->
 		Interp.type_patch = (fun t f s v ->
-			typing_timer ctx (fun() ->
+			typing_timer ctx false (fun() ->
 				let v = (match v with None -> None | Some s ->
 				let v = (match v with None -> None | Some s ->
 					match parse_string ctx.com ("typedef T = " ^ s) null_pos false with
 					match parse_string ctx.com ("typedef T = " ^ s) null_pos false with
 					| _,[ETypedef { d_data = ct },_] -> Some ct
 					| _,[ETypedef { d_data = ct },_] -> Some ct
@@ -4712,7 +4783,7 @@ let make_macro_api ctx p =
 			end
 			end
 		);
 		);
 		Interp.module_dependency = (fun mpath file ismacro ->
 		Interp.module_dependency = (fun mpath file ismacro ->
-			let m = typing_timer ctx (fun() -> Typeload.load_module ctx (parse_path mpath) p) in
+			let m = typing_timer ctx false (fun() -> Typeload.load_module ctx (parse_path mpath) p) in
 			if ismacro then
 			if ismacro then
 				m.m_extra.m_macro_calls <- file :: List.filter ((<>) file) m.m_extra.m_macro_calls
 				m.m_extra.m_macro_calls <- file :: List.filter ((<>) file) m.m_extra.m_macro_calls
 			else
 			else