Browse Source

Finish all JSON Unit tests

Frederic Torres 11 years ago
parent
commit
1e1b2f3cee
1 changed files with 64 additions and 27 deletions
  1. 64 27
      Jint/Native/Json/JsonParser.cs

+ 64 - 27
Jint/Native/Json/JsonParser.cs

@@ -206,6 +206,11 @@ namespace Jint.Native.Json
 
 
         const string TrueValue  = "true";
         const string TrueValue  = "true";
         const string FalseValue = "false";
         const string FalseValue = "false";
+        
+        private static bool IsNullChar(char ch)
+        {
+            return Null.Text.Contains(ch.ToString());
+        }
 
 
         private static bool IsTrueOrFalseChar(char ch)
         private static bool IsTrueOrFalseChar(char ch)
         {
         {
@@ -222,7 +227,7 @@ namespace Jint.Native.Json
             {
             {
                 s += _source.CharCodeAt(_index++).ToString();
                 s += _source.CharCodeAt(_index++).ToString();
             }
             }
-
+            
             if (s == TrueValue || s == FalseValue)
             if (s == TrueValue || s == FalseValue)
             {
             {
                 return new Token
                 return new Token
@@ -240,6 +245,33 @@ namespace Jint.Native.Json
             }
             }
         }
         }
 
 
+        private Token ScanNullLiteral()
+        {
+            int start = _index;
+            string s = string.Empty;
+            
+            while (IsNullChar(_source.CharCodeAt(_index)))
+            {
+                s += _source.CharCodeAt(_index++).ToString();
+            }
+
+            if (s == Null.Text)
+            {
+                return new Token
+                {
+                    Type = Tokens.NullLiteral,
+                    Value = Null.Instance,
+                    LineNumber = _lineNumber,
+                    LineStart = _lineStart,
+                    Range = new[] { start, _index }
+                };
+            }
+            else
+            {
+                throw new JavaScriptException(_engine.SyntaxError, string.Format(Messages.UnexpectedToken, s));
+            }
+        }
+
         private Token ScanStringLiteral()
         private Token ScanStringLiteral()
         {
         {
             string str = "";
             string str = "";
@@ -258,10 +290,16 @@ namespace Jint.Native.Json
                     quote = char.MinValue;
                     quote = char.MinValue;
                     break;
                     break;
                 }
                 }
+
+                if ((int)ch <= 31)
+                {
+                    throw new JavaScriptException(_engine.SyntaxError, string.Format("Invalid character '{0}', position:{1}, string:{2}", ch, _index, _source));
+                }
                 
                 
                 if (ch == '\\')
                 if (ch == '\\')
                 {
                 {
                     ch = _source.CharCodeAt(_index++);
                     ch = _source.CharCodeAt(_index++);
+
                     if (ch > 0 || !IsLineTerminator(ch))
                     if (ch > 0 || !IsLineTerminator(ch))
                     {
                     {
                         switch (ch)
                         switch (ch)
@@ -350,11 +388,6 @@ namespace Jint.Native.Json
                 throw new JavaScriptException(_engine.SyntaxError, string.Format(Messages.UnexpectedToken, _source));
                 throw new JavaScriptException(_engine.SyntaxError, string.Format(Messages.UnexpectedToken, _source));
             }
             }
             
             
-            if (StringContainsInvalidChar(str))
-            {
-                throw new JavaScriptException(_engine.SyntaxError, string.Format("Invalid character in string '{0}' '", str));
-            }
-
             return new Token
             return new Token
                 {
                 {
                     Type = Tokens.String,
                     Type = Tokens.String,
@@ -416,6 +449,11 @@ namespace Jint.Native.Json
                 return ScanBooleanLiteral();
                 return ScanBooleanLiteral();
             }
             }
 
 
+            if (ch == Null.Text[0])
+            {
+                return ScanNullLiteral();
+            }
+
             return ScanPunctuator();
             return ScanPunctuator();
         }
         }
 
 
@@ -656,7 +694,6 @@ namespace Jint.Native.Json
 
 
         public ObjectInstance ParseJsonObject()
         public ObjectInstance ParseJsonObject()
         {
         {
-
             Expect("{");
             Expect("{");
 
 
             var obj = _engine.Object.Construct(Arguments.Empty);
             var obj = _engine.Object.Construct(Arguments.Empty);
@@ -670,7 +707,7 @@ namespace Jint.Native.Json
                 }
                 }
 
 
                 var name = Lex().Value.ToString();
                 var name = Lex().Value.ToString();
-                if (StringContainsInvalidChar(name))
+                if (PropertyNameContainsInvalidChar0To31(name))
                 {
                 {
                     throw new JavaScriptException(_engine.SyntaxError, string.Format("Invalid character in property name '{0}'", name));
                     throw new JavaScriptException(_engine.SyntaxError, string.Format("Invalid character in property name '{0}'", name));
                 }
                 }
@@ -678,14 +715,6 @@ namespace Jint.Native.Json
                 Expect(":");
                 Expect(":");
                 var value = ParseJsonValue();
                 var value = ParseJsonValue();
 
 
-                if (value.IsString())
-                {
-                    if (StringContainsInvalidChar(value.AsString()))
-                    {
-                        throw new JavaScriptException(_engine.SyntaxError, string.Format("Invalid character in string '{0}' property '{1}'", value.AsString(), name));
-                    }
-                }
-
                 obj.FastAddProperty(name, value, true, true, true);
                 obj.FastAddProperty(name, value, true, true, true);
                 
                 
                 if (!Match("}"))
                 if (!Match("}"))
@@ -699,22 +728,26 @@ namespace Jint.Native.Json
             return obj;
             return obj;
         }
         }
 
 
-        /// <summary>
-        /// * @path ch15/15.12/15.12.2/15.12.2-2-3.js
-        /// * @description JSON.parse - parsing an object where property name ends with a null character
-        /// </summary>
-        /// <param name="s"></param>
-        /// <returns></returns>
-        private bool StringContainsInvalidChar(string s)
-        {
+        private bool PropertyNameContainsInvalidChar0To31(string s)
+        {    
+            const int max = 31;
+
             for (var i = 0; i < s.Length; i++)
             for (var i = 0; i < s.Length; i++)
             {
             {
-                if ((int)s[i] <= 31) 
+                var val = (int)s[i];
+                if (val <= max)
                     return true;
                     return true;
             }
             }
             return false;
             return false;
         }
         }
-
+        
+        /// <summary>
+        /// Optimization.
+        /// By calling Lex().Value for each type, we parse the token twice.
+        /// It was already parsed by the peek() method.
+        /// _lookahead.Value already contain the value.
+        /// </summary>
+        /// <returns></returns>
         private JsValue ParseJsonValue()
         private JsValue ParseJsonValue()
         {
         {
             Tokens type = _lookahead.Type;
             Tokens type = _lookahead.Type;
@@ -722,12 +755,16 @@ namespace Jint.Native.Json
 
 
             if (type == Tokens.NullLiteral)
             if (type == Tokens.NullLiteral)
             {
             {
+                var v = Lex().Value;
                 return Null.Instance;
                 return Null.Instance;
+                // if FromObject() is modified to handle JsValue of type null
+                // as input parameter we could use the following
+                // return JsValue.FromObject(Lex().Value);
             }
             }
             
             
             if (type == Tokens.String)
             if (type == Tokens.String)
             {
             {
-                return JsValue.FromObject(Lex().Value);
+                return JsValue.FromObject(Lex().Value.ToString());
             }
             }
 
 
             if (type == Tokens.Number)
             if (type == Tokens.Number)