ln.types/text/TokenReader.cs

93 lines
2.7 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Linq;
namespace ln.types.text
{
public class TokenReader
{
public TextReader Reader { get; }
public TokenReader(Stream stream)
: this(new UnbufferedStreamReader(stream)) { }
public TokenReader(TextReader textReader)
{
Reader = textReader;
}
public String Read(Func<char, bool> criteria)
{
StringBuilder stringBuilder = new StringBuilder();
int ch;
while (((ch = Reader.Peek()) != -1) && criteria((char)ch))
stringBuilder.Append((char)Reader.Read());
return stringBuilder.ToString();
}
public bool EndOfStream => Reader.Peek() == -1;
public String Read(char validChar) => Read((ch) => ch == validChar);
public String Read(char[] validChars) => Read((ch) => validChars.Contains(ch));
public String ReadWhiteSpace() => Read((ch) => char.IsWhiteSpace(ch));
public String ReadToken() => Read((ch) => char.IsLetterOrDigit(ch) || (ch == '_'));
public String ReadValue() => Reader.Peek() == '"' ? ReadQuotedString() : ReadToken();
public String ReadQuotedString()
{
StringBuilder stringBuilder = new StringBuilder();
int nextCh = Reader.Peek();
if (nextCh != -1)
{
if (nextCh != '"')
throw new FormatException("expected double quotes");
Reader.Read();
while (((nextCh = Reader.Read()) != -1) && (nextCh != '"'))
{
if (nextCh == '\\')
nextCh = Reader.Read();
stringBuilder.Append((char)nextCh);
}
}
return stringBuilder.ToString();
}
public String ReadPath()
{
StringBuilder stringBuilder = new StringBuilder();
string token;
if (Reader.Peek() == '/')
stringBuilder.Append((char)Reader.Read());
while ((token = ReadToken()).Length > 0)
{
stringBuilder.Append(token);
if (Reader.Peek() == '/')
stringBuilder.Append((char)Reader.Read());
else
break;
}
return stringBuilder.ToString();
}
class UnbufferedStreamReader : TextReader
{
public Stream BaseStream { get; }
public UnbufferedStreamReader(Stream stream)
{
BaseStream = stream;
}
public override int Read() => BaseStream.ReadByte();
}
}
}