sharp-parser/CharBuffer.cs

165 lines
3.2 KiB
C#

using System;
using sharp.extensions;
using System.Collections.Generic;
using System.Linq;
namespace sharp.parser
{
public class CharBuffer
{
char[] chars;
int position;
int lineno, linepos, linestart;
int[] lineStarts;
public char[] Characters { get { return this.chars; } }
public CharBuffer(char[] source)
{
this.chars = source;
this.initialize();
}
public CharBuffer(string source){
this.chars = source.ToCharArray();
this.initialize();
}
private void initialize(){
this.lineno = 1;
this.linepos = 1;
this.linestart = 0;
List<int> lineStartList = new List<int>();
lineStartList.Add(0);
for (int n = 0; n < this.chars.Length;n++)
{
if (this.chars[n] == 0x0a){
lineStartList.Add(n);
}
}
lineStartList.Add(this.chars.Length);
this.lineStarts = lineStartList.ToArray();
}
private int lineEnd(){
int p = position;
while (this.chars[p]!='\n'){
p++;
if (p >= this.chars.Length){
break;
}
}
return p;
}
public string getLineAt(int pos){
int n;
if (pos >= this.chars.Length){
return null;
}
for (n = 0; n < this.lineStarts.Count();n++){
if (pos >= this.lineStarts[n]){
break;
}
}
return new string( this.chars.Segment(this.lineStarts[n],this.lineStarts[n+1]-this.lineStarts[n]) );
}
public int Position {
get { return position; }
set { this.position = value >= chars.Length ? chars.Length : value; }
}
public bool MoveNext(){
if (position < this.chars.Length){
position++;
this.linepos++;
if (Last == '\n'){
this.linepos = 1;
this.linestart = position;
this.lineno++;
}
return true;
}
return false;
}
public bool MoveBack(){
if (position > 0){
position--;
return true;
}
return false;
}
public bool EndOfBuffer(){
return (this.position >= this.chars.Length);
}
public void BypassWhiteSpace(){
while (Current <= 0x20){
MoveNext();
}
}
public int CurrentLineNumber { get { return this.lineno; } }
public int CurrentLinePosition { get { return this.linepos; } }
public string CurrentLine { get { return new String(this.chars.Segment(this.linestart,lineEnd()-this.linestart)); } }
public char Last {
get {
if (position > 0) {
return this.chars[position - 1];
};
throw new IndexOutOfRangeException("No character before the first one");
}
}
public char Current
{
get {
if (position < this.chars.Length){
return this.chars[position];
}
throw new IndexOutOfRangeException("No character after the last one");
}
}
public char Next
{
get {
if (position < this.chars.Length-1) {
return this.chars[position + 1];
};
throw new IndexOutOfRangeException("No character after the last one");
}
}
public string Following(int len)
{
return new string(this.chars.Segment(position, len));
}
public string Preceding(int len)
{
return new string(this.chars.Segment(position-len, len));
}
public void Pass(char ch){
if (Current != ch){
throw new ParserFormatException(String.Format("Expected {0}, but got {1}",ch,Current),lineno,linepos,CurrentLine);
}
MoveNext();
}
}
}