##// END OF EJS Templates
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.

File last commit:

r183:4f82e0f161c3 ref20160224
r196:40d7fed4a09e default
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);
}
}
}