Check for EOF (aka input.next() -> None) and emit what we have before finishing forever

This commit is contained in:
Eryn Wells 2017-05-02 21:44:57 -07:00
parent 5fe10fe002
commit 28e5814101

View file

@ -12,6 +12,7 @@ enum Resume { Here, AtNext }
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
enum IterationResult { enum IterationResult {
Finish,
Continue, Continue,
Emit(Token, Resume), Emit(Token, Resume),
Error(String), Error(String),
@ -40,31 +41,39 @@ impl<T> Iterator for Lexer<T> where T: Iterator<Item=char> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let mut buffer = String::new(); let mut buffer = String::new();
while let Some(peek) = self.input.peek().map(char::clone) { loop {
let peek = self.input.peek().map(char::clone);
let result = if buffer.is_empty() { let result = if buffer.is_empty() {
match peek { match peek {
'(' => self.emit(Token::LeftParen, Resume::AtNext), Some('(') => self.emit(Token::LeftParen, Resume::AtNext),
')' => self.emit(Token::RightParen, Resume::AtNext), Some(')') => self.emit(Token::RightParen, Resume::AtNext),
c if c.is_whitespace() => IterationResult::Continue, Some(c) if c.is_whitespace() => IterationResult::Continue,
c if c.is_alphabetic() => { Some(c) if c.is_alphabetic() => {
buffer.push(c); buffer.push(c);
IterationResult::Continue IterationResult::Continue
}, },
c => self.fail(format!("Invalid character: {}", c)), Some(c) => self.fail(format!("Invalid character: {}", c)),
// We found EOF and there's no pending string, so just finish.
None => IterationResult::Finish,
} }
} }
else { else {
match peek { match peek {
c if c.is_alphabetic() => { Some(c) if c.is_alphabetic() => {
buffer.push(c); buffer.push(c);
IterationResult::Continue IterationResult::Continue
} }
c if c == '(' || c == ')' || c.is_whitespace() => Some(c) if c == '(' || c == ')' || c.is_whitespace() =>
self.emit(Token::Id(buffer.clone()), Resume::Here), self.emit(Token::Id(buffer.clone()), Resume::Here),
c => self.fail(format!("Invalid character: {}", c)), Some(c) => self.fail(format!("Invalid character: {}", c)),
// Found EOF. Emit what we have and finish.
// Note: the Resume argument doesn't matter in this case since the input
// iterator will always be None from here on.
None => self.emit(Token::Id(buffer.clone()), Resume::Here),
} }
}; };
match result { match result {
IterationResult::Finish => break,
IterationResult::Continue => self.input.next(), IterationResult::Continue => self.input.next(),
IterationResult::Emit(token, resume) => { IterationResult::Emit(token, resume) => {
if resume == Resume::AtNext { if resume == Resume::AtNext {