Mercurial > pub > ImplabNet
diff Implab/Formats/JSON/JSONParser.cs @ 180:c32688129f14 ref20160224
refactoring complete, JSONParser rewritten
author | cin |
---|---|
date | Thu, 24 Mar 2016 02:30:46 +0300 |
parents | d5c5db0335ee |
children | 7d07503621fe |
line wrap: on
line diff
--- a/Implab/Formats/JSON/JSONParser.cs Wed Mar 23 19:52:08 2016 +0300 +++ b/Implab/Formats/JSON/JSONParser.cs Thu Mar 24 02:30:46 2016 +0300 @@ -5,17 +5,10 @@ using Implab.Automaton.RegularExpressions; using System.Linq; using Implab.Components; +using System.Collections.Generic; namespace Implab.Formats.JSON { /// <summary> - /// internal - /// </summary> - public struct JSONParserContext { - public string memberName; - public JSONElementContext elementContext; - } - - /// <summary> /// Pull парсер JSON данных. /// </summary> /// <remarks> @@ -52,10 +45,11 @@ } public bool Move(JsonTokenType token) { - var next = m_dfa[m_state, token]; + var next = m_dfa[m_state, (int)token]; if (next == AutomatonConst.UNREACHABLE_STATE) return false; m_state = next; + return true; } public JSONElementContext ElementContext { @@ -63,40 +57,43 @@ } } + static readonly ParserContext _jsonContext; + static readonly ParserContext _objectContext; + static readonly ParserContext _arrayContext; + static JSONParser() { - - var valueExpression = Token(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String); - var memberExpression = Token(JsonTokenType.String).Cat(Token(JsonTokenType.NameSeparator)).Cat(valueExpression); + 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( - Token(JsonTokenType.ValueSeparator) + MakeToken(JsonTokenType.ValueSeparator) .Cat(memberExpression) .EClosure() ) .Optional() - .Cat(Token(JsonTokenType.EndObject)) + .Cat(MakeToken(JsonTokenType.EndObject)) .End(); var arrayExpression = valueExpression .Cat( - Token(JsonTokenType.ValueSeparator) + MakeToken(JsonTokenType.ValueSeparator) .Cat(valueExpression) .EClosure() ) .Optional() - .Cat(Token(JsonTokenType.EndArray)) + .Cat(MakeToken(JsonTokenType.EndArray)) .End(); var jsonExpression = valueExpression.End(); - _jsonDFA = CreateParserContext(jsonExpression, JSONElementContext.None); - _objectDFA = CreateParserContext(objectExpression, JSONElementContext.Object); - _arrayDFA = CreateParserContext(arrayExpression, JSONElementContext.Array); + _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None); + _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object); + _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array); } - static Token Token(params JsonTokenType[] input) { + static Token MakeToken(params JsonTokenType[] input) { return Token.New( input.Select(t => (int)t).ToArray() ); } @@ -112,32 +109,36 @@ #endregion - JSONScanner m_scanner; + readonly JSONScanner m_scanner; MemberContext m_memberContext; JSONElementType m_elementType; object 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> - public JSONParser(string text) - : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) { + public JSONParser(string text) { Safe.ArgumentNotEmpty(text, "text"); - m_scanner = new JSONScanner(); - m_scanner.Feed(text.ToCharArray()); + m_scanner = new JSONScanner(text); } /// <summary> /// Создает новый экземпляр парсера, на основе текстового потока. /// </summary> /// <param name="reader">Текстовый поток.</param> - public JSONParser(TextReader reader) - : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) { + public JSONParser(TextReader reader) { Safe.ArgumentNotNull(reader, "reader"); - m_scanner = new JSONScanner(); - m_scanner.Feed(reader, dispose); + m_scanner = new JSONScanner(reader); + } + + public int Level { + get { return m_stack.Count; } } /// <summary> @@ -152,7 +153,7 @@ /// пустая строка. /// </summary> public string ElementName { - get { return m_context.info.memberName; } + get { return m_memberName; } } /// <summary> @@ -167,55 +168,51 @@ /// </summary> /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns> 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; + + m_memberName = String.Empty; + while (m_scanner.ReadToken(out tokenValue, out tokenType)) { - Move((int)tokenType); - if (m_context.current == UNREACHEBLE_STATE) + if(!m_context.Move(tokenType)) UnexpectedToken(tokenValue, tokenType); + switch (tokenType) { case JsonTokenType.BeginObject: - Switch( - _objectDFA, - INITIAL_STATE, - new JSONParserContext { - memberName = m_context.info.memberName, - elementContext = JSONElementContext.Object - } - ); + m_stack.Push(m_context); + m_context = _objectContext; + m_elementValue = null; m_memberContext = MemberContext.MemberName; m_elementType = JSONElementType.BeginObject; return true; case JsonTokenType.EndObject: - Restore(); + 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: - Switch( - _arrayDFA, - INITIAL_STATE, - new JSONParserContext { - memberName = m_context.info.memberName, - elementContext = JSONElementContext.Array - } - ); + m_stack.Push(m_context); + m_context = _arrayContext; + m_elementValue = null; m_memberContext = MemberContext.MemberValue; m_elementType = JSONElementType.BeginArray; return true; case JsonTokenType.EndArray: - Restore(); + 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_context.info.memberName = (string)tokenValue; + m_memberName = (string)tokenValue; break; } m_elementType = JSONElementType.Value; @@ -233,15 +230,18 @@ m_memberContext = MemberContext.MemberValue; break; case JsonTokenType.ValueSeparator: - m_memberContext = m_context.info.elementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; + m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; break; default: UnexpectedToken(tokenValue, tokenType); break; } } - if (m_context.info.elementContext != JSONElementContext.None) + if (m_context.ElementContext != JSONElementContext.None) throw new ParserException("Unexpedted end of data"); + + EOF = true; + return false; } @@ -268,15 +268,13 @@ /// Признак конца потока /// </summary> public bool EOF { - get { - return m_scanner.EOF; - } + get; + private set; } protected override void Dispose(bool disposing) { - if (disposing) { - m_scanner.Dispose(); - } + if (disposing) + Safe.Dispose(m_scanner); } /// <summary>