namespace codelanguage;
/// Structural checks shared by IDE compilation and artifact builds.
public static class SyntaxValidation
{
public static List ValidateTokens(IReadOnlyList tokens)
{
var strictErrors = tokens
.Where(t => t.Type == TokenType.Error)
.Select(t => new ParseError(t.Value, t.Line, t.Column, t.File))
.ToList();
var delimiters = new Stack();
foreach (var token in tokens)
{
if (token.IsIndentation) continue;
if (token.Type is TokenType.LeftBrace or TokenType.LeftParen or TokenType.LeftBracket or TokenType.QuestionLeftBracket)
{
delimiters.Push(token);
continue;
}
TokenType? expected = token.Type switch
{
TokenType.RightBrace => TokenType.LeftBrace,
TokenType.RightParen => TokenType.LeftParen,
TokenType.RightBracket => TokenType.LeftBracket,
_ => null
};
if (expected == null) continue;
if (delimiters.Count == 0)
strictErrors.Add(new ParseError($"Unexpected closing delimiter '{token.Value}'.", token.Line, token.Column));
else
{
var opening = delimiters.Pop();
if (opening.Type != expected && !(expected == TokenType.LeftBracket && opening.Type == TokenType.QuestionLeftBracket))
strictErrors.Add(new ParseError($"Closing delimiter '{token.Value}' does not match '{opening.Value}'.", token.Line, token.Column));
}
}
foreach (var opening in delimiters)
strictErrors.Add(new ParseError($"Unclosed delimiter '{opening.Value}'.", opening.Line, opening.Column));
// The parser supports both same-line statements and indented bodies.
// Keep validation structural and let the parser diagnose empty bodies.
return strictErrors;
}
}