2021-11-16 15:47:52 -05:00
|
|
|
// XIR-based xmlo object errors
|
|
|
|
//
|
|
|
|
// Copyright (C) 2014-2021 Ryan Specialty Group, LLC.
|
|
|
|
//
|
|
|
|
// 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/>.
|
|
|
|
|
|
|
|
//! Errors while processing `xmlo` object files.
|
|
|
|
|
|
|
|
use crate::sym::SymbolId;
|
|
|
|
use crate::tpwrap::quick_xml::{Error as XmlError, InnerXmlError};
|
2021-12-23 13:17:18 -05:00
|
|
|
use crate::xir::{parse::ParseError, tree::StackError};
|
2021-11-16 15:47:52 -05:00
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
|
|
/// Error during `xmlo` processing.
|
|
|
|
///
|
|
|
|
/// Errors contain only owned values rather than references to original
|
|
|
|
/// data since they represent conditions requiring termination from
|
|
|
|
/// malformed compiler output,
|
|
|
|
/// and so should rarely occur.
|
|
|
|
/// This drastically simplifies the reader and [`Result`] chaining.
|
|
|
|
///
|
|
|
|
/// TODO: These errors provide no context (byte offset).
|
|
|
|
#[derive(Debug, PartialEq)]
|
|
|
|
pub enum XmloError {
|
|
|
|
/// XML parsing error (legacy, quick-xml).
|
|
|
|
XmlError(XmlError),
|
2021-11-18 00:59:10 -05:00
|
|
|
/// XIR parsing error.
|
tamer: xir::tree: Integrate AttrParserState into Stack
Note that AttrParse{r=>}State needs renaming, and Stack will get a better
name down the line too. This commit message is accurate, but confusing.
This performs the long-awaited task of trying to observe, concretely, how to
combine two automata. This has the effect of stitching together the state
machines, such that the union of the two is equivalent to the original
monolith.
The next step will be to abstract this away.
There are some important things to note here. First, this introduces a new
"dead" state concept, where here a dead state is defined as an _accepting_
state that has no state transitions for the given input token. This is more
strict than a dead state as defined in, for example, the Dragon Book, where
backtracking may occur.
The reason I chose for a Dead state to be accepting is simple: it represents
a lookahead situation. It says, "I don't know what this token is, but I've
done my job, so it may be useful in a parent context". The "I've done my
job" part is only applicable in an accepting state.
If the parser is _not_ in an accepting state, then an unknown token is
simply an error; we should _not_ try to backtrack or anything of the sort,
because we want only a single token of lookahead.
The reason this was done is because it's otherwise difficult to compose the
two parsers without requiring that AttrEnd exist in every XIR stream; this
has always been an awkward delimiter that was introduced to make the parser
LL(0), but I tried to compromise by saying that it was optional. Of course,
I knew that decision caused awkward inconsistencies, I had just hoped that
those inconsistencies wouldn't manifest in practical issues.
Well, now it did, and the benefits of AttrEnd that we had in the previous
construction do not exist in this one. Consequently, it makes more sense to
simply go from LL(0) to LL(1), which makes AttrEnd unnecessary, and a future
commit will remove it entirely.
All of this information will be documented, but I want to get further in
the implementation first to make sure I don't change course again and
therefore waste my time on docs.
DEV-11268
2021-12-16 09:44:02 -05:00
|
|
|
XirtError(ParseError<StackError>),
|
2021-11-16 15:47:52 -05:00
|
|
|
/// The root node was not an `lv:package`.
|
|
|
|
UnexpectedRoot,
|
|
|
|
/// A `preproc:sym` node was found, but is missing `@name`.
|
|
|
|
UnassociatedSym,
|
|
|
|
/// The provided `preproc:sym/@type` is unknown or invalid.
|
|
|
|
InvalidType(String),
|
|
|
|
/// The provided `preproc:sym/@dtype` is unknown or invalid.
|
|
|
|
InvalidDtype(String),
|
|
|
|
/// The provided `preproc:sym/@dim` is invalid.
|
|
|
|
InvalidDim(String),
|
|
|
|
/// A `preproc:sym-dep` element was found, but is missing `@name`.
|
|
|
|
UnassociatedSymDep,
|
|
|
|
/// The `preproc:sym[@type="map"]` contains unexpected or invalid data.
|
|
|
|
InvalidMapFrom(String),
|
|
|
|
/// Invalid dependency in adjacency list
|
|
|
|
/// (`preproc:sym-dep/preproc:sym-ref`).
|
|
|
|
MalformedSymRef(String),
|
|
|
|
/// A `preproc:fragment` element was found, but is missing `@id`.
|
|
|
|
UnassociatedFragment,
|
|
|
|
/// A `preproc:fragment` element was found, but is missing `text()`.
|
|
|
|
MissingFragmentText(SymbolId),
|
|
|
|
/// Token stream ended unexpectedly.
|
|
|
|
UnexpectedEof,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<InnerXmlError> for XmloError {
|
|
|
|
fn from(e: InnerXmlError) -> Self {
|
|
|
|
XmloError::XmlError(e.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
tamer: xir::tree: Integrate AttrParserState into Stack
Note that AttrParse{r=>}State needs renaming, and Stack will get a better
name down the line too. This commit message is accurate, but confusing.
This performs the long-awaited task of trying to observe, concretely, how to
combine two automata. This has the effect of stitching together the state
machines, such that the union of the two is equivalent to the original
monolith.
The next step will be to abstract this away.
There are some important things to note here. First, this introduces a new
"dead" state concept, where here a dead state is defined as an _accepting_
state that has no state transitions for the given input token. This is more
strict than a dead state as defined in, for example, the Dragon Book, where
backtracking may occur.
The reason I chose for a Dead state to be accepting is simple: it represents
a lookahead situation. It says, "I don't know what this token is, but I've
done my job, so it may be useful in a parent context". The "I've done my
job" part is only applicable in an accepting state.
If the parser is _not_ in an accepting state, then an unknown token is
simply an error; we should _not_ try to backtrack or anything of the sort,
because we want only a single token of lookahead.
The reason this was done is because it's otherwise difficult to compose the
two parsers without requiring that AttrEnd exist in every XIR stream; this
has always been an awkward delimiter that was introduced to make the parser
LL(0), but I tried to compromise by saying that it was optional. Of course,
I knew that decision caused awkward inconsistencies, I had just hoped that
those inconsistencies wouldn't manifest in practical issues.
Well, now it did, and the benefits of AttrEnd that we had in the previous
construction do not exist in this one. Consequently, it makes more sense to
simply go from LL(0) to LL(1), which makes AttrEnd unnecessary, and a future
commit will remove it entirely.
All of this information will be documented, but I want to get further in
the implementation first to make sure I don't change course again and
therefore waste my time on docs.
DEV-11268
2021-12-16 09:44:02 -05:00
|
|
|
impl From<ParseError<StackError>> for XmloError {
|
|
|
|
fn from(e: ParseError<StackError>) -> Self {
|
2021-11-18 00:59:10 -05:00
|
|
|
Self::XirtError(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:47:52 -05:00
|
|
|
impl Display for XmloError {
|
|
|
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
Self::XmlError(e) => e.fmt(fmt),
|
2021-11-18 00:59:10 -05:00
|
|
|
Self::XirtError(e) => e.fmt(fmt),
|
2021-11-16 15:47:52 -05:00
|
|
|
Self::UnexpectedRoot => {
|
|
|
|
write!(fmt, "unexpected package root (is this a package?)")
|
|
|
|
}
|
|
|
|
Self::UnassociatedSym => write!(
|
|
|
|
fmt,
|
|
|
|
"unassociated symbol table entry: preproc:sym/@name missing"
|
|
|
|
),
|
|
|
|
Self::InvalidType(ty) => {
|
|
|
|
write!(fmt, "invalid preproc:sym/@type `{}`", ty)
|
|
|
|
}
|
|
|
|
Self::InvalidDtype(dtype) => {
|
|
|
|
write!(fmt, "invalid preproc:sym/@dtype `{}`", dtype)
|
|
|
|
}
|
|
|
|
Self::InvalidDim(dim) => {
|
|
|
|
write!(fmt, "invalid preproc:sym/@dim `{}`", dim)
|
|
|
|
}
|
|
|
|
Self::InvalidMapFrom(msg) => {
|
|
|
|
write!(fmt, "invalid preproc:sym[@type=\"map\"]: {}", msg)
|
|
|
|
}
|
|
|
|
Self::UnassociatedSymDep => write!(
|
|
|
|
fmt,
|
|
|
|
"unassociated dependency list: preproc:sym-dep/@name missing"
|
|
|
|
),
|
|
|
|
Self::MalformedSymRef(msg) => {
|
|
|
|
write!(fmt, "malformed dependency ref: {}", msg)
|
|
|
|
}
|
|
|
|
Self::UnassociatedFragment => write!(
|
|
|
|
fmt,
|
|
|
|
"unassociated fragment: preproc:fragment/@id missing"
|
|
|
|
),
|
|
|
|
Self::MissingFragmentText(symname) => write!(
|
|
|
|
fmt,
|
|
|
|
"fragment found, but missing text for symbol `{}`",
|
|
|
|
symname,
|
|
|
|
),
|
|
|
|
Self::UnexpectedEof => write!(fmt, "unexpected EOF"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::error::Error for XmloError {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
|
|
match self {
|
|
|
|
Self::XmlError(e) => Some(e),
|
2021-11-18 00:59:10 -05:00
|
|
|
Self::XirtError(e) => Some(e),
|
2021-11-16 15:47:52 -05:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|