tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
// XIR element parser generator errors
|
|
|
|
//
|
2023-01-17 23:09:25 -05:00
|
|
|
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
//
|
|
|
|
// This file is part of TAME.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
//! Parsing errors from the parser generator.
|
|
|
|
|
|
|
|
use core::fmt::Debug;
|
|
|
|
use std::{
|
|
|
|
error::Error,
|
|
|
|
fmt::{Display, Formatter},
|
|
|
|
marker::PhantomData,
|
|
|
|
};
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
diagnose::{Annotate, AnnotatedSpan, Diagnostic},
|
2022-12-01 10:35:45 -05:00
|
|
|
fmt::{DisplayFn, DisplayWrapper, TtQuote},
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
span::Span,
|
|
|
|
xir::{
|
|
|
|
attr::Attr,
|
|
|
|
flat::{RefinedText, XirfToken},
|
|
|
|
EleSpan, OpenSpan, QName,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
use super::{AttrParseState, Nt, SumNt};
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq)]
|
2022-09-14 15:35:58 -04:00
|
|
|
pub enum NtError<NT: Nt> {
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
/// An element was expected,
|
|
|
|
/// but the name of the element was unexpected.
|
|
|
|
UnexpectedEle(QName, Span),
|
|
|
|
|
|
|
|
/// Unexpected input while expecting an end tag for this
|
|
|
|
/// element.
|
|
|
|
///
|
|
|
|
/// The span corresponds to the opening tag.
|
|
|
|
CloseExpected(QName, OpenSpan, XirfToken<RefinedText>),
|
|
|
|
|
2022-09-14 15:35:58 -04:00
|
|
|
Attrs(AttrParseError<NT::AttrState>, PhantomData<NT>),
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
}
|
|
|
|
|
2022-09-14 15:35:58 -04:00
|
|
|
impl<NT, A> From<AttrParseError<A>> for NtError<NT>
|
|
|
|
where
|
|
|
|
NT: Nt<AttrState = A>,
|
|
|
|
A: AttrParseState,
|
|
|
|
{
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
fn from(e: AttrParseError<A>) -> Self {
|
|
|
|
Self::Attrs(e, PhantomData::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-14 15:35:58 -04:00
|
|
|
impl<NT: Nt> Error for NtError<NT> {
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
|
|
// TODO
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-14 15:35:58 -04:00
|
|
|
impl<NT: Nt> Display for NtError<NT> {
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
|
|
|
use crate::xir::fmt::{TtCloseXmlEle, TtOpenXmlEle};
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Self::UnexpectedEle(name, _) => write!(
|
|
|
|
f,
|
|
|
|
"unexpected {unexpected} (expecting {expected})",
|
|
|
|
unexpected = TtOpenXmlEle::wrap(name),
|
|
|
|
expected = TtOpenXmlEle::wrap(NT::matcher()),
|
|
|
|
),
|
|
|
|
|
|
|
|
Self::CloseExpected(qname, _, tok) => write!(
|
|
|
|
f,
|
|
|
|
"expected {}, but found {}",
|
|
|
|
TtCloseXmlEle::wrap(qname),
|
|
|
|
TtQuote::wrap(tok)
|
|
|
|
),
|
|
|
|
|
|
|
|
Self::Attrs(e, _) => Display::fmt(e, f),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-14 15:35:58 -04:00
|
|
|
impl<NT: Nt> Diagnostic for NtError<NT> {
|
tamer: xir::parse: Extract and generalize NT errors
This is the same as the previous commits, but for non-sum NTs.
This also extracts errors into a separate module, which I had hoped to do in
a separate commit, but it's not worth separating them. My _original_ reason
for doing so was debugging (I'll get into that below), but I had wanted to
trim down `ele.rs` anyway, since that mess is large and a lot to grok.
My debugging was trying to figure out why Rust was failing to derive
`PartialEq` on `NtError` because of `AttrParseError`. As it turns out,
`AttrParseError::InvalidValue` was failing, thus the introduction of the
`PartialEq` trait bound on `AttrParseState::ValueError`. Figuring this out
required implementing `PartialEq` myself without `derive` (well, using LSP,
which did all the work for me).
I'm not sure why this was not failing previously, which is a bit of a
concern, though perhaps in the context of the macro-expanded code, Rust was
able to properly resolve the types.
DEV-7145
2022-09-13 15:39:10 -04:00
|
|
|
fn describe(&self) -> Vec<crate::diagnose::AnnotatedSpan> {
|
|
|
|
use crate::{parse::Token, xir::fmt::TtCloseXmlEle};
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Self::UnexpectedEle(_, ospan) => ospan
|
|
|
|
.error(format!(
|
|
|
|
"expected {ele_name} here",
|
|
|
|
ele_name = TtQuote::wrap(NT::matcher())
|
|
|
|
))
|
|
|
|
.into(),
|
|
|
|
|
|
|
|
Self::CloseExpected(qname, ospan, tok) => vec![
|
|
|
|
ospan.span().note("element starts here"),
|
|
|
|
tok.span()
|
|
|
|
.error(format!("expected {}", TtCloseXmlEle::wrap(qname),)),
|
|
|
|
],
|
|
|
|
|
|
|
|
Self::Attrs(e, _) => e.describe(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Error during parsing of a sum nonterminal.
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum SumNtError<NT: SumNt> {
|
|
|
|
UnexpectedEle(QName, Span, PhantomData<NT>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<NT: SumNt> Error for SumNtError<NT> {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<NT: SumNt> Display for SumNtError<NT> {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
use crate::xir::fmt::TtOpenXmlEle;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Self::UnexpectedEle(qname, _, _) => {
|
|
|
|
write!(f, "unexpected {}", TtOpenXmlEle::wrap(qname))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<NT: SumNt> Diagnostic for SumNtError<NT> {
|
|
|
|
fn describe(&self) -> Vec<crate::diagnose::AnnotatedSpan> {
|
|
|
|
// Note that we should place expected values in the help
|
|
|
|
// footnote rather than the span label because it can
|
|
|
|
// get rather long.
|
|
|
|
// Maybe in the future the diagnostic renderer can be
|
|
|
|
// smart about that based on the terminal width and
|
|
|
|
// automatically move into the footer.
|
|
|
|
match self {
|
|
|
|
Self::UnexpectedEle(qname, span, _) => span
|
|
|
|
.error(format!(
|
|
|
|
"element {name} cannot appear here",
|
|
|
|
name = TtQuote::wrap(qname),
|
|
|
|
))
|
|
|
|
.with_help(format!(
|
|
|
|
"expecting {}",
|
|
|
|
DisplayFn(NT::fmt_matches_top)
|
|
|
|
))
|
|
|
|
.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type ElementQName = QName;
|
|
|
|
|
|
|
|
/// Error while parsing element attributes.
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum AttrParseError<S: AttrParseState> {
|
|
|
|
/// An attribute was encountered that was not expected by this parser.
|
|
|
|
///
|
|
|
|
/// Parsing may recover by simply ignoring this attribute.
|
|
|
|
UnexpectedAttr(Attr, ElementQName),
|
|
|
|
|
|
|
|
/// An error occurred while parsing an attribute value into the
|
|
|
|
/// declared type.
|
|
|
|
InvalidValue(S::ValueError, ElementQName),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: AttrParseState> Display for AttrParseError<S> {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
Self::UnexpectedAttr(attr, ele_name) => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"unexpected attribute `{attr}` for \
|
|
|
|
element `{ele_name}`"
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
Self::InvalidValue(ev, ele_name) => {
|
|
|
|
Display::fmt(ev, f)?;
|
|
|
|
write!(f, " for element {}", TtQuote::wrap(ele_name))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: AttrParseState> Error for AttrParseError<S> {
|
|
|
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<S: AttrParseState> Diagnostic for AttrParseError<S> {
|
|
|
|
fn describe(&self) -> Vec<AnnotatedSpan> {
|
|
|
|
match self {
|
|
|
|
// TODO: help stating attributes that can appear instead
|
|
|
|
Self::UnexpectedAttr(attr @ Attr(.., aspan), ele_name) => aspan
|
|
|
|
.key_span()
|
|
|
|
.error(format!("element `{ele_name}` cannot contain `{attr}`"))
|
|
|
|
.into(),
|
|
|
|
|
|
|
|
Self::InvalidValue(ev, _) => ev.describe(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|