Mercurial > pub > ImplabNet
comparison 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 |
comparison
equal
deleted
inserted
replaced
179:478ef706906a | 180:c32688129f14 |
---|---|
3 using System.IO; | 3 using System.IO; |
4 using Implab.Automaton; | 4 using Implab.Automaton; |
5 using Implab.Automaton.RegularExpressions; | 5 using Implab.Automaton.RegularExpressions; |
6 using System.Linq; | 6 using System.Linq; |
7 using Implab.Components; | 7 using Implab.Components; |
8 using System.Collections.Generic; | |
8 | 9 |
9 namespace Implab.Formats.JSON { | 10 namespace Implab.Formats.JSON { |
10 /// <summary> | |
11 /// internal | |
12 /// </summary> | |
13 public struct JSONParserContext { | |
14 public string memberName; | |
15 public JSONElementContext elementContext; | |
16 } | |
17 | |
18 /// <summary> | 11 /// <summary> |
19 /// Pull парсер JSON данных. | 12 /// Pull парсер JSON данных. |
20 /// </summary> | 13 /// </summary> |
21 /// <remarks> | 14 /// <remarks> |
22 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>, | 15 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>, |
50 m_state = state; | 43 m_state = state; |
51 m_elementContext = context; | 44 m_elementContext = context; |
52 } | 45 } |
53 | 46 |
54 public bool Move(JsonTokenType token) { | 47 public bool Move(JsonTokenType token) { |
55 var next = m_dfa[m_state, token]; | 48 var next = m_dfa[m_state, (int)token]; |
56 if (next == AutomatonConst.UNREACHABLE_STATE) | 49 if (next == AutomatonConst.UNREACHABLE_STATE) |
57 return false; | 50 return false; |
58 m_state = next; | 51 m_state = next; |
52 return true; | |
59 } | 53 } |
60 | 54 |
61 public JSONElementContext ElementContext { | 55 public JSONElementContext ElementContext { |
62 get { return m_elementContext; } | 56 get { return m_elementContext; } |
63 } | 57 } |
64 } | 58 } |
65 | 59 |
60 static readonly ParserContext _jsonContext; | |
61 static readonly ParserContext _objectContext; | |
62 static readonly ParserContext _arrayContext; | |
63 | |
66 static JSONParser() { | 64 static JSONParser() { |
67 | 65 |
68 | 66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String); |
69 var valueExpression = Token(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String); | 67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression); |
70 var memberExpression = Token(JsonTokenType.String).Cat(Token(JsonTokenType.NameSeparator)).Cat(valueExpression); | |
71 | 68 |
72 var objectExpression = memberExpression | 69 var objectExpression = memberExpression |
73 .Cat( | 70 .Cat( |
74 Token(JsonTokenType.ValueSeparator) | 71 MakeToken(JsonTokenType.ValueSeparator) |
75 .Cat(memberExpression) | 72 .Cat(memberExpression) |
76 .EClosure() | 73 .EClosure() |
77 ) | 74 ) |
78 .Optional() | 75 .Optional() |
79 .Cat(Token(JsonTokenType.EndObject)) | 76 .Cat(MakeToken(JsonTokenType.EndObject)) |
80 .End(); | 77 .End(); |
81 | 78 |
82 var arrayExpression = valueExpression | 79 var arrayExpression = valueExpression |
83 .Cat( | 80 .Cat( |
84 Token(JsonTokenType.ValueSeparator) | 81 MakeToken(JsonTokenType.ValueSeparator) |
85 .Cat(valueExpression) | 82 .Cat(valueExpression) |
86 .EClosure() | 83 .EClosure() |
87 ) | 84 ) |
88 .Optional() | 85 .Optional() |
89 .Cat(Token(JsonTokenType.EndArray)) | 86 .Cat(MakeToken(JsonTokenType.EndArray)) |
90 .End(); | 87 .End(); |
91 | 88 |
92 var jsonExpression = valueExpression.End(); | 89 var jsonExpression = valueExpression.End(); |
93 | 90 |
94 _jsonDFA = CreateParserContext(jsonExpression, JSONElementContext.None); | 91 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None); |
95 _objectDFA = CreateParserContext(objectExpression, JSONElementContext.Object); | 92 _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object); |
96 _arrayDFA = CreateParserContext(arrayExpression, JSONElementContext.Array); | 93 _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array); |
97 } | 94 } |
98 | 95 |
99 static Token Token(params JsonTokenType[] input) { | 96 static Token MakeToken(params JsonTokenType[] input) { |
100 return Token.New( input.Select(t => (int)t).ToArray() ); | 97 return Token.New( input.Select(t => (int)t).ToArray() ); |
101 } | 98 } |
102 | 99 |
103 static ParserContext CreateParserContext(Token expr, JSONElementContext context) { | 100 static ParserContext CreateParserContext(Token expr, JSONElementContext context) { |
104 | 101 |
110 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context); | 107 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context); |
111 } | 108 } |
112 | 109 |
113 #endregion | 110 #endregion |
114 | 111 |
115 JSONScanner m_scanner; | 112 readonly JSONScanner m_scanner; |
116 MemberContext m_memberContext; | 113 MemberContext m_memberContext; |
117 | 114 |
118 JSONElementType m_elementType; | 115 JSONElementType m_elementType; |
119 object m_elementValue; | 116 object m_elementValue; |
117 string m_memberName = String.Empty; | |
118 | |
119 Stack<ParserContext> m_stack = new Stack<ParserContext>(); | |
120 ParserContext m_context = _jsonContext; | |
120 | 121 |
121 /// <summary> | 122 /// <summary> |
122 /// Создает новый парсер на основе строки, содержащей JSON | 123 /// Создает новый парсер на основе строки, содержащей JSON |
123 /// </summary> | 124 /// </summary> |
124 /// <param name="text"></param> | 125 /// <param name="text"></param> |
125 public JSONParser(string text) | 126 public JSONParser(string text) { |
126 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) { | |
127 Safe.ArgumentNotEmpty(text, "text"); | 127 Safe.ArgumentNotEmpty(text, "text"); |
128 m_scanner = new JSONScanner(); | 128 m_scanner = new JSONScanner(text); |
129 m_scanner.Feed(text.ToCharArray()); | |
130 } | 129 } |
131 | 130 |
132 /// <summary> | 131 /// <summary> |
133 /// Создает новый экземпляр парсера, на основе текстового потока. | 132 /// Создает новый экземпляр парсера, на основе текстового потока. |
134 /// </summary> | 133 /// </summary> |
135 /// <param name="reader">Текстовый поток.</param> | 134 /// <param name="reader">Текстовый поток.</param> |
136 public JSONParser(TextReader reader) | 135 public JSONParser(TextReader reader) { |
137 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) { | |
138 Safe.ArgumentNotNull(reader, "reader"); | 136 Safe.ArgumentNotNull(reader, "reader"); |
139 m_scanner = new JSONScanner(); | 137 m_scanner = new JSONScanner(reader); |
140 m_scanner.Feed(reader, dispose); | 138 } |
139 | |
140 public int Level { | |
141 get { return m_stack.Count; } | |
141 } | 142 } |
142 | 143 |
143 /// <summary> | 144 /// <summary> |
144 /// Тип текущего элемента на котором стоит парсер. | 145 /// Тип текущего элемента на котором стоит парсер. |
145 /// </summary> | 146 /// </summary> |
150 /// <summary> | 151 /// <summary> |
151 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда | 152 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда |
152 /// пустая строка. | 153 /// пустая строка. |
153 /// </summary> | 154 /// </summary> |
154 public string ElementName { | 155 public string ElementName { |
155 get { return m_context.info.memberName; } | 156 get { return m_memberName; } |
156 } | 157 } |
157 | 158 |
158 /// <summary> | 159 /// <summary> |
159 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c> | 160 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c> |
160 /// </summary> | 161 /// </summary> |
165 /// <summary> | 166 /// <summary> |
166 /// Читает слеюудущий объект из потока | 167 /// Читает слеюудущий объект из потока |
167 /// </summary> | 168 /// </summary> |
168 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns> | 169 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns> |
169 public bool Read() { | 170 public bool Read() { |
170 if (m_context.current == UNREACHEBLE_STATE) | |
171 throw new InvalidOperationException("The parser is in invalid state"); | |
172 object tokenValue; | 171 object tokenValue; |
173 JsonTokenType tokenType; | 172 JsonTokenType tokenType; |
174 m_context.info.memberName = String.Empty; | 173 |
174 m_memberName = String.Empty; | |
175 | |
175 while (m_scanner.ReadToken(out tokenValue, out tokenType)) { | 176 while (m_scanner.ReadToken(out tokenValue, out tokenType)) { |
176 Move((int)tokenType); | 177 if(!m_context.Move(tokenType)) |
177 if (m_context.current == UNREACHEBLE_STATE) | |
178 UnexpectedToken(tokenValue, tokenType); | 178 UnexpectedToken(tokenValue, tokenType); |
179 | |
179 switch (tokenType) { | 180 switch (tokenType) { |
180 case JsonTokenType.BeginObject: | 181 case JsonTokenType.BeginObject: |
181 Switch( | 182 m_stack.Push(m_context); |
182 _objectDFA, | 183 m_context = _objectContext; |
183 INITIAL_STATE, | 184 |
184 new JSONParserContext { | |
185 memberName = m_context.info.memberName, | |
186 elementContext = JSONElementContext.Object | |
187 } | |
188 ); | |
189 m_elementValue = null; | 185 m_elementValue = null; |
190 m_memberContext = MemberContext.MemberName; | 186 m_memberContext = MemberContext.MemberName; |
191 m_elementType = JSONElementType.BeginObject; | 187 m_elementType = JSONElementType.BeginObject; |
192 return true; | 188 return true; |
193 case JsonTokenType.EndObject: | 189 case JsonTokenType.EndObject: |
194 Restore(); | 190 if (m_stack.Count == 0) |
191 UnexpectedToken(tokenValue, tokenType); | |
192 m_context = m_stack.Pop(); | |
193 | |
195 m_elementValue = null; | 194 m_elementValue = null; |
196 m_elementType = JSONElementType.EndObject; | 195 m_elementType = JSONElementType.EndObject; |
197 return true; | 196 return true; |
198 case JsonTokenType.BeginArray: | 197 case JsonTokenType.BeginArray: |
199 Switch( | 198 m_stack.Push(m_context); |
200 _arrayDFA, | 199 m_context = _arrayContext; |
201 INITIAL_STATE, | 200 |
202 new JSONParserContext { | |
203 memberName = m_context.info.memberName, | |
204 elementContext = JSONElementContext.Array | |
205 } | |
206 ); | |
207 m_elementValue = null; | 201 m_elementValue = null; |
208 m_memberContext = MemberContext.MemberValue; | 202 m_memberContext = MemberContext.MemberValue; |
209 m_elementType = JSONElementType.BeginArray; | 203 m_elementType = JSONElementType.BeginArray; |
210 return true; | 204 return true; |
211 case JsonTokenType.EndArray: | 205 case JsonTokenType.EndArray: |
212 Restore(); | 206 if (m_stack.Count == 0) |
207 UnexpectedToken(tokenValue, tokenType); | |
208 m_context = m_stack.Pop(); | |
209 | |
213 m_elementValue = null; | 210 m_elementValue = null; |
214 m_elementType = JSONElementType.EndArray; | 211 m_elementType = JSONElementType.EndArray; |
215 return true; | 212 return true; |
216 case JsonTokenType.String: | 213 case JsonTokenType.String: |
217 if (m_memberContext == MemberContext.MemberName) { | 214 if (m_memberContext == MemberContext.MemberName) { |
218 m_context.info.memberName = (string)tokenValue; | 215 m_memberName = (string)tokenValue; |
219 break; | 216 break; |
220 } | 217 } |
221 m_elementType = JSONElementType.Value; | 218 m_elementType = JSONElementType.Value; |
222 m_elementValue = tokenValue; | 219 m_elementValue = tokenValue; |
223 return true; | 220 return true; |
231 return true; | 228 return true; |
232 case JsonTokenType.NameSeparator: | 229 case JsonTokenType.NameSeparator: |
233 m_memberContext = MemberContext.MemberValue; | 230 m_memberContext = MemberContext.MemberValue; |
234 break; | 231 break; |
235 case JsonTokenType.ValueSeparator: | 232 case JsonTokenType.ValueSeparator: |
236 m_memberContext = m_context.info.elementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; | 233 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; |
237 break; | 234 break; |
238 default: | 235 default: |
239 UnexpectedToken(tokenValue, tokenType); | 236 UnexpectedToken(tokenValue, tokenType); |
240 break; | 237 break; |
241 } | 238 } |
242 } | 239 } |
243 if (m_context.info.elementContext != JSONElementContext.None) | 240 if (m_context.ElementContext != JSONElementContext.None) |
244 throw new ParserException("Unexpedted end of data"); | 241 throw new ParserException("Unexpedted end of data"); |
242 | |
243 EOF = true; | |
244 | |
245 return false; | 245 return false; |
246 } | 246 } |
247 | 247 |
248 object ParseLiteral(string literal) { | 248 object ParseLiteral(string literal) { |
249 switch (literal) { | 249 switch (literal) { |
266 | 266 |
267 /// <summary> | 267 /// <summary> |
268 /// Признак конца потока | 268 /// Признак конца потока |
269 /// </summary> | 269 /// </summary> |
270 public bool EOF { | 270 public bool EOF { |
271 get { | 271 get; |
272 return m_scanner.EOF; | 272 private set; |
273 } | |
274 } | 273 } |
275 | 274 |
276 protected override void Dispose(bool disposing) { | 275 protected override void Dispose(bool disposing) { |
277 if (disposing) { | 276 if (disposing) |
278 m_scanner.Dispose(); | 277 Safe.Dispose(m_scanner); |
279 } | |
280 } | 278 } |
281 | 279 |
282 /// <summary> | 280 /// <summary> |
283 /// Переходит в конец текущего объекта. | 281 /// Переходит в конец текущего объекта. |
284 /// </summary> | 282 /// </summary> |