JSONScanner.cs
109 lines
| 4.7 KiB
| text/x-csharp
|
CSharpLexer
|
|
r165 | using System; | ||
|
|
r163 | using System.Globalization; | ||
|
|
r165 | using Implab.Automaton; | ||
|
|
r176 | using System.Text; | ||
| using Implab.Components; | ||||
| using System.IO; | ||||
|
|
r163 | |||
|
|
r165 | namespace Implab.Formats.JSON { | ||
|
|
r163 | /// <summary> | ||
| /// Сканнер (лексер), разбивающий поток символов на токены JSON. | ||||
| /// </summary> | ||||
|
|
r176 | public class JSONScanner : Disposable { | ||
| readonly StringBuilder m_builder = new StringBuilder(); | ||||
|
|
r179 | readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression; | ||
| readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression; | ||||
|
|
r176 | |||
| readonly TextScanner m_scanner; | ||||
|
|
r163 | |||
| /// <summary> | ||||
| /// Создает новый экземпляр сканнера | ||||
| /// </summary> | ||||
|
|
r176 | public JSONScanner(string text) { | ||
| Safe.ArgumentNotEmpty(text, "text"); | ||||
| m_scanner = new StringScanner(text); | ||||
| } | ||||
| public JSONScanner(TextReader reader, int bufferMax, int chunkSize) { | ||||
| Safe.ArgumentNotNull(reader, "reader"); | ||||
|
|
r177 | m_scanner = new ReaderScanner(reader, bufferMax, chunkSize); | ||
|
|
r163 | } | ||
|
|
r180 | public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){ | ||
| } | ||||
|
|
r163 | /// <summary> | ||
| /// Читает следующий лексический элемент из входных данных. | ||||
| /// </summary> | ||||
| /// <param name="tokenValue">Возвращает значение прочитанного токена.</param> | ||||
| /// <param name="tokenType">Возвращает тип прочитанного токена.</param> | ||||
| /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns> | ||||
| /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е. | ||||
| /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks> | ||||
| public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) { | ||||
|
|
r176 | JSONGrammar.TokenType[] tag; | ||
|
|
r183 | while (m_jsonContext.Execute(m_scanner, out tag)) { | ||
|
|
r176 | switch (tag[0]) { | ||
|
|
r163 | case JSONGrammar.TokenType.StringBound: | ||
| tokenValue = ReadString(); | ||||
| tokenType = JsonTokenType.String; | ||||
| break; | ||||
| case JSONGrammar.TokenType.Number: | ||||
|
|
r176 | tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture); | ||
|
|
r163 | tokenType = JsonTokenType.Number; | ||
| break; | ||||
|
|
r183 | case JSONGrammar.TokenType.Whitespace: | ||
| continue; | ||||
|
|
r163 | default: | ||
|
|
r176 | tokenType = (JsonTokenType)tag[0]; | ||
| tokenValue = m_scanner.GetTokenValue(); | ||||
|
|
r163 | break; | ||
| } | ||||
| return true; | ||||
| } | ||||
| tokenValue = null; | ||||
| tokenType = JsonTokenType.None; | ||||
| return false; | ||||
| } | ||||
| string ReadString() { | ||||
| int pos = 0; | ||||
|
|
r177 | var buf = new char[6]; // the buffer for unescaping chars | ||
|
|
r176 | |||
| JSONGrammar.TokenType[] tag; | ||||
| m_builder.Clear(); | ||||
|
|
r177 | while (m_stringContext.Execute(m_scanner, out tag)) { | ||
|
|
r176 | switch (tag[0]) { | ||
|
|
r163 | case JSONGrammar.TokenType.StringBound: | ||
|
|
r176 | return m_builder.ToString(); | ||
|
|
r163 | case JSONGrammar.TokenType.UnescapedChar: | ||
|
|
r176 | m_scanner.CopyTokenTo(m_builder); | ||
|
|
r163 | break; | ||
|
|
r176 | case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence | ||
| m_scanner.CopyTokenTo(buf, 0); | ||||
| m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2)); | ||||
|
|
r163 | pos++; | ||
| break; | ||||
|
|
r176 | case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence | ||
| m_scanner.CopyTokenTo(buf, 0); | ||||
| m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1])); | ||||
|
|
r163 | break; | ||
| } | ||||
| } | ||||
| throw new ParserException("Unexpected end of data"); | ||||
| } | ||||
|
|
r177 | |||
| protected override void Dispose(bool disposing) { | ||||
| if (disposing) | ||||
|
|
r208 | m_scanner.Dispose(); | ||
|
|
r177 | base.Dispose(disposing); | ||
| } | ||||
|
|
r163 | } | ||
| } | ||||
