jtr/DevDisciples.Parsing/ParserContext.cs
2024-09-15 17:23:27 +02:00

106 lines
2.6 KiB
C#

namespace DevDisciples.Parsing;
public class ParserContext<TToken> : ParsableStream<Lexer<TToken>.Token> where TToken : Enum
{
protected readonly TToken _endOfSource;
public ParserContext(Memory<Lexer<TToken>.Token> tokens, TToken endOfSource) : base(tokens)
{
_endOfSource = endOfSource;
}
public bool Check(TToken type, int offset = 0)
{
if (Ended()) return false;
if (Equals(Peek(offset).Type, _endOfSource)) return false;
return Equals(Peek(offset).Type, type);
}
/// <summary>
/// Checks whether the passed sequence can be matched against the current parsing context.
/// </summary>
/// <param name="sequence"></param>
/// <returns></returns>
public bool CheckSequence(params TToken[] sequence)
{
for (var i = 0; i < sequence.Length; i++)
{
if (!Check(sequence[i], i))
{
return false;
}
}
return true;
}
public override bool Ended()
{
return base.Ended() || Equals(Current.Type, _endOfSource);
}
public bool Match(TToken token)
{
var matched = Check(token);
if (matched) Advance();
return matched;
}
public bool MatchAny(params TToken[] types)
{
for (var i = 0; i < types.Length; i++)
{
if (Check(types[i]))
{
Advance();
return true;
}
}
return false;
}
public bool MatchSequence(params TToken[] sequence)
{
for (var i = 0; i < sequence.Length; i++)
{
if (!Check(sequence[i], i))
{
return false;
}
}
for (var i = 0; i < sequence.Length; i++)
{
Advance();
}
return true;
}
public Lexer<TToken>.Token Previous()
{
return Peek(-1);
}
public Lexer<TToken>.Token Consume(TToken type, string message)
{
if (Check(type)) return Advance();
throw Error(message);
}
public Exception Error(string message)
{
return new ParsingException(Report.FormatMessage(Current, message));
}
public Exception Error(Lexer<TToken>.Token token, string message)
{
return new ParsingException(Report.FormatMessage(token, message));
}
public void Halt(Lexer<TToken>.Token token, string message)
{
throw new ParsingException(Report.FormatMessage(token, message));
}
}