Check for EOF (aka input.next() -> None) and emit what we have before finishing forever
This commit is contained in:
parent
5fe10fe002
commit
28e5814101
1 changed files with 18 additions and 9 deletions
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue