use crate::tokenizer::is_valid_identifier;
use crate::{Position, RhaiError, ERR};
#[cfg(feature = "no_std")]
use core_error::Error;
#[cfg(not(feature = "no_std"))]
use std::error::Error;
use std::fmt;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[non_exhaustive]
#[must_use]
pub enum LexError {
UnexpectedInput(String),
UnterminatedString,
StringTooLong(usize),
MalformedEscapeSequence(String),
MalformedNumber(String),
MalformedChar(String),
MalformedIdentifier(String),
ImproperSymbol(String, String),
}
impl Error for LexError {}
impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnexpectedInput(s) => write!(f, "Unexpected '{s}'"),
Self::MalformedEscapeSequence(s) => write!(f, "Invalid escape sequence: '{s}'"),
Self::MalformedNumber(s) => write!(f, "Invalid number: '{s}'"),
Self::MalformedChar(s) => write!(f, "Invalid character: '{s}'"),
Self::MalformedIdentifier(s) => write!(f, "Variable name is not proper: '{s}'"),
Self::UnterminatedString => f.write_str("Open string is not terminated"),
Self::StringTooLong(max) => write!(f, "String is too long (max {max})"),
Self::ImproperSymbol(s, d) if d.is_empty() => {
write!(f, "Invalid symbol encountered: '{s}'")
}
Self::ImproperSymbol(.., d) => f.write_str(d),
}
}
}
impl LexError {
#[cold]
#[inline(never)]
pub fn into_err(self, pos: Position) -> ParseError {
ParseError(Box::new(self.into()), pos)
}
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[non_exhaustive]
#[must_use]
pub enum ParseErrorType {
UnexpectedEOF,
BadInput(LexError),
UnknownOperator(String),
MissingToken(String, String),
MissingSymbol(String),
#[deprecated(
since = "1.16.0",
note = "This error variant is no longer used and will be removed in the next major version."
)]
MalformedCallExpr(String),
MalformedIndexExpr(String),
#[deprecated(
since = "1.16.0",
note = "This error variant is no longer used and will be removed in the next major version."
)]
MalformedInExpr(String),
MalformedCapture(String),
DuplicatedProperty(String),
#[deprecated(
since = "1.9.0",
note = "This error variant is no longer used and will be removed in the next major version."
)]
DuplicatedSwitchCase,
DuplicatedVariable(String),
WrongSwitchIntegerCase,
WrongSwitchDefaultCase,
WrongSwitchCaseCondition,
PropertyExpected,
VariableExpected,
ForbiddenVariable(String),
Reserved(String),
MismatchedType(String, String),
ExprExpected(String),
WrongDocComment,
WrongFnDefinition,
FnDuplicatedDefinition(String, usize),
FnMissingName,
FnMissingParams(String),
FnDuplicatedParam(String, String),
FnMissingBody(String),
WrongExport,
AssignmentToConstant(String),
AssignmentToInvalidLHS(String),
VariableExists(String),
VariableUndefined(String),
ModuleUndefined(String),
ExprTooDeep,
TooManyFunctions,
LiteralTooLarge(String, usize),
LoopBreak,
}
impl fmt::Display for ParseErrorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BadInput(err) => write!(f, "{err}"),
Self::UnknownOperator(s) => write!(f, "Unknown operator: '{s}'"),
Self::MalformedIndexExpr(s) if s.is_empty() => f.write_str("Invalid index in indexing expression"),
Self::MalformedIndexExpr(s) => f.write_str(s),
Self::MalformedCapture(s) if s.is_empty() => f.write_str("Invalid capturing"),
Self::MalformedCapture(s) => f.write_str(s),
Self::FnDuplicatedDefinition(s, n) => {
write!(f, "Function {s} with ")?;
match n {
0 => f.write_str("no parameters already exists"),
1 => f.write_str("1 parameter already exists"),
_ => write!(f, "{n} parameters already exists"),
}
}
Self::FnMissingBody(s) if s.is_empty() => f.write_str("Expecting body statement block for anonymous function"),
Self::FnMissingBody(s) => write!(f, "Expecting body statement block for function {s}"),
Self::FnMissingParams(s) => write!(f, "Expecting parameters for function {s}"),
Self::FnDuplicatedParam(s, arg) => write!(f, "Duplicated parameter {arg} for function {s}"),
Self::DuplicatedProperty(s) => write!(f, "Duplicated property for object map literal: {s}"),
Self::DuplicatedVariable(s) => write!(f, "Duplicated variable name: {s}"),
Self::VariableExists(s) => write!(f, "Variable already defined: {s}"),
Self::VariableUndefined(s) => write!(f, "Undefined variable: {s}"),
Self::ModuleUndefined(s) => write!(f, "Undefined module: {s}"),
Self::MismatchedType(r, a) => write!(f, "Expecting {r}, not {a}"),
Self::ExprExpected(s) => write!(f, "Expecting {s} expression"),
Self::MissingToken(token, s) => write!(f, "Expecting '{token}' {s}"),
Self::MissingSymbol(s) if s.is_empty() => f.write_str("Expecting a symbol"),
Self::MissingSymbol(s) => f.write_str(s),
Self::AssignmentToConstant(s) if s.is_empty() => f.write_str("Cannot assign to a constant value"),
Self::AssignmentToConstant(s) => write!(f, "Cannot assign to constant {s}"),
Self::AssignmentToInvalidLHS(s) if s.is_empty() => f.write_str("Expression cannot be assigned to"),
Self::AssignmentToInvalidLHS(s) => f.write_str(s),
Self::LiteralTooLarge(typ, max) => write!(f, "{typ} exceeds the maximum limit ({max})"),
Self::Reserved(s) if is_valid_identifier(s) => write!(f, "'{s}' is a reserved keyword"),
Self::Reserved(s) => write!(f, "'{s}' is a reserved symbol"),
Self::UnexpectedEOF => f.write_str("Script is incomplete"),
Self::WrongSwitchIntegerCase => f.write_str("Numeric switch case cannot follow a range case"),
Self::WrongSwitchDefaultCase => f.write_str("Default switch case must be the last"),
Self::WrongSwitchCaseCondition => f.write_str("This switch case cannot have a condition"),
Self::PropertyExpected => f.write_str("Expecting name of a property"),
Self::VariableExpected => f.write_str("Expecting name of a variable"),
Self::ForbiddenVariable(s) => write!(f, "Forbidden variable name: {s}"),
Self::WrongFnDefinition => f.write_str("Function definitions must be at global level and cannot be inside a block or another function"),
Self::FnMissingName => f.write_str("Expecting function name in function declaration"),
Self::WrongDocComment => f.write_str("Doc-comment must be followed immediately by a function definition"),
Self::WrongExport => f.write_str("Export statement can only appear at global level"),
Self::ExprTooDeep => f.write_str("Expression exceeds maximum complexity"),
Self::TooManyFunctions => f.write_str("Number of functions defined exceeds maximum limit"),
Self::LoopBreak => f.write_str("Break statement should only be used inside a loop"),
#[allow(deprecated)]
Self::DuplicatedSwitchCase => f.write_str("Duplicated switch case"),
#[allow(deprecated)]
Self::MalformedCallExpr(s) if s.is_empty() => f.write_str(s),
#[allow(deprecated)]
Self::MalformedCallExpr(..) => f.write_str("Invalid expression in function call arguments"),
#[allow(deprecated)]
Self::MalformedInExpr(s) if s.is_empty() => f.write_str("Invalid 'in' expression"),
#[allow(deprecated)]
Self::MalformedInExpr(s) => f.write_str(s),
}
}
}
impl From<LexError> for ParseErrorType {
#[cold]
#[inline(never)]
fn from(err: LexError) -> Self {
match err {
LexError::StringTooLong(max) => {
Self::LiteralTooLarge("Length of string".to_string(), max)
}
_ => Self::BadInput(err),
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[must_use]
pub struct ParseError(
pub Box<ParseErrorType>,
pub Position,
);
impl Error for ParseError {}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)?;
if !self.1.is_none() {
write!(f, " ({})", self.1)?;
}
Ok(())
}
}
impl ParseError {
#[cold]
#[inline(never)]
pub const fn err_type(&self) -> &ParseErrorType {
&self.0
}
#[cold]
#[inline(never)]
#[must_use]
pub const fn position(&self) -> Position {
self.1
}
}
impl From<ParseErrorType> for RhaiError {
#[cold]
#[inline(never)]
fn from(err: ParseErrorType) -> Self {
Self::new(err.into())
}
}
impl From<ParseErrorType> for ERR {
#[cold]
#[inline(never)]
fn from(err: ParseErrorType) -> Self {
Self::ErrorParsing(err, Position::NONE)
}
}
impl From<ParseError> for RhaiError {
#[cold]
#[inline(never)]
fn from(err: ParseError) -> Self {
Self::new(err.into())
}
}
impl From<ParseError> for ERR {
#[cold]
#[inline(never)]
fn from(err: ParseError) -> Self {
Self::ErrorParsing(*err.0, err.1)
}
}