Fix string handling - error for unterminated strings.

This commit is contained in:
Stephen Chung 2020-02-29 21:10:31 +08:00
parent 4b3cf95871
commit 17f0001b11

View File

@ -7,6 +7,7 @@ use std::str::Chars;
#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
pub enum LexError { pub enum LexError {
UnexpectedChar(char), UnexpectedChar(char),
UnterminatedString,
MalformedEscapeSequence, MalformedEscapeSequence,
MalformedNumber, MalformedNumber,
MalformedChar, MalformedChar,
@ -19,6 +20,7 @@ impl Error for LexError {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
LERR::UnexpectedChar(_) => "Unexpected character", LERR::UnexpectedChar(_) => "Unexpected character",
LERR::UnterminatedString => "Open string is not terminated",
LERR::MalformedEscapeSequence => "Unexpected values in escape sequence", LERR::MalformedEscapeSequence => "Unexpected values in escape sequence",
LERR::MalformedNumber => "Unexpected characters in number", LERR::MalformedNumber => "Unexpected characters in number",
LERR::MalformedChar => "Char constant not a single character", LERR::MalformedChar => "Char constant not a single character",
@ -62,6 +64,10 @@ impl Position {
fn advance(&mut self) { fn advance(&mut self) {
self.pos += 1; self.pos += 1;
} }
fn rewind(&mut self) {
// Beware, should not rewind at zero position
self.pos -= 1;
}
fn new_line(&mut self) { fn new_line(&mut self) {
self.line += 1; self.line += 1;
self.pos = 0; self.pos = 0;
@ -132,7 +138,7 @@ impl fmt::Display for ParseError {
if self.line() > 0 { if self.line() > 0 {
write!(f, " at line {}, position {}", self.line(), self.position()) write!(f, " at line {}, position {}", self.line(), self.position())
} else { } else {
write!(f, " but script is incomplete") write!(f, " at the end of the script but there is no more input")
} }
} }
} }
@ -354,6 +360,9 @@ impl<'a> TokenIterator<'a> {
fn advance(&mut self) { fn advance(&mut self) {
self.pos.advance(); self.pos.advance();
} }
fn rewind(&mut self) {
self.pos.rewind();
}
fn new_line(&mut self) { fn new_line(&mut self) {
self.pos.new_line(); self.pos.new_line();
} }
@ -365,10 +374,16 @@ impl<'a> TokenIterator<'a> {
let mut result = Vec::new(); let mut result = Vec::new();
let mut escape = false; let mut escape = false;
while let Some(look_ahead) = self.char_stream.next() { loop {
let next_char = self.char_stream.next();
if next_char.is_none() {
return Err((LERR::UnterminatedString, Position::eof()));
}
self.advance(); self.advance();
match look_ahead { match next_char.unwrap() {
'\\' if !escape => escape = true, '\\' if !escape => escape = true,
'\\' if escape => { '\\' if escape => {
escape = false; escape = false;
@ -458,10 +473,11 @@ impl<'a> TokenIterator<'a> {
x if enclosing_char == x && escape => result.push(x), x if enclosing_char == x && escape => result.push(x),
x if enclosing_char == x && !escape => break, x if enclosing_char == x && !escape => break,
_ if escape => return Err((LERR::MalformedEscapeSequence, self.pos)), _ if escape => return Err((LERR::MalformedEscapeSequence, self.pos)),
'\n' => {
self.rewind();
return Err((LERR::UnterminatedString, self.pos));
}
x => { x => {
if look_ahead == '\n' {
self.new_line();
}
escape = false; escape = false;
result.push(x); result.push(x);
} }
@ -983,13 +999,7 @@ fn parse_call_expr<'a>(
} }
loop { loop {
match parse_expr(input) { args.push(parse_expr(input)?);
Ok(arg) => args.push(arg),
Err(mut err) => {
err.0 = PERR::MalformedCallExpr;
return Err(err);
}
}
match input.peek() { match input.peek() {
Some(&(Token::RightParen, _)) => { Some(&(Token::RightParen, _)) => {