feat: hint at unterminated strings in unknown prefix errors
When encountering 'unknown literal prefix' errors, check for unbalanced
quotes in recent code and suggest checking for unterminated string literals.
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index 8fff1c3..dcf3971 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -149,6 +149,24 @@
}
}
+ /// Check for likely unterminated string by analyzing STRING token content
+ fn has_likely_unterminated_string(&self) -> bool {
+ let Some(last_idx) = self.res.kind.len().checked_sub(1) else { return false };
+
+ for i in (0..=last_idx).rev().take(5) {
+ if self.res.kind[i] == STRING {
+ let start = self.res.start[i] as usize;
+ let end = self.res.start.get(i + 1).map(|&s| s as usize).unwrap_or(self.offset);
+ let content = &self.res.text[start..end];
+
+ if content.contains('(') && (content.contains("//") || content.contains(";\n")) {
+ return true;
+ }
+ }
+ }
+ false
+ }
+
fn finalize_with_eof(mut self) -> LexedStr<'a> {
self.res.push(EOF, self.offset);
self.res
@@ -267,7 +285,17 @@
rustc_lexer::TokenKind::Unknown => ERROR,
rustc_lexer::TokenKind::UnknownPrefix if token_text == "builtin" => IDENT,
rustc_lexer::TokenKind::UnknownPrefix => {
- errors.push("unknown literal prefix".into());
+ let has_unterminated = self.has_likely_unterminated_string();
+
+ let error_msg = if has_unterminated {
+ format!(
+ "unknown literal prefix `{}` (note: check for unterminated string literal)",
+ token_text
+ )
+ } else {
+ "unknown literal prefix".to_owned()
+ };
+ errors.push(error_msg);
IDENT
}
rustc_lexer::TokenKind::Eof => EOF,
diff --git a/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast b/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast
new file mode 100644
index 0000000..f7f24ca
--- /dev/null
+++ b/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rast
@@ -0,0 +1,15 @@
+FN_KW "fn"
+WHITESPACE " "
+IDENT "main"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE "\n "
+IDENT "hello"
+L_PAREN "("
+STRING "\"world);\n // a bunch of code was here\n env(\"FLAGS"
+STRING "\", \""
+MINUS "-"
+IDENT "help" error: unknown literal prefix `help` (note: check for unterminated string literal)
+STRING "\")\n}" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs b/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs
new file mode 100644
index 0000000..338b958
--- /dev/null
+++ b/crates/parser/test_data/lexer/err/unterminated_string_unknown_prefix.rs
@@ -0,0 +1,5 @@
+fn main() {
+ hello("world);
+ // a bunch of code was here
+ env("FLAGS", "-help")
+}
\ No newline at end of file