// ILReader.cs
// Author: Sergey Chaban (serge@wildwestsoftware.com)
using System;
using System.IO;
using System.Text;
namespace Mono.ILASM {
///
///
public class ILReader {
internal static readonly int CHUNK_SIZE = 4096;
private StreamReader reader;
private int inUse;
private int pos;
private int termPos;
private Location location;
private Location markedLocation;
private char[] buffer;
public ILReader (StreamReader reader)
{
this.reader = reader;
location = new Location ();
markedLocation = Location.Unknown;
buffer = new char [CHUNK_SIZE];
pos = buffer.Length + 1;
termPos = buffer.Length + 2;
inUse = 0;
}
///
///
public Location Location {
get {
return location;
}
}
///
/// Provides access to underlying StreamReader.
///
public StreamReader BaseReader {
get {
return reader;
}
}
private void EnsureCapacity (int required, int shift)
{
int n = buffer.Length;
if (shift < 0) shift = 0;
if (n < required) {
for (;n < required; n <<= 1);
char [] newBuff = new char [n];
Array.Copy (buffer, 0, newBuff, shift, buffer.Length);
}
}
private void EnsureCapacity (int required)
{
EnsureCapacity (required, 0);
}
private int NormalizeEOL (int len)
{
if (len <= 0) return -1;
int n = len;
for (int i = 0, j = 0; i < len; i++, j++) {
if (buffer [i] == '\r') {
if (i == len - 1) {
// strip the very last char
--n;
break;
} else {
buffer [j] = '\n';
if (buffer [i + 1] == '\n') {
i++;
--n;
}
}
} else if (i != j) {
buffer [j] = buffer [i];
}
}
return n;
}
private int DoRead (int advance)
{
int n = 1;
if (pos == termPos) {
n = -1;
} else if (pos >= inUse) {
pos = 0;
// read as much as possible
n = reader.Read (buffer, 0, buffer.Length);
n = NormalizeEOL (n);
// Manually terminate the buffer if we had
// reached the end of the input stream.
if (n != -1 && n < buffer.Length) termPos = n + 1;
inUse = n;
}
int res = -1;
if (n != -1) {
res = buffer [pos];
}
pos += advance;
// Track location
if (res == '\n') {
location.NewLine();
} else {
location.NextColumn();
}
return res;
}
///
///
///
public int Read ()
{
return DoRead (1);
}
///
///
///
public int Peek ()
{
return DoRead (0);
}
///
///
public void Unread (char c)
{
if (pos > 0) {
if (buffer [pos - 1] == c) {
--pos;
} else {
throw new Exception ("Invalid putback.");
}
} else {
EnsureCapacity (++inUse, 1);
pos = 0;
buffer [0] = c;
}
location.PreviousColumn ();
}
///
///
///
public void Unread (char [] chars)
{
int len = chars.Length;
if (len == 0) return;
if (pos >= len) {
pos -= len;
} else {
inUse += len;
EnsureCapacity (inUse, len);
pos -= len;
Array.Copy (chars, 0, buffer, pos, len);
}
}
///
///
///
public void Unread (int c)
{
Unread ((char)c);
}
///
///
public void SkipWhitespace ()
{
int ch = Read ();
for (; ch != -1 && Char.IsWhiteSpace((char) ch); ch = Read ());
if (ch != -1) Unread (ch);
}
///
///
///
public string ReadToWhitespace ()
{
StringBuilder sb = new StringBuilder ();
int ch = Read ();
for (; ch != -1 && !Char.IsWhiteSpace((char) ch); sb.Append ((char) ch), ch = Read ());
if (ch != -1) Unread (ch);
return sb.ToString ();
}
///
///
public void MarkLocation ()
{
if (markedLocation == Location.Unknown) {
markedLocation = new Location (location);
} else {
markedLocation.CopyFrom (location);
}
}
///
///
public void RestoreLocation ()
{
if (markedLocation != Location.Unknown) {
location.CopyFrom (markedLocation);
}
}
}
}