##// END OF EJS Templates
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler...
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler Any unhandled OperationCanceledException will cause the promise cancelation

File last commit:

r183:4f82e0f161c3 ref20160224
r187:dd4a3590f9c6 ref20160224
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)
Safe.Dispose(m_scanner);
base.Dispose(disposing);
}
}
}