tame/tamer/src/xir/attr.rs

151 lines
4.3 KiB
Rust

// XIRT attributes
//
// Copyright (C) 2014-2022 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/>.
//! XIRT attributes.
//!
//! Attributes are represented by [`Attr`].
//!
//! See [parent module](super) for additional documentation.
mod parse;
use super::QName;
use crate::{parse::Token, span::Span, sym::SymbolId};
use std::fmt::Display;
pub use parse::{AttrParseError, AttrParseState};
/// Element attribute.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Attr(pub QName, pub SymbolId, pub (Span, Span));
impl Attr {
/// Construct a new simple attribute with a name, value, and respective
/// [`Span`]s.
#[inline]
pub fn new(name: QName, value: SymbolId, span: (Span, Span)) -> Self {
Self(name, value, span)
}
/// Attribute name.
#[inline]
pub fn name(&self) -> QName {
self.0
}
/// Retrieve the value from the attribute.
///
/// Since [`SymbolId`] implements [`Copy`],
/// this returns an owned value.
#[inline]
pub fn value(&self) -> SymbolId {
self.1
}
}
impl Token for Attr {
fn span(&self) -> Span {
// TODO: This ought to represent the _entire_ token.
// However,
// this is complicated by the closing quote,
// which is not present in _either_ span,
// so we'll need to formalize that first;
// simply adding a single byte offset seems unwise,
// given that this is not responsible for producing the
// spans to begin with;
// I'd prefer help from XIR.
match self {
Attr(.., (span, _)) => *span,
}
}
}
impl crate::parse::Object for Attr {}
impl Display for Attr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "`@{}=\"{}\"` at {}", self.0, self.1, self.2 .0)
}
}
/// List of attributes.
///
/// Attributes are ordered in XIR so that this IR will be suitable for code
/// formatters and linters.
///
/// This abstraction will allow us to manipulate the internal data so that
/// it is suitable for a particular task in the future
/// (e.g. O(1) lookups by attribute name).
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct AttrList {
attrs: Vec<Attr>,
}
impl AttrList {
/// Construct a new, empty attribute list.
pub fn new() -> Self {
Self { attrs: vec![] }
}
/// Add an attribute to the end of the attribute list.
pub fn push(mut self, attr: Attr) -> Self {
self.attrs.push(attr);
self
}
/// Search for an attribute of the given `name`.
///
/// _You should use this method only when a linear search makes sense._
///
/// This performs an `O(n)` linear search in the worst case.
/// Future implementations may perform an `O(1)` lookup under certain
/// circumstances,
/// but this should not be expected.
pub fn find(&self, name: QName) -> Option<&Attr> {
self.attrs.iter().find(|attr| attr.name() == name)
}
/// Returns [`true`] if the list contains no attributes.
pub fn is_empty(&self) -> bool {
self.attrs.is_empty()
}
}
impl From<Vec<Attr>> for AttrList {
fn from(attrs: Vec<Attr>) -> Self {
AttrList { attrs }
}
}
impl FromIterator<Attr> for AttrList {
fn from_iter<T: IntoIterator<Item = Attr>>(iter: T) -> Self {
iter.into_iter().collect::<Vec<Attr>>().into()
}
}
impl<const N: usize> From<[Attr; N]> for AttrList {
fn from(attrs: [Attr; N]) -> Self {
AttrList {
attrs: attrs.into(),
}
}
}
// See [`super::test`] for tests related to attributes.