##// END OF EJS Templates
Added 'Fail' method to RunnableComponent which allows component to move from...
Added 'Fail' method to RunnableComponent which allows component to move from Running to Failed state. Added PollingComponent a timer based runnable component More tests Added FailPromise a thin class to wrap exceptions Fixed error handling in SuccessPromise classes.

File last commit:

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