diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj
--- a/Implab/Implab.csproj
+++ b/Implab/Implab.csproj
@@ -19,6 +19,7 @@
prompt
4
false
+ true
full
diff --git a/Implab/JSON/JSONParser.cs b/Implab/JSON/JSONParser.cs
--- a/Implab/JSON/JSONParser.cs
+++ b/Implab/JSON/JSONParser.cs
@@ -3,6 +3,7 @@ using Implab.Parsing;
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 @@ namespace Implab.JSON {
///
/// Pull парсер JSON данных.
///
- public class JSONParser : DFAutomaton {
+ public class JSONParser : DFAutomaton, IDisposable {
enum MemberContext {
MemberName,
MemberValue
- }
+ }
static readonly EnumAlphabet _alphabet = EnumAlphabet.FullAlphabet;
static readonly DFAStateDescriptior[] _jsonDFA;
@@ -75,25 +76,55 @@ namespace Implab.JSON {
JSONElementType m_elementType;
object m_elementValue;
+ ///
+ /// Создает новый парсер на основе строки, содержащей JSON
+ ///
+ ///
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());
}
+ ///
+ /// Создает новый экземпляр парсера, на основе текстового потока.
+ ///
+ /// Текстовый поток.
+ /// Признак того, что парсер должен конролировать время жизни входного потока.
+ 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);
+ }
+
+ ///
+ /// Тип текущего элемента на котором стоит парсер.
+ ///
public JSONElementType ElementType {
get { return m_elementType; }
}
+ ///
+ /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
+ /// пустая строка.
+ ///
public string ElementName {
get { return m_context.info.memberName; }
}
+ ///
+ /// Значение элемента. Только для элементов типа , для остальных null
+ ///
public object ElementValue {
get { return m_elementValue; }
}
+ ///
+ /// Читает слеюудущий объект из потока
+ ///
+ /// true - операция чтения прошла успешно, false - конец данных
public bool Read() {
if (m_context.current == UNREACHEBLE_STATE)
throw new InvalidOperationException("The parser is in invalid state");
@@ -109,7 +140,7 @@ namespace Implab.JSON {
Switch(
_objectDFA,
INITIAL_STATE,
- new JSONParserContext {
+ new JSONParserContext {
memberName = m_context.info.memberName,
elementContext = JSONElementContext.Object
}
@@ -178,7 +209,7 @@ namespace Implab.JSON {
switch (literal) {
case "null":
return null;
- case "false" :
+ case "false":
return false;
case "true":
return true;
@@ -193,11 +224,32 @@ namespace Implab.JSON {
}
+ ///
+ /// Признак конца потока
+ ///
public bool EOF {
get {
return m_scanner.EOF;
}
}
+
+ protected virtual void Dispose(bool disposing) {
+ if (disposing) {
+ m_scanner.Dispose();
+ }
+ }
+
+ ///
+ /// Освобождает парсер и связанный с ним сканнер.
+ ///
+ public void Dispose() {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ~JSONParser() {
+ Dispose(false);
+ }
}
}
diff --git a/Implab/JSON/JSONXmlReader.cs b/Implab/JSON/JSONXmlReader.cs
--- a/Implab/JSON/JSONXmlReader.cs
+++ b/Implab/JSON/JSONXmlReader.cs
@@ -272,7 +272,15 @@ namespace ConsPlay {
}
public override void Close() {
- m_state = System.Xml.ReadState.EndOfFile ;
+
}
+
+ protected override void Dispose(bool disposing) {
+ if (disposing) {
+ m_parser.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
}
}
diff --git a/Implab/Parsing/Alphabet.cs b/Implab/Parsing/Alphabet.cs
--- a/Implab/Parsing/Alphabet.cs
+++ b/Implab/Parsing/Alphabet.cs
@@ -8,6 +8,10 @@ using System.Threading.Tasks;
namespace Implab.Parsing {
public class Alphabet: AlphabetBase {
+ public Alphabet()
+ : base(char.MaxValue + 1) {
+ }
+
public override int GetSymbolIndex(char symbol) {
return symbol;
}
@@ -15,9 +19,5 @@ namespace Implab.Parsing {
public override IEnumerable InputSymbols {
get { return Enumerable.Range(char.MinValue, char.MaxValue).Select(x => (char)x); }
}
-
- protected override int MapSize {
- get { return char.MaxValue + 1; }
- }
}
}
diff --git a/Implab/Parsing/AlphabetBase.cs b/Implab/Parsing/AlphabetBase.cs
--- a/Implab/Parsing/AlphabetBase.cs
+++ b/Implab/Parsing/AlphabetBase.cs
@@ -17,13 +17,12 @@ namespace Implab.Parsing {
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 @@ namespace Implab.Parsing {
public abstract IEnumerable InputSymbols { get; }
- protected abstract int MapSize { get; }
-
public int[] GetTranslationMap() {
return m_map;
}
diff --git a/Implab/Parsing/EnumAlphabet.cs b/Implab/Parsing/EnumAlphabet.cs
--- a/Implab/Parsing/EnumAlphabet.cs
+++ b/Implab/Parsing/EnumAlphabet.cs
@@ -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 @@ namespace Implab.Parsing {
public EnumAlphabet()
- : base() {
+ : base(_symbols.Length) {
}
public EnumAlphabet(int[] map)
: base(map) {
+ Debug.Assert(map.Length == _symbols.Length);
}
@@ -61,8 +63,5 @@ namespace Implab.Parsing {
get { return _symbols; }
}
- protected override int MapSize {
- get { return _symbols.Length; }
- }
}
}
diff --git a/Implab/Parsing/Scanner.cs b/Implab/Parsing/Scanner.cs
--- a/Implab/Parsing/Scanner.cs
+++ b/Implab/Parsing/Scanner.cs
@@ -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 @@ namespace Implab.Parsing {
/// указателя, начала и конца токена, при перемещении искользуется ДКА для определения
/// конца токена и допустимости текущего символа.
///
- public class Scanner {
+ public abstract class Scanner : Disposable {
struct ScannerConfig {
public DFAStateDescriptior[] states;
public int[] alphabetMap;
@@ -35,15 +36,10 @@ namespace Implab.Parsing {
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 @@ namespace Implab.Parsing {
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 @@ namespace Implab.Parsing {
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();
+ }
+
///
/// Получает текущий токен в виде строки.
///
///
- public string GetTokenValue() {
+ protected string GetTokenValue() {
return new String(m_buffer, m_tokenOffset, m_tokenLen);
}
///
/// Метки текущего токена, которые были назначены в регулярном выражении.
///
- public int[] TokenTags {
+ protected int[] TokenTags {
get {
return m_currentState.tag;
}
@@ -163,13 +175,31 @@ namespace Implab.Parsing {
return true;
}
- ///
- /// Вызывается по достижению конца входного буффера для получения
- /// новых данных.
- ///
- /// true - новые двнные получены, можно продолжать обработку.
- 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;
}
///
@@ -212,5 +242,18 @@ namespace Implab.Parsing {
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);
+ }
}
}
diff --git a/Implab/Properties/AssemblyInfo.cs b/Implab/Properties/AssemblyInfo.cs
--- a/Implab/Properties/AssemblyInfo.cs
+++ b/Implab/Properties/AssemblyInfo.cs
@@ -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 @@ using System.Runtime.CompilerServices;
// 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.