Mercurial > pub > ImplabNet
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 } |
