| 
    
      
     | 
    
      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)
     | 
  
                        
    
    
         | 
    
      
     | 
    
                      m_scanner.Dispose();
     | 
  
                        
    
    
         | 
    
      
     | 
    
                  base.Dispose(disposing);
     | 
  
                        
    
    
         | 
    
      
     | 
    
              }
     | 
  
                        
    
    
         | 
    
      
     | 
    
          }
     | 
  
                        
    
    
         | 
    
      
     | 
    
      }
     | 
  
                        
    
    
         | 
    
      
     | 
    
      
     |