GeezerVison is showing github.com — Add context-aware error messages to CSS parser by Copilot · Pull Request #98 · HtmlUnit/htmlunit-cssparser
Conversation
Copilot
AI
commented
Dec 22, 2025
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
CSS parser error messages lacked context about where errors occurred and what was expected, making debugging difficult. Errors like "Error in declaration." provided no actionable information.
Changes
Core Implementation
- ParserContext class: Stack-based context tracker maintaining rule hierarchy, current token, expected tokens, and property names
- AbstractCSSParser: Integrated ParserContext into
toCSSParseException() to automatically enrich all error messages with contextual information
- CSS3Parser.jj grammar: Added context tracking to
styleRule, declaration, and mediaRule productions using try-finally blocks
Error Message Enhancement
Before:
After:
Error in declaration. (Invalid token "blue". Was expecting one of: <S>, ":".)
(in style-rule > declaration). Expected: property-name, : (property: background)
Nested context:
Error in declaration. (Invalid token "red". Was expecting one of: <S>, ":".)
(in @media > style-rule > declaration). Expected: property-name, : (property: color)
Testing
- Added
ContextAwareErrorTest with 7 tests covering declaration errors, nested rules, property context, and expected tokens
- Updated existing test expectations across 8 test files to match new error format
All 646 tests pass. Changes are backward compatible - existing error handling code unchanged.
Original prompt
Add Context-Aware Error Messages to CSS Parser
Problem
The current CSS parser produces generic error messages that lack context, making it difficult for users to understand:
- Where in the CSS structure the error occurred
- What was being parsed when the error happened
- What tokens were expected vs. what was found
Current generic error messages:
Error in declaration.
Error in selector.
Invalid token "colr".
These messages don't provide:
- The parsing context (e.g., "in @media rule > .selector")
- The actual vs. expected tokens
- Helpful suggestions for common mistakes
- The full parsing stack trace
Solution
Implement a comprehensive context-aware error messaging system that provides rich, actionable error information.
1. Create ParserContext Class
package org.htmlunit.cssparser.parser;
import java.util.*;
/**
* Tracks parsing context to provide detailed error messages.
*/
public class ParserContext {
private final Deque<String> ruleStack = new ArrayDeque<>();
private Token currentToken;
private final List<String> expectedTokens = new ArrayList<>();
private String currentProperty;
public void enterRule(String ruleName) {
ruleStack.push(ruleName);
}
public void exitRule() {
if (!ruleStack.isEmpty()) {
ruleStack.pop();
}
}
public void setCurrentToken(Token token) {
this.currentToken = token;
}
public void addExpectedToken(String token) {
expectedTokens.add(token);
}
public void clearExpectedTokens() {
expectedTokens.clear();
}
public void setCurrentProperty(String property) {
this.currentProperty = property;
}
public String buildContextualMessage(String baseMessage) {
StringBuilder sb = new StringBuilder(baseMessage);
// Add rule context
if (!ruleStack.isEmpty()) {
sb.append(" (in ");
sb.append(String.join(" > ", ruleStack));
sb.append(")");
}
// Add current token info
if (currentToken != null) {
sb.append(" at '");
sb.append(currentToken.image);
sb.append("'");
}
// Add expected tokens
if (!expectedTokens.isEmpty()) {
sb.append(". Expected: ");
sb.append(String.join(", ", expectedTokens));
}
// Add property context if available
if (currentProperty != null) {
sb.append(" (property: ");
sb.append(currentProperty);
sb.append(")");
}
return sb.toString();
}
public String getCurrentContext() {
return ruleStack.isEmpty() ? "root" : String.join(" > ", ruleStack);
}
}
2. Enhance AbstractCSSParser
// Add to AbstractCSSParser.java
private ParserContext parserContext_ = new ParserContext();
protected ParserContext getParserContext() {
return parserContext_;
}
// Update toCSSParseException methods to use context
protected CSSParseException toCSSParseException(String messageKey, ParseException e) {
String baseMessage = getParserMessage(messageKey);
String contextualMessage = parserContext_.buildContextualMessage(baseMessage);
if (e.currentToken != null && e.currentToken.next != null) {
return new CSSParseException(
contextualMessage,
getInputSource().getURI(),
e.currentToken.next.beginLine,
e.currentToken.next.beginColumn
);
}
return new CSSParseException(contextualMessage, getInputSource().getURI(), 1, 1);
}
3. Add Token Category Helper
// Add to AbstractCSSParser.java
protected String getTokenCategory(int kind) {
switch(kind) {
case CSS3ParserConstants.IDENT:
case CSS3ParserConstants.NUMBER:
case CSS3ParserConstants.STRING:
return "value";
case CSS3ParserConstants.LBRACE:
case CSS3ParserConstants.RBRACE:
case CSS3ParserConstants.LROUND:
case CSS3ParserConstants.RROUND:
return "delimiter";
case CSS3ParserConstants.SEMICOLON:
case CSS3ParserConstants.COLON:
case CSS3ParserConstants.COMMA:
return "separator";
case CSS3ParserConstants.IMPORT_SYM:
case CSS3ParserConstants.MEDIA_SYM:
case CSS3ParserConstants.PAGE_SYM:
return "at-rule";
default:
return "token";
}
}
protected List<String> getExpectedTokenNames(ParseException e) {
List<String> expected = new ArrayList<>();
if (e.expectedTokenSequences != null) {
for (int[] sequence : e.expectedTokenSequences) {
if (sequence.length > 0) {
expected.add(tokenImage[sequence[0]]);
}
}
}
return expected;
}
4. Update CSS3Parser.jj Grammar
Add context tracking to major...
This pull request was created from Copilot chat.
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Copilot
AI
changed the title
[WIP] Add context-aware error messages to CSS parser
Add context-aware error messages to CSS parser
Dec 22, 2025
Reviewers
rbri
Awaiting requested review from rbri
Uh oh!
There was an error while loading. Please reload this page.
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|