tamer: obj::xmlo::reader: Move Xmlo{Result,Error,Event}
These will need an API change, but are otherwise shared. This means that only the XmloReader is gated.main
parent
f7d8aa1e4f
commit
c76fe87acd
|
@ -17,16 +17,211 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::tpwrap::quick_xml::{Error as XmlError, InnerXmlError};
|
||||
use crate::{
|
||||
ir::legacyir::{PackageAttrs, SymAttrs},
|
||||
sym::SymbolId,
|
||||
};
|
||||
use std::{fmt::Display, io::BufRead};
|
||||
|
||||
#[cfg(feature = "wip-xmlo-xir-reader")]
|
||||
use std::io::BufRead;
|
||||
use crate::ir::xir::reader::XmlXirReader;
|
||||
|
||||
#[cfg(not(feature = "wip-xmlo-xir-reader"))]
|
||||
mod quickxml;
|
||||
|
||||
#[cfg(not(feature = "wip-xmlo-xir-reader"))]
|
||||
pub use quickxml::{XmloError, XmloEvent, XmloReader, XmloResult};
|
||||
pub use quickxml::XmloReader;
|
||||
|
||||
/// A [`Result`] with a hard-coded [`XmloError`] error type.
|
||||
///
|
||||
/// This is the result of every [`XmloReader`] operation that could
|
||||
/// potentially fail in error.
|
||||
pub type XmloResult<T> = Result<T, XmloError>;
|
||||
|
||||
#[cfg(feature = "wip-xmlo-xir-reader")]
|
||||
pub struct XmloReader<B: BufRead> {
|
||||
todo: std::marker::PhantomData<B>,
|
||||
_reader: XmlXirReader<B>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wip-xmlo-xir-reader")]
|
||||
impl<B: BufRead> XmloReader<B> {
|
||||
pub fn new(reader: B) -> Self {
|
||||
let reader = XmlXirReader::new(reader);
|
||||
|
||||
Self { _reader: reader }
|
||||
}
|
||||
|
||||
pub fn read_event<'a>(&mut self) -> XmloResult<XmloEvent> {
|
||||
todo!("XmloReader::read_event")
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Iterator for XmloReader<B>
|
||||
where
|
||||
B: BufRead,
|
||||
{
|
||||
type Item = XmloResult<XmloEvent>;
|
||||
|
||||
/// Invoke [`XmloReader::read_event`] and yield the result via an
|
||||
/// [`Iterator`] API.
|
||||
///
|
||||
/// *Warning*: This will always return [`Some`] for now.
|
||||
/// Future changes may alter this behavior.
|
||||
/// To terminate the iterator,
|
||||
/// it's recommended that you use [`Iterator::take_while`] to filter
|
||||
/// on the desired predicate,
|
||||
/// such as [`XmloEvent::Eoh`].
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
Some(self.read_event())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> From<B> for XmloReader<B>
|
||||
where
|
||||
B: BufRead,
|
||||
{
|
||||
fn from(buf: B) -> Self {
|
||||
Self::new(buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// `xmlo` reader events.
|
||||
///
|
||||
/// All data are parsed rather than being returned as [`u8`] slices,
|
||||
/// which avoids having to deal with awkward borrows or data copying since
|
||||
/// these data will likely be persisted in memory anyway.
|
||||
///
|
||||
/// To avoid extra data copying,
|
||||
/// we should instead prefer not to put data into object files that won't
|
||||
/// be useful and can't be easily skipped without parsing.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum XmloEvent {
|
||||
/// Package declaration.
|
||||
///
|
||||
/// This contains data gathered from the root `lv:package` node.
|
||||
Package(PackageAttrs),
|
||||
|
||||
/// Symbol declaration.
|
||||
///
|
||||
/// This represents an entry in the symbol table,
|
||||
/// which includes a symbol along with its variable metadata as
|
||||
/// [`SymAttrs`].
|
||||
SymDecl(SymbolId, SymAttrs),
|
||||
|
||||
/// Dependencies of a given symbol.
|
||||
///
|
||||
/// Note that, for simplicity, an owned vector is returned rather than a
|
||||
/// slice into an internal buffer.
|
||||
SymDeps(SymbolId, Vec<SymbolId>),
|
||||
|
||||
/// Text (compiled code) fragment for a given symbol.
|
||||
///
|
||||
/// This contains the compiler output for a given symbol,
|
||||
/// and is returned here as an owned value.
|
||||
/// Given that fragments can be quite large,
|
||||
/// a caller not interested in these data should choose to skip
|
||||
/// fragments entirely rather than simply ignoring fragment events.
|
||||
Fragment(SymbolId, SymbolId),
|
||||
|
||||
/// End-of-header.
|
||||
///
|
||||
/// The header of an `xmlo` file is defined as the symbol table;
|
||||
/// dependency list; and fragments.
|
||||
/// This event is emitted at the closing `preproc:fragment` node.
|
||||
Eoh,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
XmlError(XmlError),
|
||||
/// 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),
|
||||
}
|
||||
|
||||
impl From<InnerXmlError> for XmloError {
|
||||
fn from(e: InnerXmlError) -> Self {
|
||||
XmloError::XmlError(e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for XmloError {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
XmloError::XmlError(e) => e.fmt(fmt),
|
||||
XmloError::UnexpectedRoot => {
|
||||
write!(fmt, "unexpected package root (is this a package?)")
|
||||
}
|
||||
XmloError::UnassociatedSym => write!(
|
||||
fmt,
|
||||
"unassociated symbol table entry: preproc:sym/@name missing"
|
||||
),
|
||||
XmloError::InvalidType(ty) => {
|
||||
write!(fmt, "invalid preproc:sym/@type `{}`", ty)
|
||||
}
|
||||
XmloError::InvalidDtype(dtype) => {
|
||||
write!(fmt, "invalid preproc:sym/@dtype `{}`", dtype)
|
||||
}
|
||||
XmloError::InvalidDim(dim) => {
|
||||
write!(fmt, "invalid preproc:sym/@dim `{}`", dim)
|
||||
}
|
||||
XmloError::InvalidMapFrom(msg) => {
|
||||
write!(fmt, "invalid preproc:sym[@type=\"map\"]: {}", msg)
|
||||
}
|
||||
XmloError::UnassociatedSymDep => write!(
|
||||
fmt,
|
||||
"unassociated dependency list: preproc:sym-dep/@name missing"
|
||||
),
|
||||
XmloError::MalformedSymRef(msg) => {
|
||||
write!(fmt, "malformed dependency ref: {}", msg)
|
||||
}
|
||||
XmloError::UnassociatedFragment => write!(
|
||||
fmt,
|
||||
"unassociated fragment: preproc:fragment/@id missing"
|
||||
),
|
||||
XmloError::MissingFragmentText(symname) => write!(
|
||||
fmt,
|
||||
"fragment found, but missing text for symbol `{}`",
|
||||
symname,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for XmloError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::XmlError(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,6 +136,7 @@
|
|||
//! # }
|
||||
//! ```
|
||||
|
||||
use super::{XmloError, XmloEvent, XmloResult};
|
||||
use crate::ir::legacyir::{PackageAttrs, SymAttrs, SymType};
|
||||
use crate::sym::{GlobalSymbolInternUnchecked, GlobalSymbolResolve, SymbolId};
|
||||
#[cfg(test)]
|
||||
|
@ -144,7 +145,6 @@ use crate::test::quick_xml::MockBytesStart as BytesStart;
|
|||
use crate::test::quick_xml::MockXmlEvent as XmlEvent;
|
||||
#[cfg(test)]
|
||||
use crate::test::quick_xml::MockXmlReader as XmlReader;
|
||||
use crate::tpwrap::quick_xml::{Error as XmlError, InnerXmlError};
|
||||
#[cfg(not(test))]
|
||||
use quick_xml::events::BytesStart;
|
||||
#[cfg(not(test))]
|
||||
|
@ -152,17 +152,10 @@ use quick_xml::events::Event as XmlEvent;
|
|||
#[cfg(not(test))]
|
||||
use quick_xml::Reader as XmlReader;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Display;
|
||||
use std::io::BufRead;
|
||||
use std::iter::Iterator;
|
||||
use std::result::Result;
|
||||
|
||||
/// A [`Result`] with a hard-coded [`XmloError`] error type.
|
||||
///
|
||||
/// This is the result of every [`XmloReader`] operation that could
|
||||
/// potentially fail in error.
|
||||
pub type XmloResult<T> = Result<T, XmloError>;
|
||||
|
||||
/// Wrapper around [`quick_xml::Reader`] for reading and parsing `xmlo`
|
||||
/// object files.
|
||||
///
|
||||
|
@ -690,174 +683,5 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<B> Iterator for XmloReader<B>
|
||||
where
|
||||
B: BufRead,
|
||||
{
|
||||
type Item = XmloResult<XmloEvent>;
|
||||
|
||||
/// Invoke [`XmloReader::read_event`] and yield the result via an
|
||||
/// [`Iterator`] API.
|
||||
///
|
||||
/// *Warning*: This will always return [`Some`] for now.
|
||||
/// Future changes may alter this behavior.
|
||||
/// To terminate the iterator,
|
||||
/// it's recommended that you use [`Iterator::take_while`] to filter
|
||||
/// on the desired predicate,
|
||||
/// such as [`XmloEvent::Eoh`].
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
Some(self.read_event())
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> From<B> for XmloReader<B>
|
||||
where
|
||||
B: BufRead,
|
||||
{
|
||||
fn from(buf: B) -> Self {
|
||||
Self::new(buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// `xmlo` reader events.
|
||||
///
|
||||
/// All data are parsed rather than being returned as [`u8`] slices,
|
||||
/// which avoids having to deal with awkward borrows or data copying since
|
||||
/// these data will likely be persisted in memory anyway.
|
||||
///
|
||||
/// To avoid extra data copying,
|
||||
/// we should instead prefer not to put data into object files that won't
|
||||
/// be useful and can't be easily skipped without parsing.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum XmloEvent {
|
||||
/// Package declaration.
|
||||
///
|
||||
/// This contains data gathered from the root `lv:package` node.
|
||||
Package(PackageAttrs),
|
||||
|
||||
/// Symbol declaration.
|
||||
///
|
||||
/// This represents an entry in the symbol table,
|
||||
/// which includes a symbol along with its variable metadata as
|
||||
/// [`SymAttrs`].
|
||||
SymDecl(SymbolId, SymAttrs),
|
||||
|
||||
/// Dependencies of a given symbol.
|
||||
///
|
||||
/// Note that, for simplicity, an owned vector is returned rather than a
|
||||
/// slice into an internal buffer.
|
||||
SymDeps(SymbolId, Vec<SymbolId>),
|
||||
|
||||
/// Text (compiled code) fragment for a given symbol.
|
||||
///
|
||||
/// This contains the compiler output for a given symbol,
|
||||
/// and is returned here as an owned value.
|
||||
/// Given that fragments can be quite large,
|
||||
/// a caller not interested in these data should choose to skip
|
||||
/// fragments entirely rather than simply ignoring fragment events.
|
||||
Fragment(SymbolId, SymbolId),
|
||||
|
||||
/// End-of-header.
|
||||
///
|
||||
/// The header of an `xmlo` file is defined as the symbol table;
|
||||
/// dependency list; and fragments.
|
||||
/// This event is emitted at the closing `preproc:fragment` node.
|
||||
Eoh,
|
||||
}
|
||||
|
||||
/// 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.
|
||||
XmlError(XmlError),
|
||||
/// 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),
|
||||
}
|
||||
|
||||
impl From<InnerXmlError> for XmloError {
|
||||
fn from(e: InnerXmlError) -> Self {
|
||||
XmloError::XmlError(e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for XmloError {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
XmloError::XmlError(e) => e.fmt(fmt),
|
||||
XmloError::UnexpectedRoot => {
|
||||
write!(fmt, "unexpected package root (is this a package?)")
|
||||
}
|
||||
XmloError::UnassociatedSym => write!(
|
||||
fmt,
|
||||
"unassociated symbol table entry: preproc:sym/@name missing"
|
||||
),
|
||||
XmloError::InvalidType(ty) => {
|
||||
write!(fmt, "invalid preproc:sym/@type `{}`", ty)
|
||||
}
|
||||
XmloError::InvalidDtype(dtype) => {
|
||||
write!(fmt, "invalid preproc:sym/@dtype `{}`", dtype)
|
||||
}
|
||||
XmloError::InvalidDim(dim) => {
|
||||
write!(fmt, "invalid preproc:sym/@dim `{}`", dim)
|
||||
}
|
||||
XmloError::InvalidMapFrom(msg) => {
|
||||
write!(fmt, "invalid preproc:sym[@type=\"map\"]: {}", msg)
|
||||
}
|
||||
XmloError::UnassociatedSymDep => write!(
|
||||
fmt,
|
||||
"unassociated dependency list: preproc:sym-dep/@name missing"
|
||||
),
|
||||
XmloError::MalformedSymRef(msg) => {
|
||||
write!(fmt, "malformed dependency ref: {}", msg)
|
||||
}
|
||||
XmloError::UnassociatedFragment => write!(
|
||||
fmt,
|
||||
"unassociated fragment: preproc:fragment/@id missing"
|
||||
),
|
||||
XmloError::MissingFragmentText(symname) => write!(
|
||||
fmt,
|
||||
"fragment found, but missing text for symbol `{}`",
|
||||
symname,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for XmloError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::XmlError(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::super::{InnerXmlError, XmlError};
|
||||
use super::*;
|
||||
use crate::ir::legacyir::{SymDtype, SymType};
|
||||
use crate::sym::GlobalSymbolIntern;
|
||||
|
|
Loading…
Reference in New Issue