|
@@ -1,7 +1,9 @@
|
|
using System.Globalization;
|
|
using System.Globalization;
|
|
|
|
+using System.Runtime.CompilerServices;
|
|
using Esprima;
|
|
using Esprima;
|
|
using Esprima.Ast;
|
|
using Esprima.Ast;
|
|
using Jint.Native.Object;
|
|
using Jint.Native.Object;
|
|
|
|
+using Jint.Pooling;
|
|
using Jint.Runtime;
|
|
using Jint.Runtime;
|
|
|
|
|
|
using Range = Esprima.Range;
|
|
using Range = Esprima.Range;
|
|
@@ -89,9 +91,9 @@ namespace Jint.Native.Json
|
|
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
{
|
|
- if (_index < _length && IsHexDigit(_source.CharCodeAt(_index)))
|
|
|
|
|
|
+ if (_index < _length + 1 && IsHexDigit(_source[_index]))
|
|
{
|
|
{
|
|
- char ch = _source.CharCodeAt(_index++);
|
|
|
|
|
|
+ char ch = _source[_index++];
|
|
code = code * 16 + "0123456789abcdef".IndexOf(ch.ToString(), StringComparison.OrdinalIgnoreCase);
|
|
code = code * 16 + "0123456789abcdef".IndexOf(ch.ToString(), StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
@@ -104,25 +106,16 @@ namespace Jint.Native.Json
|
|
|
|
|
|
private void SkipWhiteSpace()
|
|
private void SkipWhiteSpace()
|
|
{
|
|
{
|
|
- while (_index < _length)
|
|
|
|
|
|
+ while (_index < _length && IsWhiteSpace(_source[_index]))
|
|
{
|
|
{
|
|
- char ch = _source.CharCodeAt(_index);
|
|
|
|
-
|
|
|
|
- if (IsWhiteSpace(ch))
|
|
|
|
- {
|
|
|
|
- ++_index;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ ++_index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private Token ScanPunctuator()
|
|
private Token ScanPunctuator()
|
|
{
|
|
{
|
|
int start = _index;
|
|
int start = _index;
|
|
- char code = _source.CharCodeAt(_index);
|
|
|
|
|
|
+ char code = start < _source.Length ? _source[_index] : char.MinValue;
|
|
|
|
|
|
switch ((int) code)
|
|
switch ((int) code)
|
|
{
|
|
{
|
|
@@ -239,47 +232,62 @@ namespace Jint.Native.Json
|
|
|
|
|
|
private Token ScanBooleanLiteral()
|
|
private Token ScanBooleanLiteral()
|
|
{
|
|
{
|
|
- int start = _index;
|
|
|
|
- string s = "";
|
|
|
|
|
|
+ var start = _index;
|
|
|
|
+ var s = "";
|
|
|
|
|
|
- while (IsTrueOrFalseChar(_source.CharCodeAt(_index)))
|
|
|
|
|
|
+ var boolTrue = false;
|
|
|
|
+ var boolFalse = false;
|
|
|
|
+ if (ConsumeMatch("true"))
|
|
|
|
+ {
|
|
|
|
+ boolTrue = true;
|
|
|
|
+ s = "true";
|
|
|
|
+ }
|
|
|
|
+ else if (ConsumeMatch("false"))
|
|
{
|
|
{
|
|
- s += _source.CharCodeAt(_index++).ToString();
|
|
|
|
|
|
+ boolFalse = true;
|
|
|
|
+ s = "false";
|
|
}
|
|
}
|
|
|
|
|
|
- if (s == "true" || s == "false")
|
|
|
|
|
|
+ if (boolTrue || boolFalse)
|
|
{
|
|
{
|
|
return new Token
|
|
return new Token
|
|
{
|
|
{
|
|
Type = Tokens.BooleanLiteral,
|
|
Type = Tokens.BooleanLiteral,
|
|
Text = s,
|
|
Text = s,
|
|
- Value = s == "true",
|
|
|
|
|
|
+ Value = boolTrue,
|
|
LineNumber = _lineNumber,
|
|
LineNumber = _lineNumber,
|
|
LineStart = _lineStart,
|
|
LineStart = _lineStart,
|
|
Range = new[] { start, _index }
|
|
Range = new[] { start, _index }
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
- ThrowError(start, Messages.UnexpectedToken, s);
|
|
|
|
|
|
+ ThrowError(start, Messages.UnexpectedTokenIllegal);
|
|
return null!;
|
|
return null!;
|
|
}
|
|
}
|
|
|
|
|
|
- private Token ScanNullLiteral()
|
|
|
|
|
|
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
+ private bool ConsumeMatch(string text)
|
|
{
|
|
{
|
|
- int start = _index;
|
|
|
|
- string s = "";
|
|
|
|
-
|
|
|
|
- while (IsNullChar(_source.CharCodeAt(_index)))
|
|
|
|
|
|
+ var start = _index;
|
|
|
|
+ var length = text.Length;
|
|
|
|
+ if (start + length - 1 < _source.Length && _source.AsSpan(start, length).SequenceEqual(text.AsSpan()))
|
|
{
|
|
{
|
|
- s += _source.CharCodeAt(_index++).ToString();
|
|
|
|
|
|
+ _index += length;
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (s == Null.Text)
|
|
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Token ScanNullLiteral()
|
|
|
|
+ {
|
|
|
|
+ int start = _index;
|
|
|
|
+ if (ConsumeMatch(Null.Text))
|
|
{
|
|
{
|
|
return new Token
|
|
return new Token
|
|
{
|
|
{
|
|
Type = Tokens.NullLiteral,
|
|
Type = Tokens.NullLiteral,
|
|
- Text = s,
|
|
|
|
|
|
+ Text = Null.Text,
|
|
Value = Null.Instance,
|
|
Value = Null.Instance,
|
|
LineNumber = _lineNumber,
|
|
LineNumber = _lineNumber,
|
|
LineStart = _lineStart,
|
|
LineStart = _lineStart,
|
|
@@ -287,15 +295,16 @@ namespace Jint.Native.Json
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
- ThrowError(start, Messages.UnexpectedToken, s);
|
|
|
|
|
|
+ ThrowError(start, Messages.UnexpectedTokenIllegal);
|
|
return null!;
|
|
return null!;
|
|
}
|
|
}
|
|
|
|
|
|
private Token ScanStringLiteral()
|
|
private Token ScanStringLiteral()
|
|
{
|
|
{
|
|
- var sb = new System.Text.StringBuilder();
|
|
|
|
|
|
+ using var wrapper = StringBuilderPool.Rent();
|
|
|
|
+ var sb = wrapper.Builder;
|
|
|
|
|
|
- char quote = _source.CharCodeAt(_index);
|
|
|
|
|
|
+ char quote = _source[_index];
|
|
|
|
|
|
int start = _index;
|
|
int start = _index;
|
|
++_index;
|
|
++_index;
|
|
@@ -451,22 +460,22 @@ namespace Jint.Native.Json
|
|
|
|
|
|
private Token CollectToken()
|
|
private Token CollectToken()
|
|
{
|
|
{
|
|
- var start = new Position(
|
|
|
|
|
|
+ var start = Position.From(
|
|
line: _lineNumber,
|
|
line: _lineNumber,
|
|
column: _index - _lineStart);
|
|
column: _index - _lineStart);
|
|
|
|
|
|
Token token = Advance();
|
|
Token token = Advance();
|
|
|
|
|
|
- var end = new Position(
|
|
|
|
|
|
+ var end = Position.From(
|
|
line: _lineNumber,
|
|
line: _lineNumber,
|
|
column: _index - _lineStart);
|
|
column: _index - _lineStart);
|
|
|
|
|
|
- _location = new Location(start, end, _source);
|
|
|
|
|
|
+ _location = Location.From(start, end, _source);
|
|
|
|
|
|
if (token.Type != Tokens.EOF)
|
|
if (token.Type != Tokens.EOF)
|
|
{
|
|
{
|
|
var range = new[] {token.Range[0], token.Range[1]};
|
|
var range = new[] {token.Range[0], token.Range[1]};
|
|
- string value = _source.Slice(token.Range[0], token.Range[1]);
|
|
|
|
|
|
+ var value = _source.Substring(token.Range[0], token.Range[1]);
|
|
_extra.Tokens.Add(new Token
|
|
_extra.Tokens.Add(new Token
|
|
{
|
|
{
|
|
Type = token.Type,
|
|
Type = token.Type,
|
|
@@ -523,18 +532,13 @@ namespace Jint.Native.Json
|
|
{
|
|
{
|
|
if (_extra.Range != null)
|
|
if (_extra.Range != null)
|
|
{
|
|
{
|
|
- node.Range = new Range(_state.MarkerStack.Pop(), _index);
|
|
|
|
|
|
+ node.Range = Range.From(_state.MarkerStack.Pop(), _index);
|
|
}
|
|
}
|
|
if (_extra.Loc.HasValue)
|
|
if (_extra.Loc.HasValue)
|
|
{
|
|
{
|
|
- node.Location = new Location(
|
|
|
|
- start: new Position(
|
|
|
|
- line: _state.MarkerStack.Pop(),
|
|
|
|
- column: _state.MarkerStack.Pop()),
|
|
|
|
- end: new Position(
|
|
|
|
- line: _lineNumber,
|
|
|
|
- column: _index - _lineStart),
|
|
|
|
- source: _source);
|
|
|
|
|
|
+ var start = Position.From(line: _state.MarkerStack.Pop(), column: _state.MarkerStack.Pop());
|
|
|
|
+ var end = Position.From(line: _lineNumber, column: _index - _lineStart);
|
|
|
|
+ node.Location = Location.From(start: start, end: end, source: _source);
|
|
PostProcess(node);
|
|
PostProcess(node);
|
|
}
|
|
}
|
|
return node;
|
|
return node;
|
|
@@ -837,6 +841,7 @@ namespace Jint.Native.Json
|
|
public const string InvalidCharacter = "Invalid character in JSON";
|
|
public const string InvalidCharacter = "Invalid character in JSON";
|
|
public const string ExpectedHexadecimalDigit = "Expected hexadecimal digit in JSON";
|
|
public const string ExpectedHexadecimalDigit = "Expected hexadecimal digit in JSON";
|
|
public const string UnexpectedToken = "Unexpected token '{0}' in JSON";
|
|
public const string UnexpectedToken = "Unexpected token '{0}' in JSON";
|
|
|
|
+ public const string UnexpectedTokenIllegal = "Unexpected token ILLEGAL in JSON";
|
|
public const string UnexpectedNumber = "Unexpected number in JSON";
|
|
public const string UnexpectedNumber = "Unexpected number in JSON";
|
|
public const string UnexpectedString = "Unexpected string in JSON";
|
|
public const string UnexpectedString = "Unexpected string in JSON";
|
|
public const string UnexpectedEOS = "Unexpected end of JSON input";
|
|
public const string UnexpectedEOS = "Unexpected end of JSON input";
|
|
@@ -853,4 +858,18 @@ namespace Jint.Native.Json
|
|
public Stack<int> MarkerStack;
|
|
public Stack<int> MarkerStack;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ internal static class StringExtensions
|
|
|
|
+ {
|
|
|
|
+ public static char CharCodeAt(this string source, int index)
|
|
|
|
+ {
|
|
|
|
+ if (index > source.Length - 1)
|
|
|
|
+ {
|
|
|
|
+ // char.MinValue is used as the null value
|
|
|
|
+ return char.MinValue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return source[index];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|