KumiScript/reader/Lexer.cs

151 lines
3.6 KiB
C#
Raw Normal View History

2024-01-26 05:37:51 +00:00
using KumiScript.Interpreter;
namespace KumiScript.Reader
{
public class Lexer
{
Stack<Token> _tokenStack;
readonly StreamReader _streamReader;
public Lexer(Stream stream)
{
_tokenStack = new Stack<Token>(16);
_streamReader = new StreamReader(stream);
}
public Token NextToken()
{
if (_tokenStack.IsEmpty())
return LexFromStream();
return _tokenStack.Pop();
}
public Token PeekToken()
{
Token t = NextToken();
PushToken(t);
return t;
}
public void PushToken(Token token)
{
_tokenStack.Push(token);
return;
}
private Token LexFromStream()
{
int c = GetChar();
while (char.IsWhiteSpace((char) c))
c = GetChar();
if (c == ';')
{
while ((c = GetChar()) != '\n');
c = GetChar();
}
if (c == -1)
return new EndOfFileToken();
if (c == '(')
return new ParenthesisToken(true);
if (c == ')')
return new ParenthesisToken(false);
if (c == '"')
return LexString();
if (isspec(c))
return new SpecialToken((char) c);
return LexGeneric(c);
}
private Token LexString()
{
List<char> chars = new List<char>();
int c = GetChar();
while (c != '"')
{
if (c == '\\')
c = GetChar();
chars.Add((char) c);
c = GetChar();
if (c == -1)
throw new Exception("Unexpected EOF!");
}
return new StringToken(new string(chars.ToArray()));
}
private Token LexGeneric(int c)
{
List<char> chars = new List<char>();
chars.Add((char) c); //NOTE: The language server is WRONG! List<char>((char) c) BREAKS! **** you m$
int p = PeekChar();
while (!char.IsWhiteSpace((char) p) && !isspecparen(p) && p != -1)
{
c = GetChar();
chars.Add((char) c);
p = PeekChar();
}
return new AtomToken(new string(chars.ToArray()));
}
private static bool isspec(int c)
{
switch (c)
{
case '#':
return true;
case '\'':
return true;
case '\\':
return true;
case '`':
return true;
case ',':
return true;
}
return false;
}
private static bool isspecparen(int c)
{
switch (c)
{
case '(':
return true;
case ')':
return true;
case '#':
return true;
case '\'':
return true;
case '\\':
return true;
case '`':
return true;
case ',':
return true;
}
return false;
}
private int GetChar()
{
return _streamReader.Read();
}
private int PeekChar()
{
return _streamReader.Peek();
}
}
}