165 lines
3.2 KiB
C#
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();
|
|
}
|
|
|
|
}
|
|
}
|