##// END OF EJS Templates
Added initial JSON support...
Added initial JSON support +JSONParser +JSONWriter

File last commit:

r55:c0bf853aa04f default
r55:c0bf853aa04f default
Show More
JSONParser.cs
197 lines | 7.8 KiB | text/x-csharp | CSharpLexer
using Implab;
using Implab.Parsing;
using System;
using System.Collections.Generic;
using System.Diagnostics;
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>
public class JSONParser : DFAutomaton<JSONParserContext> {
enum MemberContext {
MemberName,
MemberValue
}
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;
public JSONParser(string text)
: base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty } ) {
Safe.ArgumentNotEmpty(text, "text");
m_scanner = new JSONScanner();
m_scanner.Feed(text.ToCharArray());
}
public JSONElementType ElementType {
get { return m_elementType; }
}
public string ElementName {
get { return m_context.info.memberName; }
}
public object ElementValue {
get { return m_elementValue; }
}
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,
new JSONParserContext {
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;
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));
}
}
}