Browse Source

Adding source information in exceptions

#21
Sebastien Ros 11 years ago
parent
commit
2b1221635f

+ 29 - 0
Jint.Tests/Runtime/EngineTests.cs

@@ -4,6 +4,8 @@ using System.IO;
 using System.Reflection;
 using System.Threading;
 using Jint.Native.Number;
+using Jint.Parser;
+using Jint.Parser.Ast;
 using Jint.Runtime;
 using Xunit;
 using Xunit.Extensions;
@@ -709,5 +711,32 @@ namespace Jint.Tests.Runtime
             result = engine.Execute("JSON.parse('{\"x\" : 3.3}').x").GetCompletionValue().AsNumber();
             Assert.Equal(3.3d, result);
         }
+
+        [Fact]
+        public void ShouldGetTheLastSyntaxNode()
+        {
+            var engine = new Engine();
+            engine.Execute("1.2");
+
+            var result = engine.GetLastSyntaxNode();
+            Assert.Equal(SyntaxNodes.Literal, result.Type);
+        }
+
+        [Fact]
+        public void ShouldGetParseErrorLocation()
+        {
+            var engine = new Engine();
+            try
+            {
+                engine.Execute("1.2+ new", new ParserOptions { Source = "jQuery.js" });
+            }
+            catch (ParserException e)
+            {
+                Assert.Equal(1, e.LineNumber);
+                Assert.Equal(9, e.Column);
+                Assert.Equal("jQuery.js", e.Source);
+            }
+        }
+
     }
 }

+ 26 - 1
Jint/Engine.cs

@@ -32,7 +32,8 @@ namespace Jint
         private readonly Stack<ExecutionContext> _executionContexts;
         private JsValue _completionValue = JsValue.Undefined;
         private int _statementsCount;
-        
+        private SyntaxNode _lastSyntaxNode = null;
+
         // cache of types used when resolving CLR type names
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>(); 
 
@@ -221,9 +222,16 @@ namespace Jint
             return Execute(parser.Parse(source));
         }
 
+        public Engine Execute(string source, ParserOptions parserOptions)
+        {
+            var parser = new JavaScriptParser();
+            return Execute(parser.Parse(source, parserOptions));
+        }
+
         public Engine Execute(Program program)
         {
             ResetStatementsCount();
+            ResetLastStatement();
 
             using (new StrictModeScope(Options.IsStrict() || program.Strict))
             {
@@ -241,6 +249,11 @@ namespace Jint
             return this;
         }
 
+        private void ResetLastStatement()
+        {
+            _lastSyntaxNode = null;
+        }
+
         /// <summary>
         /// Gets the last evaluated statement completion value
         /// </summary>
@@ -257,6 +270,8 @@ namespace Jint
                 throw new StatementsCountOverflowException();
             }
 
+            _lastSyntaxNode = statement;
+
             switch (statement.Type)
             {
                 case SyntaxNodes.BlockStatement:
@@ -326,6 +341,8 @@ namespace Jint
 
         public object EvaluateExpression(Expression expression)
         {
+            _lastSyntaxNode = expression;
+
             switch (expression.Type)
             {
                 case SyntaxNodes.AssignmentExpression:
@@ -585,6 +602,14 @@ namespace Jint
             return GetValue(Global, propertyName);
         }
 
+        /// <summary>
+        /// Gets the last evaluated <see cref="SyntaxNode"/>.
+        /// </summary>
+        public SyntaxNode GetLastSyntaxNode()
+        {
+            return _lastSyntaxNode;
+        }
+
         /// <summary>
         /// Gets a named value from the specified scope.
         /// </summary>

+ 1 - 1
Jint/Native/Function/EvalFunctionInstance.cs

@@ -80,7 +80,7 @@ namespace Jint.Native.Function
                     }
                 }
             }
-            catch (ParserError)
+            catch (ParserException)
             {
                 throw new JavaScriptException(Engine.SyntaxError);
             }

+ 1 - 1
Jint/Native/Function/FunctionConstructor.cs

@@ -88,7 +88,7 @@ namespace Jint.Native.Function
                 var functionExpression = "function(" + p + ") { " + body + "}";
                 function = parser.ParseFunctionExpression(functionExpression); 
             }
-            catch (ParserError)
+            catch (ParserException)
             {
                 throw new JavaScriptException(Engine.SyntaxError);
             }

+ 5 - 5
Jint/Native/Json/JsonParser.cs

@@ -603,12 +603,12 @@ namespace Jint.Native.Json
 
         private void ThrowError(Token token, string messageFormat, params object[] arguments)
         {
-            ParserError error;
+            ParserException exception;
             string msg = System.String.Format(messageFormat, arguments);
 
             if (token.LineNumber.HasValue)
             {
-                error = new ParserError("Line " + token.LineNumber + ": " + msg)
+                exception = new ParserException("Line " + token.LineNumber + ": " + msg)
                     {
                         Index = token.Range[0],
                         LineNumber = token.LineNumber.Value,
@@ -617,7 +617,7 @@ namespace Jint.Native.Json
             }
             else
             {
-                error = new ParserError("Line " + _lineNumber + ": " + msg)
+                exception = new ParserException("Line " + _lineNumber + ": " + msg)
                     {
                         Index = _index,
                         LineNumber = _lineNumber,
@@ -625,8 +625,8 @@ namespace Jint.Native.Json
                     };
             }
 
-            error.Description = msg;
-            throw error;
+            exception.Description = msg;
+            throw exception;
         }
 
         // Throw an exception because of the token.

+ 1 - 1
Jint/Parser/Ast/Program.cs

@@ -12,7 +12,7 @@ namespace Jint.Parser.Ast
 
         public List<Comment> Comments;
         public List<Token> Tokens;
-        public List<ParserError> Errors;
+        public List<ParserException> Errors;
         public bool Strict;
 
         public IList<VariableDeclaration> VariableDeclarations { get; set; }

+ 15 - 10
Jint/Parser/JavascriptParser.cs

@@ -1829,30 +1829,32 @@ namespace Jint.Parser
 
         private void ThrowError(Token token, string messageFormat, params object[] arguments)
         {
-            ParserError error;
+            ParserException exception;
             string msg = String.Format(messageFormat, arguments);
 
             if (token != null && token.LineNumber.HasValue)
             {
-                error = new ParserError("Line " + token.LineNumber + ": " + msg)
+                exception = new ParserException("Line " + token.LineNumber + ": " + msg)
                     {
                         Index = token.Range[0],
                         LineNumber = token.LineNumber.Value,
-                        Column = token.Range[0] - _lineStart + 1
+                        Column = token.Range[0] - _lineStart + 1,
+                        Source = _extra.Source
                     };
             }
             else
             {
-                error = new ParserError("Line " + _lineNumber + ": " + msg)
+                exception = new ParserException("Line " + _lineNumber + ": " + msg)
                     {
                         Index = _index,
                         LineNumber = _lineNumber,
-                        Column = _index - _lineStart + 1
+                        Column = _index - _lineStart + 1,
+                        Source = _extra.Source
                     };
             }
 
-            error.Description = msg;
-            throw error;
+            exception.Description = msg;
+            throw exception;
         }
 
         private void ThrowErrorTolerant(Token token, string messageFormat, params object[] arguments)
@@ -1865,7 +1867,10 @@ namespace Jint.Parser
             {
                 if (_extra.Errors != null)
                 {
-                    _extra.Errors.Add(new ParserError(e.Message));
+                    _extra.Errors.Add(new ParserException(e.Message)
+                    {
+                        Source = _extra.Source
+                    });
                 }
                 else
                 {
@@ -3907,7 +3912,7 @@ namespace Jint.Parser
 
                 if (options.Tolerant)
                 {
-                    _extra.Errors = new List<ParserError>();
+                    _extra.Errors = new List<ParserException>();
                 }
             }
 
@@ -3977,7 +3982,7 @@ namespace Jint.Parser
 
             public List<Comment> Comments;
             public List<Token> Tokens;
-            public List<ParserError> Errors;
+            public List<ParserException> Errors;
         }
 
         private class LocationMarker

+ 3 - 2
Jint/Parser/ParserException.cs

@@ -2,14 +2,15 @@
 
 namespace Jint.Parser
 {
-    public class ParserError : Exception
+    public class ParserException : Exception
     {
         public int Column;
         public string Description;
         public int Index;
         public int LineNumber;
+        public string Source;
 
-        public ParserError(string message) : base(message)
+        public ParserException(string message) : base(message)
         {
         }
     }