diff --git a/src/error.rs b/src/error.rs index 2826c465..8937ffb1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,8 +17,6 @@ pub enum LexError { MalformedNumber(String), /// An character literal is in an invalid format. MalformedChar(String), - /// Error in the script text. - InputError(String), /// An identifier is in an invalid format. MalformedIdentifier(String), } @@ -35,7 +33,6 @@ impl fmt::Display for LexError { Self::MalformedIdentifier(s) => { write!(f, "Variable name is not in a legal format: '{}'", s) } - Self::InputError(s) => write!(f, "{}", s), Self::UnterminatedString => write!(f, "Open string is not terminated"), } } @@ -98,16 +95,20 @@ pub enum ParseErrorType { LoopBreak, } +impl ParseErrorType { + pub(crate) fn into_err(self, pos: Position) -> ParseError { + ParseError(self, pos) + } + pub(crate) fn into_err_eof(self) -> ParseError { + ParseError(self, Position::eof()) + } +} + /// Error when parsing a script. #[derive(Debug, PartialEq, Clone)] pub struct ParseError(pub(crate) ParseErrorType, pub(crate) Position); impl ParseError { - /// Create a new `ParseError`. - pub(crate) fn new(err: ParseErrorType, pos: Position) -> Self { - Self(err, pos) - } - /// Get the parse error. pub fn error_type(&self) -> &ParseErrorType { &self.0 diff --git a/src/parser.rs b/src/parser.rs index 7b293aac..ed627e1e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -77,9 +77,7 @@ impl Position { /// Get the character position (1-based), or `None` if at beginning of a line. pub fn position(&self) -> Option { - if self.is_none() || self.is_eof() { - None - } else if self.pos == 0 { + if self.is_none() || self.is_eof() || self.pos == 0 { None } else { Some(self.pos) @@ -521,7 +519,7 @@ pub enum Token { impl Token { /// Get the syntax of the token. - pub fn syntax<'a>(&'a self) -> Cow<'a, str> { + pub fn syntax(&self) -> Cow { use self::Token::*; match self { @@ -865,11 +863,12 @@ impl<'a> TokenIterator<'a> { let pos = self.pos; - match c { + match (c, self.stream.peek().copied().unwrap_or('\0')) { // \n - '\n' => self.new_line(), + ('\n', _) => self.new_line(), + // digit ... - '0'..='9' => { + ('0'..='9', _) => { let mut result = Vec::new(); let mut radix_base: Option = None; result.push(c); @@ -979,8 +978,9 @@ impl<'a> TokenIterator<'a> { )); } } - // letter ... - 'A'..='Z' | 'a'..='z' | '_' => { + + // letter or underscore ... + ('A'..='Z', _) | ('a'..='z', _) | ('_', _) => { let mut result = Vec::new(); result.push(c); @@ -1034,299 +1034,241 @@ impl<'a> TokenIterator<'a> { pos, )); } - // " - string literal - '"' => { - return match self.parse_string_literal('"') { - Ok(out) => Some((Token::StringConst(out), pos)), - Err(e) => Some((Token::LexError(Box::new(e.0)), e.1)), - } - } - // ' - character literal - '\'' => match self.parse_string_literal('\'') { - Ok(result) => { - let mut chars = result.chars(); - return Some(( - if let Some(first_char) = chars.next() { - if chars.count() != 0 { - Token::LexError(Box::new(LERR::MalformedChar(format!( - "'{}'", - result - )))) - } else { - Token::CharConstant(first_char) - } + // " - string literal + ('"', _) => { + return self.parse_string_literal('"').map_or_else( + |err| Some((Token::LexError(Box::new(err.0)), err.1)), + |out| Some((Token::StringConst(out), pos)), + ); + } + + // ' - character literal + ('\'', '\'') => { + return Some(( + Token::LexError(Box::new(LERR::MalformedChar("".to_string()))), + pos, + )); + } + ('\'', _) => { + return Some(self.parse_string_literal('\'').map_or_else( + |err| (Token::LexError(Box::new(err.0)), err.1), + |result| { + let mut chars = result.chars(); + let first = chars.next(); + + if chars.next().is_some() { + (Token::LexError(Box::new(LERR::MalformedChar(result))), pos) } else { - Token::LexError(Box::new(LERR::MalformedChar(format!( - "'{}'", - result - )))) - }, - pos, - )); - } - Err(e) => return Some((Token::LexError(Box::new(e.0)), e.1)), - }, + (Token::CharConstant(first.expect("should be Some")), pos) + } + }, + )); + } // Braces - '{' => return Some((Token::LeftBrace, pos)), - '}' => return Some((Token::RightBrace, pos)), + ('{', _) => return Some((Token::LeftBrace, pos)), + ('}', _) => return Some((Token::RightBrace, pos)), // Parentheses - '(' => return Some((Token::LeftParen, pos)), - ')' => return Some((Token::RightParen, pos)), + ('(', _) => return Some((Token::LeftParen, pos)), + (')', _) => return Some((Token::RightParen, pos)), // Indexing #[cfg(not(feature = "no_index"))] - '[' => return Some((Token::LeftBracket, pos)), + ('[', _) => return Some((Token::LeftBracket, pos)), #[cfg(not(feature = "no_index"))] - ']' => return Some((Token::RightBracket, pos)), + (']', _) => return Some((Token::RightBracket, pos)), // Operators - '+' => { - return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::PlusAssign - } - _ if self.can_be_unary => Token::UnaryPlus, - _ => Token::Plus, - }, - pos, - )) + ('+', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::PlusAssign, pos)); } - '-' => match self.stream.peek() { - // Negative number? - Some('0'..='9') if self.can_be_unary => negated = true, - Some('0'..='9') => return Some((Token::Minus, pos)), - Some('=') => { - self.stream.next(); + ('+', _) if self.can_be_unary => return Some((Token::UnaryPlus, pos)), + ('+', _) => return Some((Token::Plus, pos)), + + ('-', '0'..='9') if self.can_be_unary => negated = true, + ('-', '0'..='9') => return Some((Token::Minus, pos)), + ('-', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::MinusAssign, pos)); + } + ('-', _) if self.can_be_unary => return Some((Token::UnaryMinus, pos)), + ('-', _) => return Some((Token::Minus, pos)), + + ('*', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::MultiplyAssign, pos)); + } + ('*', _) => return Some((Token::Multiply, pos)), + + // Comments + ('/', '/') => { + self.stream.next(); + self.advance(); + + while let Some(c) = self.stream.next() { + if c == '\n' { + self.new_line(); + break; + } + self.advance(); - return Some((Token::MinusAssign, pos)); } - _ if self.can_be_unary => return Some((Token::UnaryMinus, pos)), - _ => return Some((Token::Minus, pos)), - }, - '*' => { - return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::MultiplyAssign - } - _ => Token::Multiply, - }, - pos, - )) } - '/' => match self.stream.peek() { - Some(&'/') => { - self.stream.next(); + ('/', '*') => { + let mut level = 1; + + self.stream.next(); + self.advance(); + + while let Some(c) = self.stream.next() { self.advance(); - while let Some(c) = self.stream.next() { - match c { - '\n' => { - self.new_line(); - break; + + match c { + '/' => { + if self.stream.next() == Some('*') { + level += 1; } - _ => self.advance(), + self.advance(); } + '*' => { + if self.stream.next() == Some('/') { + level -= 1; + } + self.advance(); + } + '\n' => self.new_line(), + _ => (), + } + + if level == 0 { + break; } } - Some(&'*') => { - let mut level = 1; - self.stream.next(); - self.advance(); - while let Some(c) = self.stream.next() { + } + + ('/', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::DivideAssign, pos)); + } + ('/', _) => return Some((Token::Divide, pos)), + + (';', _) => return Some((Token::SemiColon, pos)), + (':', _) => return Some((Token::Colon, pos)), + (',', _) => return Some((Token::Comma, pos)), + ('.', _) => return Some((Token::Period, pos)), + + ('=', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::EqualsTo, pos)); + } + ('=', _) => return Some((Token::Equals, pos)), + + ('<', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::LessThanEqualsTo, pos)); + } + ('<', '<') => { + self.stream.next(); + self.advance(); + + return Some(( + if self.stream.peek() == Some(&'=') { + self.stream.next(); self.advance(); + Token::LeftShiftAssign + } else { + Token::LeftShift + }, + pos, + )); + } + ('<', _) => return Some((Token::LessThan, pos)), - match c { - '/' => { - if let Some('*') = self.stream.next() { - level += 1; - } - self.advance(); - } - '*' => { - if let Some('/') = self.stream.next() { - level -= 1; - } - self.advance(); - } - '\n' => self.new_line(), - _ => (), - } + ('>', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::GreaterThanEqualsTo, pos)); + } + ('>', '>') => { + self.stream.next(); + self.advance(); - if level == 0 { - break; - } - } - } - Some(&'=') => { - self.stream.next(); - self.advance(); - return Some((Token::DivideAssign, pos)); - } - _ => return Some((Token::Divide, pos)), - }, - ';' => return Some((Token::SemiColon, pos)), - ':' => return Some((Token::Colon, pos)), - ',' => return Some((Token::Comma, pos)), - '.' => return Some((Token::Period, pos)), - '=' => match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - return Some((Token::EqualsTo, pos)); - } - _ => return Some((Token::Equals, pos)), - }, - '<' => match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - return Some((Token::LessThanEqualsTo, pos)); - } - Some(&'<') => { - self.stream.next(); - self.advance(); - return match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Some((Token::LeftShiftAssign, pos)) - } - _ => { - self.stream.next(); - self.advance(); - Some((Token::LeftShift, pos)) - } - }; - } - _ => return Some((Token::LessThan, pos)), - }, - '>' => { return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::GreaterThanEqualsTo - } - Some(&'>') => { - self.stream.next(); - self.advance(); - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::RightShiftAssign - } - _ => { - self.stream.next(); - self.advance(); - Token::RightShift - } - } - } - _ => Token::GreaterThan, + if self.stream.peek() == Some(&'=') { + self.stream.next(); + self.advance(); + Token::RightShiftAssign + } else { + Token::RightShift }, pos, - )) + )); } - '!' => { - return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::NotEqualsTo - } - _ => Token::Bang, - }, - pos, - )) + ('>', _) => return Some((Token::GreaterThan, pos)), + + ('!', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::NotEqualsTo, pos)); } - '|' => { - return Some(( - match self.stream.peek() { - Some(&'|') => { - self.stream.next(); - self.advance(); - Token::Or - } - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::OrAssign - } - _ => Token::Pipe, - }, - pos, - )) + ('!', _) => return Some((Token::Bang, pos)), + + ('|', '|') => { + self.stream.next(); + self.advance(); + return Some((Token::Or, pos)); } - '&' => { - return Some(( - match self.stream.peek() { - Some(&'&') => { - self.stream.next(); - self.advance(); - Token::And - } - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::AndAssign - } - _ => Token::Ampersand, - }, - pos, - )) + ('|', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::OrAssign, pos)); } - '^' => { - return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::XOrAssign - } - _ => Token::XOr, - }, - pos, - )) + ('|', _) => return Some((Token::Pipe, pos)), + + ('&', '&') => { + self.stream.next(); + self.advance(); + return Some((Token::And, pos)); } - '%' => { - return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::ModuloAssign - } - _ => Token::Modulo, - }, - pos, - )) + ('&', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::AndAssign, pos)); } - '~' => { - return Some(( - match self.stream.peek() { - Some(&'=') => { - self.stream.next(); - self.advance(); - Token::PowerOfAssign - } - _ => Token::PowerOf, - }, - pos, - )) + ('&', _) => return Some((Token::Ampersand, pos)), + + ('^', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::XOrAssign, pos)); } - x if x.is_whitespace() => (), - x => return Some((Token::LexError(Box::new(LERR::UnexpectedChar(x))), pos)), + ('^', _) => return Some((Token::XOr, pos)), + + ('%', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::ModuloAssign, pos)); + } + ('%', _) => return Some((Token::Modulo, pos)), + + ('~', '=') => { + self.stream.next(); + self.advance(); + return Some((Token::PowerOfAssign, pos)); + } + ('~', _) => return Some((Token::PowerOf, pos)), + + (ch, _) if ch.is_whitespace() => (), + (ch, _) => return Some((Token::LexError(Box::new(LERR::UnexpectedChar(ch))), pos)), } } @@ -1361,13 +1303,9 @@ fn parse_paren_expr<'a>( begin: Position, allow_stmt_expr: bool, ) -> Result { - match input.peek() { - // () - Some((Token::RightParen, _)) => { - input.next(); - return Ok(Expr::Unit(begin)); - } - _ => (), + if matches!(input.peek(), Some((Token::RightParen, _))) { + input.next(); + return Ok(Expr::Unit(begin)); } let expr = parse_expr(input, allow_stmt_expr)?; @@ -1377,16 +1315,12 @@ fn parse_paren_expr<'a>( Some((Token::RightParen, _)) => Ok(expr), // ( xxx ??? Some((_, pos)) => { - return Err(ParseError::new( - PERR::MissingRightParen("a matching ( in the expression".into()), - pos, - )) + Err(PERR::MissingRightParen("a matching ( in the expression".into()).into_err(pos)) } // ( xxx - None => Err(ParseError::new( - PERR::MissingRightParen("a matching ( in the expression".into()), - Position::eof(), - )), + None => { + Err(PERR::MissingRightParen("a matching ( in the expression".into()).into_err_eof()) + } } } @@ -1401,13 +1335,11 @@ fn parse_call_expr<'a>( // id() if let (Token::RightParen, _) = input.peek().ok_or_else(|| { - ParseError::new( - PERR::MissingRightParen(format!( - "closing the arguments to call of function '{}'", - id - )), - Position::eof(), - ) + PERR::MissingRightParen(format!( + "closing the arguments to call of function '{}'", + id + )) + .into_err_eof() })? { input.next(); return Ok(Expr::FunctionCall(id, args_expr_list, None, begin)); @@ -1417,13 +1349,11 @@ fn parse_call_expr<'a>( args_expr_list.push(parse_expr(input, allow_stmt_expr)?); match input.peek().ok_or_else(|| { - ParseError::new( - PERR::MissingRightParen(format!( - "closing the arguments to call of function '{}'", - id - )), - Position::eof(), - ) + PERR::MissingRightParen(format!( + "closing the arguments to call of function '{}'", + id + )) + .into_err_eof() })? { (Token::RightParen, _) => { input.next(); @@ -1431,13 +1361,11 @@ fn parse_call_expr<'a>( } (Token::Comma, _) => (), (_, pos) => { - return Err(ParseError::new( - PERR::MissingComma(format!( - "separating the arguments to call of function '{}'", - id - )), - *pos, + return Err(PERR::MissingComma(format!( + "separating the arguments to call of function '{}'", + id )) + .into_err(*pos)) } } @@ -1459,84 +1387,69 @@ fn parse_index_expr<'a>( match &idx_expr { // lhs[int] Expr::IntegerConstant(i, pos) if *i < 0 => { - return Err(ParseError::new( - PERR::MalformedIndexExpr(format!( - "Array access expects non-negative index: {} < 0", - i - )), - *pos, + return Err(PERR::MalformedIndexExpr(format!( + "Array access expects non-negative index: {} < 0", + i )) + .into_err(*pos)) } // lhs[float] #[cfg(not(feature = "no_float"))] Expr::FloatConstant(_, pos) => { - return Err(ParseError::new( - PERR::MalformedIndexExpr("Array access expects integer index, not a float".into()), - *pos, - )) + return Err(PERR::MalformedIndexExpr( + "Array access expects integer index, not a float".into(), + ) + .into_err(*pos)) } // lhs[char] Expr::CharConstant(_, pos) => { - return Err(ParseError::new( - PERR::MalformedIndexExpr( - "Array access expects integer index, not a character".into(), - ), - *pos, - )) + return Err(PERR::MalformedIndexExpr( + "Array access expects integer index, not a character".into(), + ) + .into_err(*pos)) } // lhs[string] Expr::StringConstant(_, pos) => { - return Err(ParseError::new( - PERR::MalformedIndexExpr("Array access expects integer index, not a string".into()), - *pos, - )) + return Err(PERR::MalformedIndexExpr( + "Array access expects integer index, not a string".into(), + ) + .into_err(*pos)) } // lhs[??? = ??? ], lhs[()] Expr::Assignment(_, _, pos) | Expr::Unit(pos) => { - return Err(ParseError::new( - PERR::MalformedIndexExpr("Array access expects integer index, not ()".into()), - *pos, - )) + return Err(PERR::MalformedIndexExpr( + "Array access expects integer index, not ()".into(), + ) + .into_err(*pos)) } // lhs[??? && ???], lhs[??? || ???] Expr::And(lhs, _) | Expr::Or(lhs, _) => { - return Err(ParseError::new( - PERR::MalformedIndexExpr( - "Array access expects integer index, not a boolean".into(), - ), - lhs.position(), - )) + return Err(PERR::MalformedIndexExpr( + "Array access expects integer index, not a boolean".into(), + ) + .into_err(lhs.position())) } // lhs[true], lhs[false] Expr::True(pos) | Expr::False(pos) => { - return Err(ParseError::new( - PERR::MalformedIndexExpr( - "Array access expects integer index, not a boolean".into(), - ), - *pos, - )) + return Err(PERR::MalformedIndexExpr( + "Array access expects integer index, not a boolean".into(), + ) + .into_err(*pos)) } // All other expressions _ => (), } // Check if there is a closing bracket - match input.peek().ok_or_else(|| { - ParseError::new( - PERR::MissingRightBracket("index expression".into()), - Position::eof(), - ) - })? { + match input + .peek() + .ok_or_else(|| PERR::MissingRightBracket("index expression".into()).into_err_eof())? + { (Token::RightBracket, _) => { input.next(); - return Ok(Expr::Index(lhs, Box::new(idx_expr), pos)); - } - (_, pos) => { - return Err(ParseError::new( - PERR::MissingRightBracket("index expression".into()), - *pos, - )) + Ok(Expr::Index(lhs, Box::new(idx_expr), pos)) } + (_, pos) => Err(PERR::MissingRightBracket("index expression".into()).into_err(*pos)), } } @@ -1606,19 +1519,15 @@ fn parse_array_literal<'a>( } match input.peek().ok_or_else(|| { - ParseError::new( - PERR::MissingRightBracket("the end of array literal".into()), - Position::eof(), - ) + PERR::MissingRightBracket("the end of array literal".into()).into_err_eof() })? { (Token::RightBracket, _) => { input.next(); Ok(Expr::Array(arr, begin)) } - (_, pos) => Err(ParseError::new( - PERR::MissingRightBracket("the end of array literal".into()), - *pos, - )), + (_, pos) => { + Err(PERR::MissingRightBracket("the end of array literal".into()).into_err(*pos)) + } } } @@ -1629,7 +1538,7 @@ fn parse_primary<'a>( ) -> Result { let token = match input .peek() - .ok_or_else(|| ParseError::new(PERR::UnexpectedEOF, Position::eof()))? + .ok_or_else(|| PERR::UnexpectedEOF.into_err_eof())? { // { - block statement as expression (Token::LeftBrace, pos) if allow_stmt_expr => { @@ -1667,11 +1576,10 @@ fn parse_primary<'a>( } (Token::True, pos) => Ok(Expr::True(pos)), (Token::False, pos) => Ok(Expr::False(pos)), - (Token::LexError(err), pos) => Err(ParseError::new(PERR::BadInput(err.to_string()), pos)), - (token, pos) => Err(ParseError::new( - PERR::BadInput(format!("Unexpected '{}'", token.syntax())), - pos, - )), + (Token::LexError(err), pos) => Err(PERR::BadInput(err.to_string()).into_err(pos)), + (token, pos) => { + Err(PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(pos)) + } }?; if can_be_indexed { @@ -1694,7 +1602,7 @@ fn parse_unary<'a>( ) -> Result { match input .peek() - .ok_or_else(|| ParseError::new(PERR::UnexpectedEOF, Position::eof()))? + .ok_or_else(|| PERR::UnexpectedEOF.into_err_eof())? { // -expr (Token::UnaryMinus, pos) => { @@ -1715,10 +1623,8 @@ fn parse_unary<'a>( return None; }) .ok_or_else(|| { - ParseError::new( - PERR::BadInput(LERR::MalformedNumber(format!("-{}", i)).to_string()), - pos, - ) + PERR::BadInput(LERR::MalformedNumber(format!("-{}", i)).to_string()) + .into_err(pos) }), // Negative float @@ -1783,13 +1689,10 @@ fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result Some(ParseError::new( - match idx_lhs.as_ref() { - Expr::Index(_, _, _) => ParseErrorType::AssignmentToCopy, - _ => ParseErrorType::AssignmentToInvalidLHS, - }, - *pos, - )), + Expr::Index(idx_lhs, _, pos) => match idx_lhs.as_ref() { + Expr::Index(_, _, _) => Some(ParseErrorType::AssignmentToCopy.into_err(*pos)), + _ => Some(ParseErrorType::AssignmentToInvalidLHS.into_err(*pos)), + }, // dot_lhs.dot_rhs Expr::Dot(dot_lhs, dot_rhs, _) => match dot_lhs.as_ref() { @@ -1813,18 +1716,14 @@ fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result Some(ParseError::new( - ParseErrorType::AssignmentToCopy, - idx_lhs.position(), - )), + Expr::Index(idx_lhs, _, _) => { + Some(ParseErrorType::AssignmentToCopy.into_err(idx_lhs.position())) + } expr => panic!("unexpected dot expression {:#?}", expr), }, - _ => Some(ParseError::new( - ParseErrorType::AssignmentToInvalidLHS, - expr.position(), - )), + _ => Some(ParseErrorType::AssignmentToInvalidLHS.into_err(expr.position())), } } @@ -1990,12 +1889,7 @@ fn parse_binary_op<'a>( Token::ModuloAssign => parse_op_assignment("%", current_lhs, rhs, pos)?, Token::PowerOf => Expr::FunctionCall("~".into(), vec![current_lhs, rhs], None, pos), Token::PowerOfAssign => parse_op_assignment("~", current_lhs, rhs, pos)?, - token => { - return Err(ParseError::new( - PERR::UnknownOperator(token.syntax().into()), - pos, - )) - } + token => return Err(PERR::UnknownOperator(token.syntax().into()).into_err(pos)), }; } } @@ -2103,25 +1997,20 @@ fn parse_for<'a>( // for name ... let name = match input .next() - .ok_or_else(|| ParseError::new(PERR::VariableExpected, Position::eof()))? + .ok_or_else(|| PERR::VariableExpected.into_err_eof())? { // Variable name (Token::Identifier(s), _) => s, // Bad identifier - (Token::LexError(err), pos) => { - return Err(ParseError::new(PERR::BadInput(err.to_string()), pos)) - } + (Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), // Not a variable name - (_, pos) => return Err(ParseError::new(PERR::VariableExpected, pos)), + (_, pos) => return Err(PERR::VariableExpected.into_err(pos)), }; // for name in ... - match input - .next() - .ok_or_else(|| ParseError::new(PERR::MissingIn, Position::eof()))? - { + match input.next().ok_or_else(|| PERR::MissingIn.into_err_eof())? { (Token::In, _) => (), - (_, pos) => return Err(ParseError::new(PERR::MissingIn, pos)), + (_, pos) => return Err(PERR::MissingIn.into_err(pos)), } // for name in expr { body } @@ -2144,13 +2033,11 @@ fn parse_let<'a>( // let name ... let (name, pos) = match input .next() - .ok_or_else(|| ParseError::new(PERR::VariableExpected, Position::eof()))? + .ok_or_else(|| PERR::VariableExpected.into_err_eof())? { (Token::Identifier(s), pos) => (s, pos), - (Token::LexError(err), pos) => { - return Err(ParseError::new(PERR::BadInput(err.to_string()), pos)) - } - (_, pos) => return Err(ParseError::new(PERR::VariableExpected, pos)), + (Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)), + (_, pos) => return Err(PERR::VariableExpected.into_err(pos)), }; // let name = ... @@ -2169,7 +2056,7 @@ fn parse_let<'a>( } // const name = expr - error VariableType::Constant => Err(ParseError( - PERR::ForbiddenConstantExpr(name.to_string()), + PERR::ForbiddenConstantExpr(name), init_value.position(), )), } @@ -2188,10 +2075,10 @@ fn parse_block<'a>( // Must start with { let pos = match input .next() - .ok_or_else(|| ParseError::new(PERR::MissingLeftBrace, Position::eof()))? + .ok_or_else(|| PERR::MissingLeftBrace.into_err_eof())? { (Token::LeftBrace, pos) => pos, - (_, pos) => return Err(ParseError::new(PERR::MissingLeftBrace, pos)), + (_, pos) => return Err(PERR::MissingLeftBrace.into_err(pos)), }; let mut statements = Vec::new(); @@ -2221,28 +2108,20 @@ fn parse_block<'a>( // { ... stmt ??? - error Some((_, pos)) => { // Semicolons are not optional between statements - return Err(ParseError::new( - PERR::MissingSemicolon("terminating a statement".into()), - *pos, - )); + return Err(PERR::MissingSemicolon("terminating a statement".into()).into_err(*pos)); } } } - match input.peek().ok_or_else(|| { - ParseError::new( - PERR::MissingRightBrace("end of block".into()), - Position::eof(), - ) - })? { + match input + .peek() + .ok_or_else(|| PERR::MissingRightBrace("end of block".into()).into_err_eof())? + { (Token::RightBrace, _) => { input.next(); Ok(Stmt::Block(statements, pos)) } - (_, pos) => Err(ParseError::new( - PERR::MissingRightBrace("end of block".into()), - *pos, - )), + (_, pos) => Err(PERR::MissingRightBrace("end of block".into()).into_err(*pos)), } } @@ -2271,7 +2150,7 @@ fn parse_stmt<'a>( // fn ... #[cfg(not(feature = "no_function"))] - (Token::Fn, pos) => return Err(ParseError::new(PERR::WrongFnDefinition, *pos)), + (Token::Fn, pos) => Err(PERR::WrongFnDefinition.into_err(*pos)), (Token::If, _) => parse_if(input, breakable, allow_stmt_expr), (Token::While, _) => parse_while(input, allow_stmt_expr), @@ -2282,7 +2161,7 @@ fn parse_stmt<'a>( input.next(); Ok(Stmt::Break(pos)) } - (Token::Break, pos) => return Err(ParseError::new(PERR::LoopBreak, *pos)), + (Token::Break, pos) => Err(PERR::LoopBreak.into_err(*pos)), (token @ Token::Return, pos) | (token @ Token::Throw, pos) => { let return_type = match token { Token::Return => ReturnType::Return, @@ -2302,7 +2181,6 @@ fn parse_stmt<'a>( Some((_, _)) => { let expr = parse_expr(input, allow_stmt_expr)?; let pos = expr.position(); - Ok(Stmt::ReturnWithVal(Some(Box::new(expr)), return_type, pos)) } } @@ -2324,20 +2202,20 @@ fn parse_fn<'a>( let name = match input .next() - .ok_or_else(|| ParseError::new(PERR::FnMissingName, Position::eof()))? + .ok_or_else(|| PERR::FnMissingName.into_err_eof())? { (Token::Identifier(s), _) => s, - (_, pos) => return Err(ParseError::new(PERR::FnMissingName, pos)), + (_, pos) => return Err(PERR::FnMissingName.into_err(pos)), }; match input .peek() - .ok_or_else(|| ParseError::new(PERR::FnMissingParams(name.clone()), Position::eof()))? + .ok_or_else(|| PERR::FnMissingParams(name.clone()).into_err_eof())? { (Token::LeftParen, _) => { input.next(); } - (_, pos) => return Err(ParseError::new(PERR::FnMissingParams(name), *pos)), + (_, pos) => return Err(PERR::FnMissingParams(name).into_err(*pos)), } let mut params = Vec::new(); @@ -2345,67 +2223,36 @@ fn parse_fn<'a>( if matches!(input.peek(), Some((Token::RightParen, _))) { input.next(); } else { + let end_err = format!("closing the parameters list of function '{}'", name); + let sep_err = format!("separating the parameters of function '{}'", name); + loop { - match input.next().ok_or_else(|| { - ParseError::new( - PERR::MissingRightParen(format!( - "closing the parameters list of function '{}'", - name - )), - Position::eof(), - ) - })? { + match input + .next() + .ok_or_else(|| PERR::MissingRightParen(end_err.to_string()).into_err_eof())? + { (Token::Identifier(s), _) => { - params.push(s.into()); - } - (_, pos) => { - return Err(ParseError::new( - PERR::MissingRightParen(format!( - "closing the parameters list of function '{}'", - name - )), - pos, - )) + params.push(s); } + (_, pos) => return Err(PERR::MissingRightParen(end_err).into_err(pos)), } - match input.next().ok_or_else(|| { - ParseError::new( - PERR::MissingRightParen(format!( - "closing the parameters list of function '{}'", - name - )), - Position::eof(), - ) - })? { + match input + .next() + .ok_or_else(|| PERR::MissingRightParen(end_err.to_string()).into_err_eof())? + { (Token::RightParen, _) => break, (Token::Comma, _) => (), - (Token::Identifier(_), _) => { - return Err(ParseError::new( - PERR::MissingComma(format!( - "separating the parameters of function '{}'", - name - )), - pos, - )) - } - (_, pos) => { - return Err(ParseError::new( - PERR::MissingRightParen(format!( - "closing the parameters list of function '{}'", - name - )), - pos, - )) - } + (Token::Identifier(_), _) => return Err(PERR::MissingComma(sep_err).into_err(pos)), + (_, pos) => return Err(PERR::MissingRightParen(sep_err).into_err(pos)), } } } let body = match input.peek() { Some((Token::LeftBrace, _)) => parse_block(input, false, allow_stmt_expr)?, - Some((_, pos)) => return Err(ParseError::new(PERR::FnMissingBody(name), *pos)), - None => return Err(ParseError::new(PERR::FnMissingBody(name), Position::eof())), + Some((_, pos)) => return Err(PERR::FnMissingBody(name).into_err(*pos)), + None => return Err(PERR::FnMissingBody(name).into_err_eof()), }; Ok(FnDef { @@ -2425,10 +2272,7 @@ pub fn parse_global_expr<'a, 'e>( if let Some((token, pos)) = input.peek() { // Return error if the expression doesn't end - return Err(ParseError::new( - PERR::BadInput(format!("Unexpected '{}'", token.syntax())), - *pos, - )); + return Err(PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(*pos)); } Ok( @@ -2487,10 +2331,7 @@ fn parse_global_level<'a>( // stmt ??? - error Some((_, pos)) => { // Semicolons are not optional between statements - return Err(ParseError::new( - PERR::MissingSemicolon("terminating a statement".into()), - *pos, - )); + return Err(PERR::MissingSemicolon("terminating a statement".into()).into_err(*pos)); } } }