// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.IO; using System.Text; namespace Microsoft.SqlTools.ServiceLayer.BatchParser { /// /// Lexer input class used by lexer in SMO Batch Parser /// internal sealed class LexerInput : IDisposable { private readonly string filename; private TextReader input; private int currentLine; private int currentColumn; private int bufferStartOffset; private int currentSbOffset; private StringBuilder buffer; /// /// Constructor method for the LexerInput class /// public LexerInput(TextReader reader, string filename) { input = reader; this.filename = filename; currentLine = 1; currentColumn = 1; bufferStartOffset = 0; currentSbOffset = 0; buffer = new StringBuilder(); EnsureBytes(1); } /// /// Get filename associated with lexer input /// public string Filename { get { return filename; } } /// /// Get current line associated with lexer input /// public int CurrentLine { get { return currentLine; } } /// /// Get current column associated with lexer input /// public int CurrentColumn { get { return currentColumn; } } /// /// Consume token used by lexer input /// public void Consume() { bool newLineWithCR = false; char? ch = Lookahead(); if (ch == null) { // end of stream return; } else if (ch == '\r') { newLineWithCR = true; } else if (ch == '\n') { currentLine++; currentColumn = 0; } int count = EnsureBytes(1); if (count == 0) { // end of stream return; } currentSbOffset++; if (newLineWithCR && Lookahead() != '\n') { currentLine++; currentColumn = 0; } currentColumn++; } public void Dispose() { if (input != null) { input.Dispose(); input = null; } } /// /// Get current offset for the lexer input /// public int CurrentOffset { get { return bufferStartOffset + currentSbOffset; } } /// /// Ensure correct number of bytes to buffer /// public int EnsureBytes(int bytesToBuffer) { if (currentSbOffset + bytesToBuffer > buffer.Length) { if (input == null) { return buffer.Length - currentSbOffset; } int chArrayLength = bytesToBuffer - (buffer.Length - currentSbOffset) + 128; char[] chArray = new char[chArrayLength]; int count = input.ReadBlock(chArray, 0, chArrayLength); buffer.Append(chArray, 0, count); if (count < chArrayLength) { input.Dispose(); input = null; } return buffer.Length - currentSbOffset; } return bytesToBuffer; } /// /// look ahead bytes in lexer input /// public char? Lookahead() { int count = EnsureBytes(1); if (count == 0) { return null; } return buffer[currentSbOffset]; } /// /// look ahead bytes in lexer input /// public char? Lookahead(int lookahead) { int count = EnsureBytes(lookahead + 1); if (count < lookahead + 1) { return null; } return buffer[currentSbOffset + lookahead]; } /// /// Flush buffered text in lexer input /// public string FlushBufferedText() { string text; text = buffer.ToString(0, currentSbOffset); bufferStartOffset += currentSbOffset; buffer.Remove(0, currentSbOffset); currentSbOffset = 0; return text; } } }