Catch indexing errors at compile time.
This commit is contained in:
parent
01d04f717b
commit
e54fb54da2
14
src/error.rs
14
src/error.rs
@ -64,9 +64,9 @@ pub enum ParseErrorType {
|
||||
/// An open `[` is missing the corresponding closing `]`.
|
||||
MissingRightBracket(String),
|
||||
/// An expression in function call arguments `()` has syntax error.
|
||||
MalformedCallExpr,
|
||||
MalformedCallExpr(String),
|
||||
/// An expression in indexing brackets `[]` has syntax error.
|
||||
MalformedIndexExpr,
|
||||
MalformedIndexExpr(String),
|
||||
/// Missing a variable name after the `let` keyword.
|
||||
VarExpectsIdentifier,
|
||||
/// Defining a function `fn` in an appropriate place (e.g. inside another function).
|
||||
@ -110,8 +110,8 @@ impl Error for ParseError {
|
||||
ParseErrorType::MissingLeftBrace => "Expecting '{'",
|
||||
ParseErrorType::MissingRightBrace(_) => "Expecting '}'",
|
||||
ParseErrorType::MissingRightBracket(_) => "Expecting ']'",
|
||||
ParseErrorType::MalformedCallExpr => "Invalid expression in function call arguments",
|
||||
ParseErrorType::MalformedIndexExpr => "Invalid index in indexing expression",
|
||||
ParseErrorType::MalformedCallExpr(_) => "Invalid expression in function call arguments",
|
||||
ParseErrorType::MalformedIndexExpr(_) => "Invalid index in indexing expression",
|
||||
ParseErrorType::VarExpectsIdentifier => "Expecting name of a variable",
|
||||
ParseErrorType::FnMissingName => "Expecting name in function declaration",
|
||||
ParseErrorType::FnMissingParams(_) => "Expecting parameters in function declaration",
|
||||
@ -128,7 +128,11 @@ impl Error for ParseError {
|
||||
impl fmt::Display for ParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {
|
||||
ParseErrorType::BadInput(ref s) => write!(f, "{}", s)?,
|
||||
ParseErrorType::BadInput(ref s)
|
||||
| ParseErrorType::MalformedIndexExpr(ref s)
|
||||
| ParseErrorType::MalformedCallExpr(ref s) => {
|
||||
write!(f, "{}", if s.is_empty() { self.description() } else { s })?
|
||||
}
|
||||
ParseErrorType::UnknownOperator(ref s) => write!(f, "{}: '{}'", self.description(), s)?,
|
||||
ParseErrorType::FnMissingParams(ref s) => {
|
||||
write!(f, "Expecting parameters for function '{}'", s)?
|
||||
|
@ -1146,7 +1146,66 @@ fn parse_index_expr<'a>(
|
||||
input: &mut Peekable<TokenIterator<'a>>,
|
||||
pos: Position,
|
||||
) -> Result<Expr, ParseError> {
|
||||
parse_expr(input).and_then(|idx_expr| match input.peek() {
|
||||
let idx_expr = parse_expr(input)?;
|
||||
|
||||
// Check type of indexing - must be integer
|
||||
match &idx_expr {
|
||||
Expr::IntegerConstant(i, pos) if *i < 0 => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr(format!(
|
||||
"Array access expects non-negative index: {} < 0",
|
||||
i
|
||||
)),
|
||||
*pos,
|
||||
))
|
||||
}
|
||||
Expr::FloatConstant(_, pos) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr("Array access expects integer index, not a float".into()),
|
||||
*pos,
|
||||
))
|
||||
}
|
||||
Expr::CharConstant(_, pos) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr(
|
||||
"Array access expects integer index, not a character".into(),
|
||||
),
|
||||
*pos,
|
||||
))
|
||||
}
|
||||
Expr::StringConstant(_, pos) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr("Array access expects integer index, not a string".into()),
|
||||
*pos,
|
||||
))
|
||||
}
|
||||
Expr::Assignment(_, _, pos) | Expr::Unit(pos) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr("Array access expects integer index, not ()".into()),
|
||||
*pos,
|
||||
))
|
||||
}
|
||||
Expr::And(lhs, _) | Expr::Or(lhs, _) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr(
|
||||
"Array access expects integer index, not a boolean".into(),
|
||||
),
|
||||
lhs.position(),
|
||||
))
|
||||
}
|
||||
Expr::True(pos) | Expr::False(pos) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedIndexExpr(
|
||||
"Array access expects integer index, not a boolean".into(),
|
||||
),
|
||||
*pos,
|
||||
))
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// Check if there is a closing bracket
|
||||
match input.peek() {
|
||||
Some(&(Token::RightBracket, _)) => {
|
||||
input.next();
|
||||
return Ok(Expr::Index(lhs, Box::new(idx_expr), pos));
|
||||
@ -1163,7 +1222,7 @@ fn parse_index_expr<'a>(
|
||||
Position::eof(),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_ident_expr<'a>(
|
||||
@ -1728,8 +1787,22 @@ fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef<'static
|
||||
Some((Token::Identifier(s), _)) => {
|
||||
params.push(s.into());
|
||||
}
|
||||
Some((_, pos)) => return Err(ParseError::new(PERR::MalformedCallExpr, pos)),
|
||||
None => return Err(ParseError::new(PERR::MalformedCallExpr, Position::eof())),
|
||||
Some((_, pos)) => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedCallExpr(
|
||||
"Function call arguments missing either a ',' or a ')'".into(),
|
||||
),
|
||||
pos,
|
||||
))
|
||||
}
|
||||
None => {
|
||||
return Err(ParseError::new(
|
||||
PERR::MalformedCallExpr(
|
||||
"Function call arguments missing a closing ')'".into(),
|
||||
),
|
||||
Position::eof(),
|
||||
))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user