From 514df34f92d138f711680fb4bf3899d46e9a24df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20W=C3=BClker?= Date: Fri, 19 Jan 2024 21:34:49 +0100 Subject: [PATCH] js: Don't eagerly consume identifiers During parsing, we would sometimes consume an identifier and see if it matched an expected value (in this case, "this") If that was not the case, parsing would continue and other branches would be tried, but the identifier was never put back, so parsing would fail if there was an identifier but it had a different value than expected. This caused us to fail to parse something like "let x = null;" --- crates/js/src/parser/expression.rs | 8 ++++---- crates/js/src/parser/tokenizer.rs | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/crates/js/src/parser/expression.rs b/crates/js/src/parser/expression.rs index a9af150a..b4381271 100644 --- a/crates/js/src/parser/expression.rs +++ b/crates/js/src/parser/expression.rs @@ -207,10 +207,10 @@ pub struct NewExpression { fn parse_primary_expression( tokenizer: &mut Tokenizer<'_>, ) -> Result { - if matches!( - tokenizer.attempt(Tokenizer::consume_identifier).as_deref(), - Ok("this") - ) { + if tokenizer + .attempt(|tokenizer| tokenizer.consume_keyword("this")) + .is_ok() + { Ok(Expression::This) } else if let Ok(literal) = Literal::parse(tokenizer) { Ok(Expression::Literal(literal)) diff --git a/crates/js/src/parser/tokenizer.rs b/crates/js/src/parser/tokenizer.rs index f13a09b5..3c672a3b 100644 --- a/crates/js/src/parser/tokenizer.rs +++ b/crates/js/src/parser/tokenizer.rs @@ -175,9 +175,9 @@ impl<'a> Tokenizer<'a> { self.source.go_back() } - pub fn consume_null_literal(&mut self) -> Result<(), SyntaxError> { - if self.source.remaining().starts_with("null") { - _ = self.source.advance_by("null".len()); + pub fn consume_keyword(&mut self, keyword: &str) -> Result<(), SyntaxError> { + if self.source.remaining().starts_with(keyword) { + _ = self.source.advance_by(keyword.len()); self.skip_whitespace(); Ok(()) } else { @@ -185,6 +185,10 @@ impl<'a> Tokenizer<'a> { } } + pub fn consume_null_literal(&mut self) -> Result<(), SyntaxError> { + self.consume_keyword("null") + } + pub fn consume_boolean_literal(&mut self) -> Result { let remaining = self.source.remaining(); let boolean_literal = if remaining.starts_with("true") {