##// END OF EJS Templates
Fixed promise rejection when there is not specified error handler in the reaction....
Fixed promise rejection when there is not specified error handler in the reaction. FIXED SPELLING IN THE XML CONTAINER CONFIGURATION signleton->singleton Code cleanup Update tests make them working on dotnet core

File last commit:

r295:28af686e24f7 default
r295:28af686e24f7 default
Show More
JsonReader.cs
317 lines | 11.9 KiB | text/x-csharp | CSharpLexer
using System;
using System.Diagnostics;
using System.IO;
using Implab.Automaton;
using Implab.Automaton.RegularExpressions;
using System.Linq;
using Implab.Components;
using System.Collections.Generic;
using System.Text;
namespace Implab.Formats.Json {
/// <summary>
/// Pull парсер JSON данных.
/// </summary>
/// <remarks>
/// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
/// оно означает текущий уровень вложенности объектов, однако закрывающий
/// элемент объекта и массива имеет уровень меньше, чем сам объект.
/// <code>
/// { // Level = 1
/// "name" : "Peter", // Level = 1
/// "address" : { // Level = 2
/// city : "Stern" // Level = 2
/// } // Level = 1
/// } // Level = 0
/// </code>
/// </remarks>
public class JsonReader : Disposable {
enum MemberContext {
MemberName,
MemberValue
}
#region Parser rules
struct ParserContext {
readonly int[,] m_dfa;
int m_state;
readonly JsonElementContext m_elementContext;
public ParserContext(int[,] dfa, int state, JsonElementContext context) {
m_dfa = dfa;
m_state = state;
m_elementContext = context;
}
public bool Move(JsonTokenType token) {
var next = m_dfa[m_state, (int)token];
if (next == AutomatonConst.UnreachableState)
return false;
m_state = next;
return true;
}
public JsonElementContext ElementContext {
get { return m_elementContext; }
}
}
static readonly ParserContext _jsonContext;
static readonly ParserContext _objectContext;
static readonly ParserContext _arrayContext;
static JsonReader() {
var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
var objectExpression = memberExpression
.Cat(
MakeToken(JsonTokenType.ValueSeparator)
.Cat(memberExpression)
.EClosure()
)
.Optional()
.Cat(MakeToken(JsonTokenType.EndObject))
.End();
var arrayExpression = valueExpression
.Cat(
MakeToken(JsonTokenType.ValueSeparator)
.Cat(valueExpression)
.EClosure()
)
.Optional()
.Cat(MakeToken(JsonTokenType.EndArray))
.End();
var jsonExpression = valueExpression.End();
_jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None);
_objectContext = CreateParserContext(objectExpression, JsonElementContext.Object);
_arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array);
}
static Token MakeToken(params JsonTokenType[] input) {
return Token.New( input.Select(t => (int)t).ToArray() );
}
static ParserContext CreateParserContext(Token expr, JsonElementContext context) {
var dfa = new DFATable();
var builder = new RegularExpressionVisitor(dfa);
expr.Accept(builder);
builder.BuildDFA();
return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
}
#endregion
readonly JsonScanner m_scanner;
// json starts from the value context and may content even a single literal
MemberContext m_memberContext = MemberContext.MemberValue;
JsonElementType m_elementType;
string m_elementValue;
string m_memberName = String.Empty;
Stack<ParserContext> m_stack = new Stack<ParserContext>();
ParserContext m_context = _jsonContext;
/// <summary>
/// Создает новый парсер на основе строки, содержащей JSON
/// </summary>
/// <param name="text"></param>
JsonReader(JsonScanner scanner) {
m_scanner = scanner;
}
public int Level {
get { return m_stack.Count; }
}
/// <summary>
/// Тип текущего элемента на котором стоит парсер.
/// </summary>
public JsonElementType ElementType {
get { return m_elementType; }
}
/// <summary>
/// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
/// пустая строка.
/// </summary>
public string ElementName {
get { return m_memberName; }
}
/// <summary>
/// Значение элемента. Только для элементов типа <see cref="JsonElementType.Value"/>, для остальных <c>null</c>
/// </summary>
public string ElementValue {
get { return m_elementValue; }
}
/// <summary>
/// Читает слеюудущий объект из потока
/// </summary>
/// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
public bool Read() {
string tokenValue;
JsonTokenType tokenType;
m_memberName = String.Empty;
while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
if(!m_context.Move(tokenType))
UnexpectedToken(tokenValue, tokenType);
switch (tokenType) {
case JsonTokenType.BeginObject:
m_stack.Push(m_context);
m_context = _objectContext;
m_elementValue = null;
m_memberContext = MemberContext.MemberName;
m_elementType = JsonElementType.BeginObject;
return true;
case JsonTokenType.EndObject:
if (m_stack.Count == 0)
UnexpectedToken(tokenValue, tokenType);
m_context = m_stack.Pop();
m_elementValue = null;
m_elementType = JsonElementType.EndObject;
return true;
case JsonTokenType.BeginArray:
m_stack.Push(m_context);
m_context = _arrayContext;
m_elementValue = null;
m_memberContext = MemberContext.MemberValue;
m_elementType = JsonElementType.BeginArray;
return true;
case JsonTokenType.EndArray:
if (m_stack.Count == 0)
UnexpectedToken(tokenValue, tokenType);
m_context = m_stack.Pop();
m_elementValue = null;
m_elementType = JsonElementType.EndArray;
return true;
case JsonTokenType.String:
if (m_memberContext == MemberContext.MemberName) {
m_memberName = tokenValue;
break;
}
m_elementType = JsonElementType.Value;
m_elementValue = tokenValue;
return true;
case JsonTokenType.Number:
m_elementType = JsonElementType.Value;
m_elementValue = tokenValue;
return true;
case JsonTokenType.Literal:
m_elementType = JsonElementType.Value;
m_elementValue = tokenValue == "null" ? null : tokenValue;
return true;
case JsonTokenType.NameSeparator:
m_memberContext = MemberContext.MemberValue;
break;
case JsonTokenType.ValueSeparator:
m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
break;
default:
UnexpectedToken(tokenValue, tokenType);
break;
}
}
if (m_context.ElementContext != JsonElementContext.None)
throw new ParserException("Unexpedted end of data");
Eof = true;
return false;
}
object ParseLiteral(string literal) {
switch (literal) {
case "null":
return null;
case "false":
return false;
case "true":
return true;
default:
UnexpectedToken(literal, JsonTokenType.Literal);
return null; // avoid compliler error
}
}
void UnexpectedToken(object value, JsonTokenType tokenType) {
throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
}
/// <summary>
/// Признак конца потока
/// </summary>
public bool Eof {
get;
private set;
}
protected override void Dispose(bool disposing) {
if (disposing)
m_scanner.Dispose();
}
/// <summary>
/// Переходит в конец текущего объекта.
/// </summary>
public void SeekElementEnd() {
var level = Level - 1;
Debug.Assert(level >= 0);
while (Level != level)
Read();
}
public static JsonReader Create(string file, Encoding encoding) {
return new JsonReader(JsonTextScanner.Create(file, encoding));
}
public static JsonReader Create(string file) {
return new JsonReader(JsonTextScanner.Create(file));
}
public static JsonReader Create(Stream stream, Encoding encoding) {
return new JsonReader(JsonTextScanner.Create(stream, encoding));
}
public static JsonReader Create(Stream stream) {
return new JsonReader(JsonTextScanner.Create(stream));
}
public static JsonReader Create(TextReader reader) {
return new JsonReader(JsonTextScanner.Create(reader));
}
public static JsonReader ParseString(string data) {
return new JsonReader(JsonStringScanner.Create(data));
}
public static JsonReader ParseString(string data, int offset, int length) {
return new JsonReader(JsonStringScanner.Create(data, offset, length));
}
public static JsonReader ParseString(char[] data, int offset, int lenght) {
return new JsonReader(JsonStringScanner.Create(data, offset, lenght));
}
}
}