Error Handling and Diagnostics
AXSLC provides clear, actionable error messages with source context.
Error Format
All compiler errors follow the format:
file:line:col: message
N-2 | source line
N-1 | source line
N | source line where error occurred
| ^
N+1 | source line
N+2 | source lineWithout Filename
When no filename is provided (e.g., when calling Compiler::compile without a filename argument):
line:col: messageSource Context
The error includes up to 2 lines of context before and after the error line (configurable via format_source_context's context_lines parameter).
The caret ^ appears under column col of the error line, pointing to the exact error location.
Example Error
shader.axsl:15:20: unresolved symbol: 'unknown_func'
13 | void main() {
14 | vec3 pos = a.a_pos;
15 | vec3 result = unknown_func(pos);
| ^
16 | gl_Position = vec4(result, 1.0);
17 | }Error Categories
Parse Errors
Unexpected token:
shader.axsl:5:1: expected ';' after expression
3 | void main() {
4 | x = 1.0
| ^
5 | }Missing closing brace:
shader.axsl:8:1: expected '}' to close block
6 | void main() {
7 | x = 1.0;
8 |
| ^Linker Errors
Unresolved symbol:
shader.axsl:12:15: unresolved symbol: 'missing_func'
10 | void main() {
11 | vec3 color = vec3(1.0);
12 | float value = missing_func(color);
| ^
13 | }Undefined identifier:
shader.axsl:8:10: undefined identifier: 'undefined_var'
6 | void main() {
7 | float x = 1.0;
8 | float y = undefined_var + 1.0;
| ^
9 | }Cannot open include:
shader.axsl:2:1: cannot open include: 'missing.axsl'
1 | @version 450;
2 | @include "missing.axsl";
| ^
3 |Include file errors:
When an included file has errors, they are prefixed with the include file path:
[common/defs.axsl] line 5:10: expected ';' after expressionDiagnostic Macros
The linker uses diagnostic macros for common error patterns:
| Macro | Produces |
|---|---|
PUSH_UNDEFINED_IDENTIFIER(r, name, loc) | "undefined identifier: 'name' at line:col" |
PUSH_UNRESOLVED_SYMBOL(r, name, loc) | "unresolved symbol: 'name' at line:col" |
PUSH_CANNOT_OPEN_INCLUDE(r, path) | "cannot open include: 'path'" |
PUSH_PREFIXED_INCLUDE_ERROR(r, path, err) | "[path] error message" |
Parse Error Recovery
When the parser encounters an unexpected token, it calls synchronize():
void Parser::synchronize() {
while (!check(TokenKind::Eof)) {
if (peek().kind == TokenKind::Semicolon) {
advance();
return;
}
if (peek().kind == TokenKind::RBrace) return;
advance();
}
}Behavior
- Discards tokens until it finds a
;(consumed) or a}(not consumed) - Returns a placeholder
LiteralExpr{0}to keep the AST structurally intact - Allows the parser to continue and report further errors
Example
void main() {
x = ; // parse error here
y = 2.0; // this line can still be parsed after recovery
}Both errors (if any) will be reported, not just the first one.
Parser Stuck Detection
The parser includes guards to detect when it hasn't advanced after attempting to parse an item:
size_t pos_before = m_pos;
parse_something();
if (m_pos == pos_before) {
fprintf(stderr, "[axslc] parse: stuck at token ...\n");
advance(); // force progress
}This prevents infinite loops on malformed input. The stuck warning goes to stderr (not the error list) and is primarily a debugging aid.
Where It's Used
parse()- top-level declarationsparse_stage_block()- stage itemsparse_block_stmt()- block statements
format_source_context
std::string format_source_context(
std::string_view source,
uint32_t line,
uint32_t col,
uint32_t context_lines = 2
);Formats an error message with source context.
Behavior
- Returns an empty string if
line == 0orline > total_lines - Right-aligns line numbers to the width of the last line number
- Uses
|as a separator between line numbers and source - Caret row has no line number, just spaces and the
^at columncol
Example Output
13 | void main() {
14 | vec3 pos = a.a_pos;
15 | vec3 result = unknown_func(pos);
| ^
16 | gl_Position = vec4(result, 1.0);
17 | }Multiple Errors
The compiler collects all errors and reports them together:
shader.axsl:8:10: undefined identifier: 'var1'
6 | void main() {
7 | float x = 1.0;
8 | float y = var1 + 1.0;
| ^
9 | }
shader.axsl:15:20: unresolved symbol: 'func1'
13 | void compute() {
14 | vec3 pos = vec3(0.0);
15 | vec3 result = func1(pos);
| ^
16 | }All errors are reported at once, allowing you to fix multiple issues in a single iteration.
Type System Limitations
AXSLC does not perform type checking. Type errors, mismatches, and semantic validation are handled by the downstream GLSL compiler.
See Limitations for details on what AXSLC doesn't check and how to handle GLSL compilation errors.