165
|
1 using System;
|
163
|
2 using System.Globalization;
|
165
|
3 using Implab.Automaton;
|
176
|
4 using System.Text;
|
|
5 using Implab.Components;
|
|
6 using System.IO;
|
163
|
7
|
165
|
8 namespace Implab.Formats.JSON {
|
163
|
9 /// <summary>
|
|
10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
|
|
11 /// </summary>
|
176
|
12 public class JSONScanner : Disposable {
|
|
13 readonly StringBuilder m_builder = new StringBuilder();
|
|
14
|
179
|
15 readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
|
|
16 readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
|
176
|
17
|
|
18
|
|
19 readonly TextScanner m_scanner;
|
163
|
20
|
|
21 /// <summary>
|
|
22 /// Создает новый экземпляр сканнера
|
|
23 /// </summary>
|
176
|
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
|
177
|
33 m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
|
163
|
34 }
|
|
35
|
180
|
36 public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
|
|
37 }
|
|
38
|
163
|
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) {
|
176
|
48 JSONGrammar.TokenType[] tag;
|
183
|
49 while (m_jsonContext.Execute(m_scanner, out tag)) {
|
176
|
50 switch (tag[0]) {
|
163
|
51 case JSONGrammar.TokenType.StringBound:
|
|
52 tokenValue = ReadString();
|
|
53 tokenType = JsonTokenType.String;
|
|
54 break;
|
|
55 case JSONGrammar.TokenType.Number:
|
176
|
56 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
|
163
|
57 tokenType = JsonTokenType.Number;
|
|
58 break;
|
183
|
59 case JSONGrammar.TokenType.Whitespace:
|
|
60 continue;
|
163
|
61 default:
|
176
|
62 tokenType = (JsonTokenType)tag[0];
|
|
63 tokenValue = m_scanner.GetTokenValue();
|
163
|
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;
|
177
|
75 var buf = new char[6]; // the buffer for unescaping chars
|
176
|
76
|
|
77 JSONGrammar.TokenType[] tag;
|
|
78 m_builder.Clear();
|
|
79
|
177
|
80 while (m_stringContext.Execute(m_scanner, out tag)) {
|
176
|
81 switch (tag[0]) {
|
163
|
82 case JSONGrammar.TokenType.StringBound:
|
176
|
83 return m_builder.ToString();
|
163
|
84 case JSONGrammar.TokenType.UnescapedChar:
|
176
|
85 m_scanner.CopyTokenTo(m_builder);
|
163
|
86 break;
|
176
|
87 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
|
|
88 m_scanner.CopyTokenTo(buf, 0);
|
|
89 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
|
163
|
90 pos++;
|
|
91 break;
|
176
|
92 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
|
|
93 m_scanner.CopyTokenTo(buf, 0);
|
|
94 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
|
163
|
95 break;
|
|
96 }
|
|
97
|
|
98 }
|
|
99
|
|
100 throw new ParserException("Unexpected end of data");
|
|
101 }
|
177
|
102
|
|
103 protected override void Dispose(bool disposing) {
|
|
104 if (disposing)
|
|
105 Safe.Dispose(m_scanner);
|
|
106 base.Dispose(disposing);
|
|
107 }
|
163
|
108 }
|
|
109 }
|