Mercurial > pub > ImplabNet
view Implab/Formats/JSON/JSONScanner.cs @ 186:75103928da09 ref20160224
working on cancelation and error handling
author | cin |
---|---|
date | Tue, 19 Apr 2016 00:50:14 +0300 |
parents | 4f82e0f161c3 |
children | 7d07503621fe |
line wrap: on
line source
using System; using System.Globalization; using Implab.Automaton; using System.Text; using Implab.Components; using System.IO; namespace Implab.Formats.JSON { /// <summary> /// Сканнер (лексер), разбивающий поток символов на токены JSON. /// </summary> public class JSONScanner : Disposable { readonly StringBuilder m_builder = new StringBuilder(); readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression; readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression; readonly TextScanner m_scanner; /// <summary> /// Создает новый экземпляр сканнера /// </summary> 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"); m_scanner = new ReaderScanner(reader, bufferMax, chunkSize); } public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){ } /// <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) { JSONGrammar.TokenType[] tag; while (m_jsonContext.Execute(m_scanner, out tag)) { switch (tag[0]) { case JSONGrammar.TokenType.StringBound: tokenValue = ReadString(); tokenType = JsonTokenType.String; break; case JSONGrammar.TokenType.Number: tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture); tokenType = JsonTokenType.Number; break; case JSONGrammar.TokenType.Whitespace: continue; default: tokenType = (JsonTokenType)tag[0]; tokenValue = m_scanner.GetTokenValue(); break; } return true; } tokenValue = null; tokenType = JsonTokenType.None; return false; } string ReadString() { int pos = 0; var buf = new char[6]; // the buffer for unescaping chars JSONGrammar.TokenType[] tag; m_builder.Clear(); while (m_stringContext.Execute(m_scanner, out tag)) { switch (tag[0]) { case JSONGrammar.TokenType.StringBound: return m_builder.ToString(); case JSONGrammar.TokenType.UnescapedChar: m_scanner.CopyTokenTo(m_builder); break; case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence m_scanner.CopyTokenTo(buf, 0); m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2)); pos++; break; case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence m_scanner.CopyTokenTo(buf, 0); m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1])); break; } } throw new ParserException("Unexpected end of data"); } protected override void Dispose(bool disposing) { if (disposing) Safe.Dispose(m_scanner); base.Dispose(disposing); } } }