Better convert LexError to ParseError.

This commit is contained in:
Stephen Chung 2020-06-14 16:56:36 +08:00
parent b51930031b
commit 0c6a939c66
4 changed files with 44 additions and 51 deletions

View File

@ -2480,7 +2480,7 @@ engine.set_max_string_size(500); // allow strings only up to 500 byte
engine.set_max_string_size(0); // allow unlimited string length engine.set_max_string_size(0); // allow unlimited string length
``` ```
A script attempting to create a string literal longer than the maximum will terminate with a parse error. A script attempting to create a string literal longer than the maximum length will terminate with a parse error.
Any script operation that produces a string longer than the maximum also terminates the script with an error result. Any script operation that produces a string longer than the maximum also terminates the script with an error result.
This check can be disabled via the [`unchecked`] feature for higher performance This check can be disabled via the [`unchecked`] feature for higher performance
(but higher risks as well). (but higher risks as well).

View File

@ -22,8 +22,8 @@ pub enum LexError {
MalformedChar(String), MalformedChar(String),
/// An identifier is in an invalid format. /// An identifier is in an invalid format.
MalformedIdentifier(String), MalformedIdentifier(String),
/// Bad keyword encountered when tokenizing the script text. /// Bad symbol encountered when tokenizing the script text.
ImproperKeyword(String), ImproperSymbol(String),
} }
impl Error for LexError {} impl Error for LexError {}
@ -42,11 +42,18 @@ impl fmt::Display for LexError {
"Length of string literal exceeds the maximum limit ({})", "Length of string literal exceeds the maximum limit ({})",
max max
), ),
Self::ImproperKeyword(s) => write!(f, "{}", s), Self::ImproperSymbol(s) => write!(f, "{}", s),
} }
} }
} }
impl LexError {
/// Convert a `LexError` into a `ParseError`.
pub fn into_err(&self, pos: Position) -> ParseError {
ParseError(Box::new(self.into()), pos)
}
}
/// Type of error encountered when parsing a script. /// Type of error encountered when parsing a script.
/// ///
/// Some errors never appear when certain features are turned on. /// Some errors never appear when certain features are turned on.
@ -217,6 +224,17 @@ impl fmt::Display for ParseErrorType {
} }
} }
impl From<&LexError> for ParseErrorType {
fn from(err: &LexError) -> Self {
match err {
LexError::StringTooLong(max) => {
Self::LiteralTooLarge("Length of string literal".to_string(), *max)
}
_ => Self::BadInput(err.to_string()),
}
}
}
/// Error when parsing a script. /// Error when parsing a script.
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ParseError(pub Box<ParseErrorType>, pub Position); pub struct ParseError(pub Box<ParseErrorType>, pub Position);

View File

@ -767,7 +767,7 @@ fn parse_paren_expr(
// ( xxx ) // ( xxx )
(Token::RightParen, _) => Ok(expr), (Token::RightParen, _) => Ok(expr),
// ( <error> // ( <error>
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
// ( xxx ??? // ( xxx ???
(_, pos) => Err(PERR::MissingToken( (_, pos) => Err(PERR::MissingToken(
Token::RightParen.into(), Token::RightParen.into(),
@ -800,7 +800,7 @@ fn parse_call_expr(
.into_err(settings.pos)) .into_err(settings.pos))
} }
// id <error> // id <error>
Token::LexError(err) => return Err(PERR::BadInput(err.to_string()).into_err(settings.pos)), Token::LexError(err) => return Err(err.into_err(settings.pos)),
// id() // id()
Token::RightParen => { Token::RightParen => {
eat_token(input, Token::RightParen); eat_token(input, Token::RightParen);
@ -880,9 +880,7 @@ fn parse_call_expr(
.into_err(*pos)) .into_err(*pos))
} }
// id(...args <error> // id(...args <error>
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(*pos)),
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
// id(...args ??? // id(...args ???
(_, pos) => { (_, pos) => {
return Err(PERR::MissingToken( return Err(PERR::MissingToken(
@ -1065,7 +1063,7 @@ fn parse_index_chain(
} }
} }
} }
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(*pos)), (Token::LexError(err), pos) => return Err(err.into_err(*pos)),
(_, pos) => Err(PERR::MissingToken( (_, pos) => Err(PERR::MissingToken(
Token::RightBracket.into(), Token::RightBracket.into(),
"for a matching [ in this index expression".into(), "for a matching [ in this index expression".into(),
@ -1110,9 +1108,7 @@ fn parse_array_literal(
) )
.into_err(*pos)) .into_err(*pos))
} }
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(*pos)),
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(_, pos) => { (_, pos) => {
return Err(PERR::MissingToken( return Err(PERR::MissingToken(
Token::Comma.into(), Token::Comma.into(),
@ -1144,9 +1140,7 @@ fn parse_map_literal(
let (name, pos) = match input.next().unwrap() { let (name, pos) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s, pos), (Token::Identifier(s), pos) => (s, pos),
(Token::StringConst(s), pos) => (s, pos), (Token::StringConst(s), pos) => (s, pos),
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(pos)),
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(_, pos) if map.is_empty() => { (_, pos) if map.is_empty() => {
return Err( return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into()) PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
@ -1164,9 +1158,7 @@ fn parse_map_literal(
match input.next().unwrap() { match input.next().unwrap() {
(Token::Colon, _) => (), (Token::Colon, _) => (),
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(pos)),
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(_, pos) => { (_, pos) => {
return Err(PERR::MissingToken( return Err(PERR::MissingToken(
Token::Colon.into(), Token::Colon.into(),
@ -1205,9 +1197,7 @@ fn parse_map_literal(
) )
.into_err(*pos)) .into_err(*pos))
} }
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(*pos)),
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(_, pos) => { (_, pos) => {
return Err( return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into()) PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
@ -1269,7 +1259,7 @@ fn parse_primary(
Token::MapStart => parse_map_literal(input, state, settings.level_up())?, Token::MapStart => parse_map_literal(input, state, settings.level_up())?,
Token::True => Expr::True(settings.pos), Token::True => Expr::True(settings.pos),
Token::False => Expr::False(settings.pos), Token::False => Expr::False(settings.pos),
Token::LexError(err) => return Err(PERR::BadInput(err.to_string()).into_err(settings.pos)), Token::LexError(err) => return Err(err.into_err(settings.pos)),
_ => { _ => {
return Err( return Err(
PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(settings.pos) PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(settings.pos)
@ -1380,12 +1370,7 @@ fn parse_unary(
None None
} }
}) })
.ok_or_else(|| { .ok_or_else(|| LexError::MalformedNumber(format!("-{}", x.0)).into_err(pos))
PERR::BadInput(
LexError::MalformedNumber(format!("-{}", x.0)).to_string(),
)
.into_err(pos)
})
} }
// Negative float // Negative float
@ -1990,7 +1975,7 @@ fn parse_for(
// Variable name // Variable name
(Token::Identifier(s), _) => s, (Token::Identifier(s), _) => s,
// Bad identifier // Bad identifier
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
// EOF // EOF
(Token::EOF, pos) => return Err(PERR::VariableExpected.into_err(pos)), (Token::EOF, pos) => return Err(PERR::VariableExpected.into_err(pos)),
// Not a variable name // Not a variable name
@ -2000,7 +1985,7 @@ fn parse_for(
// for name in ... // for name in ...
match input.next().unwrap() { match input.next().unwrap() {
(Token::In, _) => (), (Token::In, _) => (),
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => { (_, pos) => {
return Err( return Err(
PERR::MissingToken(Token::In.into(), "after the iteration variable".into()) PERR::MissingToken(Token::In.into(), "after the iteration variable".into())
@ -2038,7 +2023,7 @@ fn parse_let(
// let name ... // let name ...
let (name, pos) = match input.next().unwrap() { let (name, pos) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s, pos), (Token::Identifier(s), pos) => (s, pos),
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)), (_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
}; };
@ -2109,7 +2094,7 @@ fn parse_import(
// import expr as name ... // import expr as name ...
let (name, _) = match input.next().unwrap() { let (name, _) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s, pos), (Token::Identifier(s), pos) => (s, pos),
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)), (_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
}; };
@ -2132,9 +2117,7 @@ fn parse_export(
loop { loop {
let (id, id_pos) = match input.next().unwrap() { let (id, id_pos) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s.clone(), pos), (Token::Identifier(s), pos) => (s.clone(), pos),
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(pos)),
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)), (_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
}; };
@ -2189,7 +2172,7 @@ fn parse_block(
// Must start with { // Must start with {
settings.pos = match input.next().unwrap() { settings.pos = match input.next().unwrap() {
(Token::LeftBrace, pos) => pos, (Token::LeftBrace, pos) => pos,
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => { (_, pos) => {
return Err(PERR::MissingToken( return Err(PERR::MissingToken(
Token::LeftBrace.into(), Token::LeftBrace.into(),
@ -2229,9 +2212,7 @@ fn parse_block(
// { ... { stmt } ??? // { ... { stmt } ???
(_, _) if !need_semicolon => (), (_, _) if !need_semicolon => (),
// { ... stmt <error> // { ... stmt <error>
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(*pos)),
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
// { ... stmt ??? // { ... stmt ???
(_, pos) => { (_, pos) => {
// Semicolons are not optional between statements // Semicolons are not optional between statements
@ -2380,9 +2361,7 @@ fn parse_fn(
state.push((s.clone(), ScopeEntryType::Normal)); state.push((s.clone(), ScopeEntryType::Normal));
params.push((s, pos)) params.push((s, pos))
} }
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(pos)),
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(_, pos) => { (_, pos) => {
return Err(PERR::MissingToken(Token::RightParen.into(), end_err).into_err(pos)) return Err(PERR::MissingToken(Token::RightParen.into(), end_err).into_err(pos))
} }
@ -2394,9 +2373,7 @@ fn parse_fn(
(Token::Identifier(_), pos) => { (Token::Identifier(_), pos) => {
return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos)) return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos))
} }
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(pos)),
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(_, pos) => { (_, pos) => {
return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos)) return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos))
} }
@ -2567,9 +2544,7 @@ impl Engine {
// { stmt } ??? // { stmt } ???
(_, _) if !need_semicolon => (), (_, _) if !need_semicolon => (),
// stmt <error> // stmt <error>
(Token::LexError(err), pos) => { (Token::LexError(err), pos) => return Err(err.into_err(*pos)),
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
// stmt ??? // stmt ???
(_, pos) => { (_, pos) => {
// Semicolons are not optional between statements // Semicolons are not optional between statements

View File

@ -14,12 +14,12 @@ fn test_max_string_size() -> Result<(), Box<EvalAltResult>> {
assert!(matches!( assert!(matches!(
engine.compile(r#"let x = "hello, world!";"#).expect_err("should error"), engine.compile(r#"let x = "hello, world!";"#).expect_err("should error"),
ParseError(x, _) if *x == ParseErrorType::BadInput("Length of string literal exceeds the maximum limit (10)".to_string()) ParseError(x, _) if *x == ParseErrorType::LiteralTooLarge("Length of string literal".to_string(), 10)
)); ));
assert!(matches!( assert!(matches!(
engine.compile(r#"let x = "朝に紅顔、暮に白骨";"#).expect_err("should error"), engine.compile(r#"let x = "朝に紅顔、暮に白骨";"#).expect_err("should error"),
ParseError(x, _) if *x == ParseErrorType::BadInput("Length of string literal exceeds the maximum limit (10)".to_string()) ParseError(x, _) if *x == ParseErrorType::LiteralTooLarge("Length of string literal".to_string(), 10)
)); ));
assert!(matches!( assert!(matches!(