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 `]`.
|
/// An open `[` is missing the corresponding closing `]`.
|
||||||
MissingRightBracket(String),
|
MissingRightBracket(String),
|
||||||
/// An expression in function call arguments `()` has syntax error.
|
/// An expression in function call arguments `()` has syntax error.
|
||||||
MalformedCallExpr,
|
MalformedCallExpr(String),
|
||||||
/// An expression in indexing brackets `[]` has syntax error.
|
/// An expression in indexing brackets `[]` has syntax error.
|
||||||
MalformedIndexExpr,
|
MalformedIndexExpr(String),
|
||||||
/// Missing a variable name after the `let` keyword.
|
/// Missing a variable name after the `let` keyword.
|
||||||
VarExpectsIdentifier,
|
VarExpectsIdentifier,
|
||||||
/// Defining a function `fn` in an appropriate place (e.g. inside another function).
|
/// 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::MissingLeftBrace => "Expecting '{'",
|
||||||
ParseErrorType::MissingRightBrace(_) => "Expecting '}'",
|
ParseErrorType::MissingRightBrace(_) => "Expecting '}'",
|
||||||
ParseErrorType::MissingRightBracket(_) => "Expecting ']'",
|
ParseErrorType::MissingRightBracket(_) => "Expecting ']'",
|
||||||
ParseErrorType::MalformedCallExpr => "Invalid expression in function call arguments",
|
ParseErrorType::MalformedCallExpr(_) => "Invalid expression in function call arguments",
|
||||||
ParseErrorType::MalformedIndexExpr => "Invalid index in indexing expression",
|
ParseErrorType::MalformedIndexExpr(_) => "Invalid index in indexing expression",
|
||||||
ParseErrorType::VarExpectsIdentifier => "Expecting name of a variable",
|
ParseErrorType::VarExpectsIdentifier => "Expecting name of a variable",
|
||||||
ParseErrorType::FnMissingName => "Expecting name in function declaration",
|
ParseErrorType::FnMissingName => "Expecting name in function declaration",
|
||||||
ParseErrorType::FnMissingParams(_) => "Expecting parameters in function declaration",
|
ParseErrorType::FnMissingParams(_) => "Expecting parameters in function declaration",
|
||||||
@ -128,7 +128,11 @@ impl Error for ParseError {
|
|||||||
impl fmt::Display for ParseError {
|
impl fmt::Display for ParseError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self.0 {
|
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::UnknownOperator(ref s) => write!(f, "{}: '{}'", self.description(), s)?,
|
||||||
ParseErrorType::FnMissingParams(ref s) => {
|
ParseErrorType::FnMissingParams(ref s) => {
|
||||||
write!(f, "Expecting parameters for function '{}'", s)?
|
write!(f, "Expecting parameters for function '{}'", s)?
|
||||||
|
@ -1146,7 +1146,66 @@ fn parse_index_expr<'a>(
|
|||||||
input: &mut Peekable<TokenIterator<'a>>,
|
input: &mut Peekable<TokenIterator<'a>>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> 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, _)) => {
|
Some(&(Token::RightBracket, _)) => {
|
||||||
input.next();
|
input.next();
|
||||||
return Ok(Expr::Index(lhs, Box::new(idx_expr), pos));
|
return Ok(Expr::Index(lhs, Box::new(idx_expr), pos));
|
||||||
@ -1163,7 +1222,7 @@ fn parse_index_expr<'a>(
|
|||||||
Position::eof(),
|
Position::eof(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident_expr<'a>(
|
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), _)) => {
|
Some((Token::Identifier(s), _)) => {
|
||||||
params.push(s.into());
|
params.push(s.into());
|
||||||
}
|
}
|
||||||
Some((_, pos)) => return Err(ParseError::new(PERR::MalformedCallExpr, pos)),
|
Some((_, pos)) => {
|
||||||
None => return Err(ParseError::new(PERR::MalformedCallExpr, Position::eof())),
|
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…
x
Reference in New Issue
Block a user