1+ package haxe ;
2+
3+ import php .* ;
4+
5+ private typedef NativeTrace = NativeIndexedArray <NativeAssocArray <Dynamic >>;
6+
7+ /**
8+ Elements return by `CallStack` methods.
9+ **/
10+ enum StackItem {
11+ CFunction ;
12+ Module ( m : String );
13+ FilePos ( s : Null <StackItem >, file : String , line : Int );
14+ Method ( classname : String , method : String );
15+ LocalFunction ( ? v : Int );
16+ }
17+
18+ class CallStack {
19+ /**
20+ If defined this function will be used to transform call stack entries.
21+ @param String - generated php file name.
22+ @param Int - Line number in generated file.
23+ */
24+ static public var mapPosition : String -> Int -> Null <{? source : String , ? originalLine : Int }>;
25+
26+ @:ifFeature (" haxe.CallStack.exceptionStack" )
27+ static var lastExceptionTrace : NativeTrace ;
28+
29+ /**
30+ Return the call stack elements, or an empty array if not available.
31+ **/
32+ public static function callStack () : Array <StackItem > {
33+ return makeStack (Global .debug_backtrace (Const .DEBUG_BACKTRACE_IGNORE_ARGS ));
34+ }
35+
36+ /**
37+ Return the exception stack : this is the stack elements between
38+ the place the last exception was thrown and the place it was
39+ caught, or an empty array if not available.
40+ **/
41+ public static function exceptionStack () : Array <StackItem > {
42+ return makeStack (lastExceptionTrace == null ? new NativeIndexedArray () : lastExceptionTrace );
43+ }
44+
45+ /**
46+ Returns a representation of the stack as a printable string.
47+ **/
48+ public static function toString ( stack : Array <StackItem > ) {
49+ return jstack. Format .toString (stack );
50+ }
51+
52+ @:ifFeature (" haxe.CallStack.exceptionStack" )
53+ static function saveExceptionTrace ( e : Throwable ) : Void {
54+ lastExceptionTrace = e .getTrace ();
55+
56+ // Reduce exception stack to the place where exception was caught
57+ var currentTrace = Global .debug_backtrace (Const .DEBUG_BACKTRACE_IGNORE_ARGS );
58+ var count = Global .count (currentTrace );
59+
60+ for (i in - (count - 1 )... 1 ) {
61+ var exceptionEntry : NativeAssocArray <Dynamic > = Global .end (lastExceptionTrace );
62+
63+ if (! Global .isset (exceptionEntry [' file' ]) || ! Global .isset (currentTrace [- i ][' file' ])) {
64+ Global .array_pop (lastExceptionTrace );
65+ } else if (currentTrace [- i ][' file' ] == exceptionEntry [' file' ] && currentTrace [- i ][' line' ] == exceptionEntry [' line' ]) {
66+ Global .array_pop (lastExceptionTrace );
67+ } else {
68+ break ;
69+ }
70+ }
71+
72+ // Remove arguments from trace to avoid blocking some objects from GC
73+ var count = Global .count (lastExceptionTrace );
74+ for (i in 0 ... count ) {
75+ lastExceptionTrace [i ][' args' ] = new NativeArray ();
76+ }
77+
78+ var thrownAt = new NativeAssocArray <Dynamic >();
79+ thrownAt [' function' ] = ' ' ;
80+ thrownAt [' line' ] = e .getLine ();
81+ thrownAt [' file' ] = e .getFile ();
82+ thrownAt [' class' ] = ' ' ;
83+ thrownAt [' args' ] = new NativeArray ();
84+ Global .array_unshift (lastExceptionTrace , thrownAt );
85+ }
86+
87+ static function makeStack (native : NativeTrace ) : Array <StackItem > {
88+ var result = [];
89+ var count = Global .count (native );
90+
91+ for (i in 0 ... count ) {
92+ var entry = native [i ];
93+ var item = null ;
94+
95+ if (i + 1 < count ) {
96+ var next = native [i + 1 ];
97+
98+ if (! Global .isset (next [' function' ])) next [' function' ] = ' ' ;
99+ if (! Global .isset (next [' class' ])) next [' class' ] = ' ' ;
100+
101+ if ((next [' function' ]: String ).indexOf (' {closure}' ) >= 0 ) {
102+ item = LocalFunction ();
103+ } else if ((next [' class' ]: String ).length > 0 && (next [' function' ]: String ).length > 0 ) {
104+ var cls = Boot .getClassName (next [' class' ]);
105+ item = Method (cls , next [' function' ]);
106+ }
107+ }
108+ if (Global .isset (entry [' file' ])) {
109+ if (mapPosition != null ) {
110+ var pos = mapPosition (entry [' file' ], entry [' line' ]);
111+ if (pos != null && pos .source != null && pos .originalLine != null ) {
112+ entry [' file' ] = pos .source ;
113+ entry [' line' ] = pos .originalLine ;
114+ }
115+ }
116+ result .push (FilePos (item , entry [' file' ], entry [' line' ]));
117+ } else if (item != null ) {
118+ result .push (item );
119+ }
120+ }
121+
122+ return result ;
123+ }
124+
125+ }
0 commit comments