1 use std::{error, fmt, io}; 2 3 use crate::{date, num::Range}; 4 5 #[derive(Debug)] 6 #[non_exhaustive] 7 pub(crate) enum FendError { 8 Interrupted, 9 InvalidBasePrefix, 10 BaseTooSmall, 11 BaseTooLarge, 12 UnableToConvertToBase, 13 DivideByZero, 14 ExponentTooLarge, 15 ValueTooLarge, 16 ZeroToThePowerOfZero, 17 FactorialComplex, 18 DeserializationError, 19 Wrap(Box<dyn error::Error + Send + Sync + 'static>), 20 NoExchangeRatesAvailable, 21 OutOfRange { 22 value: Box<dyn crate::format::DisplayDebug>, 23 range: Range<Box<dyn crate::format::DisplayDebug>>, 24 }, 25 NegativeNumbersNotAllowed, 26 ProbabilityDistributionsNotAllowed, 27 EmptyDistribution, 28 FractionToInteger, 29 ModuloByZero, 30 RandomNumbersNotAvailable, 31 MustBeAnInteger(Box<dyn crate::format::DisplayDebug>), 32 ExpectedARationalNumber, 33 CannotConvertToInteger, 34 ComplexToInteger, 35 NumberWithUnitToInt, 36 InexactNumberToInt, 37 ExpectedANumber, 38 ExpectedABool(&'static str), 39 InvalidDiceSyntax, 40 SpecifyNumDp, 41 SpecifyNumSf, 42 UnableToInvertFunction(&'static str), 43 InvalidOperandsForSubtraction, 44 InversesOfLambdasUnsupported, 45 CouldNotFindKeyInObject, 46 CouldNotFindKey(String), 47 CannotFormatWithZeroSf, 48 UnableToGetCurrentDate, 49 IsNotAFunction(String), 50 IsNotAFunctionOrNumber(String), 51 IdentifierNotFound(crate::ident::Ident), 52 ExpectedACharacter, 53 StringCannotBeLonger, 54 StringCannotBeEmpty, 55 InvalidCodepoint(usize), 56 ExpectedADigit(char), 57 ExpectedChar(char, char), 58 ExpectedDigitSeparator(char), 59 DigitSeparatorsNotAllowed, 60 DigitSeparatorsOnlyBetweenDigits, 61 InvalidCharAtBeginningOfIdent(char), 62 UnexpectedChar(char), 63 UnterminatedStringLiteral, 64 UnknownBackslashEscapeSequence(char), 65 BackslashXOutOfRange, 66 ExpectedALetterOrCode, 67 ExpectedAUnitlessNumber, 68 ExpectedAnObject, 69 InvalidUnicodeEscapeSequence, 70 FormattingError(fmt::Error), 71 IoError(io::Error), 72 ParseDateError(String), 73 ParseError(crate::parser::ParseError), 74 ExpectedAString, 75 ExpectedARealNumber, 76 ConversionRhsNumerical, 77 FactorialUnitless, 78 ModuloForPositiveInts, 79 ExpUnitless, 80 IncompatibleConversion { 81 from: String, 82 to: String, 83 from_base: String, 84 to_base: String, 85 }, 86 ModuloUnitless, 87 RootsOfNegativeNumbers, 88 NonIntegerNegRoots, 89 CannotConvertValueTo(&'static str), 90 ExpectedADateLiteral, 91 NonExistentDate { 92 year: i32, 93 month: date::Month, 94 expected_day: u8, 95 before: date::Date, 96 after: date::Date, 97 }, 98 RomanNumeralZero, 99 } 100 101 impl fmt::Display for FendError { 102 #[allow(clippy::too_many_lines)] fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 104 match self { 105 Self::Interrupted => write!(f, "interrupted"), 106 Self::ParseError(e) => write!(f, "{e}"), 107 Self::FactorialUnitless => { 108 write!(f, "factorial is only supported for unitless numbers") 109 } 110 Self::DeserializationError => write!(f, "failed to deserialize object"), 111 Self::ModuloUnitless => write!(f, "modulo is only supported for unitless numbers"), 112 Self::FactorialComplex => write!(f, "factorial is not supported for complex numbers"), 113 Self::ExpUnitless => write!(f, "exponentiation is only supported for unitless numbers"), 114 Self::IoError(_) => write!(f, "I/O error"), 115 Self::InvalidBasePrefix => write!( 116 f, 117 "unable to parse a valid base prefix, expected 0b, 0o, or 0x" 118 ), 119 Self::NoExchangeRatesAvailable => write!(f, "exchange rates are not available"), 120 Self::IncompatibleConversion { 121 from, 122 to, 123 from_base, 124 to_base, 125 } => { 126 write!( 127 f, 128 "cannot convert from {from} to {to}: units '{from_base}' and '{to_base}' are incompatible" 129 ) 130 } 131 Self::NonIntegerNegRoots => write!(f, "cannot compute non-integer or negative roots"), 132 Self::RootsOfNegativeNumbers => { 133 write!(f, "roots of negative numbers are not supported") 134 } 135 Self::ModuloForPositiveInts => { 136 write!(f, "modulo is only supported for positive integers") 137 } 138 Self::CannotConvertValueTo(ty) => write!(f, "cannot convert value to {ty}"), 139 Self::BaseTooSmall => write!(f, "base must be at least 2"), 140 Self::ConversionRhsNumerical => write!( 141 f, 142 "right-hand side of unit conversion has a numerical value" 143 ), 144 Self::BaseTooLarge => write!(f, "base cannot be larger than 36"), 145 Self::UnableToConvertToBase => write!(f, "unable to convert number to a valid base"), 146 Self::DivideByZero => write!(f, "division by zero"), 147 Self::ExponentTooLarge => write!(f, "exponent too large"), 148 Self::ValueTooLarge => write!(f, "value is too large"), 149 Self::ZeroToThePowerOfZero => write!(f, "zero to the power of zero is undefined"), 150 Self::OutOfRange { range, value } => { 151 write!(f, "{value} must lie in the interval {range}") 152 } 153 Self::ModuloByZero => write!(f, "modulo by zero"), 154 Self::SpecifyNumDp => write!( 155 f, 156 "you need to specify what number of decimal places to use, e.g. '10 dp'" 157 ), 158 Self::SpecifyNumSf => write!( 159 f, 160 "you need to specify what number of significant figures to use, e.g. '10 sf'" 161 ), 162 Self::ExpectedAUnitlessNumber => write!(f, "expected a unitless number"), 163 Self::ExpectedARealNumber => write!(f, "expected a real number"), 164 Self::StringCannotBeLonger => write!(f, "string cannot be longer than one codepoint"), 165 Self::StringCannotBeEmpty => write!(f, "string cannot be empty"), 166 Self::InvalidCodepoint(codepoint) => { 167 write!(f, "invalid codepoint: U+{codepoint:04x}") 168 } 169 Self::UnableToGetCurrentDate => write!(f, "unable to get the current date"), 170 Self::NegativeNumbersNotAllowed => write!(f, "negative numbers are not allowed"), 171 Self::ProbabilityDistributionsNotAllowed => { 172 write!( 173 f, 174 "probability distributions are not allowed (consider using `sample`)" 175 ) 176 } 177 Self::EmptyDistribution => write!(f, "there must be at least one part in a dist"), 178 Self::ParseDateError(s) => write!(f, "failed to convert '{s}' to a date"), 179 Self::ExpectedAString => write!(f, "expected a string"), 180 Self::UnableToInvertFunction(name) => write!(f, "unable to invert function {name}"), 181 Self::FractionToInteger => write!(f, "cannot convert fraction to integer"), 182 Self::RandomNumbersNotAvailable => write!(f, "random numbers are not available"), 183 Self::MustBeAnInteger(x) => write!(f, "{x} is not an integer"), 184 Self::ExpectedABool(t) => write!(f, "expected a bool (found {t})"), 185 Self::CouldNotFindKeyInObject => write!(f, "could not find key in object"), 186 Self::CouldNotFindKey(k) => write!(f, "could not find key {k}"), 187 Self::InversesOfLambdasUnsupported => write!( 188 f, 189 "inverses of lambda functions are not currently supported" 190 ), 191 Self::ExpectedARationalNumber => write!(f, "expected a rational number"), 192 Self::CannotConvertToInteger => write!(f, "number cannot be converted to an integer"), 193 Self::ComplexToInteger => write!(f, "cannot convert complex number to integer"), 194 Self::NumberWithUnitToInt => write!(f, "cannot convert number with unit to integer"), 195 Self::InexactNumberToInt => write!(f, "cannot convert inexact number to integer"), 196 Self::ExpectedANumber => write!(f, "expected a number"), 197 Self::InvalidDiceSyntax => write!(f, "invalid dice syntax, try e.g. `4d6`"), 198 Self::InvalidOperandsForSubtraction => write!(f, "invalid operands for subtraction"), 199 Self::CannotFormatWithZeroSf => { 200 write!(f, "cannot format a number with zero significant figures") 201 } 202 Self::IsNotAFunction(s) => write!(f, "'{s}' is not a function"), 203 Self::IsNotAFunctionOrNumber(s) => write!(f, "'{s}' is not a function or number"), 204 Self::IdentifierNotFound(s) => write!(f, "unknown identifier '{s}'"), 205 Self::ExpectedACharacter => write!(f, "expected a character"), 206 Self::ExpectedADigit(ch) => write!(f, "expected a digit, found '{ch}'"), 207 Self::ExpectedChar(ex, fnd) => write!(f, "expected '{ex}', found '{fnd}'"), 208 Self::ExpectedDigitSeparator(ch) => { 209 write!(f, "expected a digit separator, found {ch}") 210 } 211 Self::DigitSeparatorsNotAllowed => write!(f, "digit separators are not allowed"), 212 Self::DigitSeparatorsOnlyBetweenDigits => { 213 write!(f, "digit separators can only occur between digits") 214 } 215 Self::InvalidCharAtBeginningOfIdent(ch) => { 216 write!(f, "'{ch}' is not valid at the beginning of an identifier") 217 } 218 Self::UnexpectedChar(ch) => write!(f, "unexpected character '{ch}'"), 219 Self::UnterminatedStringLiteral => write!(f, "unterminated string literal"), 220 Self::UnknownBackslashEscapeSequence(ch) => { 221 write!(f, "unknown escape sequence: \\{ch}") 222 } 223 Self::BackslashXOutOfRange => { 224 write!(f, "expected an escape sequence between \\x00 and \\x7f") 225 } 226 Self::ExpectedALetterOrCode => { 227 write!( 228 f, 229 "expected an uppercase letter, or one of @[\\]^_? (e.g. \\^H or \\^@)" 230 ) 231 } 232 Self::ExpectedAnObject => write!(f, "expected an object"), 233 Self::InvalidUnicodeEscapeSequence => { 234 write!( 235 f, 236 "invalid Unicode escape sequence, expected e.g. \\u{{7e}}" 237 ) 238 } 239 Self::FormattingError(_) => write!(f, "error during formatting"), 240 Self::Wrap(e) => write!(f, "{e}"), 241 Self::ExpectedADateLiteral => write!(f, "Expected a date literal, e.g. @1970-01-01"), 242 Self::NonExistentDate { 243 year, 244 month, 245 expected_day, 246 before, 247 after, 248 } => { 249 write!( 250 f, 251 "{month} {expected_day}, {year} does not exist, did you mean {before} or {after}?", 252 ) 253 } 254 Self::RomanNumeralZero => write!(f, "zero cannot be represented as a roman numeral"), 255 } 256 } 257 } 258 259 impl error::Error for FendError { source(&self) -> Option<&(dyn error::Error + 'static)>260 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 261 match self { 262 Self::FormattingError(e) => Some(e), 263 Self::IoError(e) => Some(e), 264 Self::Wrap(e) => Some(e.as_ref()), 265 _ => None, 266 } 267 } 268 } 269 270 impl From<fmt::Error> for FendError { from(e: fmt::Error) -> Self271 fn from(e: fmt::Error) -> Self { 272 Self::FormattingError(e) 273 } 274 } 275 276 impl From<io::Error> for FendError { from(e: io::Error) -> Self277 fn from(e: io::Error) -> Self { 278 Self::IoError(e) 279 } 280 } 281 282 impl From<Box<dyn error::Error + Send + Sync + 'static>> for FendError { from(e: Box<dyn error::Error + Send + Sync + 'static>) -> Self283 fn from(e: Box<dyn error::Error + Send + Sync + 'static>) -> Self { 284 Self::Wrap(e) 285 } 286 } 287 288 pub(crate) use crate::interrupt::Interrupt; 289