From 38d9c7e320bd1676c12c1d027512a1d5d9aeac1a Mon Sep 17 00:00:00 2001 From: xcb3d Date: Sun, 6 Sep 2026 22:20:09 +0700 Subject: [PATCH] =?UTF-8?q?fix(parser):=20allow=20HTML=20close=20comments?= =?UTF-8?q?=20on=20first=20line=20per=20Annex=20B=20=C2=A7B.1.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per ECMAScript Annex B §B.1.1, HTML close comments (`-->`) are permitted on the first line of a script (under `InputElementHashbangOrRegExp`), optionally preceded by whitespace and single-line delimited comments (`/* ... */`). Previously, `BufferedLexer` only skipped HTML close comments after a preceding `LineTerminator`, which caused files with `-->` on the first line to be lexed as punctuator `--` followed by `>`, triggering a `SyntaxError`. Also add missing `JsNativeErrorKind::Eval` match arm in `boa_tester`'s `is_error_type` check for `ErrorType::EvalError`. This resolves all 3 failing test262 tests in `test/annexB/language/comments/`, bringing the suite to 100% conformance (8/8 passed). --- .../src/parser/cursor/buffered_lexer/mod.rs | 20 ++++++++++- .../src/parser/cursor/buffered_lexer/tests.rs | 36 +++++++++++++++++++ tests/tester/src/exec/mod.rs | 1 + 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/core/parser/src/parser/cursor/buffered_lexer/mod.rs b/core/parser/src/parser/cursor/buffered_lexer/mod.rs index 67ba7aee596..d96202a5822 100644 --- a/core/parser/src/parser/cursor/buffered_lexer/mod.rs +++ b/core/parser/src/parser/cursor/buffered_lexer/mod.rs @@ -30,6 +30,7 @@ pub(super) struct BufferedLexer { read_index: usize, write_index: usize, last_linear_pos: LinearPosition, + first_token: bool, } impl From> for BufferedLexer @@ -53,6 +54,7 @@ where read_index: 0, write_index: 0, last_linear_pos: LinearPosition::default(), + first_token: true, } } } @@ -134,7 +136,23 @@ where let previous_index = self.write_index.checked_sub(1).unwrap_or(PEEK_BUF_SIZE - 1); - if let Some(ref token) = self.peeked[previous_index] + if self.first_token { + self.first_token = false; + let next = loop { + self.lexer.skip_html_close(interner)?; + let next = self.lexer.next_no_skip(interner)?; + if let Some(ref token) = next { + match token.kind() { + TokenKind::Comment => self.lexer.skip_html_close(interner)?, + _ => break next, + } + } else { + break None; + } + }; + + self.peeked[self.write_index] = next; + } else if let Some(ref token) = self.peeked[previous_index] && token.kind() == &TokenKind::LineTerminator { // We don't want to have multiple contiguous line terminators in the buffer, since diff --git a/core/parser/src/parser/cursor/buffered_lexer/tests.rs b/core/parser/src/parser/cursor/buffered_lexer/tests.rs index 7dc8c58ef5b..775e2263db2 100644 --- a/core/parser/src/parser/cursor/buffered_lexer/tests.rs +++ b/core/parser/src/parser/cursor/buffered_lexer/tests.rs @@ -287,3 +287,39 @@ fn issue_1768() { assert!(cur.peek(3, true, interner).unwrap().is_none()); } + +#[test] +#[cfg(feature = "annex-b")] +fn html_close_comment_first_line() { + let interner = &mut Interner::default(); + + // 1. Direct `-->` on the first line. + let mut cur = BufferedLexer::from(&b"--> comment\nA"[..]); + assert_eq!( + *cur.peek(0, true, interner) + .unwrap() + .expect("Some value expected") + .kind(), + TokenKind::identifier(interner.get_or_intern_static("A", utf16!("A"))) + ); + + // 2. Spaces preceding `-->` on the first line. + let mut cur = BufferedLexer::from(&b" --> comment\nB"[..]); + assert_eq!( + *cur.peek(0, true, interner) + .unwrap() + .expect("Some value expected") + .kind(), + TokenKind::identifier(interner.get_or_intern_static("B", utf16!("B"))) + ); + + // 3. Single-line delimited comments and spaces preceding `-->` on the first line. + let mut cur = BufferedLexer::from(&b"/* comment 1 */ /* comment 2 */--> comment 3\nC"[..]); + assert_eq!( + *cur.peek(0, true, interner) + .unwrap() + .expect("Some value expected") + .kind(), + TokenKind::identifier(interner.get_or_intern_static("C", utf16!("C"))) + ); +} diff --git a/tests/tester/src/exec/mod.rs b/tests/tester/src/exec/mod.rs index 62c0afaf5ad..fa78ffc9f10 100644 --- a/tests/tester/src/exec/mod.rs +++ b/tests/tester/src/exec/mod.rs @@ -602,6 +602,7 @@ fn is_error_type(error: &JsError, target_type: ErrorType, context: &mut Context) JsNativeErrorKind::Reference if target_type == ErrorType::ReferenceError => {} JsNativeErrorKind::Range if target_type == ErrorType::RangeError => {} JsNativeErrorKind::Type if target_type == ErrorType::TypeError => {} + JsNativeErrorKind::Eval if target_type == ErrorType::EvalError => {} _ => return false, } true