///|
/// Why a version or a range was refused, and where.
///
/// `at` is the zero-based character index of the first offending character, or
/// the input's length when it ended early; the message says what was expected.
pub(all) suberror Refused {
// Empty input where the grammar wants a version or a range.
Empty(at~ : Int32, String)
// A character that does not belong where it stands.
Unexpected(at~ : Int32, String)
// The input ended partway through.
Truncated(at~ : Int32, String)
// A numeric component that is not a number.
Number(at~ : Int32, String)
// A numeric component, or a numeric prerelease identifier, with a leading zero
// (SemVer 2.0.0 §2, §9).
LeadingZero(at~ : Int32, String)
// An empty identifier, as in `1.0.0-` or `1.0.0-a..b`.
EmptyIdentifier(at~ : Int32, String)
// An identifier with characters §9 and §10 do not allow.
Identifier(at~ : Int32, String)
// A spelling the chosen `Syntax` does not accept.
Unsupported(at~ : Int32, String)
// A range that does not hang together, such as a concrete part after a wildcard.
Range(at~ : Int32, String)
} derive(Eq)
///|
pub extend Refused with Eq::{equal, not_equal}
///|
/// Where the input went wrong.
pub fn Refused::at(self : Refused) -> Int32 {
match self {
Empty(_, at~)
| Unexpected(_, at~)
| Truncated(_, at~)
| Number(_, at~)
| LeadingZero(_, at~)
| EmptyIdentifier(_, at~)
| Identifier(_, at~)
| Unsupported(_, at~)
| Range(_, at~) => at
}
}
///|
/// What was wrong, in words.
pub fn Refused::message(self : Refused) -> String {
match self {
Empty(m, ..)
| Unexpected(m, ..)
| Truncated(m, ..)
| Number(m, ..)
| LeadingZero(m, ..)
| EmptyIdentifier(m, ..)
| Identifier(m, ..)
| Unsupported(m, ..)
| Range(m, ..) => m
}
}
///|
pub impl Show for Refused with fn output(self, logger) {
logger.write_string(self.message() + " (at " + self.at().to_string() + ")")
}
///|
pub extend Refused with Show::{to_string, output}
///|
pub impl @debug.Debug for Refused with fn to_repr(self) {
@debug.Repr(self.to_string())
}
///|
pub extend Refused with @debug.Debug::{to_repr}
///|
/// The parser's own names for what went wrong, turned into a `Refused` by `fail`.
priv enum ErrorKind {
EmptyInput
UnexpectedChar
UnexpectedEnd
InvalidNumber
LeadingZero
EmptyIdentifier
InvalidIdentifier
UnsupportedSyntax
InvalidRange
}
///|
/// Raise a refusal. The generic return type lets it sit in a `match` arm.
fn[T] fail(
kind : ErrorKind,
message : String,
position : Int32,
) -> T raise Refused {
let at = position
raise match kind {
EmptyInput => Empty(at~, message)
UnexpectedChar => Unexpected(at~, message)
UnexpectedEnd => Truncated(at~, message)
InvalidNumber => Number(at~, message)
LeadingZero => Refused::LeadingZero(at~, message)
EmptyIdentifier => Refused::EmptyIdentifier(at~, message)
InvalidIdentifier => Identifier(at~, message)
UnsupportedSyntax => Unsupported(at~, message)
InvalidRange => Range(at~, message)
}
}