##// END OF EJS Templates
Bound promise to CancellationToken...
Bound promise to CancellationToken Added new states to ExecutionSate enum. Added Safe.Guard() method to handle cleanup of the result of the promise

File last commit:

r208:7d07503621fe v2
r209:a867536c68fc v2
Show More
JSONScanner.cs
109 lines | 4.7 KiB | text/x-csharp | CSharpLexer
using System;
using System.Globalization;
using Implab.Automaton;
using System.Text;
using Implab.Components;
using System.IO;
namespace Implab.Formats.JSON {
/// <summary>
/// Сканнер (лексер), разбивающий поток символов на токены JSON.
/// </summary>
public class JSONScanner : Disposable {
readonly StringBuilder m_builder = new StringBuilder();
readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
readonly TextScanner m_scanner;
/// <summary>
/// Создает новый экземпляр сканнера
/// </summary>
public JSONScanner(string text) {
Safe.ArgumentNotEmpty(text, "text");
m_scanner = new StringScanner(text);
}
public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
Safe.ArgumentNotNull(reader, "reader");
m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
}
public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
}
/// <summary>
/// Читает следующий лексический элемент из входных данных.
/// </summary>
/// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
/// <param name="tokenType">Возвращает тип прочитанного токена.</param>
/// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
/// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
/// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
JSONGrammar.TokenType[] tag;
while (m_jsonContext.Execute(m_scanner, out tag)) {
switch (tag[0]) {
case JSONGrammar.TokenType.StringBound:
tokenValue = ReadString();
tokenType = JsonTokenType.String;
break;
case JSONGrammar.TokenType.Number:
tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
tokenType = JsonTokenType.Number;
break;
case JSONGrammar.TokenType.Whitespace:
continue;
default:
tokenType = (JsonTokenType)tag[0];
tokenValue = m_scanner.GetTokenValue();
break;
}
return true;
}
tokenValue = null;
tokenType = JsonTokenType.None;
return false;
}
string ReadString() {
int pos = 0;
var buf = new char[6]; // the buffer for unescaping chars
JSONGrammar.TokenType[] tag;
m_builder.Clear();
while (m_stringContext.Execute(m_scanner, out tag)) {
switch (tag[0]) {
case JSONGrammar.TokenType.StringBound:
return m_builder.ToString();
case JSONGrammar.TokenType.UnescapedChar:
m_scanner.CopyTokenTo(m_builder);
break;
case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
m_scanner.CopyTokenTo(buf, 0);
m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
pos++;
break;
case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
m_scanner.CopyTokenTo(buf, 0);
m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
break;
}
}
throw new ParserException("Unexpected end of data");
}
protected override void Dispose(bool disposing) {
if (disposing)
m_scanner.Dispose();
base.Dispose(disposing);
}
}
}