##// END OF EJS Templates
Added Skip method to JSON parser to skip contents of the current node
Added Skip method to JSON parser to skip contents of the current node

File last commit:

r62:62b440d46313 default
r62:62b440d46313 default
Show More
JSONParser.cs
264 lines | 10.5 KiB | text/x-csharp | CSharpLexer
cin
Added initial JSON support...
r55 using Implab;
using Implab.Parsing;
using System;
using System.Collections.Generic;
using System.Diagnostics;
cin
code cleanup
r59 using System.IO;
cin
Added initial JSON support...
r55 using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Implab.JSON {
/// <summary>
/// internal
/// </summary>
public struct JSONParserContext {
public string memberName;
public JSONElementContext elementContext;
}
/// <summary>
/// Pull парсер JSON данных.
/// </summary>
cin
code cleanup
r59 public class JSONParser : DFAutomaton<JSONParserContext>, IDisposable {
cin
Added initial JSON support...
r55
enum MemberContext {
MemberName,
MemberValue
cin
code cleanup
r59 }
cin
Added initial JSON support...
r55
static readonly EnumAlphabet<JsonTokenType> _alphabet = EnumAlphabet<JsonTokenType>.FullAlphabet;
static readonly DFAStateDescriptior[] _jsonDFA;
static readonly DFAStateDescriptior[] _objectDFA;
static readonly DFAStateDescriptior[] _arrayDFA;
static JSONParser() {
var jsonExpression = Token.New(JsonTokenType.BeginObject, JsonTokenType.BeginArray).Tag(0);
var valueExpression = Token.New(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
var memberExpression = Token.New(JsonTokenType.String).Cat(Token.New(JsonTokenType.NameSeparator)).Cat(valueExpression);
var objectExpression = memberExpression
.Cat(
Token.New(JsonTokenType.ValueSeparator)
.Cat(memberExpression)
.EClosure()
)
.Optional()
.Cat(Token.New(JsonTokenType.EndObject))
.Tag(0);
var arrayExpression = valueExpression
.Cat(
Token.New(JsonTokenType.ValueSeparator)
.Cat(valueExpression)
.EClosure()
)
.Optional()
.Cat(Token.New(JsonTokenType.EndArray))
.Tag(0);
_jsonDFA = BuildDFA(jsonExpression).States;
_objectDFA = BuildDFA(objectExpression).States;
_arrayDFA = BuildDFA(arrayExpression).States;
}
static EDFADefinition<JsonTokenType> BuildDFA(Token expr) {
var builder = new DFABuilder();
var dfa = new EDFADefinition<JsonTokenType>(_alphabet);
expr.Accept(builder);
builder.BuildDFA(dfa);
return dfa;
}
JSONScanner m_scanner;
MemberContext m_memberContext;
JSONElementType m_elementType;
object m_elementValue;
cin
code cleanup
r59 /// <summary>
/// Создает новый парсер на основе строки, содержащей JSON
/// </summary>
/// <param name="text"></param>
cin
Added initial JSON support...
r55 public JSONParser(string text)
cin
code cleanup
r59 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) {
cin
Added initial JSON support...
r55 Safe.ArgumentNotEmpty(text, "text");
m_scanner = new JSONScanner();
m_scanner.Feed(text.ToCharArray());
}
cin
code cleanup
r59 /// <summary>
/// Создает новый экземпляр парсера, на основе текстового потока.
/// </summary>
/// <param name="reader">Текстовый поток.</param>
/// <param name="dispose">Признак того, что парсер должен конролировать время жизни входного потока.</param>
public JSONParser(TextReader reader, bool dispose)
: base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) {
Safe.ArgumentNotNull(reader, "reader");
m_scanner = new JSONScanner();
m_scanner.Feed(reader, dispose);
}
/// <summary>
/// Тип текущего элемента на котором стоит парсер.
/// </summary>
cin
Added initial JSON support...
r55 public JSONElementType ElementType {
get { return m_elementType; }
}
cin
code cleanup
r59 /// <summary>
/// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
/// пустая строка.
/// </summary>
cin
Added initial JSON support...
r55 public string ElementName {
get { return m_context.info.memberName; }
}
cin
code cleanup
r59 /// <summary>
/// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
/// </summary>
cin
Added initial JSON support...
r55 public object ElementValue {
get { return m_elementValue; }
}
cin
code cleanup
r59 /// <summary>
/// Читает слеюудущий объект из потока
/// </summary>
/// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
cin
Added initial JSON support...
r55 public bool Read() {
if (m_context.current == UNREACHEBLE_STATE)
throw new InvalidOperationException("The parser is in invalid state");
object tokenValue;
JsonTokenType tokenType;
m_context.info.memberName = String.Empty;
while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
Move((int)tokenType);
if (m_context.current == UNREACHEBLE_STATE)
UnexpectedToken(tokenValue, tokenType);
switch (tokenType) {
case JsonTokenType.BeginObject:
Switch(
_objectDFA,
INITIAL_STATE,
cin
code cleanup
r59 new JSONParserContext {
cin
Added initial JSON support...
r55 memberName = m_context.info.memberName,
elementContext = JSONElementContext.Object
}
);
m_elementValue = null;
m_memberContext = MemberContext.MemberName;
m_elementType = JSONElementType.BeginObject;
return true;
case JsonTokenType.EndObject:
Restore();
m_elementValue = null;
m_elementType = JSONElementType.EndObject;
return true;
case JsonTokenType.BeginArray:
Switch(
_arrayDFA,
INITIAL_STATE,
new JSONParserContext {
memberName = m_context.info.memberName,
elementContext = JSONElementContext.Array
}
);
m_elementValue = null;
m_memberContext = MemberContext.MemberValue;
m_elementType = JSONElementType.BeginArray;
return true;
case JsonTokenType.EndArray:
Restore();
m_elementValue = null;
m_elementType = JSONElementType.EndArray;
return true;
case JsonTokenType.String:
if (m_memberContext == MemberContext.MemberName) {
m_context.info.memberName = (string)tokenValue;
break;
} else {
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 = ParseLiteral((string)tokenValue);
return true;
case JsonTokenType.NameSeparator:
m_memberContext = MemberContext.MemberValue;
break;
case JsonTokenType.ValueSeparator:
m_memberContext = m_context.info.elementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
break;
default:
UnexpectedToken(tokenValue, tokenType);
break;
}
}
if (m_context.info.elementContext != JSONElementContext.None)
throw new ParserException("Unexpedted end of data");
return false;
}
object ParseLiteral(string literal) {
switch (literal) {
case "null":
return null;
cin
code cleanup
r59 case "false":
cin
Added initial JSON support...
r55 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));
}
cin
minor changes
r57
cin
code cleanup
r59 /// <summary>
/// Признак конца потока
/// </summary>
cin
minor changes
r57 public bool EOF {
get {
return m_scanner.EOF;
}
}
cin
code cleanup
r59
protected virtual void Dispose(bool disposing) {
if (disposing) {
m_scanner.Dispose();
}
}
/// <summary>
/// Освобождает парсер и связанный с ним сканнер.
/// </summary>
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
~JSONParser() {
Dispose(false);
}
cin
Added Skip method to JSON parser to skip contents of the current node
r62
public void Skip() {
var level = Level-1;
Debug.Assert(level >= 0);
while (Level != level)
Read();
}
cin
Added initial JSON support...
r55 }
}