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>