evalExceptions.ml 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. (*
  2. The Haxe Compiler
  3. Copyright (C) 2005-2019 Haxe Foundation
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. *)
  16. open Globals
  17. open EvalContext
  18. open EvalValue
  19. open EvalPrinting
  20. open EvalHash
  21. open EvalField
  22. exception Break
  23. exception Continue
  24. exception Return of value
  25. exception Sys_exit of int
  26. let is v path =
  27. path = key_Dynamic || match v with
  28. | VInt32 _ -> path = key_Int || path = key_Float
  29. | VFloat f -> path = key_Float || (path = key_Int && f = (float_of_int (int_of_float f)) && f <= 2147483647. && f >= -2147483648.)
  30. | VTrue | VFalse -> path = key_Bool
  31. | VPrototype {pkind = PClass _} -> path = key_Class
  32. | VPrototype {pkind = PEnum _} -> path = key_Enum
  33. | VEnumValue ve -> path = key_EnumValue || path = ve.epath
  34. | VString _ -> path = key_String
  35. | VArray _ -> path = key_Array
  36. | VVector _ -> path = key_eval_Vector
  37. | VInstance vi ->
  38. let has_interface path' =
  39. try begin match (get_static_prototype_raise (get_ctx()) path').pkind with
  40. | PClass interfaces -> List.mem path interfaces
  41. | _ -> false
  42. end with Not_found ->
  43. false
  44. in
  45. let rec loop proto =
  46. if path = proto.ppath || has_interface proto.ppath then true
  47. else begin match proto.pparent with
  48. | Some proto -> loop proto
  49. | None -> false
  50. end
  51. in
  52. loop vi.iproto
  53. | _ -> false
  54. let s_value_kind = function
  55. | VNull -> "VNull"
  56. | VTrue -> "VTrue"
  57. | VFalse -> "VFalse"
  58. | VInt32 _ -> "VInt32"
  59. | VFloat _ -> "VFloat"
  60. | VEnumValue _ -> "VEnumValue"
  61. | VObject _ -> "VObject"
  62. | VString _ -> "VString"
  63. | VArray _ -> "VArray"
  64. | VVector _ -> "VVector"
  65. | VInstance _ -> "VInstance"
  66. | VPrototype _ -> "VPrototype"
  67. | VFunction _ -> "VFunction"
  68. | VFieldClosure _ -> "VFieldClosure"
  69. | VLazy _ -> "VLazy"
  70. let unexpected_value : 'a . value -> string -> 'a = fun v s ->
  71. let str = Printf.sprintf "Unexpected value %s(%s), expected %s" (s_value_kind v) (value_string v) s in
  72. exc_string str
  73. let invalid_call_arg_number i i2 =
  74. exc_string (Printf.sprintf "Invalid number of call arguments: Expected %i, got %i" i i2)
  75. let format_pos p =
  76. let error_printer file line = Printf.sprintf "%s:%d:" file line in
  77. Lexer.get_error_pos error_printer p
  78. let uncaught_exception_string v p extra =
  79. (Printf.sprintf "%s : Uncaught exception %s%s" (format_pos p) (value_string v) extra)
  80. let get_exc_error_message ctx v stack p =
  81. let pl = List.map (fun env -> {pfile = rev_file_hash env.env_info.pfile;pmin = env.env_leave_pmin; pmax = env.env_leave_pmax}) stack in
  82. let pl = List.filter (fun p -> p <> null_pos) pl in
  83. match pl with
  84. | [] ->
  85. uncaught_exception_string v p ""
  86. | _ ->
  87. let sstack = String.concat "\n" (List.map (fun p -> Printf.sprintf "%s : Called from here" (format_pos p)) pl) in
  88. Printf.sprintf "%s : Uncaught exception %s\n%s" (format_pos p) (value_string v) sstack
  89. let build_exception_stack ctx environment_offset =
  90. let eval = get_eval ctx in
  91. let d = DynArray.to_list (DynArray.sub eval.environments environment_offset (eval.environment_offset - environment_offset)) in
  92. ctx.exception_stack <- List.map (fun env ->
  93. env.env_debug.timer();
  94. {pfile = rev_file_hash env.env_info.pfile;pmin = env.env_leave_pmin; pmax = env.env_leave_pmax},env.env_info.kind
  95. ) d
  96. let catch_exceptions ctx ?(final=(fun() -> ())) f p =
  97. let prev = !get_ctx_ref in
  98. select ctx;
  99. let eval = get_eval ctx in
  100. let environment_offset = eval.environment_offset in
  101. let r = try
  102. let v = f() in
  103. get_ctx_ref := prev;
  104. final();
  105. Some v
  106. with
  107. | RunTimeException(v,stack,p') ->
  108. ctx.debug.caught_exception <- vnull;
  109. build_exception_stack ctx environment_offset;
  110. eval.environment_offset <- environment_offset;
  111. if is v key_haxe_macro_Error then begin
  112. let v1 = field v key_message in
  113. let v2 = field v key_pos in
  114. get_ctx_ref := prev;
  115. final();
  116. match v1,v2 with
  117. | VString s,VInstance {ikind = IPos p} ->
  118. raise (Error.Error (Error.Custom s.sstring,p))
  119. | _ ->
  120. Error.error "Something went wrong" null_pos
  121. end else begin
  122. (* Careful: We have to get the message before resetting the context because toString() might access it. *)
  123. let msg = get_exc_error_message ctx v (match stack with [] -> [] | _ :: l -> l) (if p' = null_pos then p else p') in
  124. get_ctx_ref := prev;
  125. final();
  126. Error.error msg null_pos
  127. end
  128. | MacroApi.Abort ->
  129. final();
  130. None
  131. | exc ->
  132. get_ctx_ref := prev;
  133. final();
  134. raise exc
  135. in
  136. r