Mercurial > pub > ImplabNet
comparison Implab/Formats/Json/JsonReader.cs @ 232:133ba4444acc v2
Слияние
| author | cin |
|---|---|
| date | Thu, 21 Sep 2017 01:14:27 +0300 |
| parents | 3e26338eb977 |
| children | 302ca905c19e |
comparison
equal
deleted
inserted
replaced
| 231:3eaa9372c754 | 232:133ba4444acc |
|---|---|
| 1 using System; | |
| 2 using System.Diagnostics; | |
| 3 using System.IO; | |
| 4 using Implab.Automaton; | |
| 5 using Implab.Automaton.RegularExpressions; | |
| 6 using System.Linq; | |
| 7 using Implab.Components; | |
| 8 using System.Collections.Generic; | |
| 9 using System.Text; | |
| 10 using System.Globalization; | |
| 11 | |
| 12 namespace Implab.Formats.Json { | |
| 13 /// <summary> | |
| 14 /// Pull парсер JSON данных. | |
| 15 /// </summary> | |
| 16 /// <remarks> | |
| 17 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>, | |
| 18 /// оно означает текущий уровень вложенности объектов, однако закрывающий | |
| 19 /// элемент объекта и массива имеет уровень меньше, чем сам объект. | |
| 20 /// <code> | |
| 21 /// { // Level = 1 | |
| 22 /// "name" : "Peter", // Level = 1 | |
| 23 /// "address" : { // Level = 2 | |
| 24 /// city : "Stern" // Level = 2 | |
| 25 /// } // Level = 1 | |
| 26 /// } // Level = 0 | |
| 27 /// </code> | |
| 28 /// </remarks> | |
| 29 public class JsonReader : Disposable { | |
| 30 | |
| 31 enum MemberContext { | |
| 32 MemberName, | |
| 33 MemberValue | |
| 34 } | |
| 35 | |
| 36 #region Parser rules | |
| 37 struct ParserContext { | |
| 38 readonly int[,] m_dfa; | |
| 39 int m_state; | |
| 40 | |
| 41 readonly JsonElementContext m_elementContext; | |
| 42 | |
| 43 public ParserContext(int[,] dfa, int state, JsonElementContext context) { | |
| 44 m_dfa = dfa; | |
| 45 m_state = state; | |
| 46 m_elementContext = context; | |
| 47 } | |
| 48 | |
| 49 public bool Move(JsonTokenType token) { | |
| 50 var next = m_dfa[m_state, (int)token]; | |
| 51 if (next == AutomatonConst.UNREACHABLE_STATE) | |
| 52 return false; | |
| 53 m_state = next; | |
| 54 return true; | |
| 55 } | |
| 56 | |
| 57 public JsonElementContext ElementContext { | |
| 58 get { return m_elementContext; } | |
| 59 } | |
| 60 } | |
| 61 | |
| 62 static readonly ParserContext _jsonContext; | |
| 63 static readonly ParserContext _objectContext; | |
| 64 static readonly ParserContext _arrayContext; | |
| 65 | |
| 66 static JsonReader() { | |
| 67 | |
| 68 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String); | |
| 69 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression); | |
| 70 | |
| 71 var objectExpression = memberExpression | |
| 72 .Cat( | |
| 73 MakeToken(JsonTokenType.ValueSeparator) | |
| 74 .Cat(memberExpression) | |
| 75 .EClosure() | |
| 76 ) | |
| 77 .Optional() | |
| 78 .Cat(MakeToken(JsonTokenType.EndObject)) | |
| 79 .End(); | |
| 80 | |
| 81 var arrayExpression = valueExpression | |
| 82 .Cat( | |
| 83 MakeToken(JsonTokenType.ValueSeparator) | |
| 84 .Cat(valueExpression) | |
| 85 .EClosure() | |
| 86 ) | |
| 87 .Optional() | |
| 88 .Cat(MakeToken(JsonTokenType.EndArray)) | |
| 89 .End(); | |
| 90 | |
| 91 var jsonExpression = valueExpression.End(); | |
| 92 | |
| 93 _jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None); | |
| 94 _objectContext = CreateParserContext(objectExpression, JsonElementContext.Object); | |
| 95 _arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array); | |
| 96 } | |
| 97 | |
| 98 static Token MakeToken(params JsonTokenType[] input) { | |
| 99 return Token.New( input.Select(t => (int)t).ToArray() ); | |
| 100 } | |
| 101 | |
| 102 static ParserContext CreateParserContext(Token expr, JsonElementContext context) { | |
| 103 | |
| 104 var dfa = new DFATable(); | |
| 105 var builder = new RegularExpressionVisitor(dfa); | |
| 106 expr.Accept(builder); | |
| 107 builder.BuildDFA(); | |
| 108 | |
| 109 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context); | |
| 110 } | |
| 111 | |
| 112 #endregion | |
| 113 | |
| 114 readonly JsonScanner m_scanner; | |
| 115 // json starts from the value context and may content even a single literal | |
| 116 MemberContext m_memberContext = MemberContext.MemberValue; | |
| 117 | |
| 118 JsonElementType m_elementType; | |
| 119 object m_elementValue; | |
| 120 string m_memberName = String.Empty; | |
| 121 | |
| 122 Stack<ParserContext> m_stack = new Stack<ParserContext>(); | |
| 123 ParserContext m_context = _jsonContext; | |
| 124 | |
| 125 /// <summary> | |
| 126 /// Создает новый парсер на основе строки, содержащей JSON | |
| 127 /// </summary> | |
| 128 /// <param name="text"></param> | |
| 129 JsonReader(JsonScanner scanner) { | |
| 130 m_scanner = scanner; | |
| 131 } | |
| 132 | |
| 133 public int Level { | |
| 134 get { return m_stack.Count; } | |
| 135 } | |
| 136 | |
| 137 /// <summary> | |
| 138 /// Тип текущего элемента на котором стоит парсер. | |
| 139 /// </summary> | |
| 140 public JsonElementType ElementType { | |
| 141 get { return m_elementType; } | |
| 142 } | |
| 143 | |
| 144 /// <summary> | |
| 145 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда | |
| 146 /// пустая строка. | |
| 147 /// </summary> | |
| 148 public string ElementName { | |
| 149 get { return m_memberName; } | |
| 150 } | |
| 151 | |
| 152 /// <summary> | |
| 153 /// Значение элемента. Только для элементов типа <see cref="JsonElementType.Value"/>, для остальных <c>null</c> | |
| 154 /// </summary> | |
| 155 public object ElementValue { | |
| 156 get { return m_elementValue; } | |
| 157 } | |
| 158 | |
| 159 /// <summary> | |
| 160 /// Читает слеюудущий объект из потока | |
| 161 /// </summary> | |
| 162 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns> | |
| 163 public bool Read() { | |
| 164 string tokenValue; | |
| 165 JsonTokenType tokenType; | |
| 166 | |
| 167 m_memberName = String.Empty; | |
| 168 | |
| 169 while (m_scanner.ReadToken(out tokenValue, out tokenType)) { | |
| 170 if(!m_context.Move(tokenType)) | |
| 171 UnexpectedToken(tokenValue, tokenType); | |
| 172 | |
| 173 switch (tokenType) { | |
| 174 case JsonTokenType.BeginObject: | |
| 175 m_stack.Push(m_context); | |
| 176 m_context = _objectContext; | |
| 177 | |
| 178 m_elementValue = null; | |
| 179 m_memberContext = MemberContext.MemberName; | |
| 180 m_elementType = JsonElementType.BeginObject; | |
| 181 return true; | |
| 182 case JsonTokenType.EndObject: | |
| 183 if (m_stack.Count == 0) | |
| 184 UnexpectedToken(tokenValue, tokenType); | |
| 185 m_context = m_stack.Pop(); | |
| 186 | |
| 187 m_elementValue = null; | |
| 188 m_elementType = JsonElementType.EndObject; | |
| 189 return true; | |
| 190 case JsonTokenType.BeginArray: | |
| 191 m_stack.Push(m_context); | |
| 192 m_context = _arrayContext; | |
| 193 | |
| 194 m_elementValue = null; | |
| 195 m_memberContext = MemberContext.MemberValue; | |
| 196 m_elementType = JsonElementType.BeginArray; | |
| 197 return true; | |
| 198 case JsonTokenType.EndArray: | |
| 199 if (m_stack.Count == 0) | |
| 200 UnexpectedToken(tokenValue, tokenType); | |
| 201 m_context = m_stack.Pop(); | |
| 202 | |
| 203 m_elementValue = null; | |
| 204 m_elementType = JsonElementType.EndArray; | |
| 205 return true; | |
| 206 case JsonTokenType.String: | |
| 207 if (m_memberContext == MemberContext.MemberName) { | |
| 208 m_memberName = tokenValue; | |
| 209 break; | |
| 210 } | |
| 211 m_elementType = JsonElementType.Value; | |
| 212 m_elementValue = tokenValue; | |
| 213 return true; | |
| 214 case JsonTokenType.Number: | |
| 215 m_elementType = JsonElementType.Value; | |
| 216 m_elementValue = double.Parse(tokenValue, CultureInfo.InvariantCulture); | |
| 217 return true; | |
| 218 case JsonTokenType.Literal: | |
| 219 m_elementType = JsonElementType.Value; | |
| 220 m_elementValue = ParseLiteral(tokenValue); | |
| 221 return true; | |
| 222 case JsonTokenType.NameSeparator: | |
| 223 m_memberContext = MemberContext.MemberValue; | |
| 224 break; | |
| 225 case JsonTokenType.ValueSeparator: | |
| 226 m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; | |
| 227 break; | |
| 228 default: | |
| 229 UnexpectedToken(tokenValue, tokenType); | |
| 230 break; | |
| 231 } | |
| 232 } | |
| 233 if (m_context.ElementContext != JsonElementContext.None) | |
| 234 throw new ParserException("Unexpedted end of data"); | |
| 235 | |
| 236 Eof = true; | |
| 237 | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 object ParseLiteral(string literal) { | |
| 242 switch (literal) { | |
| 243 case "null": | |
| 244 return null; | |
| 245 case "false": | |
| 246 return false; | |
| 247 case "true": | |
| 248 return true; | |
| 249 default: | |
| 250 UnexpectedToken(literal, JsonTokenType.Literal); | |
| 251 return null; // avoid compliler error | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 void UnexpectedToken(object value, JsonTokenType tokenType) { | |
| 256 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value)); | |
| 257 } | |
| 258 | |
| 259 | |
| 260 /// <summary> | |
| 261 /// Признак конца потока | |
| 262 /// </summary> | |
| 263 public bool Eof { | |
| 264 get; | |
| 265 private set; | |
| 266 } | |
| 267 | |
| 268 protected override void Dispose(bool disposing) { | |
| 269 if (disposing) | |
| 270 m_scanner.Dispose(); | |
| 271 } | |
| 272 | |
| 273 /// <summary> | |
| 274 /// Переходит в конец текущего объекта. | |
| 275 /// </summary> | |
| 276 public void SeekElementEnd() { | |
| 277 var level = Level - 1; | |
| 278 | |
| 279 Debug.Assert(level >= 0); | |
| 280 | |
| 281 while (Level != level) | |
| 282 Read(); | |
| 283 } | |
| 284 | |
| 285 public static JsonReader Create(string file, Encoding encoding) { | |
| 286 return new JsonReader(JsonTextScanner.Create(file, encoding)); | |
| 287 } | |
| 288 | |
| 289 public static JsonReader Create(string file) { | |
| 290 return new JsonReader(JsonTextScanner.Create(file)); | |
| 291 } | |
| 292 | |
| 293 public static JsonReader Create(Stream stream, Encoding encoding) { | |
| 294 return new JsonReader(JsonTextScanner.Create(stream, encoding)); | |
| 295 } | |
| 296 | |
| 297 public static JsonReader Create(Stream stream) { | |
| 298 return new JsonReader(JsonTextScanner.Create(stream)); | |
| 299 } | |
| 300 | |
| 301 public static JsonReader Create(TextReader reader) { | |
| 302 return new JsonReader(JsonTextScanner.Create(reader)); | |
| 303 } | |
| 304 | |
| 305 public static JsonReader ParseString(string data) { | |
| 306 return new JsonReader(JsonStringScanner.Create(data)); | |
| 307 } | |
| 308 | |
| 309 public static JsonReader ParseString(string data, int offset, int length) { | |
| 310 return new JsonReader(JsonStringScanner.Create(data, offset, length)); | |
| 311 } | |
| 312 | |
| 313 public static JsonReader ParseString(char[] data, int offset, int lenght) { | |
| 314 return new JsonReader(JsonStringScanner.Create(data, offset, lenght)); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 } |
