diff --git a/src/error.rs b/src/error.rs index b631c4cf..5c4419d4 100644 --- a/src/error.rs +++ b/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)? diff --git a/src/parser.rs b/src/parser.rs index 5fe02586..84a67007 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1146,7 +1146,66 @@ fn parse_index_expr<'a>( input: &mut Peekable>, pos: Position, ) -> Result { - 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>) -> Result { 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(), + )) + } } }, }