|
|
using Implab.Parsing;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Globalization;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace Implab.JSON {
|
|
|
/// <summary>
|
|
|
/// Сканнер, разбивающий поток символов на токены JSON.
|
|
|
/// </summary>
|
|
|
public class JSONScanner : Scanner {
|
|
|
char[] m_stringBuffer;
|
|
|
DFAStateDescriptior[] m_stringDFA;
|
|
|
int[] m_stringAlphabet;
|
|
|
|
|
|
public JSONScanner()
|
|
|
: base(JSONGrammar.Instance.JsonDFA) {
|
|
|
m_stringBuffer = new char[1024];
|
|
|
var dfa = JSONGrammar.Instance.JsonStringDFA;
|
|
|
m_stringAlphabet = dfa.Alphabet.GetTranslationMap();
|
|
|
m_stringDFA = dfa.States;
|
|
|
}
|
|
|
|
|
|
public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
|
|
|
if (ReadTokenInternal()) {
|
|
|
switch ((JSONGrammar.TokenType)m_currentState.tag[0]) {
|
|
|
case JSONGrammar.TokenType.StringBound:
|
|
|
tokenValue = ReadString();
|
|
|
tokenType = JsonTokenType.String;
|
|
|
break;
|
|
|
case JSONGrammar.TokenType.Number:
|
|
|
tokenValue = Double.Parse(new String(m_buffer, m_tokenOffset, m_tokenLen), CultureInfo.InvariantCulture);
|
|
|
tokenType = JsonTokenType.Number;
|
|
|
break;
|
|
|
default:
|
|
|
tokenType = (JsonTokenType)m_currentState.tag[0];
|
|
|
tokenValue = new String(m_buffer, m_tokenOffset, m_tokenLen);
|
|
|
break;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
tokenValue = null;
|
|
|
tokenType = JsonTokenType.None;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
string ReadString() {
|
|
|
int pos = 0;
|
|
|
Switch(m_stringDFA, m_stringAlphabet);
|
|
|
while (ReadTokenInternal()) {
|
|
|
switch ((JSONGrammar.TokenType)m_currentState.tag[0]) {
|
|
|
case JSONGrammar.TokenType.StringBound:
|
|
|
Restore();
|
|
|
return new String(m_stringBuffer, 0, pos);
|
|
|
case JSONGrammar.TokenType.UnescapedChar:
|
|
|
EnsureStringBufferSize(pos + m_tokenLen);
|
|
|
Array.Copy(m_buffer, m_tokenOffset, m_stringBuffer, pos, m_tokenLen);
|
|
|
pos += m_tokenLen;
|
|
|
break;
|
|
|
case JSONGrammar.TokenType.EscapedUnicode:
|
|
|
EnsureStringBufferSize(pos + 1);
|
|
|
m_stringBuffer[pos] = StringTranslator.TranslateHexUnicode(m_buffer, m_tokenOffset + 2);
|
|
|
pos++;
|
|
|
break;
|
|
|
case JSONGrammar.TokenType.EscapedChar:
|
|
|
EnsureStringBufferSize(pos + 1);
|
|
|
m_stringBuffer[pos] = StringTranslator.TranslateEscapedChar(m_buffer[m_tokenOffset + 1]);
|
|
|
pos++;
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
throw new ParserException("Unexpected end of data");
|
|
|
}
|
|
|
|
|
|
void EnsureStringBufferSize(int size) {
|
|
|
if (size > m_stringBuffer.Length) {
|
|
|
var newBuffer = new char[size];
|
|
|
m_stringBuffer.CopyTo(newBuffer, 0);
|
|
|
m_stringBuffer = newBuffer;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|