use core::{fmt, num};
use crate::descriptor::checksum;
use crate::prelude::*;
use crate::ThresholdError;
#[derive(Debug, PartialEq, Eq)]
pub enum ParseTreeError {
Checksum(checksum::Error),
MaxRecursionDepthExceeded {
actual: usize,
maximum: u32,
},
ExpectedParenOrComma {
ch: char,
pos: usize,
},
UnmatchedOpenParen {
ch: char,
pos: usize,
},
UnmatchedCloseParen {
ch: char,
pos: usize,
},
MismatchedParens {
open_ch: char,
open_pos: usize,
close_ch: char,
close_pos: usize,
},
IncorrectName {
actual: String,
expected: &'static str,
},
IncorrectNumberOfChildren {
description: &'static str,
n_children: usize,
minimum: Option<usize>,
maximum: Option<usize>,
},
IllegalCurlyBrace {
pos: usize,
},
MultipleSeparators {
separator: char,
pos: usize,
},
TrailingCharacter {
ch: char,
pos: usize,
},
UnknownName {
name: String,
},
}
impl From<checksum::Error> for ParseTreeError {
fn from(e: checksum::Error) -> Self { Self::Checksum(e) }
}
impl fmt::Display for ParseTreeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ParseTreeError::Checksum(ref e) => e.fmt(f),
ParseTreeError::MaxRecursionDepthExceeded { actual, maximum } => {
write!(f, "maximum recursion depth exceeded (max {}, got {})", maximum, actual)
}
ParseTreeError::ExpectedParenOrComma { ch, pos } => {
write!(
f,
"invalid character `{}` (position {}); expected comma or close-paren",
ch, pos
)
}
ParseTreeError::UnmatchedOpenParen { ch, pos } => {
write!(f, "`{}` (position {}) not closed", ch, pos)
}
ParseTreeError::UnmatchedCloseParen { ch, pos } => {
write!(f, "`{}` (position {}) not opened", ch, pos)
}
ParseTreeError::MismatchedParens { open_ch, open_pos, close_ch, close_pos } => {
write!(
f,
"`{}` (position {}) closed by `{}` (position {})",
open_ch, open_pos, close_ch, close_pos
)
}
ParseTreeError::IllegalCurlyBrace { pos } => {
write!(f, "illegal `{{` at position {} (Taproot branches not allowed here)", pos)
}
ParseTreeError::IncorrectName { actual, expected } => {
if expected.is_empty() {
write!(f, "found node '{}', expected nameless node", actual)
} else {
write!(f, "expected node '{}', found '{}'", expected, actual)
}
}
ParseTreeError::IncorrectNumberOfChildren {
description,
n_children,
minimum,
maximum,
} => {
write!(f, "{} must have ", description)?;
match (minimum, maximum) {
(_, Some(0)) => f.write_str("no children"),
(Some(min), Some(max)) if min == max => write!(f, "{} children", min),
(Some(min), None) if n_children < min => write!(f, "at least {} children", min),
(Some(min), Some(max)) if n_children < min => write!(f, "at least {} children (maximum {})", min, max),
(None, Some(max)) if n_children > max => write!(f, "at most {} children", max),
(Some(min), Some(max)) if n_children > max => write!(f, "at most {} children (minimum {})", max, min),
(x, y) => panic!("IncorrectNumberOfChildren error was constructed inconsistently (min {:?} max {:?})", x, y),
}?;
write!(f, ", but found {}", n_children)
}
ParseTreeError::MultipleSeparators { separator, pos } => {
write!(
f,
"separator '{}' occurred multiple times (second time at position {})",
separator, pos
)
}
ParseTreeError::TrailingCharacter { ch, pos } => {
write!(f, "trailing data `{}...` (position {})", ch, pos)
}
ParseTreeError::UnknownName { name } => write!(f, "unrecognized name '{}'", name),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseTreeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ParseTreeError::Checksum(ref e) => Some(e),
ParseTreeError::MaxRecursionDepthExceeded { .. }
| ParseTreeError::ExpectedParenOrComma { .. }
| ParseTreeError::UnmatchedOpenParen { .. }
| ParseTreeError::UnmatchedCloseParen { .. }
| ParseTreeError::MismatchedParens { .. }
| ParseTreeError::IllegalCurlyBrace { .. }
| ParseTreeError::IncorrectName { .. }
| ParseTreeError::IncorrectNumberOfChildren { .. }
| ParseTreeError::MultipleSeparators { .. }
| ParseTreeError::TrailingCharacter { .. }
| ParseTreeError::UnknownName { .. } => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParseNumError {
StdParse(num::ParseIntError),
InvalidLeadingDigit(char),
IllegalZero {
context: &'static str,
},
}
impl fmt::Display for ParseNumError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ParseNumError::StdParse(ref e) => e.fmt(f),
ParseNumError::InvalidLeadingDigit(ch) => {
write!(f, "numbers must start with 1-9, not {}", ch)
}
ParseNumError::IllegalZero { context } => {
write!(f, "{} may not be 0", context)
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseNumError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ParseNumError::StdParse(ref e) => Some(e),
ParseNumError::InvalidLeadingDigit(..) => None,
ParseNumError::IllegalZero { .. } => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParseThresholdError {
NoChildren,
KNotTerminal,
IllegalOr,
IllegalAnd,
ParseK(ParseNumError),
Threshold(ThresholdError),
}
impl fmt::Display for ParseThresholdError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ParseThresholdError::*;
match *self {
NoChildren => f.write_str("expected threshold, found terminal"),
KNotTerminal => f.write_str("expected positive integer, found expression"),
IllegalOr => f.write_str(
"1-of-n thresholds not allowed here; please use an 'or' fragment instead",
),
IllegalAnd => f.write_str(
"n-of-n thresholds not allowed here; please use an 'and' fragment instead",
),
ParseK(ref x) => write!(f, "failed to parse threshold value: {}", x),
Threshold(ref e) => e.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseThresholdError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use ParseThresholdError::*;
match *self {
NoChildren | KNotTerminal | IllegalOr | IllegalAnd => None,
ParseK(ref e) => Some(e),
Threshold(ref e) => Some(e),
}
}
}