comparison Implab/Formats/JSON/JSONScanner.cs @ 190:1c2a16d071a7 v2

Слияние с ref20160224
author cin
date Fri, 22 Apr 2016 13:08:08 +0300
parents 4f82e0f161c3
children 7d07503621fe
comparison
equal deleted inserted replaced
161:2a8466f0cb8a 190:1c2a16d071a7
1 using System;
2 using System.Globalization;
3 using Implab.Automaton;
4 using System.Text;
5 using Implab.Components;
6 using System.IO;
7
8 namespace Implab.Formats.JSON {
9 /// <summary>
10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
11 /// </summary>
12 public class JSONScanner : Disposable {
13 readonly StringBuilder m_builder = new StringBuilder();
14
15 readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
16 readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
17
18
19 readonly TextScanner m_scanner;
20
21 /// <summary>
22 /// Создает новый экземпляр сканнера
23 /// </summary>
24 public JSONScanner(string text) {
25 Safe.ArgumentNotEmpty(text, "text");
26
27 m_scanner = new StringScanner(text);
28 }
29
30 public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
31 Safe.ArgumentNotNull(reader, "reader");
32
33 m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
34 }
35
36 public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
37 }
38
39 /// <summary>
40 /// Читает следующий лексический элемент из входных данных.
41 /// </summary>
42 /// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
43 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
44 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
45 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
46 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
47 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
48 JSONGrammar.TokenType[] tag;
49 while (m_jsonContext.Execute(m_scanner, out tag)) {
50 switch (tag[0]) {
51 case JSONGrammar.TokenType.StringBound:
52 tokenValue = ReadString();
53 tokenType = JsonTokenType.String;
54 break;
55 case JSONGrammar.TokenType.Number:
56 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
57 tokenType = JsonTokenType.Number;
58 break;
59 case JSONGrammar.TokenType.Whitespace:
60 continue;
61 default:
62 tokenType = (JsonTokenType)tag[0];
63 tokenValue = m_scanner.GetTokenValue();
64 break;
65 }
66 return true;
67 }
68 tokenValue = null;
69 tokenType = JsonTokenType.None;
70 return false;
71 }
72
73 string ReadString() {
74 int pos = 0;
75 var buf = new char[6]; // the buffer for unescaping chars
76
77 JSONGrammar.TokenType[] tag;
78 m_builder.Clear();
79
80 while (m_stringContext.Execute(m_scanner, out tag)) {
81 switch (tag[0]) {
82 case JSONGrammar.TokenType.StringBound:
83 return m_builder.ToString();
84 case JSONGrammar.TokenType.UnescapedChar:
85 m_scanner.CopyTokenTo(m_builder);
86 break;
87 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
88 m_scanner.CopyTokenTo(buf, 0);
89 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
90 pos++;
91 break;
92 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
93 m_scanner.CopyTokenTo(buf, 0);
94 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
95 break;
96 }
97
98 }
99
100 throw new ParserException("Unexpected end of data");
101 }
102
103 protected override void Dispose(bool disposing) {
104 if (disposing)
105 Safe.Dispose(m_scanner);
106 base.Dispose(disposing);
107 }
108 }
109 }