Skip to content

Commit a1f1818

Browse files
fix(splitter): improve EOF handling (#556)
1 parent 6077f9c commit a1f1818

File tree

6 files changed

+140
-105
lines changed

6 files changed

+140
-105
lines changed

crates/pgt_lexer/src/lexed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct LexDiagnostic {
2323
}
2424

2525
/// Result of lexing a string, providing access to tokens and diagnostics
26+
#[derive(Debug)]
2627
pub struct Lexed<'a> {
2728
pub(crate) text: &'a str,
2829
pub(crate) kind: Vec<SyntaxKind>,

crates/pgt_statement_splitter/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn split(sql: &str) -> SplitResult {
1919

2020
let mut splitter = Splitter::new(&lexed);
2121

22-
source(&mut splitter);
22+
let _ = source(&mut splitter);
2323

2424
let split_result = splitter.finish();
2525

@@ -587,4 +587,10 @@ VALUES
587587
TextRange::new(0.into(), 6.into()),
588588
)]);
589589
}
590+
591+
#[test]
592+
fn does_not_panic_on_incomplete_statements() {
593+
// does not panic
594+
let _ = Tester::from("select case ");
595+
}
590596
}

crates/pgt_statement_splitter/src/splitter.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub use common::source;
88
use pgt_lexer::{Lexed, SyntaxKind};
99
use pgt_text_size::TextRange;
1010

11+
use crate::splitter::common::{ReachedEOFException, SplitterResult};
12+
1113
pub struct SplitResult {
1214
pub ranges: Vec<TextRange>,
1315
pub errors: Vec<SplitError>,
@@ -29,6 +31,7 @@ pub struct SplitError {
2931
pub token: usize,
3032
}
3133

34+
#[derive(Debug)]
3235
pub struct Splitter<'a> {
3336
lexed: &'a Lexed<'a>,
3437
current_pos: usize,
@@ -102,12 +105,12 @@ impl<'a> Splitter<'a> {
102105
self.lexed.kind(self.current_pos)
103106
}
104107

105-
fn eat(&mut self, kind: SyntaxKind) -> bool {
108+
fn eat(&mut self, kind: SyntaxKind) -> Result<bool, ReachedEOFException> {
106109
if self.current() == kind {
107-
self.advance();
108-
true
110+
self.advance()?;
111+
Ok(true)
109112
} else {
110-
false
113+
Ok(false)
111114
}
112115
}
113116

@@ -118,13 +121,17 @@ impl<'a> Splitter<'a> {
118121
/// Advances the parser to the next relevant token and returns it.
119122
///
120123
/// NOTE: This will skip trivia tokens.
121-
fn advance(&mut self) -> SyntaxKind {
124+
fn advance(&mut self) -> Result<SyntaxKind, ReachedEOFException> {
125+
if self.current() == SyntaxKind::EOF {
126+
return Err(ReachedEOFException);
127+
}
128+
122129
let pos = (self.current_pos + 1..self.lexed.len())
123130
.find(|&idx| !self.is_trivia(idx))
124-
.expect("lexed should have non-trivia eof token");
131+
.unwrap();
125132

126133
self.current_pos = pos;
127-
self.lexed.kind(pos)
134+
Ok(self.lexed.kind(pos))
128135
}
129136

130137
fn look_ahead(&self, ignore_trivia: bool) -> SyntaxKind {
@@ -164,9 +171,9 @@ impl<'a> Splitter<'a> {
164171

165172
/// Will advance if the `kind` matches the current token.
166173
/// Otherwise, will add a diagnostic to the internal `errors`.
167-
fn expect(&mut self, kind: SyntaxKind) {
174+
fn expect(&mut self, kind: SyntaxKind) -> SplitterResult {
168175
if self.current() == kind {
169-
self.advance();
176+
self.advance()?;
170177
} else {
171178
let token = if self.current() == SyntaxKind::EOF {
172179
self.current_pos - 1
@@ -178,6 +185,8 @@ impl<'a> Splitter<'a> {
178185
msg: format!("Expected {:#?}", kind),
179186
token,
180187
});
181-
}
188+
};
189+
190+
Ok(())
182191
}
183192
}

0 commit comments

Comments
 (0)