Sfoglia il codice sorgente

Merge branch 'development' of github.com:HaxeFoundation/haxe into strict-name-encoding

杨博 11 anni fa
parent
commit
1b4992f7bf

+ 1 - 0
extra/CHANGES.txt

@@ -36,6 +36,7 @@
 	Macro features and changes:
 	Macro features and changes:
 
 
 	macro : added Context.getLocalTVars
 	macro : added Context.getLocalTVars
+	macro : added TypedExprTools.iter
 
 
 	Deprecations:
 	Deprecations:
 
 

+ 18 - 3
gencommon.ml

@@ -6176,19 +6176,34 @@ struct
 
 
 		let in_value = ref false in
 		let in_value = ref false in
 
 
+		let rec clean_cast e = match e.eexpr with
+		 | TCast(e,_) -> clean_cast e
+		 | TParenthesis(e) | TMeta(_,e) -> clean_cast e
+		 | _ -> e
+		in
+
 		let rec run ?(just_type = false) e =
 		let rec run ?(just_type = false) e =
 			let handle = if not just_type then handle else fun e t1 t2 -> { e with etype = gen.greal_type t2 } in
 			let handle = if not just_type then handle else fun e t1 t2 -> { e with etype = gen.greal_type t2 } in
 			let was_in_value = !in_value in
 			let was_in_value = !in_value in
 			in_value := true;
 			in_value := true;
 			match e.eexpr with
 			match e.eexpr with
-				| TConst ( TInt _ | TFloat _ | TBool _ ) ->
+				| TConst ( TInt _ | TFloat _ | TBool _ as const ) ->
 					(* take off any Null<> that it may have *)
 					(* take off any Null<> that it may have *)
-					{ e with etype = follow (run_follow gen e.etype) }
+					let t = follow (run_follow gen e.etype) in
+					(* do not allow constants typed as Single - need to cast them *)
+					let real_t = match const with
+						| TInt _ -> gen.gcon.basic.tint
+						| TFloat _ -> gen.gcon.basic.tfloat
+						| TBool _ -> gen.gcon.basic.tbool
+						| _ -> assert false
+					in
+					handle e t real_t
 				| TCast( { eexpr = TCall( { eexpr = TLocal { v_name = "__delegate__" } } as local, [del] ) } as e2, _) ->
 				| TCast( { eexpr = TCall( { eexpr = TLocal { v_name = "__delegate__" } } as local, [del] ) } as e2, _) ->
 					{ e with eexpr = TCast({ e2 with eexpr = TCall(local, [Type.map_expr run del]) }, None) }
 					{ e with eexpr = TCast({ e2 with eexpr = TCall(local, [Type.map_expr run del]) }, None) }
 
 
 				| TBinop ( (Ast.OpAssign | Ast.OpAssignOp _ as op), e1, e2 ) ->
 				| TBinop ( (Ast.OpAssign | Ast.OpAssignOp _ as op), e1, e2 ) ->
-					{ e with eexpr = TBinop(op, run ~just_type:true e1, run e2) }
+					let e1 = run ~just_type:true e1 in
+					{ e with eexpr = TBinop(op, clean_cast e1, run e2) }
 				| TField(ef, f) ->
 				| TField(ef, f) ->
 					handle_type_parameter gen None e (run ef) ~clean_ef:ef ~overloads_cast_to_base:overloads_cast_to_base f [] calls_parameters_explicitly
 					handle_type_parameter gen None e (run ef) ~clean_ef:ef ~overloads_cast_to_base:overloads_cast_to_base f [] calls_parameters_explicitly
 				| TArrayDecl el ->
 				| TArrayDecl el ->

+ 31 - 19
gencpp.ml

@@ -4138,6 +4138,9 @@ let create_constructor_dependencies common_ctx =
       ) common_ctx.types;
       ) common_ctx.types;
    result;;
    result;;
 
 
+(*
+
+  Exports can now be done with macros and a class list
 
 
 let rec s_type t =
 let rec s_type t =
    let result =
    let result =
@@ -4178,9 +4181,6 @@ and s_type_params = function
 ;;
 ;;
 
 
 
 
-
-
-
 let gen_extern_class common_ctx class_def file_info =
 let gen_extern_class common_ctx class_def file_info =
    let file = new_source_file common_ctx common_ctx.file  "extern" ".hx" class_def.cl_path in
    let file = new_source_file common_ctx common_ctx.file  "extern" ".hx" class_def.cl_path in
    let path = class_def.cl_path in
    let path = class_def.cl_path in
@@ -4294,6 +4294,7 @@ let gen_extern_enum common_ctx enum_def file_info =
    output "}\n";
    output "}\n";
    file#close
    file#close
 ;;
 ;;
+*)
 
 
 let is_this expression =
 let is_this expression =
    match (remove_parens expression).eexpr with
    match (remove_parens expression).eexpr with
@@ -4378,6 +4379,7 @@ class script_writer common_ctx ctx filename =
    val mutable indents = []
    val mutable indents = []
    val mutable just_finished_block = false
    val mutable just_finished_block = false
    val mutable classCount = 0
    val mutable classCount = 0
+   val mutable return_type = TMono(ref None)
    val buffer = Buffer.create 0
    val buffer = Buffer.create 0
    val identTable = Hashtbl.create 0
    val identTable = Hashtbl.create 0
    val fileTable = Hashtbl.create 0
    val fileTable = Hashtbl.create 0
@@ -4448,6 +4450,10 @@ class script_writer common_ctx ctx filename =
    | TThis -> "THIS "
    | TThis -> "THIS "
    | TSuper -> "SUPER "
    | TSuper -> "SUPER "
 
 
+   method pushReturn inType =
+      let oldReturnType = return_type in
+      return_type <- inType;
+      fun () -> return_type <- oldReturnType;
    method fileText file = string_of_int (this#fileId file)
    method fileText file = string_of_int (this#fileId file)
    method indent_one = this#write indent_str
    method indent_one = this#write indent_str
    method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents
    method push_indent = indents <- indent_str::indents; indent <- String.concat "" indents
@@ -4486,11 +4492,12 @@ class script_writer common_ctx ctx filename =
       this#writeBool v.v_capture;
       this#writeBool v.v_capture;
       this#writeType v.v_type;
       this#writeType v.v_type;
    method writeList prefix len = this#write (prefix ^" "  ^ (string_of_int (len)) ^ "\n");
    method writeList prefix len = this#write (prefix ^" "  ^ (string_of_int (len)) ^ "\n");
-   method checkCast toType expr forceCast =
+   method checkCast toType expr forceCast fromGenExpression=
    let write_cast text =
    let write_cast text =
-      this#begin_expr;
-      this#write ((string_of_int (Lexer.get_error_line expr.epos) ) ^ "\t" ^ (this#fileText expr.epos.pfile) ^ indent);
+      if (not fromGenExpression) then
+         this#write ( (this#fileText expr.epos.pfile) ^ "\t" ^ (string_of_int (Lexer.get_error_line expr.epos) ) ^ indent);
       this#write (text ^"\n" );
       this#write (text ^"\n" );
+      this#begin_expr;
       this#gen_expression expr;
       this#gen_expression expr;
       this#end_expr;
       this#end_expr;
       true;
       true;
@@ -4561,7 +4568,9 @@ class script_writer common_ctx ctx filename =
             | Some const when const <> TNull -> this#write ("1 " ^ (this#constText const) ^ "\n")
             | Some const when const <> TNull -> this#write ("1 " ^ (this#constText const) ^ "\n")
             | _ -> this#write "0\n";
             | _ -> this#write "0\n";
          ) function_def.tf_args;
          ) function_def.tf_args;
+         let pop = this#pushReturn function_def.tf_type in
          this#gen_expression function_def.tf_expr;
          this#gen_expression function_def.tf_expr;
+         pop ();
    | TBlock expr_list -> this#writeList "BLOCK" (List.length expr_list);
    | TBlock expr_list -> this#writeList "BLOCK" (List.length expr_list);
          List.iter this#gen_expression expr_list;
          List.iter this#gen_expression expr_list;
    | TConst const -> this#write (this#constText const)
    | TConst const -> this#write (this#constText const)
@@ -4571,7 +4580,7 @@ class script_writer common_ctx ctx filename =
    | TBinop (op,e1,e2) when op=OpAssign ->
    | TBinop (op,e1,e2) when op=OpAssign ->
       this#write ("SET \n");
       this#write ("SET \n");
       this#gen_expression e1;
       this#gen_expression e1;
-      this#checkCast e1.etype e2 false;
+      this#checkCast e1.etype e2 false false;
    | TBinop (OpEq ,e1, { eexpr = TConst TNull } ) -> this#write "ISNULL\n";
    | TBinop (OpEq ,e1, { eexpr = TConst TNull } ) -> this#write "ISNULL\n";
       this#gen_expression e1;
       this#gen_expression e1;
    | TBinop (OpNotEq ,e1, { eexpr = TConst TNull }) -> this#write "NOTNULL\n";
    | TBinop (OpNotEq ,e1, { eexpr = TConst TNull }) -> this#write "NOTNULL\n";
@@ -4632,7 +4641,7 @@ class script_writer common_ctx ctx filename =
       let matched_args = match func.etype with
       let matched_args = match func.etype with
          | TFun (args,_) ->
          | TFun (args,_) ->
             ( try (
             ( try (
-               List.iter2 (fun (_,_,protoT) arg -> this#checkCast protoT arg false )  args arg_list;
+               List.iter2 (fun (_,_,protoT) arg -> this#checkCast protoT arg false false)  args arg_list;
                true; )
                true; )
             with Invalid_argument _ -> (*print_endline "Bad count?";*) false )
             with Invalid_argument _ -> (*print_endline "Bad count?";*) false )
          | _ -> false
          | _ -> false
@@ -4685,14 +4694,14 @@ class script_writer common_ctx ctx filename =
                      this#writeVar tvar;
                      this#writeVar tvar;
                      this#write (" " ^ (this#typeText init.etype));
                      this#write (" " ^ (this#typeText init.etype));
                      this#write "\n";
                      this#write "\n";
-                     this#checkCast tvar.v_type init false);
+                     this#checkCast tvar.v_type init false false);
    | TNew (clazz,params,arg_list) ->
    | TNew (clazz,params,arg_list) ->
       this#write ("NEW " ^ (this#typeText (TInst(clazz,params))) ^ (string_of_int (List.length arg_list)) ^ "\n");
       this#write ("NEW " ^ (this#typeText (TInst(clazz,params))) ^ (string_of_int (List.length arg_list)) ^ "\n");
       List.iter this#gen_expression arg_list;
       List.iter this#gen_expression arg_list;
    | TReturn optval -> (match optval with
    | TReturn optval -> (match optval with
          | None -> this#write "RETURN\n"
          | None -> this#write "RETURN\n"
          | Some value -> this#write ("RETVAL " ^ (this#typeText value.etype) ^ "\n");
          | Some value -> this#write ("RETVAL " ^ (this#typeText value.etype) ^ "\n");
-                     this#gen_expression value;
+              this#checkCast return_type value false false;
          )
          )
    | TObjectDecl (
    | TObjectDecl (
       ("fileName" , { eexpr = (TConst (TString file)) }) ::
       ("fileName" , { eexpr = (TConst (TString file)) }) ::
@@ -4745,7 +4754,7 @@ class script_writer common_ctx ctx filename =
             this#gen_expression catch_expr;
             this#gen_expression catch_expr;
          ) catches;
          ) catches;
    | TCast (cast,None) -> error "Unexpected cast" expression.epos
    | TCast (cast,None) -> error "Unexpected cast" expression.epos
-   | TCast (cast,Some _) -> this#checkCast expression.etype cast true
+   | TCast (cast,Some _) -> this#checkCast expression.etype cast true true
    | TParenthesis _ -> error "Unexpected parens" expression.epos
    | TParenthesis _ -> error "Unexpected parens" expression.epos
    | TMeta(_,_) -> error "Unexpected meta" expression.epos
    | TMeta(_,_) -> error "Unexpected meta" expression.epos
    | TPatMatch _ ->  error "Unexpected pattern match" expression.epos
    | TPatMatch _ ->  error "Unexpected pattern match" expression.epos
@@ -4916,18 +4925,12 @@ let generate_source common_ctx =
    let main_deps = ref [] in
    let main_deps = ref [] in
    let build_xml = ref "" in
    let build_xml = ref "" in
    let scriptable = (Common.defined common_ctx Define.Scriptable) in
    let scriptable = (Common.defined common_ctx Define.Scriptable) in
-   let gen_externs = scriptable || (Common.defined common_ctx Define.DllExport) in
-   if (gen_externs) then begin
-   make_base_directory (common_ctx.file ^ "/extern");
-   end;
 
 
    List.iter (fun object_def ->
    List.iter (fun object_def ->
       (match object_def with
       (match object_def with
-      | TClassDecl class_def when is_extern_class class_def ->
-         (*if (gen_externs) then gen_extern_class common_ctx class_def file_info;*)();
+      | TClassDecl class_def when is_extern_class class_def -> ()
       | TClassDecl class_def ->
       | TClassDecl class_def ->
          let name =  class_text class_def.cl_path in
          let name =  class_text class_def.cl_path in
-         if (gen_externs) then gen_extern_class common_ctx class_def file_info;
          let is_internal = is_internal_class class_def.cl_path in
          let is_internal = is_internal_class class_def.cl_path in
          let is_generic_def = match class_def.cl_kind with KGeneric -> true | _ -> false in
          let is_generic_def = match class_def.cl_kind with KGeneric -> true | _ -> false in
          if (is_internal || (is_macro class_def.cl_meta) || is_generic_def) then
          if (is_internal || (is_macro class_def.cl_meta) || is_generic_def) then
@@ -4947,7 +4950,6 @@ let generate_source common_ctx =
       | TEnumDecl enum_def when enum_def.e_extern -> ()
       | TEnumDecl enum_def when enum_def.e_extern -> ()
       | TEnumDecl enum_def ->
       | TEnumDecl enum_def ->
          let name =  class_text enum_def.e_path in
          let name =  class_text enum_def.e_path in
-         if (gen_externs) then gen_extern_enum common_ctx enum_def file_info;
          let is_internal = is_internal_class enum_def.e_path in
          let is_internal = is_internal_class enum_def.e_path in
          if (is_internal) then
          if (is_internal) then
             (if (debug>1) then print_endline (" internal enum " ^ name ))
             (if (debug>1) then print_endline (" internal enum " ^ name ))
@@ -4979,6 +4981,16 @@ let generate_source common_ctx =
 
 
    write_resources common_ctx;
    write_resources common_ctx;
 
 
+   (* Output class list if requested *)
+   if (scriptable || (Common.defined common_ctx Define.DllExport) ) then begin
+      let filename = match Common.defined_value_safe common_ctx Define.DllExport with
+         | "" -> "exe.classes"
+         | x -> x
+      in
+      let exeClasses = open_out filename in
+      List.iter (fun x -> output_string exeClasses ((join_class_path (fst x) ".") ^ "\n") ) !exe_classes;
+      close_out exeClasses;
+   end;
 
 
    let output_name = match  common_ctx.main_class with
    let output_name = match  common_ctx.main_class with
    | Some path -> (snd path)
    | Some path -> (snd path)

+ 23 - 0
gencs.ml

@@ -1050,6 +1050,29 @@ let configure gen =
 			let was_in_value = !in_value in
 			let was_in_value = !in_value in
 			in_value := true;
 			in_value := true;
 			(match e.eexpr with
 			(match e.eexpr with
+				| TCall({ eexpr = TField(ef,f) }, (_ :: _ as args) ) when (field_name f) = "get_Item" ->
+					expr_s w ef;
+					write w "[";
+					let first = ref true in
+					List.iter (fun f ->
+						if !first then first := false else write w ", ";
+						expr_s w f
+					) args;
+					write w "]"
+				| TCall({ eexpr = TField(ef,f) }, (_ :: _ :: _ as args) ) when (field_name f) = "set_Item" ->
+					expr_s w ef;
+					write w "[";
+					let args, value = match List.rev args with
+						| v :: args -> List.rev args, v
+						| _ -> assert false
+					in
+					let first = ref true in
+					List.iter (fun f ->
+						if !first then first := false else write w ", ";
+						expr_s w f
+					) args;
+					write w "] = ";
+					expr_s w value
 				| TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "add_" ->
 				| TCall( ({ eexpr = TField(ef,f) } as e), [ev] ) when String.starts_with (field_name f) "add_" ->
 					let name = field_name f in
 					let name = field_name f in
 					let propname = String.sub name 4 (String.length name - 4) in
 					let propname = String.sub name 4 (String.length name - 4) in

+ 8 - 1
genjava.ml

@@ -2065,7 +2065,14 @@ let configure gen =
 			)
 			)
 			(base_exception_t)
 			(base_exception_t)
 			(hx_exception_t)
 			(hx_exception_t)
-			(fun v e -> e)
+			(fun v e ->
+
+				let exc_cl = get_cl (get_type gen (["haxe";"lang"],"Exceptions")) in
+				let exc_field = mk_static_field_access_infer exc_cl "setException" e.epos [] in
+				let esetstack = { eexpr = TCall(exc_field,[mk_local v e.epos]); etype = gen.gcon.basic.tvoid; epos = e.epos } in
+
+				Type.concat esetstack e;
+			)
 	);
 	);
 
 
 	let get_typeof e =
 	let get_typeof e =

+ 6 - 0
genswf9.ml

@@ -104,6 +104,12 @@ type context = {
 	mutable for_call : bool;
 	mutable for_call : bool;
 }
 }
 
 
+let rec follow t = match Type.follow t with
+	| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
+		follow (Codegen.Abstract.get_underlying_type a tl)
+	| t ->
+		t
+
 let invalid_expr p = error "Invalid expression" p
 let invalid_expr p = error "Invalid expression" p
 let stack_error p = error "Stack error" p
 let stack_error p = error "Stack error" p
 
 

+ 30 - 10
genxml.ml

@@ -23,6 +23,7 @@
 open Ast
 open Ast
 open Type
 open Type
 open Common
 open Common
+open ExtString
 
 
 type xml =
 type xml =
 	| Node of string * (string * string) list * xml list
 	| Node of string * (string * string) list * xml list
@@ -292,9 +293,27 @@ let conv_path p =
 	| x :: l when x.[0] = '_' -> List.rev (("priv" ^ x) :: l), snd p
 	| x :: l when x.[0] = '_' -> List.rev (("priv" ^ x) :: l), snd p
 	| _ -> p
 	| _ -> p
 
 
+let get_real_path meta path =
+	try
+		let real_path = match Meta.get Meta.RealPath meta with
+			| (_,[(EConst(String s),_)],_) ->
+				s
+			| _ -> raise Not_found
+		in
+		match List.rev (String.nsplit real_path ".") with
+			| name :: pack ->
+				(List.rev pack), name
+			| _ -> raise Not_found
+	with | Not_found ->
+		path
+
+
 let generate_type com t =
 let generate_type com t =
 	let base_path = "hxclasses" in
 	let base_path = "hxclasses" in
-	let pack , name = conv_path (t_path t) in
+	let pack, name =
+		let info = t_infos t in
+		get_real_path info.mt_meta info.mt_path
+	in
 	create_dir "." (base_path :: pack);
 	create_dir "." (base_path :: pack);
 	match pack, name with
 	match pack, name with
 	| ["flash";"net"], "NetStreamPlayTransitions"
 	| ["flash";"net"], "NetStreamPlayTransitions"
@@ -318,8 +337,8 @@ let generate_type com t =
 		| _ ->
 		| _ ->
 			t
 			t
 	in
 	in
-	let rec path p tl =
-		let p = conv_path p in
+	let rec path meta p tl =
+		let p = conv_path (get_real_path meta p) in
 		(if fst p = pack then snd p else s_type_path p) ^ (match tl with [] -> "" | _ -> "<" ^ String.concat "," (List.map stype tl) ^ ">")
 		(if fst p = pack then snd p else s_type_path p) ^ (match tl with [] -> "" | _ -> "<" ^ String.concat "," (List.map stype tl) ^ ">")
 	and stype t =
 	and stype t =
 		match t with
 		match t with
@@ -328,15 +347,15 @@ let generate_type com t =
 			| None -> "Unknown"
 			| None -> "Unknown"
 			| Some t -> stype t)
 			| Some t -> stype t)
 		| TInst ({ cl_kind = KTypeParameter _ } as c,tl) ->
 		| TInst ({ cl_kind = KTypeParameter _ } as c,tl) ->
-			path ([],snd c.cl_path) tl
+			path [] ([],snd c.cl_path) tl
 		| TInst (c,tl) ->
 		| TInst (c,tl) ->
-			path c.cl_path tl
+			path c.cl_meta c.cl_path tl
 		| TEnum (e,tl) ->
 		| TEnum (e,tl) ->
-			path e.e_path tl
+			path e.e_meta e.e_path tl
 		| TType (t,tl) ->
 		| TType (t,tl) ->
-			path t.t_path tl
+			path t.t_meta t.t_path tl
 		| TAbstract (a,tl) ->
 		| TAbstract (a,tl) ->
-			path a.a_path tl
+			path a.a_meta a.a_path tl
 		| TAnon a ->
 		| TAnon a ->
 			let fields = PMap.fold (fun f acc -> (f.cf_name ^ " : " ^ stype f.cf_type) :: acc) a.a_fields [] in
 			let fields = PMap.fold (fun f acc -> (f.cf_name ^ " : " ^ stype f.cf_type) :: acc) a.a_fields [] in
 			"{" ^ String.concat ", " fields ^ "}"
 			"{" ^ String.concat ", " fields ^ "}"
@@ -392,7 +411,7 @@ let generate_type com t =
 		| AccNever, "flash" :: _ -> "null"
 		| AccNever, "flash" :: _ -> "null"
 		| _ -> s_access is_read a
 		| _ -> s_access is_read a
 	in
 	in
-	let print_field stat f =
+	let rec print_field stat f =
 		p "\t";
 		p "\t";
 		print_meta f.cf_meta;
 		print_meta f.cf_meta;
 		if stat then p "static ";
 		if stat then p "static ";
@@ -430,7 +449,8 @@ let generate_type com t =
 			let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map fst l) ^ ">") in
 			let tparams = (match f.cf_params with [] -> "" | l -> "<" ^ String.concat "," (List.map fst l) ^ ">") in
 			p "function %s%s(%s) : %s" f.cf_name tparams (String.concat ", " (List.map sparam params)) (stype ret);
 			p "function %s%s(%s) : %s" f.cf_name tparams (String.concat ", " (List.map sparam params)) (stype ret);
 		);
 		);
-		p ";\n"
+		p ";\n";
+		if Meta.has Meta.Overload f.cf_meta then List.iter (fun f -> print_field stat f) f.cf_overloads
 	in
 	in
 	(match t with
 	(match t with
 	| TClassDecl c ->
 	| TClassDecl c ->

+ 5 - 0
std/cpp/_std/sys/FileSystem.hx

@@ -53,6 +53,11 @@ class FileSystem {
 		return new String(file_full_path(relPath));
 		return new String(file_full_path(relPath));
 	}
 	}
 
 
+	public static function absPath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
+	}
+
 	static function kind( path : String ) : FileKind {
 	static function kind( path : String ) : FileKind {
 		var k:String = sys_file_type(haxe.io.Path.removeTrailingSlashes(path));
 		var k:String = sys_file_type(haxe.io.Path.removeTrailingSlashes(path));
 		return switch(k) {
 		return switch(k) {

+ 6 - 1
std/cs/_std/sys/FileSystem.hx

@@ -82,6 +82,11 @@ class FileSystem {
 		return new FileInfo(relPath).FullName;
 		return new FileInfo(relPath).FullName;
 	}
 	}
 
 
+	public static function absPath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
+	}
+
 	public static function isDirectory( path : String ) : Bool
 	public static function isDirectory( path : String ) : Bool
 	{
 	{
 		var isdir = Directory.Exists(path);
 		var isdir = Directory.Exists(path);
@@ -124,4 +129,4 @@ class FileSystem {
 		return cs.Lib.array( ret );
 		return cs.Lib.array( ret );
 	}
 	}
 
 
-}
+}

+ 9 - 0
std/haxe/io/Path.hx

@@ -299,4 +299,13 @@ class Path {
 		}
 		}
 		return path;
 		return path;
 	}
 	}
+
+	/**
+		Returns true if the path is an absolute path, and false otherwise.
+	**/
+	public static function isAbsolute ( path : String ) : Bool {
+		if (StringTools.startsWith(path, '/')) return true;
+		if (path.charAt(2) == ':') return true;
+		return false;
+	}
 }
 }

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

@@ -41,7 +41,7 @@ class Compiler {
 	}
 	}
 
 
 	public static function define( flag : String, ?value : String ) untyped {
 	public static function define( flag : String, ?value : String ) untyped {
-		var v = flag + (value == null ? "" : "= " + value);
+		var v = flag + (value == null ? "" : "=" + value);
 		load("define", 1)(v.__s);
 		load("define", 1)(v.__s);
 	}
 	}
 
 

+ 42 - 0
std/haxe/macro/TypedExprTools.hx

@@ -72,6 +72,48 @@ class TypedExprTools {
 		}
 		}
 	}
 	}
 
 
+	/**
+		Calls function [f] on each sub-expression of [e].
+
+		See `haxe.macro.ExprTools.iter` for details on iterating expressions in
+		general. This function works the same way, but with a different data
+		structure.
+	**/
+	static public function iter(e:TypedExpr, f:TypedExpr -> Void):Void {
+		switch(e.expr) {
+			case TConst(_) | TLocal(_) | TBreak | TContinue | TTypeExpr(_):
+			case TArray(e1, e2) | TBinop(_, e1, e2) | TFor(_, e1, e2) | TWhile(e1, e2, _):
+				f(e1);
+				f(e2);
+			case TThrow(e1) | TEnumParameter(e1, _, _) | TField(e1, _) | TParenthesis(e1) | TUnop(_, _, e1) | TCast(e1, _) | TMeta(_, e1):
+				f(e1);
+			case TArrayDecl(el) | TNew(_, _, el) | TBlock(el):
+				for (e in el) f(e);
+			case TObjectDecl(fl):
+				for (field in fl) f(field.expr);
+			case TCall(e1, el):
+				f(e1);
+				for (e in el) f(e);
+			case TVar(_, e1) | TReturn(e1):
+				if (e1 != null) f(e1);
+			case TFunction(fu):
+				f(fu.expr);
+			case TIf(e1, e2, e3):
+				f(e1);
+				f(e2);
+				if (e3 != null) f(e3);
+			case TSwitch(e1, cases, e2):
+				f(e1);
+				for (c in cases) f(c.expr);
+				if (e2 != null) f(e2);
+			case TTry(e1, catches):
+				f(e1);
+				for (c in catches) f(c.expr);
+			case TPatMatch:
+				throw false;
+		}
+	}
+
 	/**
 	/**
 		Transforms the sub-expressions of [e] by calling [f] on each of them.
 		Transforms the sub-expressions of [e] by calling [f] on each of them.
 		Additionally, types are mapped using `ft` and variables are mapped using
 		Additionally, types are mapped using `ft` and variables are mapped using

+ 1 - 1
std/java/_std/haxe/ds/WeakMap.hx

@@ -390,7 +390,7 @@ import java.lang.ref.ReferenceQueue;
 				{
 				{
 					if (!isEither(hashes[j]))
 					if (!isEither(hashes[j]))
 					{
 					{
-						var entry = entries[i];
+						var entry = entries[j];
 						var last = entry.get();
 						var last = entry.get();
 						if (last != null)
 						if (last != null)
 						{
 						{

+ 6 - 1
std/java/_std/sys/FileSystem.hx

@@ -61,7 +61,12 @@ class FileSystem {
 
 
 	public static function fullPath( relPath : String ) : String
 	public static function fullPath( relPath : String ) : String
 	{
 	{
-		return new File(relPath).getAbsolutePath();
+		return new File(relPath).getCanonicalPath();
+	}
+
+	public static function absPath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
 	}
 	}
 
 
 	public static function isDirectory( path : String ) : Bool
 	public static function isDirectory( path : String ) : Bool

+ 8 - 5
std/java/internal/Exceptions.hx

@@ -24,13 +24,17 @@ import java.lang.Throwable;
 import java.lang.RuntimeException;
 import java.lang.RuntimeException;
 import java.lang.Exception;
 import java.lang.Exception;
 
 
-@:allow(haxe.CallStack)
-@:allow(java.lang.RuntimeException)
 @:native("haxe.lang.Exceptions")
 @:native("haxe.lang.Exceptions")
 class Exceptions {
 class Exceptions {
-	private static var exception = new java.lang.ThreadLocal<java.lang.RuntimeException>();
+	private static var exception = new java.lang.ThreadLocal<java.lang.Throwable>();
 
 
-	private static function currentException() {
+	@:keep private static function setException(exc:Throwable)
+	{
+		exception.set(exc);
+	}
+
+	public static function currentException()
+	{
 		return exception.get();
 		return exception.get();
 	}
 	}
 }
 }
@@ -73,7 +77,6 @@ class Exceptions {
 			ret = new HaxeException(obj, null, obj);
 			ret = new HaxeException(obj, null, obj);
 		else
 		else
 			ret = new HaxeException(obj, null, null);
 			ret = new HaxeException(obj, null, null);
-		Exceptions.exception.set( ret );
 		return ret;
 		return ret;
 	}
 	}
 }
 }

+ 39 - 5
std/js/Boot.hx

@@ -70,8 +70,15 @@ class Boot {
 	static inline function getClass(o:Dynamic) : Dynamic {
 	static inline function getClass(o:Dynamic) : Dynamic {
 		if (Std.is(o, Array))
 		if (Std.is(o, Array))
 			return Array;
 			return Array;
-		else
-			return untyped __define_feature__("js.Boot.getClass", o.__class__);
+		else {
+			var cl = untyped __define_feature__("js.Boot.getClass", o.__class__);
+			if (cl != null)
+				return cl;
+			var name = __nativeClassName(o);
+			if (name != null)
+				return __resolveNativeClass(name);
+			return null;
+		}
 	}
 	}
 
 
 	@:ifFeature("may_print_enum")
 	@:ifFeature("may_print_enum")
@@ -180,14 +187,17 @@ class Boot {
 			return true;
 			return true;
 		default:
 		default:
 			if( o != null ) {
 			if( o != null ) {
-				// Check if o is an instance of a Haxe class
+				// Check if o is an instance of a Haxe class or a native JS object
 				if( (untyped __js__("typeof"))(cl) == "function" ) {
 				if( (untyped __js__("typeof"))(cl) == "function" ) {
-					if( untyped __js__("o instanceof cl") ) {
+					if( untyped __js__("o instanceof cl") )
 						return true;
 						return true;
-					}
 					if( __interfLoop(getClass(o),cl) )
 					if( __interfLoop(getClass(o),cl) )
 						return true;
 						return true;
 				}
 				}
+				else if ( (untyped __js__("typeof"))(cl) == "object" && __isNativeObj(cl) ) {
+					if( untyped __js__("o instanceof cl") )
+						return true;
+				}
 			} else {
 			} else {
 				return false;
 				return false;
 			}
 			}
@@ -202,5 +212,29 @@ class Boot {
 		if (__instanceof(o, t)) return o;
 		if (__instanceof(o, t)) return o;
 		else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t);
 		else throw "Cannot cast " +Std.string(o) + " to " +Std.string(t);
 	}
 	}
+	
+	static var __toStr = untyped __js__("{}.toString");
+	// get native JS [[Class]]
+	static function __nativeClassName(o:Dynamic):String {
+		var name = untyped __toStr.call(o).slice(8, -1);
+		// exclude general Object and Function
+		// also exclude Math and JSON, because instanceof cannot be called on them
+		if (name == "Object" || name == "Function" || name == "Math" || name == "JSON")
+			return null;
+		return name;
+	}
+	
+	// check for usable native JS object
+	static function __isNativeObj(o:Dynamic):Bool {
+		return __nativeClassName(o) != null;
+	}
+	
+	// resolve native JS class (with window or global):
+	static function __resolveNativeClass(name:String) untyped {
+		if (__js__("typeof window") != "undefined")
+			return window[name];
+		else
+			return global[name];
+	}
 
 
 }
 }

+ 2 - 0
std/js/_std/Type.hx

@@ -52,6 +52,8 @@ enum ValueType {
 
 
 	public static function getClassName( c : Class<Dynamic> ) : String {
 	public static function getClassName( c : Class<Dynamic> ) : String {
 		var a : Array<String> = untyped c.__name__;
 		var a : Array<String> = untyped c.__name__;
+		if (a == null)
+			return null;
 		return a.join(".");
 		return a.join(".");
 	}
 	}
 
 

+ 5 - 0
std/neko/_std/sys/FileSystem.hx

@@ -50,6 +50,11 @@ class FileSystem {
 		return new String(file_full_path(untyped relPath.__s));
 		return new String(file_full_path(untyped relPath.__s));
 	}
 	}
 
 
+	public static function absPath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
+	}
+
 	static function kind( path : String ) : FileKind {
 	static function kind( path : String ) : FileKind {
 		var k = new String(sys_file_type(untyped (haxe.io.Path.removeTrailingSlashes(path)).__s));
 		var k = new String(sys_file_type(untyped (haxe.io.Path.removeTrailingSlashes(path)).__s));
 		return switch(k) {
 		return switch(k) {

+ 5 - 0
std/php/_std/sys/FileSystem.hx

@@ -63,6 +63,11 @@ class FileSystem {
 			return p;
 			return p;
 	}
 	}
 
 
+	public static function absPath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
+	}
+
 	static function kind( path : String ) : FileKind {
 	static function kind( path : String ) : FileKind {
 		var k = untyped __call__("filetype", path);
 		var k = untyped __call__("filetype", path);
 		switch(k) {
 		switch(k) {

+ 7 - 2
std/python/_std/sys/FileSystem.hx

@@ -53,7 +53,12 @@ class FileSystem {
 	}
 	}
 
 
 	public static function fullPath( relPath : String ) : String {
 	public static function fullPath( relPath : String ) : String {
-		return Path.abspath(relPath);
+		return Path.realpath(relPath);
+	}
+
+	public static function absPath ( relPath : String ) : String {
+		if (haxe.io.Path.isAbsolute(relPath)) return relPath;
+		return haxe.io.Path.join([Sys.getCwd(), relPath]);
 	}
 	}
 
 
 	public static function isDirectory( path : String ) : Bool
 	public static function isDirectory( path : String ) : Bool
@@ -77,4 +82,4 @@ class FileSystem {
 		return Os.listdir(path);
 		return Os.listdir(path);
 	}
 	}
 
 
-}
+}

+ 11 - 1
std/sys/FileSystem.hx

@@ -55,12 +55,22 @@ extern class FileSystem {
 
 
 	/**
 	/**
 		Returns the full path of the file or directory specified by `relPath`,
 		Returns the full path of the file or directory specified by `relPath`,
-		which is relative to the current working directory.
+		which is relative to the current working directory. Symlinks will be 
+		followed and the path will be normalized.
 
 
 		If `relPath` is null, the result is unspecified.
 		If `relPath` is null, the result is unspecified.
 	**/
 	**/
 	static function fullPath( relPath : String ) : String;
 	static function fullPath( relPath : String ) : String;
 
 
+	/**
+		Returns the full path of the file or directory specified by `relPath`,
+		which is relative to the current working directory. The path doesn't 
+		have to exist.
+
+		If `relPath` is null, the result is unspecified.
+	**/
+	static function absPath( relPath : String ) : String;
+
 	/**
 	/**
 		Tells if the file or directory specified by `path` is a directory.
 		Tells if the file or directory specified by `path` is a directory.
 
 

+ 3 - 0
tests/RunTravis.hx

@@ -262,6 +262,9 @@ class RunTravis {
 	static function getPhpDependencies() {
 	static function getPhpDependencies() {
 		switch (systemName) {
 		switch (systemName) {
 			case "Linux":
 			case "Linux":
+				//let's install php 5.4 to avoid #3175
+				runCommand("sudo", ["add-apt-repository", "ppa:ondrej/php5-oldstable", "-y"], true);
+				runCommand("sudo", ["apt-get", "update"], true);
 				runCommand("sudo", ["apt-get", "install", "php5", "-y"], true);
 				runCommand("sudo", ["apt-get", "install", "php5", "-y"], true);
 			case "Mac":
 			case "Mac":
 				//pass
 				//pass

+ 16 - 0
tests/unit/issues/Issue2857.hx

@@ -0,0 +1,16 @@
+package unit.issues;
+
+class Issue2857 extends unit.Test {
+#if js
+	function testElement() {
+		if (js.Browser.supported) {
+			var vid = js.Browser.document.createVideoElement();
+			t(Std.is(vid, js.html.VideoElement));
+			t(Std.is(vid, js.html.Element));
+			f(Std.is(vid, haxe.Http));
+			f(Std.is(vid, js.html.ArrayBuffer));
+			eq(Type.getClass(vid), js.html.VideoElement);
+		}
+	}
+#end
+}

+ 26 - 0
tests/unit/issues/Issue3118.hx

@@ -0,0 +1,26 @@
+package unit.issues;
+
+class Issue3118 extends Test
+{
+	public function test()
+	{
+		var data = new Final();
+		data.a2 = [];
+		data.a2.push(1);
+		eq(data.a2[0],1);
+		eq(data.a2.length,1);
+	}
+}
+
+class Base<A>
+{
+  public function new() {}
+
+  public var a2:A;
+
+}
+
+@:final
+class Final extends Base<Array<Int>>
+{
+}

+ 0 - 0
tests/unit/issues/Issue3159.hx → tests/unit/issues/Issue3159.hx.disabled


+ 23 - 0
tests/unit/issues/Issue3178.hx

@@ -0,0 +1,23 @@
+package unit.issues;
+
+private abstract A(String) {
+	public inline function new(s : String) {
+		this = s;
+	}
+
+	public function f(index : Int) {
+		return StringTools.fastCodeAt(this, index);
+	}
+
+	public inline function g(index : Int) {
+		return StringTools.fastCodeAt(this, index);
+	}
+}
+
+class Issue3178 extends unit.Test {
+	function test() {
+		var a = new A("a");
+		eq(97, a.f(0));
+		eq(97, a.g(0));
+	}
+}

+ 2 - 2
tests/unit/unitstd/haxe/ds/WeakMap.unit.hx

@@ -1,4 +1,4 @@
-#if flash
+#if (flash || java)
 var k1 = new IntWrap(1);
 var k1 = new IntWrap(1);
 var k2 = new IntWrap(2);
 var k2 = new IntWrap(2);
 var k3 = new IntWrap(3);
 var k3 = new IntWrap(3);
@@ -84,4 +84,4 @@ a.length == 2;
 a[0] in ["9", "7"];
 a[0] in ["9", "7"];
 a[1] in ["9", "7"];
 a[1] in ["9", "7"];
 o.remove(k2) == false;
 o.remove(k2) == false;
-#end
+#end