swc-project/swc · error · swc_css_parser::error::Error

Unexpected end of file

Error message

Unexpected end of file

What it means

This is the cur!() parser macro: it calls Input::cur(), and when that fails (no current token left) it converts the failure into ErrorKind::Eof at the last position, first draining any lexer errors accumulated on the input into the parser error list. So the visible 'Unexpected end of file' may ride along with earlier lexer diagnostics that were deferred until now.

Source

Thrown at crates/swc_css_parser/src/parser/macros.rs:60

        tok!($t)
    };
}

macro_rules! cur {
    ($parser:expr) => {
        match $parser.input.cur() {
            Some(v) => v,
            None => {
                let last_pos = $parser.input.last_pos();
                let span = swc_common::Span::new(last_pos, last_pos);

                for error in $parser.input.take_errors() {
                    let (span, kind) = *error.into_inner();

                    $parser.errors.push(Error::new(span, kind));
                }

                return Err(crate::error::Error::new(span, crate::error::ErrorKind::Eof));
            }
        }
    };
}

macro_rules! bump {
    ($parser:expr) => {
        $parser.input.bump().unwrap().token
    };
}

macro_rules! is_case_insensitive_ident {
    ($parser:expr, $tt:tt) => {{
        match $parser.input.cur() {
            Some(swc_css_ast::Token::Ident { value, .. })
                if (&**value).eq_ignore_ascii_case($tt) =>
            {
                true

View on GitHub (pinned to 5176682b65)

Solutions

  1. Close unclosed blocks/parens/strings and re-parse
  2. Inspect ALL collected errors (the macro flushes deferred lexer errors before returning EOF) — fix the earliest one first
  3. For tooling, treat Eof kind with empty-position span as 'incomplete input' signal and request the rest of the stream

Example fix

/* before */
.a { color: red;
/* after */
.a { color: red; }
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: balanced delimiters and terminated strings/comments catch most causes
if (!isBalanced(css) || /\/\*(?!.*\*\/)/s.test(css)) throw new Error('incomplete stylesheet');

Try / catch

// Rust: Eof here flushes deferred lexer errors — drain ALL errors, fix the first
match parse_string(css) {
  Err(e) => { for err in parser.errors.iter() { diagnostics.push(err.clone()); } Err(first_diagnostic()) }
  ok => ok,
}

Prevention

When it happens

Trigger: Any parse rule that calls cur!() after the token stream is exhausted — typically inside a loop that expects more tokens, e.g. parsing declaration values or selector lists of an unclosed block: '.a { color: red;' then the value loop calls cur!() past the end.

Common situations: Unclosed rules at EOF (most common), and secondarily stylesheets whose early lexing errors were buffered: the EOF message is what surfaces, but the root cause may be an earlier invalid token — inspect the full error list, not just the last one.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/06151d03669c2d2e. Report an issue: GitHub.