context: using System;
  using System.Collections.Generic;
  using System.Globalization;
  using System.Linq;
  using Jint.Native.Object;
  using Jint.Parser;
  using Jint.Parser.Ast;
  using Jint.Runtime;
  
  namespace Jint.Native.Json
  {
      public class JsonParser
      {
          private readonly Engine _engine;
  
          public JsonParser(Engine engine)
          {
              _engine = engine;
          }
  
          private Extra _extra;
  
          private int _index; // position in the stream
          private int _length; // length of the stream
          private int _lineNumber;
          private int _lineStart;
          private Location _location;
          private Token _lookahead;
          private string _source;
  
          private State _state;
  
          private static bool IsDecimalDigit(char ch)
          {
              return (ch >= '0' && ch <= '9');
          }
  
          private static bool IsHexDigit(char ch)
          {
              return
                  ch >= '0' && ch <= '9' ||
                  ch >= 'a' && ch <= 'f' ||
                  ch >= 'A' && ch <= 'F'
                  ;
          }
  
          private static bool IsOctalDigit(char ch)
          {
              return ch >= '0' && ch <= '7';
          }
  
          private static bool IsWhiteSpace(char ch)
          {
              return (ch == ' ')  ||
                     (ch == '\t') ||
                     (ch == '\n') ||
                     (ch == '\r');
          }
  
          private static bool IsLineTerminator(char ch)
          {
              return (ch == 10) || (ch == 13) || (ch == 0x2028) || (ch == 0x2029);
          }
  
          private static bool IsNullChar(char ch)
          {
              return ch == 'n'
                  || ch == 'u'
                  || ch == 'l'
                  || ch == 'l'
                  ;
          }
  
          private static bool IsTrueOrFalseChar(char ch)
          {
              return ch == 't'
                  || ch == 'r'
                  || ch == 'u'
                  || ch == 'e'
                  || ch == 'f'
                  || ch == 'a'
                  || ch == 'l'
                  || ch == 's'
                  ;
          }
  
          private char ScanHexEscape(char prefix)
          {
              int code = char.MinValue;
  
              int len = (prefix == 'u') ? 4 : 2;
              for (int i = 0; i < len; ++i)
              {
                  if (_index < _length && IsHexDigit(_source.CharCodeAt(_index)))
                  {
                      char ch = _source.CharCodeAt(_index++);
                      code = code * 16 + "0123456789abcdef".IndexOf(ch.ToString(), StringComparison.OrdinalIgnoreCase);
                  }
                  else
                  {
                      throw new JavaScriptException(_engine.SyntaxError, string.Format("Expected hexadecimal digit:{0}", _source));
                  }
              }
              return (char)code;
          }
  
          private void SkipWhiteSpace()
          {
              while (_index < _length)
              {
                  char ch = _source.CharCodeAt(_index);
  
                  if (IsWhiteSpace(ch))
                  {
                      ++_index;
                  }
                  else
                  {
                      break;
                  }
              }
          }
  
          private Token ScanPunctuator()
          {
              int start = _index;
              char code = _source.CharCodeAt(_index);
  
              switch ((int) code)
              {
                      // Check for most common single-character punctuators.
                  case 46: // . dot
                  case 40: // ( open bracket
                  case 41: // ) close bracket
                  case 59: // ; semicolon
                  case 44: // , comma
                  case 123: // { open curly brace
                  case 125: // } close curly brace
                  case 91: // [
                  case 93: // ]
                  case 58: // :
                  case 63: // ?
                  case 126: // ~
                      ++_index;
  
                      return new Token
                          {
                              Type = Tokens.Punctuator,
                              Value = code.ToString(),
                              LineNumber = _lineNumber,
                              LineStart = _lineStart,
                              Range = new[] {start, _index}
                          };
              }
              throw new JavaScriptException(_engine.SyntaxError, string.Format(Messages.UnexpectedToken, code));
          }
  
          private Token ScanNumericLiteral()
          {
              char ch = _source.CharCodeAt(_index);
  
              int start = _index;
              string number = "";
              
              // Number start with a -
              if (ch == '-')
              {
                  number += _source.CharCodeAt(_index++).ToString();
                  ch = _source.CharCodeAt(_index);
              }
  
              if (ch != '.')
              {
                  number += _source.CharCodeAt(_index++).ToString();
                  ch = _source.CharCodeAt(_index);
  
                  // Hex number starts with '0x'.
                  // Octal number starts with '0'.
                  if (number == "0")
                  {
                      // decimal number starts with '0' such as '09' is illegal.
                      if (ch > 0 && IsDecimalDigit(ch))
                      {
                          throw new Exception(Messages.UnexpectedToken);
                      }
                  }
  
                  while (IsDecimalDigit(_source.CharCodeAt(_index)))
                  {
                      number += _source.CharCodeAt(_index++).ToString();
                  }
                  ch = _source.CharCodeAt(_index);
              }
  
              if (ch == '.')
              {
                  number += _source.CharCodeAt(_index++).ToString();
                  while (IsDecimalDigit(_source.CharCodeAt(_index)))
                  {
                      number += _source.CharCodeAt(_index++).ToString();
                  }
                  ch = _source.CharCodeAt(_index);
              }
  
              if (ch == 'e' || ch == 'E')
              {
                  number += _source.CharCodeAt(_index++).ToString();
  
                  ch = _source.CharCodeAt(_index);
                  if (ch == '+' || ch == '-')
                  {
                      number += _source.CharCodeAt(_index++).ToString();
                  }
                  if (IsDecimalDigit(_source.CharCodeAt(_index)))
                  {
                      while (IsDecimalDigit(_source.CharCodeAt(_index)))
                      {
                          number += _source.CharCodeAt(_index++).ToString();
                      }
                  }
                  else
                  {
                      throw new Exception(Messages.UnexpectedToken);
                  }
              }
  
              return new Token
                  {
                      Type = Tokens.Number,
                      Value = Double.Parse(number, NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture),
                      LineNumber = _lineNumber,
                      LineStart = _lineStart,
                      Range = new[] {start, _index}
                  };
          }
  
          private Token ScanBooleanLiteral()
          {
              int start = _index;
              string s = "";
              
              while (IsTrueOrFalseChar(_source.CharCodeAt(_index)))
              {
                  s += _source.CharCodeAt(_index++).ToString();
              }
              
              if (s == "true" || s == "false")
              {
                  return new Token
                  {
                      Type = Tokens.BooleanLiteral,
                      Value = s == "true",
                      LineNumber = _lineNumber,
                      LineStart = _lineStart,
                      Range = new[] { start, _index }
                  };
              }
              else 
              {
                  throw new JavaScriptException(_engine.SyntaxError, string.Format(Messages.UnexpectedToken, s));
              }
          }
  
          private Token ScanNullLiteral()
          {
              int start = _index;
              string s = "";
              
              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()
          {
              string str = "";
  
              char quote = _source.CharCodeAt(_index);
  
              int start = _index;
              ++_index;
  
              while (_index < _length)
              {
                  char ch = _source.CharCodeAt(_index++);
  
                  if (ch == quote)
                  {
                      quote = char.MinValue;
                      break;
                  }
  
                  if (ch <= 31)
                  {
                      throw new JavaScriptException(_engine.SyntaxError, string.Format("Invalid character '{0}', position:{1}, string:{2}", ch, _index, _source));
                  }
                  
                  if (ch == '\\')
                  {
                      ch = _source.CharCodeAt(_index++);
  
  
gt:                     if (ch > 0 || !IsLineTerminator(ch))