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