Browse Source

[js] wrap thrown objects that are not instances of js.Errors into a special error object that preserves callstack, unwrap on catch

Dan Korostelev 10 years ago
parent
commit
0f9138e5fc
3 changed files with 39 additions and 0 deletions
  1. 23 0
      filters.ml
  2. 5 0
      genjs.ml
  3. 11 0
      std/js/Boot.hx

+ 23 - 0
filters.ml

@@ -139,6 +139,27 @@ let rec add_final_return e =
 			{ e with eexpr = TFunction f }
 			{ e with eexpr = TFunction f }
 		| _ -> e
 		| _ -> e
 
 
+let rec wrap_js_exceptions com e =
+	let terr = List.find (fun mt -> match mt with TClassDecl {cl_path = ["js";"_Boot"],"HaxeError"} -> true | _ -> false) com.types in
+	let cerr = match terr with TClassDecl c -> c | _ -> assert false in
+
+	let rec is_error = function
+	| TInst ({cl_path = (["js"],"Error")},_) -> true
+	| TInst ({cl_super = Some (csup,tl)}, _) -> is_error (TInst (csup,tl))
+	| _ -> false
+	in
+
+	let rec loop e =
+		match e.eexpr with
+		| TThrow eerr when not (is_error eerr.etype) ->
+			let ewrap = { eerr with eexpr = TNew (cerr,[],[eerr]) } in
+			{ e with eexpr = TThrow ewrap }
+		| _ ->
+			Type.map_expr loop e
+	in
+
+	loop e
+
 (* -------------------------------------------------------------------------- *)
 (* -------------------------------------------------------------------------- *)
 (* CHECK LOCAL VARS INIT *)
 (* CHECK LOCAL VARS INIT *)
 
 
@@ -1088,6 +1109,7 @@ let run com tctx main =
 		let filters = [
 		let filters = [
 			Optimizer.sanitize com;
 			Optimizer.sanitize com;
 			if com.config.pf_add_final_return then add_final_return else (fun e -> e);
 			if com.config.pf_add_final_return then add_final_return else (fun e -> e);
+			if com.platform = Js then wrap_js_exceptions com else (fun e -> e);
 			rename_local_vars tctx;
 			rename_local_vars tctx;
 		] in
 		] in
 		List.iter (run_expression_filters tctx filters) new_types;
 		List.iter (run_expression_filters tctx filters) new_types;
@@ -1113,6 +1135,7 @@ let run com tctx main =
 			captured_vars com;
 			captured_vars com;
 			promote_complex_rhs com;
 			promote_complex_rhs com;
 			if com.config.pf_add_final_return then add_final_return else (fun e -> e);
 			if com.config.pf_add_final_return then add_final_return else (fun e -> e);
+			if com.platform = Js then wrap_js_exceptions com else (fun e -> e);
 			rename_local_vars tctx;
 			rename_local_vars tctx;
 		] in
 		] in
 		List.iter (run_expression_filters tctx filters) new_types;
 		List.iter (run_expression_filters tctx filters) new_types;

+ 5 - 0
genjs.ml

@@ -663,6 +663,11 @@ and gen_expr ctx e =
 		let bend = open_block ctx in
 		let bend = open_block ctx in
 		let last = ref false in
 		let last = ref false in
 		let else_block = ref false in
 		let else_block = ref false in
+		if (has_feature ctx "js.Boot.HaxeError") then begin
+			newline ctx;
+			print ctx "if (%s instanceof %s) %s = %s.val" vname (ctx.type_accessor (TClassDecl { null_class with cl_path = ["js";"_Boot"],"HaxeError" })) vname vname;
+		end;
+
 		List.iter (fun (v,e) ->
 		List.iter (fun (v,e) ->
 			if !last then () else
 			if !last then () else
 			let t = (match follow v.v_type with
 			let t = (match follow v.v_type with

+ 11 - 0
std/js/Boot.hx

@@ -21,6 +21,17 @@
  */
  */
 package js;
 package js;
 
 
+private class HaxeError extends js.Error {
+
+	var val:Dynamic;
+
+	public function new(val:Dynamic) {
+		super();
+		this.val = untyped __define_feature__("js.Boot.HaxeError", val);
+		untyped js.Error.captureStackTrace(this, HaxeError);
+	}
+}
+
 @:dox(hide)
 @:dox(hide)
 class Boot {
 class Boot {