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