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>