##// END OF EJS Templates
Rewritten JsonScanner, JsonParser, fixed naming style
cin -
r228:6fa235c5a760 v2
parent child
Show More
@@ -0,0 +1,42
1 using Implab.Automaton;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Runtime.CompilerServices;
6 using System.Text;
7 using System.Threading.Tasks;
8
9 namespace Implab.Formats {
10 public class CharMap : IAlphabet<char> {
11 readonly char m_min;
12 readonly char m_max;
13 readonly int[] m_map;
14
15 public CharMap(char min, int[] map) {
16 Safe.ArgumentNotNull(map, nameof(map));
17 Count = map.Max()+1;
18 m_min = min;
19 m_map = map;
20 m_max = (char)(min + map.Length);
21 }
22
23 public int Count {
24 get; private set;
25 }
26
27 public bool Contains(char symbol) {
28 return symbol >= m_min && symbol <= m_max && m_map[symbol-m_min] != AutomatonConst.UNCLASSIFIED_INPUT;
29 }
30
31 public IEnumerable<char> GetSymbols(int cls) {
32 for (var i = 0; i < m_map.Length; i++)
33 if (m_map[i] == cls)
34 yield return (char)(i + m_min);
35 }
36
37 [MethodImpl(MethodImplOptions.AggressiveInlining)]
38 public int Translate(char symbol) {
39 return symbol >= m_min && symbol <= m_max ? m_map[symbol-m_min] : AutomatonConst.UNCLASSIFIED_INPUT;
40 }
41 }
42 }
@@ -0,0 +1,84
1 using Implab.Automaton;
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.Formats {
9 public class InputScanner<TTag> {
10 readonly TTag[] m_tags;
11 readonly int m_initialState;
12 readonly int[,] m_dfa;
13 readonly CharMap m_alphabet;
14 readonly bool[] m_final;
15
16 int m_position;
17 int m_state;
18
19 public InputScanner(int[,] dfaTable, bool[] finalStates, TTag[] tags, int initialState, CharMap alphabet) {
20 Safe.ArgumentNotNull(dfaTable, nameof(dfaTable));
21 Safe.ArgumentNotNull(finalStates, nameof(finalStates));
22 Safe.ArgumentNotNull(tags, nameof(tags));
23 Safe.ArgumentNotNull(alphabet, nameof(alphabet));
24
25 m_dfa = dfaTable;
26 m_final = finalStates;
27 m_tags = tags;
28 m_initialState = initialState;
29 m_alphabet = alphabet;
30 }
31
32 public TTag Tag {
33 get {
34 return m_tags[m_state];
35 }
36 }
37
38 public int Position {
39 get {
40 return m_position;
41 }
42 }
43
44 public bool IsFinal {
45 get {
46 return m_final[m_state];
47 }
48 }
49
50 public void Reset() {
51 m_state = m_initialState;
52 }
53
54 public InputScanner<TTag> Clone() {
55 var clone = new InputScanner<TTag>(m_dfa, m_final, m_tags, m_initialState, m_alphabet);
56 clone.m_state = m_state;
57 clone.m_position = m_position;
58 return clone;
59 }
60
61 public bool Scan(char[] data, int offset, int length) {
62 if (length <= 0) {
63 m_position = offset;
64 return false; // EOF
65 }
66
67 var max = offset + length;
68 var next = m_state;
69
70 while(offset < max) {
71 next = m_dfa[next, m_alphabet.Translate(data[offset])];
72 if (next == AutomatonConst.UNREACHABLE_STATE) {
73 // scanner stops on the next position after last recognized symbol
74 m_position = offset;
75 return false;
76 }
77 m_state = next;
78 offset++;
79 }
80 m_position = offset;
81 return true;
82 }
83 }
84 }
@@ -0,0 +1,76
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Implab.Formats.Json {
8 public class JsonStringScanner : JsonScanner {
9 const int _defaultBuffer = 64;
10
11 readonly string m_data;
12 int m_offset;
13
14 JsonStringScanner(string data, char[] buffer, int pos, int length, int offset) : base(buffer, pos, length) {
15 m_data = data;
16 m_offset = offset;
17 }
18
19 protected override int Read(char[] buffer, int offset, int size) {
20 if (m_data == null)
21 return 0;
22 if (m_offset >= m_data.Length)
23 return 0;
24
25 var count = Math.Min(size, m_data.Length - m_offset);
26
27 m_data.CopyTo(m_offset, buffer, offset, count);
28 m_offset += count;
29
30 return count;
31 }
32
33 public static JsonStringScanner Create(string data) {
34 Safe.ArgumentNotNull(data, nameof(data));
35
36 if (data.Length <= _defaultBuffer)
37 return new JsonStringScanner(null, data.ToCharArray(), 0, data.Length, data.Length);
38
39 var buffer = new char[_defaultBuffer];
40 data.CopyTo(0, buffer, 0, _defaultBuffer);
41 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, _defaultBuffer);
42 }
43
44 public static JsonStringScanner Create(string data, int offset, int length) {
45 Safe.ArgumentNotNull(data, nameof(data));
46 Safe.ArgumentGreaterThan(offset, 0, nameof(offset));
47 Safe.ArgumentGreaterThan(length, 0, nameof(length));
48
49 if (offset + length > data.Length)
50 throw new ArgumentOutOfRangeException("Specified offset and length are out of the string bounds");
51
52 if (length <= _defaultBuffer) {
53 var buffer = new char[length];
54 data.CopyTo(offset, buffer, 0, length);
55
56 return new JsonStringScanner(null, buffer, 0, length, length);
57 } else {
58 var buffer = new char[_defaultBuffer];
59 data.CopyTo(offset, buffer, 0, _defaultBuffer);
60 return new JsonStringScanner(data, buffer, 0, _defaultBuffer, offset + _defaultBuffer);
61 }
62 }
63
64 public static JsonStringScanner Create(char[] data, int offset, int length) {
65 Safe.ArgumentNotNull(data, nameof(data));
66 Safe.ArgumentGreaterThan(offset, 0, nameof(offset));
67 Safe.ArgumentGreaterThan(length, 0, nameof(length));
68
69 if (offset + length > data.Length)
70 throw new ArgumentOutOfRangeException("Specified offset and length are out of the array bounds");
71
72 return new JsonStringScanner(null, data, offset, offset + length, offset + length);
73
74 }
75 }
76 }
@@ -0,0 +1,49
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.Formats.Json {
9 public class JsonTextScanner : JsonScanner {
10 const int _bufferSize = 4096;
11 readonly TextReader m_reader;
12
13 JsonTextScanner(TextReader reader, char[] buffer) : base(buffer, 0, 0) {
14 m_reader = reader;
15 }
16
17 protected override int Read(char[] buffer, int offset, int size) {
18 return m_reader.Read(buffer, offset, size);
19 }
20
21 public static JsonTextScanner Create(string file, Encoding encoding) {
22 return new JsonTextScanner(new StreamReader(file, encoding), new char[_bufferSize]);
23 }
24
25 public static JsonTextScanner Create(string file) {
26 return new JsonTextScanner(new StreamReader(file), new char[_bufferSize]);
27 }
28
29 public static JsonTextScanner Create(Stream stream, Encoding encoding) {
30 return new JsonTextScanner(new StreamReader(stream, encoding), new char[_bufferSize]);
31 }
32
33 public static JsonTextScanner Create(Stream stream) {
34 return new JsonTextScanner(new StreamReader(stream), new char[_bufferSize]);
35 }
36
37 public static JsonTextScanner Create(TextReader reader) {
38 Safe.ArgumentNotNull(reader, nameof(reader));
39 return new JsonTextScanner(reader, new char[_bufferSize]);
40 }
41
42 protected override void Dispose(bool disposing) {
43 if (disposing)
44 Safe.Dispose(m_reader);
45
46 base.Dispose(disposing);
47 }
48 }
49 }
@@ -1,41 +1,42
1 1 using NUnit.Framework;
2 2 using System;
3 using Implab.Formats.JSON;
4 3 using Implab.Automaton;
5 4 using Implab.Xml;
6 5 using System.Xml;
7 using System.Text;
6 using Implab.Formats;
7 using Implab.Formats.Json;
8 8
9 9 namespace Implab.Format.Test {
10 10 [TestFixture]
11 11 public class JsonTests {
12
12 13 [Test]
13 14 public void TestScannerValidTokens() {
14 using (var scanner = new JSONScanner(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
15 using (var scanner = JsonStringScanner.Create(@"9123, -123, 0, 0.1, -0.2, -0.1e3, 1.3E-3, ""some \t\n\u0020 text"", literal []{}:")) {
15 16
16 17 Tuple<JsonTokenType, object>[] expexted = {
17 18 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 9123d),
18 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
19 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
19 20 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -123d),
20 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
21 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
21 22 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0d),
22 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
23 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
23 24 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 0.1d),
24 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
25 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
25 26 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.2d),
26 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
27 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
27 28 new Tuple<JsonTokenType,object>(JsonTokenType.Number, -0.1e3d),
28 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
29 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
29 30 new Tuple<JsonTokenType,object>(JsonTokenType.Number, 1.3E-3d),
30 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
31 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
31 32 new Tuple<JsonTokenType,object>(JsonTokenType.String, "some \t\n text"),
32 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, ", "),
33 new Tuple<JsonTokenType,object>(JsonTokenType.ValueSeparator, null),
33 34 new Tuple<JsonTokenType,object>(JsonTokenType.Literal, "literal"),
34 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, " ["),
35 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, "]"),
36 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, "{"),
37 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, "}"),
38 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, ":")
35 new Tuple<JsonTokenType,object>(JsonTokenType.BeginArray, null),
36 new Tuple<JsonTokenType,object>(JsonTokenType.EndArray, null),
37 new Tuple<JsonTokenType,object>(JsonTokenType.BeginObject, null),
38 new Tuple<JsonTokenType,object>(JsonTokenType.EndObject, null),
39 new Tuple<JsonTokenType,object>(JsonTokenType.NameSeparator, null)
39 40 };
40 41
41 42 object value;
@@ -70,7 +71,7 namespace Implab.Format.Test {
70 71 };
71 72
72 73 foreach (var json in bad) {
73 using (var scanner = new JSONScanner(json)) {
74 using (var scanner = JsonStringScanner.Create(json)) {
74 75 try {
75 76 object value;
76 77 JsonTokenType token;
@@ -122,7 +123,7 namespace Implab.Format.Test {
122 123 void DumpJsonParse(string json) {
123 124 Console.WriteLine($"JSON: {json}");
124 125 Console.WriteLine("XML");
125 using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
126 using (var xmlReader = new JsonXmlReader(new JsonParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "json" })) {
126 127 while (xmlReader.Read())
127 128 Console.WriteLine($"{new string(' ', xmlReader.Depth * 2)}{xmlReader}");
128 129 }
@@ -136,7 +137,7 namespace Implab.Format.Test {
136 137 CloseOutput = false,
137 138 ConformanceLevel = ConformanceLevel.Document
138 139 }))
139 using (var xmlReader = new JsonXmlReader(new JSONParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
140 using (var xmlReader = new JsonXmlReader(new JsonParser(json), new JsonXmlReaderOptions { NamespaceUri = "JsonXmlReaderSimpleTest", NodesPrefix = "", FlattenArrays = true })) {
140 141 xmlWriter.WriteNode(xmlReader, false);
141 142 }
142 143 }
@@ -1,6 +1,7
1 1 using System.Collections.Generic;
2 2 using System.Linq;
3 3 using Implab.Automaton;
4 using System;
4 5
5 6 namespace Implab.Formats {
6 7 public class CharAlphabet: IndexedAlphabetBase<char> {
@@ -12,5 +13,24 namespace Implab.Formats {
12 13 public IEnumerable<char> InputSymbols {
13 14 get { return Enumerable.Range(char.MinValue, char.MaxValue).Cast<char>(); }
14 15 }
16
17 public CharMap CreateCharMap() {
18 var map = new Dictionary<int, int>();
19
20 int max = 0, min = char.MaxValue;
21 foreach (var p in Mappings) {
22 var index = GetSymbolIndex(p.Key);
23 max = Math.Max(max, index);
24 min = Math.Min(min, index);
25 map[index] = p.Value;
26 }
27
28 var result = new int[max - min + 1];
29
30 for (int i = 0; i < result.Length; i++)
31 map.TryGetValue(min + i, out result[i]);
32
33 return new CharMap((char)min, result);
15 34 }
16 35 }
36 }
@@ -67,32 +67,6 namespace Implab.Formats {
67 67
68 68 return Token.New( Enumerable.Range(0, AlphabetBuilder.Count).Except(TranslateOrDie(symbols)).ToArray() );
69 69 }
70
71 protected abstract IndexedAlphabetBase<TSymbol> CreateAlphabet();
72
73 protected ScannerContext<TTag> BuildScannerContext<TTag>(Token regexp) {
74
75 var dfa = new RegularDFA<TSymbol, TTag>(AlphabetBuilder);
76
77 var visitor = new RegularExpressionVisitor<TTag>(dfa);
78 regexp.Accept(visitor);
79 visitor.BuildDFA();
80
81 if (dfa.IsFinalState(dfa.InitialState))
82 throw new ApplicationException("The specified language contains empty token");
83
84 var ab = CreateAlphabet();
85 var optimal = dfa.Optimize(ab);
86
87 return new ScannerContext<TTag>(
88 optimal.CreateTransitionTable(),
89 optimal.CreateFinalStateTable(),
90 optimal.CreateTagTable(),
91 optimal.InitialState,
92 ab.GetTranslationMap()
93 );
94 }
95
96 70 }
97 71
98 72
@@ -1,8 +1,8
1 namespace Implab.Formats.JSON {
1 namespace Implab.Formats.Json {
2 2 /// <summary>
3 3 /// internal
4 4 /// </summary>
5 enum JSONElementContext {
5 enum JsonElementContext {
6 6 None,
7 7 Object,
8 8 Array,
@@ -1,8 +1,8
1 namespace Implab.Formats.JSON {
1 namespace Implab.Formats.Json {
2 2 /// <summary>
3 3 /// Тип элемента на котором находится парсер
4 4 /// </summary>
5 public enum JSONElementType {
5 public enum JsonElementType {
6 6 None,
7 7 /// <summary>
8 8 /// Начало объекта
@@ -4,8 +4,8 using System;
4 4 using Implab.Automaton;
5 5 using Implab.Components;
6 6
7 namespace Implab.Formats.JSON {
8 class JSONGrammar : Grammar<char> {
7 namespace Implab.Formats.Json {
8 public class JsonGrammar : Grammar<char> {
9 9 public enum TokenType {
10 10 None,
11 11 BeginObject,
@@ -25,17 +25,19 namespace Implab.Formats.JSON {
25 25 EscapedUnicode
26 26 }
27 27
28 static LazyAndWeak<JSONGrammar> _instance = new LazyAndWeak<JSONGrammar>(() => new JSONGrammar());
28 static LazyAndWeak<JsonGrammar> _instance = new LazyAndWeak<JsonGrammar>(() => new JsonGrammar());
29 29
30 public static JSONGrammar Instance {
30 public static JsonGrammar Instance {
31 31 get { return _instance.Value; }
32 32 }
33 33
34 readonly ScannerContext<TokenType> m_jsonExpression;
35 readonly ScannerContext<TokenType> m_stringExpression;
34 readonly InputScanner<TokenType> m_jsonExpression;
35 readonly InputScanner<TokenType> m_stringExpression;
36 36 readonly CharAlphabet m_defaultAlphabet = new CharAlphabet();
37 37
38 public JSONGrammar() {
38 public CharAlphabet DefaultAlphabet { get { return m_defaultAlphabet; } }
39
40 public JsonGrammar() {
39 41 DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x));
40 42 var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9'));
41 43 var digit9 = SymbolRangeToken('1', '9');
@@ -85,10 +87,16 namespace Implab.Formats.JSON {
85 87 .Or(unescaped.Closure().Tag(TokenType.UnescapedChar));
86 88
87 89
88 m_jsonExpression = BuildScannerContext<TokenType>(jsonExpression);
89 m_stringExpression = BuildScannerContext<TokenType>(jsonStringExpression);
90 m_jsonExpression = BuildScanner(jsonExpression);
91 m_stringExpression = BuildScanner(jsonStringExpression);
92 }
90 93
94 public static InputScanner<TokenType> CreateJsonExpressionScanner() {
95 return Instance.m_jsonExpression.Clone();
96 }
91 97
98 public static InputScanner<TokenType> CreateStringExpressionScanner() {
99 return Instance.m_stringExpression.Clone();
92 100 }
93 101
94 102 protected override IAlphabetBuilder<char> AlphabetBuilder {
@@ -97,24 +105,43 namespace Implab.Formats.JSON {
97 105 }
98 106 }
99 107
100 public ScannerContext<TokenType> JsonExpression {
101 get {
102 return m_jsonExpression;
103 }
104 }
105
106 public ScannerContext<TokenType> JsonStringExpression {
107 get {
108 return m_stringExpression;
109 }
110 }
111
112 108 Token SymbolRangeToken(char start, char stop) {
113 109 return SymbolToken(Enumerable.Range(start, stop - start + 1).Select(x => (char)x));
114 110 }
115 111
116 protected override IndexedAlphabetBase<char> CreateAlphabet() {
117 return new CharAlphabet();
112 public InputScanner<TokenType> BuildScanner(Token regexp) {
113 var dfa = new RegularDFA<char, TokenType>(AlphabetBuilder);
114
115 var visitor = new RegularExpressionVisitor<TokenType>(dfa);
116 regexp.Accept(visitor);
117 visitor.BuildDFA();
118
119 if (dfa.IsFinalState(dfa.InitialState))
120 throw new ApplicationException("The specified language contains empty token");
121
122 var ab = new CharAlphabet();
123 var optimal = dfa.Optimize(ab);
124
125 return new InputScanner<TokenType>(
126 optimal.CreateTransitionTable(),
127 optimal.CreateFinalStateTable(),
128 NormalizeTags(optimal.CreateTagTable()),
129 optimal.InitialState,
130 ab.CreateCharMap()
131 );
132 }
133
134 static TokenType[] NormalizeTags(TokenType[][] tags) {
135 var result = new TokenType[tags.Length];
136 for(var i = 0; i< tags.Length; i++) {
137 if (tags[i] == null || tags[i].Length == 0)
138 result[i] = default(TokenType);
139 else if (tags[i].Length == 1)
140 result[i] = tags[i][0];
141 else
142 throw new Exception($"Ambigous state tags {string.Join(", ", tags[i])}");
143 }
144 return result;
118 145 }
119 146
120 147 }
@@ -7,7 +7,7 using System.Linq;
7 7 using Implab.Components;
8 8 using System.Collections.Generic;
9 9
10 namespace Implab.Formats.JSON {
10 namespace Implab.Formats.Json {
11 11 /// <summary>
12 12 /// Pull парсер JSON данных.
13 13 /// </summary>
@@ -24,7 +24,7 namespace Implab.Formats.JSON {
24 24 /// } // Level = 0
25 25 /// </code>
26 26 /// </remarks>
27 public class JSONParser : Disposable {
27 public class JsonParser : Disposable {
28 28
29 29 enum MemberContext {
30 30 MemberName,
@@ -36,9 +36,9 namespace Implab.Formats.JSON {
36 36 readonly int[,] m_dfa;
37 37 int m_state;
38 38
39 readonly JSONElementContext m_elementContext;
39 readonly JsonElementContext m_elementContext;
40 40
41 public ParserContext(int[,] dfa, int state, JSONElementContext context) {
41 public ParserContext(int[,] dfa, int state, JsonElementContext context) {
42 42 m_dfa = dfa;
43 43 m_state = state;
44 44 m_elementContext = context;
@@ -52,7 +52,7 namespace Implab.Formats.JSON {
52 52 return true;
53 53 }
54 54
55 public JSONElementContext ElementContext {
55 public JsonElementContext ElementContext {
56 56 get { return m_elementContext; }
57 57 }
58 58 }
@@ -61,7 +61,7 namespace Implab.Formats.JSON {
61 61 static readonly ParserContext _objectContext;
62 62 static readonly ParserContext _arrayContext;
63 63
64 static JSONParser() {
64 static JsonParser() {
65 65
66 66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
67 67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
@@ -88,16 +88,16 namespace Implab.Formats.JSON {
88 88
89 89 var jsonExpression = valueExpression.End();
90 90
91 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None);
92 _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object);
93 _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array);
91 _jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None);
92 _objectContext = CreateParserContext(objectExpression, JsonElementContext.Object);
93 _arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array);
94 94 }
95 95
96 96 static Token MakeToken(params JsonTokenType[] input) {
97 97 return Token.New( input.Select(t => (int)t).ToArray() );
98 98 }
99 99
100 static ParserContext CreateParserContext(Token expr, JSONElementContext context) {
100 static ParserContext CreateParserContext(Token expr, JsonElementContext context) {
101 101
102 102 var dfa = new DFATable();
103 103 var builder = new RegularExpressionVisitor(dfa);
@@ -109,11 +109,11 namespace Implab.Formats.JSON {
109 109
110 110 #endregion
111 111
112 readonly JSONScanner m_scanner;
112 readonly JsonScanner m_scanner;
113 113 // json starts from the value context and may content even a single literal
114 114 MemberContext m_memberContext = MemberContext.MemberValue;
115 115
116 JSONElementType m_elementType;
116 JsonElementType m_elementType;
117 117 object m_elementValue;
118 118 string m_memberName = String.Empty;
119 119
@@ -124,18 +124,18 namespace Implab.Formats.JSON {
124 124 /// Создает новый парсер на основе строки, содержащей JSON
125 125 /// </summary>
126 126 /// <param name="text"></param>
127 public JSONParser(string text) {
127 public JsonParser(string text) {
128 128 Safe.ArgumentNotEmpty(text, "text");
129 m_scanner = new JSONScanner(text);
129 m_scanner = JsonStringScanner.Create(text);
130 130 }
131 131
132 132 /// <summary>
133 133 /// Создает новый экземпляр парсера, на основе текстового потока.
134 134 /// </summary>
135 135 /// <param name="reader">Текстовый поток.</param>
136 public JSONParser(TextReader reader) {
136 public JsonParser(TextReader reader) {
137 137 Safe.ArgumentNotNull(reader, "reader");
138 m_scanner = new JSONScanner(reader);
138 m_scanner = JsonTextScanner.Create(reader);
139 139 }
140 140
141 141 public int Level {
@@ -145,7 +145,7 namespace Implab.Formats.JSON {
145 145 /// <summary>
146 146 /// Тип текущего элемента на котором стоит парсер.
147 147 /// </summary>
148 public JSONElementType ElementType {
148 public JsonElementType ElementType {
149 149 get { return m_elementType; }
150 150 }
151 151
@@ -158,7 +158,7 namespace Implab.Formats.JSON {
158 158 }
159 159
160 160 /// <summary>
161 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
161 /// Значение элемента. Только для элементов типа <see cref="JsonElementType.Value"/>, для остальных <c>null</c>
162 162 /// </summary>
163 163 public object ElementValue {
164 164 get { return m_elementValue; }
@@ -185,7 +185,7 namespace Implab.Formats.JSON {
185 185
186 186 m_elementValue = null;
187 187 m_memberContext = MemberContext.MemberName;
188 m_elementType = JSONElementType.BeginObject;
188 m_elementType = JsonElementType.BeginObject;
189 189 return true;
190 190 case JsonTokenType.EndObject:
191 191 if (m_stack.Count == 0)
@@ -193,7 +193,7 namespace Implab.Formats.JSON {
193 193 m_context = m_stack.Pop();
194 194
195 195 m_elementValue = null;
196 m_elementType = JSONElementType.EndObject;
196 m_elementType = JsonElementType.EndObject;
197 197 return true;
198 198 case JsonTokenType.BeginArray:
199 199 m_stack.Push(m_context);
@@ -201,7 +201,7 namespace Implab.Formats.JSON {
201 201
202 202 m_elementValue = null;
203 203 m_memberContext = MemberContext.MemberValue;
204 m_elementType = JSONElementType.BeginArray;
204 m_elementType = JsonElementType.BeginArray;
205 205 return true;
206 206 case JsonTokenType.EndArray:
207 207 if (m_stack.Count == 0)
@@ -209,36 +209,36 namespace Implab.Formats.JSON {
209 209 m_context = m_stack.Pop();
210 210
211 211 m_elementValue = null;
212 m_elementType = JSONElementType.EndArray;
212 m_elementType = JsonElementType.EndArray;
213 213 return true;
214 214 case JsonTokenType.String:
215 215 if (m_memberContext == MemberContext.MemberName) {
216 216 m_memberName = (string)tokenValue;
217 217 break;
218 218 }
219 m_elementType = JSONElementType.Value;
219 m_elementType = JsonElementType.Value;
220 220 m_elementValue = tokenValue;
221 221 return true;
222 222 case JsonTokenType.Number:
223 m_elementType = JSONElementType.Value;
223 m_elementType = JsonElementType.Value;
224 224 m_elementValue = tokenValue;
225 225 return true;
226 226 case JsonTokenType.Literal:
227 m_elementType = JSONElementType.Value;
227 m_elementType = JsonElementType.Value;
228 228 m_elementValue = ParseLiteral((string)tokenValue);
229 229 return true;
230 230 case JsonTokenType.NameSeparator:
231 231 m_memberContext = MemberContext.MemberValue;
232 232 break;
233 233 case JsonTokenType.ValueSeparator:
234 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
234 m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
235 235 break;
236 236 default:
237 237 UnexpectedToken(tokenValue, tokenType);
238 238 break;
239 239 }
240 240 }
241 if (m_context.ElementContext != JSONElementContext.None)
241 if (m_context.ElementContext != JsonElementContext.None)
242 242 throw new ParserException("Unexpedted end of data");
243 243
244 244 EOF = true;
@@ -5,37 +5,65 using System.Text;
5 5 using Implab.Components;
6 6 using System.IO;
7 7
8 namespace Implab.Formats.JSON {
8 namespace Implab.Formats.Json {
9 9 /// <summary>
10 10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
11 11 /// </summary>
12 public class JSONScanner : Disposable {
13 readonly StringBuilder m_builder = new StringBuilder();
14
15 readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
16 readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
17
12 public abstract class JsonScanner : Disposable {
13 readonly InputScanner<JsonGrammar.TokenType> m_jsonContext = JsonGrammar.CreateJsonExpressionScanner();
14 readonly InputScanner<JsonGrammar.TokenType> m_stringContext = JsonGrammar.CreateStringExpressionScanner();
18 15
19 readonly TextScanner m_scanner;
16 readonly char[] m_unescapeBuf = new char[4];
17 readonly char[] m_buffer;
18 int m_length;
19 int m_pos;
20 readonly StringBuilder m_tokenBuilder = new StringBuilder();
20 21
21 /// <summary>
22 /// Создает новый экземпляр сканнера
23 /// </summary>
24 public JSONScanner(string text) {
25 Safe.ArgumentNotEmpty(text, "text");
26
27 m_scanner = new StringScanner(text);
22 protected JsonScanner(char[] buffer, int pos, int length) {
23 m_buffer = buffer;
24 m_pos = pos;
25 m_length = length;
28 26 }
29 27
30 public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
31 Safe.ArgumentNotNull(reader, "reader");
28 bool Read(InputScanner<JsonGrammar.TokenType> scanner, out JsonGrammar.TokenType tokenType) {
29 scanner.Reset();
32 30
33 m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
31 if (m_pos == m_length) {
32 m_pos = 0;
33 m_length = Read(m_buffer, 0, m_buffer.Length);
34 if (m_length == 0) {
35 tokenType = JsonGrammar.TokenType.None;
36 return false; // EOF
37 }
34 38 }
35 39
36 public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
40 while(scanner.Scan(m_buffer, m_pos, m_length - m_pos)) {
41 m_tokenBuilder.Append(m_buffer, m_pos, m_length - m_pos);
42 m_pos = 0;
43 m_length = Read(m_buffer, 0, m_buffer.Length);
44 }
45 var scannerPos = scanner.Position;
46 if (scannerPos != m_pos) {
47 m_tokenBuilder.Append(m_buffer, m_pos, scannerPos - m_pos);
48 m_pos = scannerPos;
37 49 }
38 50
51 if (!scanner.IsFinal) {
52 if (m_length == 0) {
53 // unexpected EOF
54 throw new ParserException("Unexpected EOF");
55 } else {
56 // unecpected character
57 throw new ParserException($"Unexpected character '{m_buffer[m_pos + 1]}'");
58 }
59 }
60 tokenType = scanner.Tag;
61 return true;
62 }
63
64 protected abstract int Read(char[] buffer, int offset, int size);
65
66
39 67 /// <summary>
40 68 /// Читает следующий лексический элемент из входных данных.
41 69 /// </summary>
@@ -45,22 +73,28 namespace Implab.Formats.JSON {
45 73 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
46 74 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
47 75 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
48 JSONGrammar.TokenType[] tag;
49 while (m_jsonContext.Execute(m_scanner, out tag)) {
50 switch (tag[0]) {
51 case JSONGrammar.TokenType.StringBound:
76 JsonGrammar.TokenType tag;
77 m_tokenBuilder.Clear();
78 while (Read(m_jsonContext, out tag)) {
79 switch (tag) {
80 case JsonGrammar.TokenType.StringBound:
52 81 tokenValue = ReadString();
53 82 tokenType = JsonTokenType.String;
54 83 break;
55 case JSONGrammar.TokenType.Number:
56 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
84 case JsonGrammar.TokenType.Number:
85 tokenValue = Double.Parse(m_tokenBuilder.ToString(), CultureInfo.InvariantCulture);
57 86 tokenType = JsonTokenType.Number;
58 87 break;
59 case JSONGrammar.TokenType.Whitespace:
88 case JsonGrammar.TokenType.Literal:
89 tokenType = JsonTokenType.Literal;
90 tokenValue = m_tokenBuilder.ToString();
91 break;
92 case JsonGrammar.TokenType.Whitespace:
93 m_tokenBuilder.Clear();
60 94 continue;
61 95 default:
62 tokenType = (JsonTokenType)tag[0];
63 tokenValue = m_scanner.GetTokenValue();
96 tokenType = (JsonTokenType)tag;
97 tokenValue = null;
64 98 break;
65 99 }
66 100 return true;
@@ -71,39 +105,30 namespace Implab.Formats.JSON {
71 105 }
72 106
73 107 string ReadString() {
74 int pos = 0;
75 var buf = new char[6]; // the buffer for unescaping chars
76
77 JSONGrammar.TokenType[] tag;
78 m_builder.Clear();
108 JsonGrammar.TokenType tag;
109 m_tokenBuilder.Clear();
79 110
80 while (m_stringContext.Execute(m_scanner, out tag)) {
81 switch (tag[0]) {
82 case JSONGrammar.TokenType.StringBound:
83 return m_builder.ToString();
84 case JSONGrammar.TokenType.UnescapedChar:
85 m_scanner.CopyTokenTo(m_builder);
111 while (Read(m_stringContext, out tag)) {
112 switch (tag) {
113 case JsonGrammar.TokenType.StringBound:
114 m_tokenBuilder.Length--;
115 return m_tokenBuilder.ToString();
116 case JsonGrammar.TokenType.UnescapedChar:
86 117 break;
87 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
88 m_scanner.CopyTokenTo(buf, 0);
89 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
90 pos++;
118 case JsonGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
119 m_tokenBuilder.CopyTo(m_tokenBuilder.Length - 4, m_unescapeBuf, 0, 4);
120 m_tokenBuilder.Length -= 6;
121 m_tokenBuilder.Append(StringTranslator.TranslateHexUnicode(m_unescapeBuf, 0));
91 122 break;
92 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
93 m_scanner.CopyTokenTo(buf, 0);
94 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
123 case JsonGrammar.TokenType.EscapedChar: // \t - escape sequence
124 var ch = m_tokenBuilder[m_tokenBuilder.Length-1];
125 m_tokenBuilder.Length -= 2;
126 m_tokenBuilder.Append(StringTranslator.TranslateEscapedChar(ch));
95 127 break;
96 128 }
97
98 129 }
99 130
100 131 throw new ParserException("Unexpected end of data");
101 132 }
102
103 protected override void Dispose(bool disposing) {
104 if (disposing)
105 m_scanner.Dispose();
106 base.Dispose(disposing);
107 133 }
108 134 }
109 }
@@ -1,6 +1,6
1 namespace Implab.Formats.JSON {
1 namespace Implab.Formats.Json {
2 2 /// <summary>
3 /// Тип токенов, возвращаемых <see cref="JSONScanner"/>.
3 /// Тип токенов, возвращаемых <see cref="JsonScanner"/>.
4 4 /// </summary>
5 5 public enum JsonTokenType : int {
6 6 None = 0,
@@ -4,11 +4,11 using System.IO;
4 4 using System.Globalization;
5 5 using System.Diagnostics;
6 6
7 namespace Implab.Formats.JSON {
8 public class JSONWriter {
7 namespace Implab.Formats.Json {
8 public class JsonWriter {
9 9 struct Context {
10 10 public bool needComma;
11 public JSONElementContext element;
11 public JsonElementContext element;
12 12 }
13 13 Stack<Context> m_contextStack = new Stack<Context>();
14 14 Context m_context;
@@ -30,7 +30,7 namespace Implab.Formats.JSON {
30 30 _escapeBSLASH,
31 31 _escapeQ;
32 32
33 static JSONWriter() {
33 static JsonWriter() {
34 34 _escapeBKS = "\\b".ToCharArray();
35 35 _escapeFWD = "\\f".ToCharArray();
36 36 _escapeCR = "\\r".ToCharArray();
@@ -40,12 +40,12 namespace Implab.Formats.JSON {
40 40 _escapeQ = "\\\"".ToCharArray();
41 41 }
42 42
43 public JSONWriter(TextWriter writer) {
43 public JsonWriter(TextWriter writer) {
44 44 Safe.ArgumentNotNull(writer, "writer");
45 45 m_writer = writer;
46 46 }
47 47
48 public JSONWriter(TextWriter writer, bool indent) {
48 public JsonWriter(TextWriter writer, bool indent) {
49 49 Safe.ArgumentNotNull(writer, "writer");
50 50
51 51 m_writer = writer;
@@ -66,7 +66,7 namespace Implab.Formats.JSON {
66 66
67 67 void WriteMemberName(string name) {
68 68 Safe.ArgumentNotEmpty(name, "name");
69 if (m_context.element != JSONElementContext.Object)
69 if (m_context.element != JsonElementContext.Object)
70 70 OperationNotApplicable("WriteMember");
71 71 if (m_context.needComma)
72 72 m_writer.Write(",");
@@ -93,7 +93,7 namespace Implab.Formats.JSON {
93 93 }
94 94
95 95 public void WriteValue(string value) {
96 if (m_context.element == JSONElementContext.Array) {
96 if (m_context.element == JsonElementContext.Array) {
97 97
98 98 if (m_context.needComma)
99 99 m_writer.Write(",");
@@ -101,16 +101,16 namespace Implab.Formats.JSON {
101 101 m_context.needComma = true;
102 102
103 103 Write(value);
104 } else if (m_context.element == JSONElementContext.None) {
104 } else if (m_context.element == JsonElementContext.None) {
105 105 Write(value);
106 m_context.element = JSONElementContext.Closed;
106 m_context.element = JsonElementContext.Closed;
107 107 } else {
108 108 OperationNotApplicable("WriteValue");
109 109 }
110 110 }
111 111
112 112 public void WriteValue(bool value) {
113 if (m_context.element == JSONElementContext.Array) {
113 if (m_context.element == JsonElementContext.Array) {
114 114
115 115 if (m_context.needComma)
116 116 m_writer.Write(",");
@@ -118,16 +118,16 namespace Implab.Formats.JSON {
118 118 m_context.needComma = true;
119 119
120 120 Write(value);
121 } else if (m_context.element == JSONElementContext.None) {
121 } else if (m_context.element == JsonElementContext.None) {
122 122 Write(value);
123 m_context.element = JSONElementContext.Closed;
123 m_context.element = JsonElementContext.Closed;
124 124 } else {
125 125 OperationNotApplicable("WriteValue");
126 126 }
127 127 }
128 128
129 129 public void WriteValue(double value) {
130 if (m_context.element == JSONElementContext.Array) {
130 if (m_context.element == JsonElementContext.Array) {
131 131
132 132 if (m_context.needComma)
133 133 m_writer.Write(",");
@@ -135,16 +135,16 namespace Implab.Formats.JSON {
135 135 m_context.needComma = true;
136 136
137 137 Write(value);
138 } else if (m_context.element == JSONElementContext.None) {
138 } else if (m_context.element == JsonElementContext.None) {
139 139 Write(value);
140 m_context.element = JSONElementContext.Closed;
140 m_context.element = JsonElementContext.Closed;
141 141 } else {
142 142 OperationNotApplicable("WriteValue");
143 143 }
144 144 }
145 145
146 146 public void BeginObject() {
147 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
147 if (m_context.element != JsonElementContext.None && m_context.element != JsonElementContext.Array)
148 148 OperationNotApplicable("BeginObject");
149 149 if (m_context.needComma)
150 150 m_writer.Write(",");
@@ -155,7 +155,7 namespace Implab.Formats.JSON {
155 155
156 156 m_contextStack.Push(m_context);
157 157
158 m_context = new Context { element = JSONElementContext.Object, needComma = false };
158 m_context = new Context { element = JsonElementContext.Object, needComma = false };
159 159 m_writer.Write("{");
160 160 }
161 161
@@ -164,23 +164,23 namespace Implab.Formats.JSON {
164 164
165 165 m_contextStack.Push(m_context);
166 166
167 m_context = new Context { element = JSONElementContext.Object, needComma = false };
167 m_context = new Context { element = JsonElementContext.Object, needComma = false };
168 168 m_writer.Write("{");
169 169 }
170 170
171 171 public void EndObject() {
172 if (m_context.element != JSONElementContext.Object)
172 if (m_context.element != JsonElementContext.Object)
173 173 OperationNotApplicable("EndObject");
174 174
175 175 m_context = m_contextStack.Pop();
176 176 if (m_contextStack.Count == 0)
177 m_context.element = JSONElementContext.Closed;
177 m_context.element = JsonElementContext.Closed;
178 178 WriteIndent();
179 179 m_writer.Write("}");
180 180 }
181 181
182 182 public void BeginArray() {
183 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
183 if (m_context.element != JsonElementContext.None && m_context.element != JsonElementContext.Array)
184 184 throw new InvalidOperationException();
185 185 if (m_context.needComma) {
186 186 m_writer.Write(",");
@@ -190,7 +190,7 namespace Implab.Formats.JSON {
190 190
191 191 WriteIndent();
192 192 m_contextStack.Push(m_context);
193 m_context = new Context { element = JSONElementContext.Array, needComma = false };
193 m_context = new Context { element = JsonElementContext.Array, needComma = false };
194 194 m_writer.Write("[");
195 195 }
196 196
@@ -199,17 +199,17 namespace Implab.Formats.JSON {
199 199
200 200 m_contextStack.Push(m_context);
201 201
202 m_context = new Context { element = JSONElementContext.Array, needComma = false };
202 m_context = new Context { element = JsonElementContext.Array, needComma = false };
203 203 m_writer.Write("[");
204 204 }
205 205
206 206 public void EndArray() {
207 if (m_context.element != JSONElementContext.Array)
207 if (m_context.element != JsonElementContext.Array)
208 208 OperationNotApplicable("EndArray");
209 209
210 210 m_context = m_contextStack.Pop();
211 211 if (m_contextStack.Count == 0)
212 m_context.element = JSONElementContext.Closed;
212 m_context.element = JsonElementContext.Closed;
213 213 WriteIndent();
214 214 m_writer.Write("]");
215 215 }
@@ -7,7 +7,7 using System.Linq;
7 7 using System.Text;
8 8 using System.Threading.Tasks;
9 9
10 namespace Implab.Formats.JSON {
10 namespace Implab.Formats.Json {
11 11 /// <summary>
12 12 /// Класс для преобразования экранированной строки JSON
13 13 /// </summary>
@@ -83,6 +83,10
83 83 <Compile Include="Diagnostics\TraceEvent.cs" />
84 84 <Compile Include="Diagnostics\TraceEventType.cs" />
85 85 <Compile Include="Diagnostics\TraceSourceAttribute.cs" />
86 <Compile Include="Formats\CharMap.cs" />
87 <Compile Include="Formats\InputScanner.cs" />
88 <Compile Include="Formats\Json\JsonStringScanner.cs" />
89 <Compile Include="Formats\Json\JsonTextScanner.cs" />
86 90 <Compile Include="ICancellable.cs" />
87 91 <Compile Include="IProgressHandler.cs" />
88 92 <Compile Include="IProgressNotifier.cs" />
@@ -164,16 +168,14
164 168 <Compile Include="Automaton\RegularExpressions\Token.cs" />
165 169 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
166 170 <Compile Include="Automaton\AutomatonTransition.cs" />
167 <Compile Include="Formats\JSON\JSONElementContext.cs" />
168 <Compile Include="Formats\JSON\JSONElementType.cs" />
169 <Compile Include="Formats\JSON\JSONGrammar.cs" />
170 <Compile Include="Formats\JSON\JSONParser.cs" />
171 <Compile Include="Formats\JSON\JSONScanner.cs" />
172 <Compile Include="Formats\JSON\JsonTokenType.cs" />
173 <Compile Include="Formats\JSON\JSONWriter.cs" />
174 <Compile Include="Formats\JSON\JSONXmlReader.cs" />
175 <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" />
176 <Compile Include="Formats\JSON\StringTranslator.cs" />
171 <Compile Include="Formats\Json\JsonElementContext.cs" />
172 <Compile Include="Formats\Json\JsonElementType.cs" />
173 <Compile Include="Formats\Json\JsonGrammar.cs" />
174 <Compile Include="Formats\Json\JsonParser.cs" />
175 <Compile Include="Formats\Json\JsonScanner.cs" />
176 <Compile Include="Formats\Json\JsonTokenType.cs" />
177 <Compile Include="Formats\Json\JsonWriter.cs" />
178 <Compile Include="Formats\Json\StringTranslator.cs" />
177 179 <Compile Include="Automaton\MapAlphabet.cs" />
178 180 <Compile Include="Formats\CharAlphabet.cs" />
179 181 <Compile Include="Formats\ByteAlphabet.cs" />
@@ -182,10 +184,6
182 184 <Compile Include="Automaton\DFATable.cs" />
183 185 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
184 186 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
185 <Compile Include="Formats\TextScanner.cs" />
186 <Compile Include="Formats\StringScanner.cs" />
187 <Compile Include="Formats\ReaderScanner.cs" />
188 <Compile Include="Formats\ScannerContext.cs" />
189 187 <Compile Include="Formats\Grammar.cs" />
190 188 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
191 189 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
@@ -5,6 +5,7 using System.Text;
5 5 using System.Text.RegularExpressions;
6 6 using System.Diagnostics;
7 7 using System.Collections;
8 using System.Runtime.CompilerServices;
8 9
9 10 #if NET_4_5
10 11 using System.Threading.Tasks;
@@ -14,11 +15,13 namespace Implab
14 15 {
15 16 public static class Safe
16 17 {
18 [MethodImpl(MethodImplOptions.AggressiveInlining)]
17 19 public static void ArgumentAssert(bool condition, string paramName) {
18 20 if (!condition)
19 21 throw new ArgumentException("The parameter is invalid", paramName);
20 22 }
21 23
24 [MethodImpl(MethodImplOptions.AggressiveInlining)]
22 25 public static void ArgumentMatch(string value, string paramName, Regex rx) {
23 26 if (rx == null)
24 27 throw new ArgumentNullException("rx");
@@ -26,26 +29,37 namespace Implab
26 29 throw new ArgumentException(String.Format("The prameter value must match {0}", rx), paramName);
27 30 }
28 31
32 [MethodImpl(MethodImplOptions.AggressiveInlining)]
29 33 public static void ArgumentNotEmpty(string value, string paramName) {
30 34 if (String.IsNullOrEmpty(value))
31 35 throw new ArgumentException("The parameter can't be empty", paramName);
32 36 }
33 37
38 [MethodImpl(MethodImplOptions.AggressiveInlining)]
34 39 public static void ArgumentNotEmpty<T>(T[] value, string paramName) {
35 40 if (value == null || value.Length == 0)
36 41 throw new ArgumentException("The array must be not emty", paramName);
37 42 }
38 43
44 [MethodImpl(MethodImplOptions.AggressiveInlining)]
39 45 public static void ArgumentNotNull(object value, string paramName) {
40 46 if (value == null)
41 47 throw new ArgumentNullException(paramName);
42 48 }
43 49
50 [MethodImpl(MethodImplOptions.AggressiveInlining)]
51 internal static void ArgumentGreaterThan(int value, int min, string paramName) {
52 if (value < min)
53 throw new ArgumentOutOfRangeException(paramName);
54 }
55
56 [MethodImpl(MethodImplOptions.AggressiveInlining)]
44 57 public static void ArgumentInRange(int value, int min, int max, string paramName) {
45 58 if (value < min || value > max)
46 59 throw new ArgumentOutOfRangeException(paramName);
47 60 }
48 61
62 [MethodImpl(MethodImplOptions.AggressiveInlining)]
49 63 public static void ArgumentOfType(object value, Type type, string paramName) {
50 64 if (!type.IsInstanceOfType(value))
51 65 throw new ArgumentException(String.Format("The parameter must be of type {0}", type), paramName);
@@ -1,10 +1,8
1 using Implab.Formats.JSON;
1 using Implab.Formats.Json;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Globalization;
5 5 using System.Linq;
6 using System.Text;
7 using System.Threading.Tasks;
8 6 using System.Xml;
9 7
10 8 namespace Implab.Xml {
@@ -14,7 +12,7 namespace Implab.Xml {
14 12 public bool skip;
15 13 }
16 14
17 JSONParser m_parser;
15 JsonParser m_parser;
18 16 JsonXmlReaderOptions m_options;
19 17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
20 18 XmlNameTable m_nameTable;
@@ -52,7 +50,6 namespace Implab.Xml {
52 50
53 51
54 52 XmlNameContext m_context;
55 int m_nextPrefix = 1;
56 53
57 54 readonly string m_xmlnsPrefix;
58 55 readonly string m_xmlnsNamespace;
@@ -60,7 +57,7 namespace Implab.Xml {
60 57 readonly string m_xsiNamespace;
61 58
62 59
63 public JsonXmlReader(JSONParser parser, JsonXmlReaderOptions options) {
60 public JsonXmlReader(JsonParser parser, JsonXmlReaderOptions options) {
64 61 Safe.ArgumentNotNull(parser, nameof(parser));
65 62 m_parser = parser;
66 63
@@ -480,35 +477,35 namespace Implab.Xml {
480 477 var jsonName = m_nameTable.Add(m_parser.ElementName);
481 478
482 479 switch (m_parser.ElementType) {
483 case JSONElementType.BeginObject:
480 case JsonElementType.BeginObject:
484 481 if (!EnterJsonObject(jsonName, out elementName))
485 482 continue;
486 483
487 484 m_position = JsonXmlReaderPosition.BeginObject;
488 485 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
489 486 break;
490 case JSONElementType.EndObject:
487 case JsonElementType.EndObject:
491 488 if (!LeaveJsonScope(out elementName))
492 489 continue;
493 490
494 491 m_position = JsonXmlReaderPosition.EndObject;
495 492 EndElementNode(elementName, m_jsonNamespace);
496 493 break;
497 case JSONElementType.BeginArray:
494 case JsonElementType.BeginArray:
498 495 if (!EnterJsonArray(jsonName, out elementName))
499 496 continue;
500 497
501 498 m_position = JsonXmlReaderPosition.BeginArray;
502 499 ElementNode(elementName, m_jsonNamespace, elementAttrs, false);
503 500 break;
504 case JSONElementType.EndArray:
501 case JsonElementType.EndArray:
505 502 if (!LeaveJsonScope(out elementName))
506 503 continue;
507 504
508 505 m_position = JsonXmlReaderPosition.EndArray;
509 506 EndElementNode(elementName, m_jsonNamespace);
510 507 break;
511 case JSONElementType.Value:
508 case JsonElementType.Value:
512 509 if (!VisitJsonValue(jsonName, out m_jsonValueName))
513 510 continue;
514 511
@@ -2,16 +2,16
2 2 using System;
3 3 using System.Xml;
4 4
5 namespace Implab.Formats.JSON {
5 namespace Implab.Xml {
6 6 /// <summary>
7 /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
7 /// Набор необязательных параметров для <see cref="JsonXmlReader"/>, позволяющий управлять процессом
8 8 /// интерпретации <c>JSON</c> документа.
9 9 /// </summary>
10 public class JSONXmlReaderOptions : ICloneable {
10 public class JsonXmlReaderOptions : ICloneable {
11 11 /// <summary>
12 12 /// Пространство имен в котором будут располагаться читаемые элементы документа
13 13 /// </summary>
14 public string NamespaceURI {
14 public string NamespaceUri {
15 15 get;
16 16 set;
17 17 }
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now