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> |
