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; } }