1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Diagnostics ;
4+ using System . Text ;
5+ using System . Text . RegularExpressions ;
6+
7+ using AdvancedStringBuilder ;
8+
9+ using JavaScriptEngineSwitcher . Core . Extensions ;
10+ using JavaScriptEngineSwitcher . Core . Helpers ;
11+
12+ using CoreStrings = JavaScriptEngineSwitcher . Core . Resources . Strings ;
13+
14+ namespace JavaScriptEngineSwitcher . Jint . Helpers
15+ {
16+ /// <summary>
17+ /// JS error helpers
18+ /// </summary>
19+ internal static class JintJsErrorHelpers
20+ {
21+ #region Error location
22+
23+ private const string OriginalAnonymousFunctionName = "(anonymous)" ;
24+ private const string WrapperAnonymousFunctionName = "Anonymous function" ;
25+
26+ /// <summary>
27+ /// Regular expression for working with line of the script error location
28+ /// </summary>
29+ private static readonly Regex _errorLocationLineRegex =
30+ new Regex ( @"^[ ]{3}at " +
31+ @"(?:" +
32+ @"(?<functionName>" +
33+ @"[\w][\w ]*" +
34+ @"|" +
35+ CommonRegExps . JsFullNamePattern +
36+ @"|" +
37+ Regex . Escape ( OriginalAnonymousFunctionName ) +
38+ @") " +
39+ @"(?:\(" + CommonRegExps . JsFullNamePattern + @"(?:, " + CommonRegExps . JsFullNamePattern + @")*\) )?" +
40+ @")?" +
41+ @"(?<documentName>" + CommonRegExps . DocumentNamePattern + @"):" +
42+ @"(?<lineNumber>\d+)(?::(?<columnNumber>\d+))?$" ) ;
43+
44+
45+ /// <summary>
46+ /// Parses a string representation of the script error location to produce an array of
47+ /// <see cref="ErrorLocationItem"/> instances
48+ /// </summary>
49+ /// <param name="errorLocation">String representation of the script error location</param>
50+ /// <returns>An array of <see cref="ErrorLocationItem"/> instances</returns>
51+ public static ErrorLocationItem [ ] ParseErrorLocation ( string errorLocation )
52+ {
53+ if ( string . IsNullOrWhiteSpace ( errorLocation ) )
54+ {
55+ return new ErrorLocationItem [ 0 ] ;
56+ }
57+
58+ var errorLocationItems = new List < ErrorLocationItem > ( ) ;
59+ string [ ] lines = errorLocation . SplitToLines ( ) ;
60+ int lineCount = lines . Length ;
61+
62+ for ( int lineIndex = 0 ; lineIndex < lineCount ; lineIndex ++ )
63+ {
64+ string line = lines [ lineIndex ] ;
65+ Match lineMatch = _errorLocationLineRegex . Match ( line ) ;
66+
67+ if ( lineMatch . Success )
68+ {
69+ GroupCollection lineGroups = lineMatch . Groups ;
70+
71+ var errorLocationItem = new ErrorLocationItem
72+ {
73+ FunctionName = lineGroups [ "functionName" ] . Value ,
74+ DocumentName = lineGroups [ "documentName" ] . Value ,
75+ LineNumber = int . Parse ( lineGroups [ "lineNumber" ] . Value ) ,
76+ ColumnNumber = lineGroups [ "columnNumber" ] . Success ?
77+ int . Parse ( lineGroups [ "columnNumber" ] . Value ) : 0
78+ } ;
79+ errorLocationItems . Add ( errorLocationItem ) ;
80+ }
81+ else
82+ {
83+ Debug . WriteLine ( string . Format ( CoreStrings . Runtime_InvalidErrorLocationLineFormat , line ) ) ;
84+ return new ErrorLocationItem [ 0 ] ;
85+ }
86+ }
87+
88+ return errorLocationItems . ToArray ( ) ;
89+ }
90+
91+ /// <summary>
92+ /// Fixes a error location items
93+ /// </summary>
94+ /// <param name="errorLocationItems">An array of <see cref="ErrorLocationItem"/> instances</param>
95+ /// <param name="currentDocumentName">Current document name</param>
96+ public static void FixErrorLocationItems ( ErrorLocationItem [ ] errorLocationItems , string currentDocumentName )
97+ {
98+ foreach ( ErrorLocationItem errorLocationItem in errorLocationItems )
99+ {
100+ string functionName = errorLocationItem . FunctionName ;
101+ if ( functionName . Length > 0 )
102+ {
103+ if ( functionName == OriginalAnonymousFunctionName )
104+ {
105+ errorLocationItem . FunctionName = WrapperAnonymousFunctionName ;
106+ }
107+ }
108+ else
109+ {
110+ errorLocationItem . FunctionName = "Global code" ;
111+ }
112+
113+ if ( errorLocationItem . DocumentName == ":0" && errorLocationItem . LineNumber == 1 )
114+ {
115+ errorLocationItem . DocumentName = currentDocumentName ;
116+ errorLocationItem . LineNumber = 0 ;
117+ errorLocationItem . ColumnNumber = 0 ;
118+ }
119+ }
120+ }
121+
122+ /// <summary>
123+ /// Converts a call chain to stack
124+ /// </summary>
125+ /// <param name="callChain">Call chain</param>
126+ /// <returns>Call stack</returns>
127+ public static string ConvertCallChainToStack ( string callChain )
128+ {
129+ string callStack = string . Empty ;
130+ string [ ] callChainItems = callChain
131+ . Split ( new string [ ] { "->" } , StringSplitOptions . None )
132+ ;
133+
134+ if ( callChainItems . Length > 0 )
135+ {
136+ var stringBuilderPool = StringBuilderPool . Shared ;
137+ StringBuilder stackBuilder = stringBuilderPool . Rent ( ) ;
138+
139+ for ( int chainItemIndex = callChainItems . Length - 1 ; chainItemIndex >= 0 ; chainItemIndex -- )
140+ {
141+ string chainItem = callChainItems [ chainItemIndex ] ;
142+ if ( chainItem == OriginalAnonymousFunctionName )
143+ {
144+ chainItem = WrapperAnonymousFunctionName ;
145+ }
146+
147+ JsErrorHelpers . WriteErrorLocationLine ( stackBuilder , chainItem , string . Empty , 0 , 0 ) ;
148+ if ( chainItemIndex > 0 )
149+ {
150+ stackBuilder . AppendLine ( ) ;
151+ }
152+ }
153+
154+ callStack = stackBuilder . ToString ( ) ;
155+ stringBuilderPool . Return ( stackBuilder ) ;
156+ }
157+
158+ return callStack ;
159+ }
160+
161+ #endregion
162+ }
163+ }
0 commit comments