changeset 59:21611344d366

code cleanup
author cin
date Wed, 18 Jun 2014 03:54:02 +0400
parents 1710dcda34bb
children 10c7337d29e7
files Implab/Implab.csproj Implab/JSON/JSONParser.cs Implab/JSON/JSONXmlReader.cs Implab/Parsing/Alphabet.cs Implab/Parsing/AlphabetBase.cs Implab/Parsing/EnumAlphabet.cs Implab/Parsing/Scanner.cs Implab/Properties/AssemblyInfo.cs
diffstat 8 files changed, 141 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/Implab/Implab.csproj	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Implab.csproj	Wed Jun 18 03:54:02 2014 +0400
@@ -19,6 +19,7 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>full</DebugType>
--- a/Implab/JSON/JSONParser.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/JSON/JSONParser.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -3,6 +3,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -19,12 +20,12 @@
     /// <summary>
     /// Pull парсер JSON данных.
     /// </summary>
-    public class JSONParser : DFAutomaton<JSONParserContext> {
+    public class JSONParser : DFAutomaton<JSONParserContext>, IDisposable {
 
         enum MemberContext {
             MemberName,
             MemberValue
-        }        
+        }
 
         static readonly EnumAlphabet<JsonTokenType> _alphabet = EnumAlphabet<JsonTokenType>.FullAlphabet;
         static readonly DFAStateDescriptior[] _jsonDFA;
@@ -75,25 +76,55 @@
         JSONElementType m_elementType;
         object m_elementValue;
 
+        /// <summary>
+        /// Создает новый парсер на основе строки, содержащей JSON
+        /// </summary>
+        /// <param name="text"></param>
         public JSONParser(string text)
-            : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty } ) {
+            : 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());
         }
 
+        /// <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>
         public JSONElementType ElementType {
             get { return m_elementType; }
         }
 
+        /// <summary>
+        /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
+        /// пустая строка.
+        /// </summary>
         public string ElementName {
             get { return m_context.info.memberName; }
         }
 
+        /// <summary>
+        /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
+        /// </summary>
         public object ElementValue {
             get { return m_elementValue; }
         }
 
+        /// <summary>
+        /// Читает слеюудущий объект из потока
+        /// </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");
@@ -109,7 +140,7 @@
                         Switch(
                             _objectDFA,
                             INITIAL_STATE,
-                            new JSONParserContext { 
+                            new JSONParserContext {
                                 memberName = m_context.info.memberName,
                                 elementContext = JSONElementContext.Object
                             }
@@ -178,7 +209,7 @@
             switch (literal) {
                 case "null":
                     return null;
-                case "false" :
+                case "false":
                     return false;
                 case "true":
                     return true;
@@ -193,11 +224,32 @@
         }
 
 
+        /// <summary>
+        /// Признак конца потока
+        /// </summary>
         public bool EOF {
             get {
                 return m_scanner.EOF;
             }
         }
+
+        protected virtual void Dispose(bool disposing) {
+            if (disposing) {
+                m_scanner.Dispose();
+            }
+        }
+
+        /// <summary>
+        /// Освобождает парсер и связанный с ним сканнер.
+        /// </summary>
+        public void Dispose() {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        ~JSONParser() {
+            Dispose(false);
+        }
     }
 
 }
--- a/Implab/JSON/JSONXmlReader.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/JSON/JSONXmlReader.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -272,7 +272,15 @@
         }
 
         public override void Close() {
-            m_state = System.Xml.ReadState.EndOfFile ;
+            
         }
+
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+                m_parser.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
     }
 }
--- a/Implab/Parsing/Alphabet.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Parsing/Alphabet.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -8,6 +8,10 @@
 namespace Implab.Parsing {
     public class Alphabet: AlphabetBase<char> {
 
+        public Alphabet()
+            : base(char.MaxValue + 1) {
+        }
+
         public override int GetSymbolIndex(char symbol) {
             return symbol;
         }
@@ -15,9 +19,5 @@
         public override IEnumerable<char> InputSymbols {
             get { return Enumerable.Range(char.MinValue, char.MaxValue).Select(x => (char)x); }
         }
-
-        protected override int MapSize {
-            get { return char.MaxValue + 1; }
-        }
     }
 }
--- a/Implab/Parsing/AlphabetBase.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Parsing/AlphabetBase.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -17,13 +17,12 @@
             get { return m_nextId; }
         }
 
-        protected AlphabetBase() {
-            m_map = new int[MapSize];
+        protected AlphabetBase(int mapSize) {
+            m_map = new int[mapSize];
         }
 
         protected AlphabetBase(int[] map) {
             Debug.Assert(map != null);
-            Debug.Assert(map.Length == MapSize);
 
             m_map = map;
             m_nextId = map.Max() + 1;
@@ -94,8 +93,6 @@
 
         public abstract IEnumerable<T> InputSymbols { get; }
 
-        protected abstract int MapSize { get; }
-
         public int[] GetTranslationMap() {
             return m_map;
         }
--- a/Implab/Parsing/EnumAlphabet.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Parsing/EnumAlphabet.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -1,6 +1,7 @@
 using Implab;
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
 using System.Text;
@@ -45,11 +46,12 @@
 
 
         public EnumAlphabet()
-            : base() {
+            : base(_symbols.Length) {
         }
 
         public EnumAlphabet(int[] map)
             : base(map) {
+            Debug.Assert(map.Length == _symbols.Length);
         }
 
 
@@ -61,8 +63,5 @@
             get { return _symbols; }
         }
 
-        protected override int MapSize {
-            get { return _symbols.Length; }
-        }
     }
 }
--- a/Implab/Parsing/Scanner.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Parsing/Scanner.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -1,6 +1,7 @@
 using Implab;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -14,7 +15,7 @@
     /// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
     /// конца токена и допустимости текущего символа.
     /// </remarks>
-    public class Scanner {
+    public abstract class Scanner : Disposable {
         struct ScannerConfig {
             public DFAStateDescriptior[] states;
             public int[] alphabetMap;
@@ -35,15 +36,10 @@
         protected int m_bufferSize;
         protected int m_pointer;
 
-        public Scanner(CDFADefinition definition, string text) {
-            Safe.ArgumentNotNull(definition, "definition");
-            Safe.ArgumentNotEmpty(text, "text");
-
-            m_states = definition.States;
-            m_alphabetMap = definition.Alphabet.GetTranslationMap();
-
-            Feed(text.ToCharArray());
-        }
+        TextReader m_reader;
+        bool m_disposeReader;
+        int m_chunkSize = 1024; // 1k
+        int m_limit = 10 * 1024 * 1024; // 10Mb
 
         public Scanner(CDFADefinition definition) {
             Safe.ArgumentNotNull(definition, "definition");
@@ -76,6 +72,7 @@
         public void Feed(char[] data, int length) {
             Safe.ArgumentNotNull(data, "data");
             Safe.ArgumentInRange(length, 0, data.Length, "length");
+            AssertNotDisposed();
 
             m_pointer = -1;
             m_buffer = data;
@@ -83,18 +80,33 @@
             Shift();
         }
 
+        public void Feed(TextReader reader, bool dispose) {
+            Safe.ArgumentNotNull(reader, "reader");
+            AssertNotDisposed();
+
+            if (m_reader != null && m_disposeReader)
+                m_reader.Dispose();
+
+            m_reader = reader;
+            m_disposeReader = dispose;
+            m_pointer = -1;
+            m_buffer = new char[m_chunkSize];
+            m_bufferSize = 0;
+            Shift();
+        }
+
         /// <summary>
         /// Получает текущий токен в виде строки.
         /// </summary>
         /// <returns></returns>
-        public string GetTokenValue() {
+        protected string GetTokenValue() {
             return new String(m_buffer, m_tokenOffset, m_tokenLen);
         }
 
         /// <summary>
         /// Метки текущего токена, которые были назначены в регулярном выражении.
         /// </summary>
-        public int[] TokenTags {
+        protected int[] TokenTags {
             get {
                 return m_currentState.tag;
             }
@@ -163,13 +175,31 @@
             return true;
         }
 
-        /// <summary>
-        /// Вызывается по достижению конца входного буффера для получения
-        /// новых данных.
-        /// </summary>
-        /// <returns><c>true</c> - новые двнные получены, можно продолжать обработку.</returns>
-        protected virtual bool ReadNextChunk() {
-            return false;
+        bool ReadNextChunk() {
+            if (m_reader == null)
+                return false;
+
+            //  extend buffer if nesessary
+            if (m_pointer + m_chunkSize > m_buffer.Length) {
+                // trim unused buffer head
+                var size = m_tokenLen + m_chunkSize;
+                if (size >= m_limit)
+                    throw new ParserException(String.Format("Input buffer {0} bytes limit exceeded", m_limit));
+                var temp = new char[size];
+                Array.Copy(m_buffer, m_tokenOffset, temp, 0, m_tokenLen);
+                m_pointer -= m_tokenOffset;
+                m_bufferSize -= m_tokenOffset;
+                m_tokenOffset = 0;
+                m_buffer = temp;
+            }
+            
+            var read = m_reader.Read(m_buffer, m_tokenLen, m_chunkSize);
+            if (read == 0)
+                return false;
+
+            m_bufferSize += read;
+
+            return true;
         }
 
         /// <summary>
@@ -212,5 +242,18 @@
             m_alphabetMap = prev.alphabetMap;
             m_previewCode = m_alphabetMap[m_buffer[m_pointer]];
         }
+
+        protected override void Dispose(bool disposing) {
+            if (disposing) {
+                if (m_reader != null && m_disposeReader)
+                    m_reader.Dispose();
+                m_buffer = null;
+                m_bufferSize = 0;
+                m_pointer = 0;
+                m_tokenLen = 0;
+                m_tokenOffset = 0;
+            }
+            base.Dispose(disposing);
+        }
     }
 }
--- a/Implab/Properties/AssemblyInfo.cs	Tue Jun 17 19:40:43 2014 +0400
+++ b/Implab/Properties/AssemblyInfo.cs	Wed Jun 18 03:54:02 2014 +0400
@@ -1,5 +1,6 @@
 using System.Reflection;
-using System.Runtime.CompilerServices;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 
 // Information about this assembly is defined by the following attributes. 
 // Change them to the values specific to your project.
@@ -16,6 +17,7 @@
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
 
 [assembly: AssemblyVersion("1.0.*")]
+[assembly: ComVisible(false)]
 
 // The following attributes are used to specify the signing key for the assembly, 
 // if desired. See the Mono documentation for more information about signing.