##// END OF EJS Templates
refactoring
cin -
r70:0349189d2564 default
parent child
Show More
@@ -1,264 +1,280
1 1 using Implab;
2 2 using Implab.Parsing;
3 3 using System;
4 4 using System.Collections.Generic;
5 5 using System.Diagnostics;
6 6 using System.IO;
7 7 using System.Linq;
8 8 using System.Text;
9 9 using System.Threading.Tasks;
10 10
11 11 namespace Implab.JSON {
12 12 /// <summary>
13 13 /// internal
14 14 /// </summary>
15 15 public struct JSONParserContext {
16 16 public string memberName;
17 17 public JSONElementContext elementContext;
18 18 }
19 19
20 20 /// <summary>
21 21 /// Pull парсер JSON данных.
22 22 /// </summary>
23 /// <remarks>
24 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
25 /// оно означает текущий уровень вложенности объектов, однако закрывающий
26 /// элемент объекта и массива имеет уровень меньше, чем сам объект.
27 /// <code>
28 /// { // Level = 1
29 /// "name" : "Peter", // Level = 1
30 /// "address" : { // Level = 2
31 /// city : "Stern" // Level = 2
32 /// } // Level = 1
33 /// } // Level = 0
34 /// </code>
35 /// </remarks>
23 36 public class JSONParser : DFAutomaton<JSONParserContext>, IDisposable {
24 37
25 38 enum MemberContext {
26 39 MemberName,
27 40 MemberValue
28 41 }
29 42
30 43 static readonly EnumAlphabet<JsonTokenType> _alphabet = EnumAlphabet<JsonTokenType>.FullAlphabet;
31 44 static readonly DFAStateDescriptior[] _jsonDFA;
32 45 static readonly DFAStateDescriptior[] _objectDFA;
33 46 static readonly DFAStateDescriptior[] _arrayDFA;
34 47
35 48 static JSONParser() {
36 49 var jsonExpression = Token.New(JsonTokenType.BeginObject, JsonTokenType.BeginArray).Tag(0);
37 50
38 51 var valueExpression = Token.New(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
39 52 var memberExpression = Token.New(JsonTokenType.String).Cat(Token.New(JsonTokenType.NameSeparator)).Cat(valueExpression);
40 53 var objectExpression = memberExpression
41 54 .Cat(
42 55 Token.New(JsonTokenType.ValueSeparator)
43 56 .Cat(memberExpression)
44 57 .EClosure()
45 58 )
46 59 .Optional()
47 60 .Cat(Token.New(JsonTokenType.EndObject))
48 61 .Tag(0);
49 62 var arrayExpression = valueExpression
50 63 .Cat(
51 64 Token.New(JsonTokenType.ValueSeparator)
52 65 .Cat(valueExpression)
53 66 .EClosure()
54 67 )
55 68 .Optional()
56 69 .Cat(Token.New(JsonTokenType.EndArray))
57 70 .Tag(0);
58 71
59 72 _jsonDFA = BuildDFA(jsonExpression).States;
60 73 _objectDFA = BuildDFA(objectExpression).States;
61 74 _arrayDFA = BuildDFA(arrayExpression).States;
62 75 }
63 76
64 77 static EDFADefinition<JsonTokenType> BuildDFA(Token expr) {
65 78 var builder = new DFABuilder();
66 79 var dfa = new EDFADefinition<JsonTokenType>(_alphabet);
67 80 expr.Accept(builder);
68 81
69 82 builder.BuildDFA(dfa);
70 83 return dfa;
71 84 }
72 85
73 86 JSONScanner m_scanner;
74 87 MemberContext m_memberContext;
75 88
76 89 JSONElementType m_elementType;
77 90 object m_elementValue;
78 91
79 92 /// <summary>
80 93 /// Создает новый парсер на основе строки, содержащей JSON
81 94 /// </summary>
82 95 /// <param name="text"></param>
83 96 public JSONParser(string text)
84 97 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) {
85 98 Safe.ArgumentNotEmpty(text, "text");
86 99 m_scanner = new JSONScanner();
87 100 m_scanner.Feed(text.ToCharArray());
88 101 }
89 102
90 103 /// <summary>
91 104 /// Создает новый экземпляр парсера, на основе текстового потока.
92 105 /// </summary>
93 106 /// <param name="reader">Текстовый поток.</param>
94 107 /// <param name="dispose">Признак того, что парсер должен конролировать время жизни входного потока.</param>
95 108 public JSONParser(TextReader reader, bool dispose)
96 109 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) {
97 110 Safe.ArgumentNotNull(reader, "reader");
98 111 m_scanner = new JSONScanner();
99 112 m_scanner.Feed(reader, dispose);
100 113 }
101 114
102 115 /// <summary>
103 116 /// Тип текущего элемента на котором стоит парсер.
104 117 /// </summary>
105 118 public JSONElementType ElementType {
106 119 get { return m_elementType; }
107 120 }
108 121
109 122 /// <summary>
110 123 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
111 124 /// пустая строка.
112 125 /// </summary>
113 126 public string ElementName {
114 127 get { return m_context.info.memberName; }
115 128 }
116 129
117 130 /// <summary>
118 131 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
119 132 /// </summary>
120 133 public object ElementValue {
121 134 get { return m_elementValue; }
122 135 }
123 136
124 137 /// <summary>
125 138 /// Читает слеюудущий объект из потока
126 139 /// </summary>
127 140 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
128 141 public bool Read() {
129 142 if (m_context.current == UNREACHEBLE_STATE)
130 143 throw new InvalidOperationException("The parser is in invalid state");
131 144 object tokenValue;
132 145 JsonTokenType tokenType;
133 146 m_context.info.memberName = String.Empty;
134 147 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
135 148 Move((int)tokenType);
136 149 if (m_context.current == UNREACHEBLE_STATE)
137 150 UnexpectedToken(tokenValue, tokenType);
138 151 switch (tokenType) {
139 152 case JsonTokenType.BeginObject:
140 153 Switch(
141 154 _objectDFA,
142 155 INITIAL_STATE,
143 156 new JSONParserContext {
144 157 memberName = m_context.info.memberName,
145 158 elementContext = JSONElementContext.Object
146 159 }
147 160 );
148 161 m_elementValue = null;
149 162 m_memberContext = MemberContext.MemberName;
150 163 m_elementType = JSONElementType.BeginObject;
151 164 return true;
152 165 case JsonTokenType.EndObject:
153 166 Restore();
154 167 m_elementValue = null;
155 168 m_elementType = JSONElementType.EndObject;
156 169 return true;
157 170 case JsonTokenType.BeginArray:
158 171 Switch(
159 172 _arrayDFA,
160 173 INITIAL_STATE,
161 174 new JSONParserContext {
162 175 memberName = m_context.info.memberName,
163 176 elementContext = JSONElementContext.Array
164 177 }
165 178 );
166 179 m_elementValue = null;
167 180 m_memberContext = MemberContext.MemberValue;
168 181 m_elementType = JSONElementType.BeginArray;
169 182 return true;
170 183 case JsonTokenType.EndArray:
171 184 Restore();
172 185 m_elementValue = null;
173 186 m_elementType = JSONElementType.EndArray;
174 187 return true;
175 188 case JsonTokenType.String:
176 189 if (m_memberContext == MemberContext.MemberName) {
177 190 m_context.info.memberName = (string)tokenValue;
178 191 break;
179 192 } else {
180 193 m_elementType = JSONElementType.Value;
181 194 m_elementValue = tokenValue;
182 195 return true;
183 196 }
184 197 case JsonTokenType.Number:
185 198 m_elementType = JSONElementType.Value;
186 199 m_elementValue = tokenValue;
187 200 return true;
188 201 case JsonTokenType.Literal:
189 202 m_elementType = JSONElementType.Value;
190 203 m_elementValue = ParseLiteral((string)tokenValue);
191 204 return true;
192 205 case JsonTokenType.NameSeparator:
193 206 m_memberContext = MemberContext.MemberValue;
194 207 break;
195 208 case JsonTokenType.ValueSeparator:
196 209 m_memberContext = m_context.info.elementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
197 210 break;
198 211 default:
199 212 UnexpectedToken(tokenValue, tokenType);
200 213 break;
201 214 }
202 215 }
203 216 if (m_context.info.elementContext != JSONElementContext.None)
204 217 throw new ParserException("Unexpedted end of data");
205 218 return false;
206 219 }
207 220
208 221 object ParseLiteral(string literal) {
209 222 switch (literal) {
210 223 case "null":
211 224 return null;
212 225 case "false":
213 226 return false;
214 227 case "true":
215 228 return true;
216 229 default:
217 230 UnexpectedToken(literal, JsonTokenType.Literal);
218 231 return null; // avoid compliler error
219 232 }
220 233 }
221 234
222 235 void UnexpectedToken(object value, JsonTokenType tokenType) {
223 236 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
224 237 }
225 238
226 239
227 240 /// <summary>
228 241 /// Признак конца потока
229 242 /// </summary>
230 243 public bool EOF {
231 244 get {
232 245 return m_scanner.EOF;
233 246 }
234 247 }
235 248
236 249 protected virtual void Dispose(bool disposing) {
237 250 if (disposing) {
238 251 m_scanner.Dispose();
239 252 }
240 253 }
241 254
242 255 /// <summary>
243 256 /// Освобождает парсер и связанный с ним сканнер.
244 257 /// </summary>
245 258 public void Dispose() {
246 259 Dispose(true);
247 260 GC.SuppressFinalize(this);
248 261 }
249 262
250 263 ~JSONParser() {
251 264 Dispose(false);
252 265 }
253 266
254 public void Skip() {
255 var level = Level-1;
267 /// <summary>
268 /// Переходит в конец текущего объекта.
269 /// </summary>
270 public void SeekElementEnd() {
271 var level = Level - 1;
256 272
257 273 Debug.Assert(level >= 0);
258 274
259 275 while (Level != level)
260 276 Read();
261 277 }
262 278 }
263 279
264 280 }
General Comments 0
You need to be logged in to leave comments. Login now