Mercurial > pub > ImplabNet
annotate Implab/Formats/Json/JsonReader.cs @ 240:fa6cbf4d8841 v3
refactoring, moving to dotnercore, simplifying promises
author | cin |
---|---|
date | Tue, 23 Jan 2018 19:39:21 +0300 |
parents | 302ca905c19e |
children |
rev | line source |
---|---|
165 | 1 using System; |
163 | 2 using System.Diagnostics; |
3 using System.IO; | |
165 | 4 using Implab.Automaton; |
5 using Implab.Automaton.RegularExpressions; | |
6 using System.Linq; | |
7 using Implab.Components; | |
180 | 8 using System.Collections.Generic; |
229 | 9 using System.Text; |
10 using System.Globalization; | |
163 | 11 |
228 | 12 namespace Implab.Formats.Json { |
163 | 13 /// <summary> |
14 /// Pull парсер JSON данных. | |
15 /// </summary> | |
16 /// <remarks> | |
17 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>, | |
18 /// оно означает текущий уровень вложенности объектов, однако закрывающий | |
19 /// элемент объекта и массива имеет уровень меньше, чем сам объект. | |
20 /// <code> | |
21 /// { // Level = 1 | |
22 /// "name" : "Peter", // Level = 1 | |
23 /// "address" : { // Level = 2 | |
24 /// city : "Stern" // Level = 2 | |
25 /// } // Level = 1 | |
26 /// } // Level = 0 | |
27 /// </code> | |
28 /// </remarks> | |
229 | 29 public class JsonReader : Disposable { |
163 | 30 |
31 enum MemberContext { | |
32 MemberName, | |
33 MemberValue | |
34 } | |
35 | |
178 | 36 #region Parser rules |
165 | 37 struct ParserContext { |
178 | 38 readonly int[,] m_dfa; |
39 int m_state; | |
40 | |
228 | 41 readonly JsonElementContext m_elementContext; |
165 | 42 |
228 | 43 public ParserContext(int[,] dfa, int state, JsonElementContext context) { |
178 | 44 m_dfa = dfa; |
45 m_state = state; | |
46 m_elementContext = context; | |
47 } | |
48 | |
49 public bool Move(JsonTokenType token) { | |
180 | 50 var next = m_dfa[m_state, (int)token]; |
236 | 51 if (next == AutomatonConst.UnreachableState) |
178 | 52 return false; |
53 m_state = next; | |
180 | 54 return true; |
178 | 55 } |
56 | |
228 | 57 public JsonElementContext ElementContext { |
178 | 58 get { return m_elementContext; } |
59 } | |
60 } | |
163 | 61 |
180 | 62 static readonly ParserContext _jsonContext; |
63 static readonly ParserContext _objectContext; | |
64 static readonly ParserContext _arrayContext; | |
65 | |
229 | 66 static JsonReader() { |
163 | 67 |
180 | 68 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String); |
69 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression); | |
163 | 70 |
71 var objectExpression = memberExpression | |
72 .Cat( | |
180 | 73 MakeToken(JsonTokenType.ValueSeparator) |
163 | 74 .Cat(memberExpression) |
75 .EClosure() | |
76 ) | |
77 .Optional() | |
180 | 78 .Cat(MakeToken(JsonTokenType.EndObject)) |
178 | 79 .End(); |
80 | |
163 | 81 var arrayExpression = valueExpression |
82 .Cat( | |
180 | 83 MakeToken(JsonTokenType.ValueSeparator) |
163 | 84 .Cat(valueExpression) |
85 .EClosure() | |
86 ) | |
87 .Optional() | |
180 | 88 .Cat(MakeToken(JsonTokenType.EndArray)) |
178 | 89 .End(); |
163 | 90 |
178 | 91 var jsonExpression = valueExpression.End(); |
163 | 92 |
228 | 93 _jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None); |
94 _objectContext = CreateParserContext(objectExpression, JsonElementContext.Object); | |
95 _arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array); | |
163 | 96 } |
97 | |
180 | 98 static Token MakeToken(params JsonTokenType[] input) { |
178 | 99 return Token.New( input.Select(t => (int)t).ToArray() ); |
165 | 100 } |
101 | |
228 | 102 static ParserContext CreateParserContext(Token expr, JsonElementContext context) { |
178 | 103 |
104 var dfa = new DFATable(); | |
105 var builder = new RegularExpressionVisitor(dfa); | |
163 | 106 expr.Accept(builder); |
178 | 107 builder.BuildDFA(); |
163 | 108 |
178 | 109 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context); |
163 | 110 } |
111 | |
178 | 112 #endregion |
113 | |
228 | 114 readonly JsonScanner m_scanner; |
227
8d5de4eb9c2c
Reimplemented JsonXmlReader, added support for null values: JSON null values are
cin
parents:
208
diff
changeset
|
115 // json starts from the value context and may content even a single literal |
8d5de4eb9c2c
Reimplemented JsonXmlReader, added support for null values: JSON null values are
cin
parents:
208
diff
changeset
|
116 MemberContext m_memberContext = MemberContext.MemberValue; |
163 | 117 |
228 | 118 JsonElementType m_elementType; |
236 | 119 string m_elementValue; |
180 | 120 string m_memberName = String.Empty; |
121 | |
122 Stack<ParserContext> m_stack = new Stack<ParserContext>(); | |
123 ParserContext m_context = _jsonContext; | |
163 | 124 |
125 /// <summary> | |
126 /// Создает новый парсер на основе строки, содержащей JSON | |
127 /// </summary> | |
128 /// <param name="text"></param> | |
229 | 129 JsonReader(JsonScanner scanner) { |
130 m_scanner = scanner; | |
163 | 131 } |
229 | 132 |
180 | 133 public int Level { |
134 get { return m_stack.Count; } | |
163 | 135 } |
136 | |
137 /// <summary> | |
138 /// Тип текущего элемента на котором стоит парсер. | |
139 /// </summary> | |
228 | 140 public JsonElementType ElementType { |
163 | 141 get { return m_elementType; } |
142 } | |
143 | |
144 /// <summary> | |
145 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда | |
146 /// пустая строка. | |
147 /// </summary> | |
148 public string ElementName { | |
180 | 149 get { return m_memberName; } |
163 | 150 } |
151 | |
152 /// <summary> | |
228 | 153 /// Значение элемента. Только для элементов типа <see cref="JsonElementType.Value"/>, для остальных <c>null</c> |
163 | 154 /// </summary> |
236 | 155 public string ElementValue { |
163 | 156 get { return m_elementValue; } |
157 } | |
158 | |
159 /// <summary> | |
160 /// Читает слеюудущий объект из потока | |
161 /// </summary> | |
162 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns> | |
163 public bool Read() { | |
229 | 164 string tokenValue; |
163 | 165 JsonTokenType tokenType; |
180 | 166 |
167 m_memberName = String.Empty; | |
168 | |
163 | 169 while (m_scanner.ReadToken(out tokenValue, out tokenType)) { |
180 | 170 if(!m_context.Move(tokenType)) |
163 | 171 UnexpectedToken(tokenValue, tokenType); |
180 | 172 |
163 | 173 switch (tokenType) { |
174 case JsonTokenType.BeginObject: | |
180 | 175 m_stack.Push(m_context); |
176 m_context = _objectContext; | |
177 | |
163 | 178 m_elementValue = null; |
179 m_memberContext = MemberContext.MemberName; | |
228 | 180 m_elementType = JsonElementType.BeginObject; |
163 | 181 return true; |
182 case JsonTokenType.EndObject: | |
180 | 183 if (m_stack.Count == 0) |
184 UnexpectedToken(tokenValue, tokenType); | |
185 m_context = m_stack.Pop(); | |
186 | |
163 | 187 m_elementValue = null; |
228 | 188 m_elementType = JsonElementType.EndObject; |
163 | 189 return true; |
190 case JsonTokenType.BeginArray: | |
180 | 191 m_stack.Push(m_context); |
192 m_context = _arrayContext; | |
193 | |
163 | 194 m_elementValue = null; |
195 m_memberContext = MemberContext.MemberValue; | |
228 | 196 m_elementType = JsonElementType.BeginArray; |
163 | 197 return true; |
198 case JsonTokenType.EndArray: | |
180 | 199 if (m_stack.Count == 0) |
200 UnexpectedToken(tokenValue, tokenType); | |
201 m_context = m_stack.Pop(); | |
202 | |
163 | 203 m_elementValue = null; |
228 | 204 m_elementType = JsonElementType.EndArray; |
163 | 205 return true; |
206 case JsonTokenType.String: | |
207 if (m_memberContext == MemberContext.MemberName) { | |
229 | 208 m_memberName = tokenValue; |
163 | 209 break; |
210 } | |
228 | 211 m_elementType = JsonElementType.Value; |
163 | 212 m_elementValue = tokenValue; |
213 return true; | |
214 case JsonTokenType.Number: | |
228 | 215 m_elementType = JsonElementType.Value; |
236 | 216 m_elementValue = tokenValue; |
163 | 217 return true; |
218 case JsonTokenType.Literal: | |
228 | 219 m_elementType = JsonElementType.Value; |
236 | 220 m_elementValue = tokenValue == "null" ? null : tokenValue; |
163 | 221 return true; |
222 case JsonTokenType.NameSeparator: | |
223 m_memberContext = MemberContext.MemberValue; | |
224 break; | |
225 case JsonTokenType.ValueSeparator: | |
228 | 226 m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; |
163 | 227 break; |
228 default: | |
229 UnexpectedToken(tokenValue, tokenType); | |
230 break; | |
231 } | |
232 } | |
228 | 233 if (m_context.ElementContext != JsonElementContext.None) |
163 | 234 throw new ParserException("Unexpedted end of data"); |
180 | 235 |
229 | 236 Eof = true; |
180 | 237 |
163 | 238 return false; |
239 } | |
240 | |
241 object ParseLiteral(string literal) { | |
242 switch (literal) { | |
243 case "null": | |
244 return null; | |
245 case "false": | |
246 return false; | |
247 case "true": | |
248 return true; | |
249 default: | |
250 UnexpectedToken(literal, JsonTokenType.Literal); | |
251 return null; // avoid compliler error | |
252 } | |
253 } | |
254 | |
255 void UnexpectedToken(object value, JsonTokenType tokenType) { | |
256 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value)); | |
257 } | |
258 | |
259 | |
260 /// <summary> | |
261 /// Признак конца потока | |
262 /// </summary> | |
229 | 263 public bool Eof { |
180 | 264 get; |
265 private set; | |
163 | 266 } |
267 | |
165 | 268 protected override void Dispose(bool disposing) { |
180 | 269 if (disposing) |
208
7d07503621fe
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)
cin
parents:
180
diff
changeset
|
270 m_scanner.Dispose(); |
163 | 271 } |
272 | |
273 /// <summary> | |
274 /// Переходит в конец текущего объекта. | |
275 /// </summary> | |
276 public void SeekElementEnd() { | |
277 var level = Level - 1; | |
278 | |
279 Debug.Assert(level >= 0); | |
280 | |
281 while (Level != level) | |
282 Read(); | |
283 } | |
229 | 284 |
285 public static JsonReader Create(string file, Encoding encoding) { | |
286 return new JsonReader(JsonTextScanner.Create(file, encoding)); | |
287 } | |
288 | |
289 public static JsonReader Create(string file) { | |
290 return new JsonReader(JsonTextScanner.Create(file)); | |
291 } | |
292 | |
293 public static JsonReader Create(Stream stream, Encoding encoding) { | |
294 return new JsonReader(JsonTextScanner.Create(stream, encoding)); | |
295 } | |
296 | |
297 public static JsonReader Create(Stream stream) { | |
298 return new JsonReader(JsonTextScanner.Create(stream)); | |
299 } | |
300 | |
301 public static JsonReader Create(TextReader reader) { | |
302 return new JsonReader(JsonTextScanner.Create(reader)); | |
303 } | |
304 | |
305 public static JsonReader ParseString(string data) { | |
306 return new JsonReader(JsonStringScanner.Create(data)); | |
307 } | |
308 | |
309 public static JsonReader ParseString(string data, int offset, int length) { | |
310 return new JsonReader(JsonStringScanner.Create(data, offset, length)); | |
311 } | |
312 | |
313 public static JsonReader ParseString(char[] data, int offset, int lenght) { | |
314 return new JsonReader(JsonStringScanner.Create(data, offset, lenght)); | |
315 } | |
163 | 316 } |
317 | |
318 } |