tamer: Remove Ix generalization throughout system

This had the writing on the wall all the same as the `'i` interner lifetime
that came before it.  It was too much of a maintenance burden trying to
accommodate both 16-bit and 32-bit symbols generically.

There is a situation where we do still want 16-bit symbols---the
`Span`.  Therefore, I have left generic support for symbol sizes, as well as
the different global interners, but `SymbolId` now defaults to 32-bit, as
does `Asg`.  Further, the size parameter has been removed from the rest of
the code, with the exception of `Span`.

This cleans things up quite a bit, and is much nicer to work with.  If we
want 16-bit symbols in the future for packing to increase CPU cache
performance, we can handle that situation then in that specific case; it's a
premature optimization that's not at all worth the effort here.
main
Mike Gerwitz 2021-09-23 14:52:53 -04:00
parent ed245bb099
commit e91aeef478
28 changed files with 516 additions and 774 deletions

View File

@ -29,25 +29,15 @@ extern crate test;
use test::Bencher;
mod base {
use std::convert::TryFrom;
use std::fmt::Debug;
use super::*;
use tamer::global;
use tamer::ir::asg::{
Asg, DataType, DefaultAsg, IdentKind, IdentObject, SortableAsg, Source,
};
use tamer::sym::{GlobalSymbolIntern, SymbolId, SymbolIndexSize};
use tamer::sym::{GlobalSymbolIntern, SymbolId};
type Sut =
DefaultAsg<IdentObject<global::PkgSymSize>, global::PkgIdentSize>;
type SutProg<'i> =
DefaultAsg<IdentObject<global::ProgSymSize>, global::ProgIdentSize>;
type Sut = DefaultAsg<IdentObject>;
fn interned_n<Ix: SymbolIndexSize>(n: u16) -> Vec<SymbolId<Ix>>
where
<Ix as TryFrom<usize>>::Error: Debug,
{
fn interned_n(n: u16) -> Vec<SymbolId> {
(0..n).map(|i| i.to_string().intern()).collect()
}
@ -75,10 +65,9 @@ mod base {
});
}
// The Ix size affects memory, but how about performance?
#[bench]
fn declare_1_000_prog_ident_size(bench: &mut Bencher) {
let mut sut = SutProg::new();
let mut sut = Sut::new();
let xs = interned_n(1_000);
bench.iter(|| {
@ -390,13 +379,12 @@ mod object {
mod ident {
use super::*;
use tamer::global;
use tamer::ir::asg::{
IdentKind, IdentObject, IdentObjectData, IdentObjectState, Source,
};
use tamer::sym::GlobalSymbolIntern;
type Sut = IdentObject<global::ProgSymSize>;
type Sut = IdentObject;
#[bench]
fn declare_1_000(bench: &mut Bencher) {

View File

@ -228,7 +228,7 @@ mod interner {
bench.iter(|| {
strs.iter()
.map::<ProgSymbolId, _>(|s| s.intern())
.map::<SymbolId, _>(|s| s.intern())
.for_each(drop);
});
}
@ -237,7 +237,7 @@ mod interner {
fn with_one_new_1000(bench: &mut Bencher) {
bench.iter(|| {
(0..1000)
.map::<ProgSymbolId, _>(|_| "onenew".intern())
.map::<SymbolId, _>(|_| "onenew".intern())
.for_each(drop);
});
}
@ -246,7 +246,7 @@ mod interner {
fn with_one_new_1000_utf8_unchecked(bench: &mut Bencher) {
bench.iter(|| {
(0..1000)
.map::<ProgSymbolId, _>(|_| unsafe {
.map::<SymbolId, _>(|_| unsafe {
(b"onenewu8").intern_utf8_unchecked()
})
.for_each(drop);

View File

@ -44,8 +44,6 @@ use tamer::ir::xir::{NCName, QName, Token};
use tamer::sym::{GlobalSymbolIntern, GlobalSymbolResolve, SymbolId};
use test::Bencher;
type Ix = tamer::global::PkgSymSize;
fn gen_strs(n: usize, suffix: &str) -> Vec<String> {
(0..n).map(|n| n.to_string() + suffix).collect()
}
@ -62,7 +60,7 @@ mod name {
bench.iter(|| {
strs.iter()
.map(|s| s.as_str().intern() as SymbolId<Ix>)
.map(|s| s.as_str().intern() as SymbolId)
.for_each(drop);
});
}
@ -74,9 +72,7 @@ mod name {
bench.iter(|| {
strs.iter()
.map(|s| unsafe {
NCName::<Ix>::new_unchecked(s.as_str().intern())
})
.map(|s| unsafe { NCName::new_unchecked(s.as_str().intern()) })
.for_each(drop);
});
}
@ -100,7 +96,7 @@ mod name {
bench.iter(|| {
strs.iter()
.map(|s| NCName::<Ix>::try_from(s.as_str()))
.map(|s| NCName::try_from(s.as_str()))
.for_each(drop);
});
}
@ -115,7 +111,7 @@ mod name {
prefixes
.iter()
.zip(names.iter())
.map(|(p, s)| QName::<Ix>::try_from((p.as_str(), s.as_str())))
.map(|(p, s)| QName::try_from((p.as_str(), s.as_str())))
.for_each(drop);
});
}
@ -129,7 +125,7 @@ mod ws {
fn whitespace_1000(bench: &mut Bencher) {
bench.iter(|| {
(0..1000)
.map(|_| Whitespace::<Ix>::try_from(" \t "))
.map(|_| Whitespace::try_from(" \t "))
.for_each(drop);
});
}
@ -203,7 +199,7 @@ This is pretend fragment text. We need a lot of it.</fragment>
// common values such as these (QNames) will be pre-defined and
// reused.
let span = Span::from_byte_interval((0, 0), "path".intern());
let name = QName::<Ix>::try_from(("test", "foo")).unwrap();
let name = QName::try_from(("test", "foo")).unwrap();
let attr1 = QName::new_local("first".try_into().unwrap());
let attr2 = QName::new_local("second".try_into().unwrap());
let val1 = "value".intern();
@ -233,7 +229,7 @@ This is pretend fragment text. We need a lot of it.</fragment>
let buf = Vec::<u8>::with_capacity(FRAGMENT.len() * 50);
let mut writer = QuickXmlWriter::new(buf);
let frag: SymbolId<Ix> = FRAGMENT.intern();
let frag: SymbolId = FRAGMENT.intern();
bench.iter(|| {
(0..50).for_each(|_| {
@ -251,7 +247,7 @@ This is pretend fragment text. We need a lot of it.</fragment>
#[bench]
fn xir_text_50(bench: &mut Bencher) {
let mut buf = Vec::<u8>::with_capacity(FRAGMENT.len() * 50);
let frag: SymbolId<Ix> = FRAGMENT.intern();
let frag: SymbolId = FRAGMENT.intern();
let span = Span::from_byte_interval((0, 0), "path".intern());
bench.iter(|| {

View File

@ -35,19 +35,12 @@
use std::{mem::size_of, num};
/// A size capable of representing every interned string in a package.
pub type PkgSymSize = u16;
const_assert!(size_of::<PkgSymSize>() <= size_of::<ProgSymSize>());
/// A non-zero equivalent of [`PkgSymSize`];
pub type NonZeroPkgSymSize = num::NonZeroU16;
/// The initial capacity for global interners.
pub const INIT_GLOBAL_INTERNER_CAPACITY: usize = 1024;
/// A size capable of representing every interned string in a program.
pub type ProgSymSize = u32;
/// The initial capacity for global interners.
pub const INIT_GLOBAL_INTERNER_CAPACITY: usize = 1024;
/// A non-zero equivalent of [`ProgSymSize`];
pub type NonZeroProgSymSize = num::NonZeroU32;
@ -66,30 +59,6 @@ pub type SourceFileSize = u32;
pub type FrontendTokenLength = u16;
const_assert!(size_of::<FrontendTokenLength>() <= size_of::<SourceFileSize>());
/// A size capable of representing indexes of each individual identifier
/// within a single package.
///
/// Note that,
/// since TAME is a metalanguage and can easily expand into a great
/// deal of code,
/// this must accommodate far more than the user's expectations
/// working within the provided level of abstraction.
///
/// This must be ≥ [`PkgSymSize`].
pub type PkgIdentSize = u16;
const_assert!(size_of::<PkgIdentSize>() >= size_of::<PkgSymSize>());
/// A size capable of representing every individual identifier and
/// expression within a single package.
///
/// Note that,
/// since TAME is a metalanguage and can easily expand into a great
/// deal of code,
/// this must accommodate far more than the user's expectations
/// working within the provided level of abstraction.
pub type PkgIdentExprSize = u32;
const_assert!(size_of::<PkgIdentExprSize>() <= size_of::<ProgIdentExprSize>());
/// A size capable of representing the union of every identifier of every
/// package used by an entire program.
///

View File

@ -19,9 +19,6 @@
//! Base concrete [`Asg`] implementation.
use std::convert::TryInto;
use std::fmt::Debug;
use super::graph::{
Asg, AsgEdge, AsgResult, IndexType, Node, ObjectRef, SortableAsg,
SortableAsgError, SortableAsgResult,
@ -31,7 +28,7 @@ use super::object::{
FragmentText, IdentObjectData, IdentObjectState, Source, TransitionResult,
};
use super::Sections;
use crate::sym::{GlobalSymbolResolve, SymbolId, SymbolIndexSize};
use crate::sym::{GlobalSymbolResolve, SymbolId};
use petgraph::graph::{DiGraph, Graph, NodeIndex};
use petgraph::visit::DfsPostOrder;
@ -47,7 +44,7 @@ use petgraph::visit::DfsPostOrder;
/// see [`Asg`].
pub struct BaseAsg<O, Ix>
where
Ix: IndexType + SymbolIndexSize,
Ix: IndexType,
{
/// Directed graph on which objects are stored.
graph: DiGraph<Node<O>, AsgEdge, Ix>,
@ -66,9 +63,8 @@ where
impl<O, Ix> BaseAsg<O, Ix>
where
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectState<Ix, O> + IdentObjectData<Ix>,
Ix: IndexType,
O: IdentObjectState<O> + IdentObjectData,
{
/// Create a new ASG.
///
@ -118,7 +114,7 @@ where
/// Panics
/// ======
/// Will panic if unable to allocate more space for the index.
fn index_identifier(&mut self, name: SymbolId<Ix>, node: NodeIndex<Ix>) {
fn index_identifier(&mut self, name: SymbolId, node: NodeIndex<Ix>) {
let i = name.as_usize();
if i >= self.index.len() {
@ -141,7 +137,7 @@ where
/// reference to it.
///
/// See [`IdentObjectState::declare`] for more information.
fn lookup_or_missing(&mut self, ident: SymbolId<Ix>) -> ObjectRef<Ix> {
fn lookup_or_missing(&mut self, ident: SymbolId) -> ObjectRef<Ix> {
self.lookup(ident).unwrap_or_else(|| {
let index = self.graph.add_node(Some(O::declare(ident)));
@ -161,7 +157,7 @@ where
/// value on transition failure.
fn with_ident_lookup<F>(
&mut self,
name: SymbolId<Ix>,
name: SymbolId,
f: F,
) -> AsgResult<ObjectRef<Ix>>
where
@ -206,24 +202,23 @@ where
impl<O, Ix> Asg<O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectState<Ix, O> + IdentObjectData<Ix>,
Ix: IndexType,
O: IdentObjectState<O> + IdentObjectData,
{
fn declare(
&mut self,
name: SymbolId<Ix>,
name: SymbolId,
kind: IdentKind,
src: Source<Ix>,
src: Source,
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident_lookup(name, |obj| obj.resolve(kind, src))
}
fn declare_extern(
&mut self,
name: SymbolId<Ix>,
name: SymbolId,
kind: IdentKind,
src: Source<Ix>,
src: Source,
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident_lookup(name, |obj| obj.extern_(kind, src))
}
@ -231,7 +226,7 @@ where
fn set_fragment(
&mut self,
identi: ObjectRef<Ix>,
text: FragmentText<Ix>,
text: FragmentText,
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident(identi, |obj| obj.set_fragment(text))
}
@ -245,7 +240,7 @@ where
}
#[inline]
fn lookup(&self, name: SymbolId<Ix>) -> Option<ObjectRef<Ix>> {
fn lookup(&self, name: SymbolId) -> Option<ObjectRef<Ix>> {
let i = name.as_usize();
self.index
@ -266,8 +261,8 @@ where
fn add_dep_lookup(
&mut self,
ident: SymbolId<Ix>,
dep: SymbolId<Ix>,
ident: SymbolId,
dep: SymbolId,
) -> (ObjectRef<Ix>, ObjectRef<Ix>) {
let identi = self.lookup_or_missing(ident);
let depi = self.lookup_or_missing(dep);
@ -281,9 +276,8 @@ where
impl<O, Ix> SortableAsg<O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectData<Ix> + IdentObjectState<Ix, O>,
Ix: IndexType,
O: IdentObjectData + IdentObjectState<O>,
{
fn sort<'i>(
&'i self,
@ -345,9 +339,8 @@ where
/// they are, we ignore the cycle, otherwise we will return an error.
fn check_cycles<O, Ix>(asg: &BaseAsg<O, Ix>) -> SortableAsgResult<(), Ix>
where
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectData<Ix> + IdentObjectState<Ix, O>,
Ix: IndexType,
O: IdentObjectData + IdentObjectState<O>,
{
// While `tarjan_scc` does do a topological sort, it does not suit our
// needs because we need to filter out some allowed cycles. It would
@ -403,22 +396,20 @@ mod test {
use crate::sym::{GlobalSymbolIntern, SymbolStr};
use std::cell::RefCell;
type Ix = u16;
#[derive(Debug, Default, PartialEq)]
struct StubIdentObject {
given_declare: Option<SymbolId<Ix>>,
given_extern: Option<(IdentKind, Source<Ix>)>,
given_resolve: Option<(IdentKind, Source<Ix>)>,
given_set_fragment: Option<FragmentText<Ix>>,
given_declare: Option<SymbolId>,
given_extern: Option<(IdentKind, Source)>,
given_resolve: Option<(IdentKind, Source)>,
given_set_fragment: Option<FragmentText>,
fail_redeclare: RefCell<Option<TransitionError>>,
fail_extern: RefCell<Option<TransitionError>>,
fail_set_fragment: RefCell<Option<TransitionError>>,
fail_resolved: RefCell<Option<UnresolvedError>>,
}
impl<'i> IdentObjectData<Ix> for StubIdentObject {
fn name(&self) -> Option<SymbolId<Ix>> {
impl<'i> IdentObjectData for StubIdentObject {
fn name(&self) -> Option<SymbolId> {
self.given_declare
}
@ -426,21 +417,21 @@ mod test {
self.given_resolve.as_ref().map(|args| &args.0)
}
fn src(&self) -> Option<&Source<Ix>> {
fn src(&self) -> Option<&Source> {
None
}
fn fragment(&self) -> Option<&FragmentText<Ix>> {
fn fragment(&self) -> Option<&FragmentText> {
None
}
fn as_ident(&self) -> Option<&IdentObject<Ix>> {
fn as_ident(&self) -> Option<&IdentObject> {
None
}
}
impl<'i> IdentObjectState<Ix, StubIdentObject> for StubIdentObject {
fn declare(ident: SymbolId<Ix>) -> Self {
impl<'i> IdentObjectState<StubIdentObject> for StubIdentObject {
fn declare(ident: SymbolId) -> Self {
Self {
given_declare: Some(ident),
..Default::default()
@ -450,7 +441,7 @@ mod test {
fn resolve(
mut self,
kind: IdentKind,
src: Source<Ix>,
src: Source,
) -> TransitionResult<StubIdentObject> {
if self.fail_redeclare.borrow().is_some() {
let err = self.fail_redeclare.replace(None).unwrap();
@ -472,7 +463,7 @@ mod test {
fn extern_(
mut self,
kind: IdentKind,
src: Source<Ix>,
src: Source,
) -> TransitionResult<StubIdentObject> {
if self.fail_extern.borrow().is_some() {
let err = self.fail_extern.replace(None).unwrap();
@ -485,7 +476,7 @@ mod test {
fn set_fragment(
mut self,
text: FragmentText<Ix>,
text: FragmentText,
) -> TransitionResult<StubIdentObject> {
if self.fail_set_fragment.borrow().is_some() {
let err = self.fail_set_fragment.replace(None).unwrap();

View File

@ -25,7 +25,7 @@ use super::object::{
UnresolvedError,
};
use super::Sections;
use crate::sym::{SymbolId, SymbolIndexSize};
use crate::sym::SymbolId;
use petgraph::graph::NodeIndex;
use std::fmt::Debug;
use std::result::Result;
@ -48,8 +48,8 @@ impl<T: petgraph::graph::IndexType> IndexType for T {}
/// see the [module-level documentation][self].
pub trait Asg<O, Ix>
where
Ix: IndexType + SymbolIndexSize,
O: IdentObjectState<Ix, O>,
Ix: IndexType,
O: IdentObjectState<O>,
{
/// Declare a concrete identifier.
///
@ -84,9 +84,9 @@ where
/// and return an [`ObjectRef`] reference.
fn declare(
&mut self,
name: SymbolId<Ix>,
name: SymbolId,
kind: IdentKind,
src: Source<Ix>,
src: Source,
) -> AsgResult<ObjectRef<Ix>>;
/// Declare an abstract identifier.
@ -111,9 +111,9 @@ where
/// compatibility related to extern resolution.
fn declare_extern(
&mut self,
name: SymbolId<Ix>,
name: SymbolId,
kind: IdentKind,
src: Source<Ix>,
src: Source,
) -> AsgResult<ObjectRef<Ix>>;
/// Set the fragment associated with a concrete identifier.
@ -124,7 +124,7 @@ where
fn set_fragment(
&mut self,
identi: ObjectRef<Ix>,
text: FragmentText<Ix>,
text: FragmentText,
) -> AsgResult<ObjectRef<Ix>>;
/// Retrieve an object from the graph by [`ObjectRef`].
@ -142,7 +142,7 @@ where
/// this method cannot be used to retrieve all possible objects on the
/// graph---for
/// that, see [`Asg::get`].
fn lookup(&self, name: SymbolId<Ix>) -> Option<ObjectRef<Ix>>;
fn lookup(&self, name: SymbolId) -> Option<ObjectRef<Ix>>;
/// Declare that `dep` is a dependency of `ident`.
///
@ -173,8 +173,8 @@ where
/// References to both identifiers are returned in argument order.
fn add_dep_lookup(
&mut self,
ident: SymbolId<Ix>,
dep: SymbolId<Ix>,
ident: SymbolId,
dep: SymbolId,
) -> (ObjectRef<Ix>, ObjectRef<Ix>);
}
@ -184,8 +184,8 @@ where
/// used as an `Intermediate Representation`.
pub trait SortableAsg<O, Ix>
where
O: IdentObjectData<Ix>,
Ix: IndexType + SymbolIndexSize,
O: IdentObjectData,
Ix: IndexType,
{
/// Sort graph into [`Sections`].
///

View File

@ -19,9 +19,8 @@
//! Identifiers (a type of [object][super::object::IdentObject]).
use crate::global;
use crate::ir::legacyir::{SymAttrs, SymDtype, SymType};
use crate::sym::{GlobalSymbolIntern, SymbolId, SymbolIndexSize};
use crate::sym::{GlobalSymbolIntern, SymbolId};
use paste::paste;
use std::convert::TryFrom;
use std::error::Error;
@ -148,16 +147,14 @@ pub enum IdentKind {
Worksheet,
}
/// Produce [`AsRef`] impls for [`str`], [`global::ProgSymSize`] and
/// [`global::PkgSymSize`] for identifier kind strings.
/// Produce [`AsRef`] impls for [`str`] and [`global::ProgSymSize`] for
/// identifier kind strings.
macro_rules! kind_intern {
($($variant:ident $($v:pat)? => $str:expr),*) => {
paste! {
lazy_static! {
$(
static ref [<PROG_KIND_ $variant:upper>]: SymbolId<global::ProgSymSize>
= $str.intern();
static ref [<PKG_KIND_ $variant:upper>]: SymbolId<global::PkgSymSize>
static ref [<PROG_KIND_ $variant:upper>]: SymbolId
= $str.intern();
)*
}
@ -172,8 +169,8 @@ macro_rules! kind_intern {
}
}
impl AsRef<SymbolId<global::ProgSymSize>> for IdentKind {
fn as_ref(&self) -> &SymbolId<global::ProgSymSize> {
impl AsRef<SymbolId> for IdentKind {
fn as_ref(&self) -> &SymbolId {
match self {
$(
Self::$variant$($v)* => &[<PROG_KIND_ $variant:upper>],
@ -181,16 +178,6 @@ macro_rules! kind_intern {
}
}
}
impl AsRef<SymbolId<global::PkgSymSize>> for IdentKind {
fn as_ref(&self) -> &SymbolId<global::PkgSymSize> {
match self {
$(
Self::$variant$($v)* => &[<PKG_KIND_ $variant:upper>],
)*
}
}
}
}
}
}
@ -255,32 +242,26 @@ impl std::fmt::Display for IdentKind {
}
}
impl<Ix> TryFrom<SymAttrs<Ix>> for IdentKind
where
Ix: SymbolIndexSize,
{
impl TryFrom<SymAttrs> for IdentKind {
type Error = IdentKindError;
/// Attempt to raise [`SymAttrs`] into an [`IdentKind`].
///
/// Certain [`IdentKind`] require that certain attributes be present,
/// otherwise the conversion will fail.
fn try_from(attrs: SymAttrs<Ix>) -> Result<Self, Self::Error> {
fn try_from(attrs: SymAttrs) -> Result<Self, Self::Error> {
Self::try_from(&attrs)
}
}
impl<Ix> TryFrom<&SymAttrs<Ix>> for IdentKind
where
Ix: SymbolIndexSize,
{
impl TryFrom<&SymAttrs> for IdentKind {
type Error = IdentKindError;
/// Attempt to raise [`SymAttrs`] into an [`IdentKind`].
///
/// Certain [`IdentKind`] require that certain attributes be present,
/// otherwise the conversion will fail.
fn try_from(attrs: &SymAttrs<Ix>) -> Result<Self, Self::Error> {
fn try_from(attrs: &SymAttrs) -> Result<Self, Self::Error> {
let ty = attrs.ty.as_ref().ok_or(Self::Error::MissingType)?;
macro_rules! ident {
@ -406,8 +387,6 @@ mod test {
use super::*;
use std::convert::TryInto;
type Ix = u16;
#[test]
fn dim_from_u8() {
let n = 5u8;
@ -431,7 +410,7 @@ mod test {
fn $name() {
assert_eq!(
Ok($dest),
SymAttrs::<Ix> {
SymAttrs {
ty: Some($src),
..Default::default()
}
@ -447,7 +426,7 @@ mod test {
assert_eq!(
Ok($dest(Dim(dim))),
SymAttrs::<Ix> {
SymAttrs {
ty: Some($src),
dim: Some(dim),
..Default::default()
@ -456,7 +435,7 @@ mod test {
);
// no dim
let result = IdentKind::try_from(SymAttrs::<Ix> {
let result = IdentKind::try_from(SymAttrs {
ty: Some($src),
..Default::default()
})
@ -473,7 +452,7 @@ mod test {
assert_eq!(
Ok($dest(dtype)),
SymAttrs::<Ix> {
SymAttrs {
ty: Some($src),
dtype: Some(dtype),
..Default::default()
@ -482,7 +461,7 @@ mod test {
);
// no dtype
let result = IdentKind::try_from(SymAttrs::<Ix> {
let result = IdentKind::try_from(SymAttrs {
ty: Some($src),
..Default::default()
})
@ -500,7 +479,7 @@ mod test {
assert_eq!(
Ok($dest(Dim(dim), dtype)),
SymAttrs::<Ix> {
SymAttrs {
ty: Some($src),
dim: Some(dim),
dtype: Some(dtype),
@ -510,7 +489,7 @@ mod test {
);
// no dim
let dim_result = IdentKind::try_from(SymAttrs::<Ix> {
let dim_result = IdentKind::try_from(SymAttrs {
ty: Some($src),
dtype: Some(dtype),
..Default::default()
@ -520,7 +499,7 @@ mod test {
assert_eq!(IdentKindError::MissingDim, dim_result);
// no dtype
let dtype_result = IdentKind::try_from(SymAttrs::<Ix> {
let dtype_result = IdentKind::try_from(SymAttrs {
ty: Some($src),
dim: Some(dim),
..Default::default()

View File

@ -62,17 +62,17 @@
//! ```
//! use tamer::global;
//! use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, IdentObject, Source};
//! use tamer::sym::{Interner, DefaultPkgInterner};
//! use tamer::sym::{Interner, DefaultProgInterner};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Be sure to choose size and initial capacities appropriate for your
//! // situation.
//! let mut asg = DefaultAsg::<IdentObject<_>, global::PkgIdentSize>::with_capacity(
//! let mut asg = DefaultAsg::<IdentObject>::with_capacity(
//! 1024,
//! 1024,
//! );
//!
//! let interner = DefaultPkgInterner::new();
//! let interner = DefaultProgInterner::new();
//! let identa_sym = interner.intern("identa");
//! let identb_sym = interner.intern("identb");
//!
@ -111,14 +111,14 @@
//! ```
//! # use tamer::global;
//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, IdentObject, FragmentText, Source};
//! # use tamer::sym::{Interner, DefaultPkgInterner};
//! # use tamer::sym::{Interner, DefaultProgInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let mut asg = DefaultAsg::<IdentObject<_>, global::PkgIdentSize>::with_capacity(
//! # let mut asg = DefaultAsg::<IdentObject>::with_capacity(
//! # 1024,
//! # 1024,
//! # );
//! # let interner = DefaultPkgInterner::new();
//! # let interner = DefaultProgInterner::new();
//! #
//! let identa_sym = interner.intern("identa");
//! let identb_sym = interner.intern("identb");
@ -157,14 +157,14 @@
//! ```
//! # use tamer::global;
//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, IdentObject, FragmentText, Source};
//! # use tamer::sym::{Interner, DefaultPkgInterner};
//! # use tamer::sym::{Interner, DefaultProgInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let mut asg = DefaultAsg::<IdentObject<_>, global::PkgIdentSize>::with_capacity(
//! # let mut asg = DefaultAsg::<IdentObject>::with_capacity(
//! # 1024,
//! # 1024,
//! # );
//! # let interner = DefaultPkgInterner::new();
//! # let interner = DefaultProgInterner::new();
//! #
//! // Fragments can be attached to resolved identifiers.
//! let ident = asg.declare(
@ -208,4 +208,4 @@ pub use object::{
pub use section::{Section, SectionIter, Sections, SectionsIter};
/// Default concrete ASG implementation.
pub type DefaultAsg<O, Ix> = base::BaseAsg<O, Ix>;
pub type DefaultAsg<O, Ix = crate::global::ProgSymSize> = base::BaseAsg<O, Ix>;

View File

@ -24,7 +24,7 @@
use super::ident::IdentKind;
use crate::ir::legacyir::SymAttrs;
use crate::sym::{GlobalSymbolResolve, SymbolId, SymbolIndexSize, SymbolStr};
use crate::sym::{GlobalSymbolResolve, SymbolId, SymbolStr};
use std::result::Result;
pub type TransitionResult<T> = Result<T, (T, TransitionError)>;
@ -40,7 +40,7 @@ pub type TransitionResult<T> = Result<T, (T, TransitionError)>;
/// `--------------------` `-----------'
/// ```
#[derive(Debug, PartialEq, Clone)]
pub enum IdentObject<Ix: SymbolIndexSize> {
pub enum IdentObject {
/// An identifier is expected to be defined but is not yet available.
///
/// This variant contains the symbol representing the name of the
@ -48,13 +48,13 @@ pub enum IdentObject<Ix: SymbolIndexSize> {
/// By defining an object as missing,
/// this allows the graph to be built incrementally as objects are
/// discovered.
Missing(SymbolId<Ix>),
Missing(SymbolId),
/// A resolved identifier.
///
/// This represents an identifier that has been declared with certain
/// type information.
Ident(SymbolId<Ix>, IdentKind, Source<Ix>),
Ident(SymbolId, IdentKind, Source),
/// An identifier that has not yet been resolved.
///
@ -68,7 +68,7 @@ pub enum IdentObject<Ix: SymbolIndexSize> {
/// Once resolved, however,
/// the source will instead represent the location of the concrete
/// identifier.
Extern(SymbolId<Ix>, IdentKind, Source<Ix>),
Extern(SymbolId, IdentKind, Source),
/// Identifier with associated text.
///
@ -77,7 +77,7 @@ pub enum IdentObject<Ix: SymbolIndexSize> {
/// They are produced by the compiler and it is the job of the
/// [linker][crate::ld] to put them into the correct order for the
/// final executable.
IdentFragment(SymbolId<Ix>, IdentKind, Source<Ix>, FragmentText<Ix>),
IdentFragment(SymbolId, IdentKind, Source, FragmentText),
}
/// Retrieve information about an [`IdentObject`].
@ -95,12 +95,12 @@ pub enum IdentObject<Ix: SymbolIndexSize> {
/// an [`Option`].
/// These methods also provide a convenient alternative to `match`ing on
/// data that may not be present in all variants.
pub trait IdentObjectData<Ix: SymbolIndexSize> {
pub trait IdentObjectData {
/// Identifier name.
///
/// If the object is not an identifier,
/// [`None`] is returned.
fn name(&self) -> Option<SymbolId<Ix>>;
fn name(&self) -> Option<SymbolId>;
/// Identifier [`IdentKind`].
///
@ -114,13 +114,13 @@ pub trait IdentObjectData<Ix: SymbolIndexSize> {
/// If the object does not have source information
/// (as is the case with [`IdentObject::Extern`]),
/// [`None`] is returned.
fn src(&self) -> Option<&Source<Ix>>;
fn src(&self) -> Option<&Source>;
/// Identifier [`FragmentText`].
///
/// If the object does not have an associated code fragment,
/// [`None`] is returned.
fn fragment(&self) -> Option<&FragmentText<Ix>>;
fn fragment(&self) -> Option<&FragmentText>;
/// IdentObject as an identifier ([`IdentObject`]).
///
@ -132,14 +132,11 @@ pub trait IdentObjectData<Ix: SymbolIndexSize> {
///
/// This allows pattern matching on [`IdentObject`] variants regardless
/// of the underlying object type.
fn as_ident(&self) -> Option<&IdentObject<Ix>>;
fn as_ident(&self) -> Option<&IdentObject>;
}
impl<Ix> IdentObjectData<Ix> for IdentObject<Ix>
where
Ix: SymbolIndexSize,
{
fn name(&self) -> Option<SymbolId<Ix>> {
impl IdentObjectData for IdentObject {
fn name(&self) -> Option<SymbolId> {
match self {
Self::Missing(name)
| Self::Ident(name, _, _)
@ -157,7 +154,7 @@ where
}
}
fn src(&self) -> Option<&Source<Ix>> {
fn src(&self) -> Option<&Source> {
match self {
Self::Missing(_) | Self::Extern(_, _, _) => None,
Self::Ident(_, _, src) | Self::IdentFragment(_, _, src, _) => {
@ -166,7 +163,7 @@ where
}
}
fn fragment(&self) -> Option<&FragmentText<Ix>> {
fn fragment(&self) -> Option<&FragmentText> {
match self {
Self::Missing(_) | Self::Ident(_, _, _) | Self::Extern(_, _, _) => {
None
@ -184,28 +181,27 @@ where
/// so it's important _not_ to rely on this as an excuse to be lazy
/// with unwrapping.
#[inline]
fn as_ident(&self) -> Option<&IdentObject<Ix>> {
fn as_ident(&self) -> Option<&IdentObject> {
Some(&self)
}
}
/// Objects as a state machine.
pub trait IdentObjectState<Ix, T>
pub trait IdentObjectState<T>
where
T: IdentObjectState<Ix, T>,
Ix: SymbolIndexSize,
T: IdentObjectState<T>,
{
/// Produce an object representing a missing identifier.
///
/// This is the base state for all identifiers.
fn declare(ident: SymbolId<Ix>) -> T;
fn declare(ident: SymbolId) -> T;
/// Attempt to transition to a concrete identifier.
///
/// For specific information on compatibility rules,
/// see implementers of this trait,
/// since rules may vary between implementations.
fn resolve(self, kind: IdentKind, src: Source<Ix>) -> TransitionResult<T>;
fn resolve(self, kind: IdentKind, src: Source) -> TransitionResult<T>;
/// Assertion to return self if identifier is resolved,
/// otherwise failing with [`UnresolvedError`].
@ -239,7 +235,7 @@ where
/// If no kind is assigned (such as [`IdentObject::Missing`]),
/// then a new extern is produced.
/// See for example [`IdentObject::Extern`].
fn extern_(self, kind: IdentKind, src: Source<Ix>) -> TransitionResult<T>;
fn extern_(self, kind: IdentKind, src: Source) -> TransitionResult<T>;
/// Attach a code fragment (compiled text) to an identifier.
///
@ -249,14 +245,11 @@ where
/// Note, however, that an identifier's fragment may be cleared under
/// certain circumstances (such as symbol overrides),
/// making way for a new fragment to be set.
fn set_fragment(self, text: FragmentText<Ix>) -> TransitionResult<T>;
fn set_fragment(self, text: FragmentText) -> TransitionResult<T>;
}
impl<Ix> IdentObjectState<Ix, IdentObject<Ix>> for IdentObject<Ix>
where
Ix: SymbolIndexSize,
{
fn declare(ident: SymbolId<Ix>) -> Self {
impl IdentObjectState<IdentObject> for IdentObject {
fn declare(ident: SymbolId) -> Self {
IdentObject::Missing(ident)
}
@ -291,8 +284,8 @@ where
fn resolve(
self,
kind: IdentKind,
mut src: Source<Ix>,
) -> TransitionResult<IdentObject<Ix>> {
mut src: Source,
) -> TransitionResult<IdentObject> {
match self {
IdentObject::Ident(name, ref orig_kind, ref orig_src)
| IdentObject::IdentFragment(
@ -389,7 +382,7 @@ where
}
}
fn resolved(&self) -> Result<&IdentObject<Ix>, UnresolvedError> {
fn resolved(&self) -> Result<&IdentObject, UnresolvedError> {
match self {
IdentObject::Missing(name) => Err(UnresolvedError::Missing {
name: name.lookup_str(),
@ -411,8 +404,8 @@ where
fn extern_(
self,
kind: IdentKind,
src: Source<Ix>,
) -> TransitionResult<IdentObject<Ix>> {
src: Source,
) -> TransitionResult<IdentObject> {
match self.kind() {
None => Ok(IdentObject::Extern(self.name().unwrap(), kind, src)),
Some(cur_kind) => {
@ -432,10 +425,7 @@ where
}
}
fn set_fragment(
self,
text: FragmentText<Ix>,
) -> TransitionResult<IdentObject<Ix>> {
fn set_fragment(self, text: FragmentText) -> TransitionResult<IdentObject> {
match self {
IdentObject::Ident(sym, kind, src) => {
Ok(IdentObject::IdentFragment(sym, kind, src, text))
@ -608,7 +598,7 @@ impl std::error::Error for UnresolvedError {
/// Compiled fragment for identifier.
///
/// This represents the text associated with an identifier.
pub type FragmentText<Ix> = SymbolId<Ix>;
pub type FragmentText = SymbolId;
/// Metadata about the source of an object.
///
@ -620,26 +610,26 @@ pub type FragmentText<Ix> = SymbolId<Ix>;
/// since the original XSLT-based compiler did not have that capability;
/// this will provide that information in the future.
#[derive(Debug, Default, PartialEq, Clone)]
pub struct Source<Ix: SymbolIndexSize> {
pub struct Source {
/// Name of package containing reference to this object.
pub pkg_name: Option<SymbolId<Ix>>,
pub pkg_name: Option<SymbolId>,
/// Relative path to the source of this object,
/// if not present in the current package.
pub src: Option<SymbolId<Ix>>,
pub src: Option<SymbolId>,
/// The identifier from which this one is derived.
///
/// See [`IdentKind`] for more information on parents.
/// For example,
/// a [`IdentKind::Cgen`] always has a parent [`IdentKind::Class`].
pub parent: Option<SymbolId<Ix>>,
pub parent: Option<SymbolId>,
/// Child identifier associated with this identifier.
///
/// For [`IdentKind::Class`],
/// this represents an associated [`IdentKind::Cgen`].
pub yields: Option<SymbolId<Ix>>,
pub yields: Option<SymbolId>,
/// User-friendly identifier description.
///
@ -667,7 +657,7 @@ pub struct Source<Ix: SymbolIndexSize> {
///
/// TODO: We have `parent`, `yields`, and `from`.
/// We should begin to consolodate.
pub from: Option<Vec<SymbolId<Ix>>>,
pub from: Option<Vec<SymbolId>>,
/// Whether identifier is virtual (can be overridden).
///
@ -686,14 +676,11 @@ pub struct Source<Ix: SymbolIndexSize> {
pub override_: bool,
}
impl<Ix> From<SymAttrs<Ix>> for Source<Ix>
where
Ix: SymbolIndexSize,
{
impl From<SymAttrs> for Source {
/// Raise Legacy IR [`SymAttrs`].
///
/// This simply extracts a subset of fields from the source attributes.
fn from(attrs: SymAttrs<Ix>) -> Self {
fn from(attrs: SymAttrs) -> Self {
Source {
pkg_name: attrs.pkg_name,
src: attrs.src,
@ -712,7 +699,7 @@ where
mod test {
use super::super::ident::Dim;
use super::*;
use crate::sym::{GlobalSymbolIntern, PkgSymbolId};
use crate::sym::{GlobalSymbolIntern, SymbolId};
mod ident_object_data {
use super::*;
@ -720,7 +707,7 @@ mod test {
// Note that IdentObject has no variants capable of None
#[test]
fn ident_object_name() {
let sym: PkgSymbolId = "sym".intern();
let sym: SymbolId = "sym".intern();
assert_eq!(Some(sym), IdentObject::Missing(sym).name());
@ -750,7 +737,7 @@ mod test {
#[test]
fn ident_object_kind() {
let sym: PkgSymbolId = "sym".intern();
let sym: SymbolId = "sym".intern();
let kind = IdentKind::Class(Dim::from_u8(5));
assert_eq!(None, IdentObject::Missing(sym).kind());
@ -780,7 +767,7 @@ mod test {
#[test]
fn ident_object_src() {
let sym: PkgSymbolId = "sym".intern();
let sym: SymbolId = "sym".intern();
let src = Source {
desc: Some("test source".into()),
..Default::default()
@ -812,7 +799,7 @@ mod test {
#[test]
fn ident_object_fragment() {
let sym: PkgSymbolId = "sym".intern();
let sym: SymbolId = "sym".intern();
let text = "foo".into();
assert_eq!(None, IdentObject::Missing(sym).fragment());
@ -843,7 +830,7 @@ mod test {
#[test]
fn ident_object_as_ident() {
let sym: PkgSymbolId = "sym".intern();
let sym: SymbolId = "sym".intern();
let ident = IdentObject::Missing(sym);
// Since we _are_ an IdentObject, we should return a reference
@ -860,13 +847,13 @@ mod test {
#[test]
fn ident_object_missing() {
let sym: PkgSymbolId = "missing".intern();
let sym: SymbolId = "missing".intern();
assert_eq!(IdentObject::Missing(sym), IdentObject::declare(sym));
}
#[test]
fn resolved_on_missing() {
let sym: PkgSymbolId = "missing".intern();
let sym: SymbolId = "missing".intern();
let result = IdentObject::declare(sym)
.resolved()
@ -882,7 +869,7 @@ mod test {
#[test]
fn ident_object_ident() {
let sym: PkgSymbolId = "ident".intern();
let sym: SymbolId = "ident".intern();
let kind = IdentKind::Meta;
let src = Source {
desc: Some("ident ctor".into()),
@ -899,7 +886,7 @@ mod test {
#[test]
fn resolved_on_ident() {
let sym: PkgSymbolId = "ident resolve".intern();
let sym: SymbolId = "ident resolve".intern();
let kind = IdentKind::Meta;
let src = Source {
desc: Some("ident ctor".into()),
@ -922,7 +909,7 @@ mod test {
// packages have the same local symbol.
#[test]
fn ident_object_redeclare_same_src() {
let sym: PkgSymbolId = "redecl".intern();
let sym: SymbolId = "redecl".intern();
let kind = IdentKind::Meta;
let src = Source::default();
@ -952,7 +939,7 @@ mod test {
#[test]
fn ident_object() {
let sym: PkgSymbolId = "extern".intern();
let sym: SymbolId = "extern".intern();
let kind = IdentKind::Class(Dim::from_u8(1));
let src = Source {
desc: Some("extern".into()),
@ -967,9 +954,9 @@ mod test {
#[test]
fn resolved_on_extern() {
let sym: PkgSymbolId = "extern resolved".intern();
let sym: SymbolId = "extern resolved".intern();
let kind = IdentKind::Class(Dim::from_u8(1));
let pkg_name: PkgSymbolId = "pkg/name".intern();
let pkg_name: SymbolId = "pkg/name".intern();
let src = Source {
pkg_name: Some(pkg_name),
desc: Some("extern".into()),
@ -1034,7 +1021,7 @@ mod test {
// Extern first, then identifier
#[test]
fn redeclare_compatible_resolves() {
let sym: PkgSymbolId = "extern_re_pre".intern();
let sym: SymbolId = "extern_re_pre".intern();
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("okay".into()),
@ -1052,7 +1039,7 @@ mod test {
// Identifier first, then extern
#[test]
fn redeclare_compatible_resolves_post() {
let sym: PkgSymbolId = "extern_re_post".intern();
let sym: SymbolId = "extern_re_post".intern();
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("okay".into()),
@ -1069,7 +1056,7 @@ mod test {
#[test]
fn redeclare_another_extern() {
let sym: PkgSymbolId = "extern_extern".intern();
let sym: SymbolId = "extern_extern".intern();
let kind = IdentKind::Class(Dim::from_u8(20));
let src_first = Source {
desc: Some("first src".into()),
@ -1095,7 +1082,7 @@ mod test {
// Extern first, then identifier
#[test]
fn redeclare_post_incompatible_kind() {
let sym: PkgSymbolId = "extern_re_bad_post".intern();
let sym: SymbolId = "extern_re_bad_post".intern();
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("bad kind".into()),
@ -1139,7 +1126,7 @@ mod test {
// Identifier first, then extern
#[test]
fn redeclare_pre_incompatible_kind() {
let sym: PkgSymbolId = "extern_re_bad_pre".intern();
let sym: SymbolId = "extern_re_bad_pre".intern();
let kind_given = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("bad kind".into()),
@ -1185,7 +1172,7 @@ mod test {
#[test]
fn add_fragment_to_ident() {
let sym: PkgSymbolId = "tofrag".intern();
let sym: SymbolId = "tofrag".intern();
let src = Source {
generated: true,
..Default::default()
@ -1206,7 +1193,7 @@ mod test {
#[test]
fn resolved_on_fragment() {
let sym: PkgSymbolId = "tofrag resolved".intern();
let sym: SymbolId = "tofrag resolved".intern();
let src = Source {
generated: true,
..Default::default()
@ -1227,7 +1214,7 @@ mod test {
#[test]
fn add_fragment_to_fragment_fails() {
let sym: PkgSymbolId = "badsym".intern();
let sym: SymbolId = "badsym".intern();
let ident = IdentObject::declare(sym)
.resolve(IdentKind::Meta, Source::default())
.unwrap();
@ -1258,7 +1245,7 @@ mod test {
#[test]
fn declare_virtual_ident_first() {
let sym: PkgSymbolId = "virtual".intern();
let sym: SymbolId = "virtual".intern();
let over_src = "src".intern();
let kind = IdentKind::Meta;
@ -1297,7 +1284,7 @@ mod test {
// Override is encountered before the virtual
#[test]
fn declare_virtual_ident_after_override() {
let sym: PkgSymbolId = "virtual_second".intern();
let sym: SymbolId = "virtual_second".intern();
let virt_src = "virt_src".intern();
let kind = IdentKind::Meta;
@ -1335,7 +1322,7 @@ mod test {
#[test]
fn declare_override_non_virtual() {
let sym: PkgSymbolId = "non_virtual".intern();
let sym: SymbolId = "non_virtual".intern();
let kind = IdentKind::Meta;
let non_virt = IdentObject::declare(sym)
@ -1389,8 +1376,8 @@ mod test {
#[test]
fn declare_virtual_ident_incompatible_kind() {
let sym: PkgSymbolId = "virtual".intern();
let src_sym: PkgSymbolId = "src".intern();
let sym: SymbolId = "virtual".intern();
let src_sym: SymbolId = "src".intern();
let kind = IdentKind::Meta;
let virt = IdentObject::declare(sym)
@ -1449,7 +1436,7 @@ mod test {
// fragment to be cleared to make way for the new fragment.
#[test]
fn declare_override_virtual_ident_fragment_virtual_first() {
let sym: PkgSymbolId = "virtual".intern();
let sym: SymbolId = "virtual".intern();
let over_src = "src".intern();
let kind = IdentKind::Meta;
@ -1522,7 +1509,7 @@ mod test {
// precedence over the override.
#[test]
fn declare_override_virtual_ident_fragment_override_first() {
let sym: PkgSymbolId = "virtual".intern();
let sym: SymbolId = "virtual".intern();
let over_src = "src".intern();
let kind = IdentKind::Meta;
@ -1565,7 +1552,7 @@ mod test {
#[test]
fn declare_override_virtual_ident_fragment_incompatible_type() {
let sym: PkgSymbolId = "virtual".intern();
let sym: SymbolId = "virtual".intern();
let over_src = "src".intern();
let kind = IdentKind::Meta;
@ -1623,7 +1610,7 @@ mod test {
}
fn add_ident_kind_ignores(given: IdentKind, expected: IdentKind) {
let sym: PkgSymbolId = "tofrag".intern();
let sym: SymbolId = "tofrag".intern();
let src = Source {
generated: true,
..Default::default()
@ -1665,11 +1652,11 @@ mod test {
#[test]
fn source_from_sym_attrs() {
let nsym: PkgSymbolId = "name".intern();
let ssym: PkgSymbolId = "src".intern();
let psym: PkgSymbolId = "parent".intern();
let ysym: PkgSymbolId = "yields".intern();
let fsym: PkgSymbolId = "from".intern();
let nsym: SymbolId = "name".intern();
let ssym: SymbolId = "src".intern();
let psym: SymbolId = "parent".intern();
let ysym: SymbolId = "yields".intern();
let fsym: SymbolId = "from".intern();
let attrs = SymAttrs {
pkg_name: Some(nsym),

View File

@ -244,7 +244,7 @@ mod test {
use crate::ir::asg::IdentObject;
use crate::sym::GlobalSymbolIntern;
type Sut<'a, 'i> = Section<'a, IdentObject<u16>>;
type Sut<'a, 'i> = Section<'a, IdentObject>;
#[test]
fn section_empty() {
@ -356,7 +356,7 @@ mod test {
let mut sections = Sections::new();
let objs = (0..=10)
.map(|i| IdentObject::<u16>::Missing(i.to_string().into()))
.map(|i| IdentObject::Missing(i.to_string().into()))
.collect::<Vec<_>>();
sections.map.head.push(&objs[0]);

View File

@ -27,18 +27,18 @@
//! This IR should be converted into a higher-level IR quickly,
//! especially considering that it will be going away in the future.
use crate::sym::{SymbolId, SymbolIndexSize};
use crate::sym::SymbolId;
use std::convert::TryFrom;
use std::result::Result;
/// Toplevel package attributes.
#[derive(Debug, PartialEq, Eq)]
pub struct PackageAttrs<Ix: SymbolIndexSize> {
#[derive(Debug, Default, PartialEq, Eq)]
pub struct PackageAttrs {
/// Unique package identifier.
///
/// The package name is derived from the filename relative to the
/// project root during compilation (see `relroot`).
pub name: Option<SymbolId<Ix>>,
pub name: Option<SymbolId>,
/// Relative path from package to project root.
pub relroot: Option<String>,
@ -57,20 +57,7 @@ pub struct PackageAttrs<Ix: SymbolIndexSize> {
/// met.
/// This symbol is responsible for including each of those invariants as
/// dependencies so that they are included at link-time.
pub elig: Option<SymbolId<Ix>>,
}
// The derive macro seems to add an `Ix: Default` bound,
// so we'll implement it manually to avoid that.
impl<Ix: SymbolIndexSize> Default for PackageAttrs<Ix> {
fn default() -> Self {
Self {
name: Default::default(),
relroot: Default::default(),
program: Default::default(),
elig: Default::default(),
}
}
pub elig: Option<SymbolId>,
}
/// Symbol attributes.
@ -86,14 +73,14 @@ impl<Ix: SymbolIndexSize> Default for PackageAttrs<Ix> {
/// this is not an opaque type.
/// Consequently,
/// valid values should be enforced by the Rust's type system.
#[derive(Debug, PartialEq, Eq)]
pub struct SymAttrs<Ix: SymbolIndexSize> {
#[derive(Debug, Default, PartialEq, Eq)]
pub struct SymAttrs {
/// Relative path to the package that defined this symbol.
///
/// Object files store relative paths so that they are somewhat
/// portable—the
/// entire project root should be able to be relocated.
pub src: Option<SymbolId<Ix>>,
pub src: Option<SymbolId>,
/// Symbol type.
///
@ -135,14 +122,14 @@ pub struct SymAttrs<Ix: SymbolIndexSize> {
/// relative to the project root.
/// _Note that this is problematic if one wants to compile the equivalent
/// of shared libraries._
pub pkg_name: Option<SymbolId<Ix>>,
pub pkg_name: Option<SymbolId>,
/// The identifier from which this one is derived.
///
/// For example,
/// [`SymType::Cgen`] has a parent [`SymType::Class`] and
/// [`SymType::Gen`] has a parent [`SymType::Rate`].
pub parent: Option<SymbolId<Ix>>,
pub parent: Option<SymbolId>,
/// Whether this identifier was generated by the compiler.
///
@ -157,7 +144,7 @@ pub struct SymAttrs<Ix: SymbolIndexSize> {
///
/// For [`SymType::Class`],
/// this represents an associated [`SymType::Cgen`].
pub yields: Option<SymbolId<Ix>>,
pub yields: Option<SymbolId>,
/// User-friendly identifier description.
///
@ -172,7 +159,7 @@ pub struct SymAttrs<Ix: SymbolIndexSize> {
/// - [`SymType::Map`] includes the name of the source field; and
/// - [`SymType::Func`] lists params in order (so that the compiler
/// knows application order).
pub from: Option<Vec<SymbolId<Ix>>>,
pub from: Option<Vec<SymbolId>>,
/// Whether symbol can be overridden.
///
@ -185,28 +172,6 @@ pub struct SymAttrs<Ix: SymbolIndexSize> {
pub override_: bool,
}
// The derive macro seems to add an `Ix: Default` bound,
// so we'll implement it manually to avoid that.
impl<Ix: SymbolIndexSize> Default for SymAttrs<Ix> {
fn default() -> Self {
Self {
src: Default::default(),
ty: Default::default(),
dim: Default::default(),
dtype: Default::default(),
extern_: Default::default(),
pkg_name: Default::default(),
parent: Default::default(),
generated: Default::default(),
yields: Default::default(),
desc: Default::default(),
from: Default::default(),
virtual_: Default::default(),
override_: Default::default(),
}
}
}
/// Legacy symbol types.
///
/// This enum represents all symbol types represented in the `xmlo` files.

View File

@ -29,9 +29,8 @@
//!
//! _This is a work in progress!_
use crate::global;
use crate::span::Span;
use crate::sym::{GlobalSymbolIntern, SymbolId, SymbolIndexSize};
use crate::sym::{GlobalSymbolIntern, SymbolId};
use std::convert::{TryFrom, TryInto};
use std::fmt::Display;
use std::ops::Deref;
@ -45,18 +44,18 @@ macro_rules! newtype_symbol {
$(
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct $name<Ix: SymbolIndexSize>(SymbolId<Ix>);
pub struct $name(SymbolId);
impl<Ix: SymbolIndexSize> Deref for $name<Ix> {
type Target = SymbolId<Ix>;
impl Deref for $name {
type Target = SymbolId;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<Ix: SymbolIndexSize> PartialEq<SymbolId<Ix>> for $name<Ix> {
fn eq(&self, other: &SymbolId<Ix>) -> bool {
impl PartialEq<SymbolId> for $name {
fn eq(&self, other: &SymbolId) -> bool {
self.0 == *other
}
}
@ -79,7 +78,7 @@ newtype_symbol! {
pub struct NCName;
}
impl<Ix: SymbolIndexSize> NCName<Ix> {
impl NCName {
/// Create a new NCName from a symbol without validating that the symbol
/// is a valid NCName.
///
@ -89,7 +88,7 @@ impl<Ix: SymbolIndexSize> NCName<Ix> {
/// it's unsafe in a sense similar to non-UTF-8 `str` slices,
/// in that it is expected that an `NCName` means that you do not
/// have to worry about whether it's syntatically valid as XML.
pub unsafe fn new_unchecked(value: SymbolId<Ix>) -> Self {
pub unsafe fn new_unchecked(value: SymbolId) -> Self {
Self(value)
}
}
@ -122,7 +121,7 @@ impl std::error::Error for Error {
}
}
impl<Ix: SymbolIndexSize> TryFrom<&str> for NCName<Ix> {
impl TryFrom<&str> for NCName {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
@ -135,39 +134,39 @@ impl<Ix: SymbolIndexSize> TryFrom<&str> for NCName<Ix> {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Prefix<Ix: SymbolIndexSize>(NCName<Ix>);
pub struct Prefix(NCName);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LocalPart<Ix: SymbolIndexSize>(NCName<Ix>);
pub struct LocalPart(NCName);
impl<Ix: SymbolIndexSize> Deref for Prefix<Ix> {
type Target = SymbolId<Ix>;
impl Deref for Prefix {
type Target = SymbolId;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl<Ix: SymbolIndexSize> Deref for LocalPart<Ix> {
type Target = SymbolId<Ix>;
impl Deref for LocalPart {
type Target = SymbolId;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl<Ix: SymbolIndexSize> From<NCName<Ix>> for Prefix<Ix> {
fn from(name: NCName<Ix>) -> Self {
impl From<NCName> for Prefix {
fn from(name: NCName) -> Self {
Self(name)
}
}
impl<Ix: SymbolIndexSize> From<NCName<Ix>> for LocalPart<Ix> {
fn from(name: NCName<Ix>) -> Self {
impl From<NCName> for LocalPart {
fn from(name: NCName) -> Self {
Self(name)
}
}
impl<Ix: SymbolIndexSize> TryFrom<&str> for Prefix<Ix> {
impl TryFrom<&str> for Prefix {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
@ -175,7 +174,7 @@ impl<Ix: SymbolIndexSize> TryFrom<&str> for Prefix<Ix> {
}
}
impl<Ix: SymbolIndexSize> TryFrom<&str> for LocalPart<Ix> {
impl TryFrom<&str> for LocalPart {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
@ -184,17 +183,17 @@ impl<Ix: SymbolIndexSize> TryFrom<&str> for LocalPart<Ix> {
}
#[derive(Debug, PartialEq, Eq)]
pub struct Whitespace<Ix: SymbolIndexSize>(SymbolId<Ix>);
pub struct Whitespace(SymbolId);
impl<Ix: SymbolIndexSize> Deref for Whitespace<Ix> {
type Target = SymbolId<Ix>;
impl Deref for Whitespace {
type Target = SymbolId;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<Ix: SymbolIndexSize> TryFrom<&str> for Whitespace<Ix> {
impl TryFrom<&str> for Whitespace {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
@ -210,8 +209,8 @@ impl<Ix: SymbolIndexSize> TryFrom<&str> for Whitespace<Ix> {
}
}
impl<Ix: SymbolIndexSize> From<Whitespace<Ix>> for Text<Ix> {
fn from(ws: Whitespace<Ix>) -> Self {
impl From<Whitespace> for Text {
fn from(ws: Whitespace) -> Self {
// Whitespace needs no escaping
Self::Escaped(ws.0)
}
@ -219,18 +218,15 @@ impl<Ix: SymbolIndexSize> From<Whitespace<Ix>> for Text<Ix> {
/// A qualified name (namespace prefix and local name).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QName<Ix: SymbolIndexSize>(Option<Prefix<Ix>>, LocalPart<Ix>);
pub struct QName(Option<Prefix>, LocalPart);
// Since we implement Copy, ensure size matches our expectations:
const_assert!(
std::mem::size_of::<QName<global::ProgSymSize>>()
<= std::mem::size_of::<usize>()
);
const_assert!(std::mem::size_of::<QName>() <= std::mem::size_of::<usize>());
impl<Ix: SymbolIndexSize> QName<Ix> {
impl QName {
/// Create a new fully-qualified name (including both a namespace URI
/// and local name).
pub fn new(prefix: Prefix<Ix>, local_name: LocalPart<Ix>) -> Self {
pub fn new(prefix: Prefix, local_name: LocalPart) -> Self {
Self(Some(prefix), local_name)
}
@ -241,26 +237,25 @@ impl<Ix: SymbolIndexSize> QName<Ix> {
///
/// _(If this is ever not true (e.g. due to new targets),
/// please update this comment.)_
pub fn new_local(local_name: LocalPart<Ix>) -> Self {
pub fn new_local(local_name: LocalPart) -> Self {
Self(None, local_name)
}
/// Fully qualified namespace associated with a name.
pub fn prefix(&self) -> Option<Prefix<Ix>> {
pub fn prefix(&self) -> Option<Prefix> {
self.0
}
/// Local part of a name (name without namespace).
pub fn local_name(&self) -> LocalPart<Ix> {
pub fn local_name(&self) -> LocalPart {
self.1
}
}
impl<Ix, P, L> TryFrom<(P, L)> for QName<Ix>
impl<P, L> TryFrom<(P, L)> for QName
where
Ix: SymbolIndexSize,
P: TryInto<Prefix<Ix>>,
L: TryInto<LocalPart<Ix>, Error = P::Error>,
P: TryInto<Prefix>,
L: TryInto<LocalPart, Error = P::Error>,
{
type Error = P::Error;
@ -269,11 +264,10 @@ where
}
}
impl<Ix, P, L> TryFrom<(Option<P>, L)> for QName<Ix>
impl<P, L> TryFrom<(Option<P>, L)> for QName
where
Ix: SymbolIndexSize,
P: TryInto<Prefix<Ix>>,
L: TryInto<LocalPart<Ix>, Error = P::Error>,
P: TryInto<Prefix>,
L: TryInto<LocalPart, Error = P::Error>,
{
type Error = P::Error;
@ -287,10 +281,7 @@ where
}
}
impl<Ix> TryFrom<&str> for QName<Ix>
where
Ix: SymbolIndexSize,
{
impl TryFrom<&str> for QName {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
@ -307,7 +298,7 @@ where
/// (TODO: More information on why this burden isn"t all that bad,
/// despite the risk.)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Text<Ix: SymbolIndexSize> {
pub enum Text {
/// Text node that requires escaping.
///
/// Unescaped text requires further processing before writing.
@ -320,13 +311,13 @@ pub enum Text<Ix: SymbolIndexSize> {
/// if escaping is only needed for writing,
/// it is likely better to leave it to the writer to escape,
/// which does _not_ require interning of the resulting string.
Unescaped(SymbolId<Ix>),
Unescaped(SymbolId),
/// Text node that either has already been escaped or is known not to
/// require escaping.
///
/// Escaped text can be written as-is without any further processing.
Escaped(SymbolId<Ix>),
Escaped(SymbolId),
}
/// Represents an attribute value and its escaped contents.
@ -336,17 +327,17 @@ pub enum Text<Ix: SymbolIndexSize> {
/// This does, however, put the onus on the caller to ensure that they got
/// the escaping status correct.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AttrValue<Ix: SymbolIndexSize> {
pub enum AttrValue {
/// Value that requires escaping.
///
/// Unescaped values require further processing before writing.
Unescaped(SymbolId<Ix>),
Unescaped(SymbolId),
/// Value that either has already been escaped or is known not to
/// require escaping.
///
/// Escaped values can be written as-is without any further processing.
Escaped(SymbolId<Ix>),
Escaped(SymbolId),
}
/// Lightly-structured XML tokens with associated [`Span`]s.
@ -357,9 +348,9 @@ pub enum AttrValue<Ix: SymbolIndexSize> {
/// and so this IR can be processed by a simple state machine
/// (see [`writer::WriterState`]).
#[derive(Debug, PartialEq, Eq)]
pub enum Token<Ix: SymbolIndexSize> {
pub enum Token {
/// Opening tag of an element.
Open(QName<Ix>, Span),
Open(QName, Span),
/// Closing tag of an element.
///
@ -383,13 +374,13 @@ pub enum Token<Ix: SymbolIndexSize> {
/// given especially that bindings after `@` in patterns have not
/// yet been stabalized at the time of writing (but are very
/// close!).
Close(Option<QName<Ix>>, Span),
Close(Option<QName>, Span),
/// Element attribute name.
AttrName(QName<Ix>, Span),
AttrName(QName, Span),
/// Element attribute value.
AttrValue(AttrValue<Ix>, Span),
AttrValue(AttrValue, Span),
/// A portion of an element attribute value.
///
@ -400,15 +391,15 @@ pub enum Token<Ix: SymbolIndexSize> {
/// Since each fragment contains a span,
/// this also potentially gives higher resolution for the origin of
/// components of generated attribute values.
AttrValueFragment(AttrValue<Ix>, Span),
AttrValueFragment(AttrValue, Span),
/// Comment node.
Comment(Text<Ix>, Span),
Comment(Text, Span),
/// Character data as part of an element.
///
/// See also [`CData`](Token::CData) variant.
Text(Text<Ix>, Span),
Text(Text, Span),
/// CData node (`<![CDATA[...]]>`).
///
@ -419,21 +410,20 @@ pub enum Token<Ix: SymbolIndexSize> {
/// This is intended for reading existing XML data where CData is
/// already present,
/// not for producing new CData safely!
CData(Text<Ix>, Span),
CData(Text, Span),
/// Similar to `Text`,
/// but intended for use where only whitespace is allowed,
/// such as alignment of attributes.
Whitespace(Whitespace<Ix>, Span),
Whitespace(Whitespace, Span),
}
#[cfg(test)]
mod test {
use super::*;
use crate::{global, sym::GlobalSymbolIntern};
use crate::sym::GlobalSymbolIntern;
use std::convert::TryInto;
type Ix = global::PkgSymSize;
type TestResult = Result<(), Box<dyn std::error::Error>>;
lazy_static! {
@ -447,12 +437,12 @@ mod test {
#[test]
fn ncname_comparable_to_sym() {
let foo = "foo".intern();
assert_eq!(NCName::<Ix>(foo), foo);
assert_eq!(NCName(foo), foo);
}
#[test]
fn ncname_try_into_from_str_no_colon() -> TestResult {
let name: NCName<Ix> = "no-colon".try_into()?;
let name: NCName = "no-colon".try_into()?;
assert_eq!(name, "no-colon".intern());
Ok(())
}
@ -460,14 +450,14 @@ mod test {
#[test]
fn ncname_try_into_from_str_fails_with_colon() {
assert_eq!(
NCName::<Ix>::try_from("look:a-colon"),
NCName::try_from("look:a-colon"),
Err(Error::NCColon("look:a-colon".into()))
);
}
#[test]
fn local_name_from_local_part_only() -> TestResult {
let name = QName::<Ix>::new_local("foo".try_into()?);
let name = QName::new_local("foo".try_into()?);
assert_eq!(name.local_name(), "foo".try_into()?);
assert_eq!(None, name.prefix());
@ -477,7 +467,7 @@ mod test {
#[test]
fn fully_qualified_name() -> TestResult {
let name: QName<Ix> = ("foons", "foo").try_into()?;
let name: QName = ("foons", "foo").try_into()?;
assert_eq!(name.prefix(), Some("foons".try_into()?));
assert_eq!(name.local_name(), "foo".try_into()?);
@ -488,11 +478,11 @@ mod test {
#[test]
fn whitespace() -> TestResult {
assert_eq!(Whitespace::<Ix>::try_from(" ")?, " ".try_into()?);
assert_eq!(Whitespace::<Ix>::try_from(" \t ")?, " \t ".try_into()?);
assert_eq!(Whitespace::try_from(" ")?, " ".try_into()?);
assert_eq!(Whitespace::try_from(" \t ")?, " \t ".try_into()?);
assert_eq!(
Whitespace::<Ix>::try_from("not ws!"),
Whitespace::try_from("not ws!"),
Err(Error::NotWhitespace("not ws!".into()))
);
@ -503,7 +493,7 @@ mod test {
fn whitespace_as_text() -> TestResult {
assert_eq!(
Text::Escaped(" ".intern()),
Whitespace::<Ix>::try_from(" ")?.into(),
Whitespace::try_from(" ")?.into(),
);
Ok(())

View File

@ -30,13 +30,12 @@
//! use tamer::ir::xir::tree::{ParserState, parse, parser_from};
//!# use tamer::ir::xir::Token;
//!
//!# type Ix = u16;
//!# let token_stream: std::vec::IntoIter<Token<Ix>> = vec![].into_iter();
//!# let token_stream: std::vec::IntoIter<Token> = vec![].into_iter();
//! // Lazily parse a stream of XIR tokens as an iterator, yielding the next
//! // fully parsed object. This may consume any number of tokens.
//! let parser = parser_from(token_stream);
//!
//!# let token_stream: std::vec::IntoIter<Token<Ix>> = vec![].into_iter();
//!# let token_stream: std::vec::IntoIter<Token> = vec![].into_iter();
//! // Consume a single token at a time, yielding either an incomplete state
//! // or the next parsed object.
//! let parser = token_stream.scan(ParserState::new(), parse);
@ -193,7 +192,7 @@
//! see [`AttrParts`].
use super::{AttrValue, QName, Token};
use crate::{span::Span, sym::SymbolIndexSize};
use crate::span::Span;
use std::{fmt::Display, mem::take};
mod attr;
@ -214,14 +213,14 @@ pub use attr::{Attr, AttrList, AttrParts, SimpleAttr};
/// For more information,
/// see the [module-level documentation](self).
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Tree<Ix: SymbolIndexSize> {
pub enum Tree {
/// XML element.
Element(Element<Ix>),
Element(Element),
}
impl<Ix: SymbolIndexSize> Tree<Ix> {
impl Tree {
/// If the tree object is an [`Element`], retrieve it.
pub fn element(self) -> Option<Element<Ix>> {
pub fn element(self) -> Option<Element> {
match self {
Self::Element(ele) => Some(ele),
}
@ -237,17 +236,17 @@ impl<Ix: SymbolIndexSize> Tree<Ix> {
///
/// [XML element]: https://www.w3.org/TR/REC-xml/#sec-starttags
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Element<Ix: SymbolIndexSize> {
name: QName<Ix>,
pub struct Element {
name: QName,
/// Zero or more attributes.
attrs: AttrList<Ix>,
attrs: AttrList,
/// Zero or more child nodes.
children: Vec<Tree<Ix>>,
children: Vec<Tree>,
/// Spans for opening and closing tags respectively.
span: (Span, Span),
}
impl<Ix: SymbolIndexSize> Element<Ix> {
impl Element {
/// Opens an element for incremental construction.
///
/// This is intended for use by the parser to begin building an element.
@ -255,7 +254,7 @@ impl<Ix: SymbolIndexSize> Element<Ix> {
/// to any outside caller until it is complete.
/// This incomplete state is encoded in [`Stack::BuddingElement`].
#[inline]
fn open(name: QName<Ix>, span: Span) -> Self {
fn open(name: QName, span: Span) -> Self {
Self {
name,
attrs: AttrList::new(),
@ -290,15 +289,15 @@ impl<Ix: SymbolIndexSize> Element<Ix> {
/// but we want to nest _only_ element stacks,
/// not any type of stack.
#[derive(Debug, Eq, PartialEq)]
pub struct ElementStack<Ix: SymbolIndexSize> {
element: Element<Ix>,
pub struct ElementStack {
element: Element,
/// Parent element stack to be restored once element has finished
/// processing.
pstack: Option<Box<ElementStack<Ix>>>,
pstack: Option<Box<ElementStack>>,
}
impl<Ix: SymbolIndexSize> ElementStack<Ix> {
impl ElementStack {
/// Attempt to close an element,
/// verifying that the closing tag is either self-closing or
/// balanced.
@ -310,9 +309,9 @@ impl<Ix: SymbolIndexSize> ElementStack<Ix> {
/// attribute parsing.
fn try_close(
self,
close_name: Option<QName<Ix>>,
close_name: Option<QName>,
close_span: Span,
) -> Result<Self, Ix> {
) -> Result<Self> {
let Element {
name: ele_name,
span: (open_span, _),
@ -345,7 +344,7 @@ impl<Ix: SymbolIndexSize> ElementStack<Ix> {
/// then the returned [`Stack`] will represent the state of the stack
/// prior to the child element being opened,
/// as stored with [`ElementStack::store`].
fn consume_child_or_complete(self) -> Stack<Ix> {
fn consume_child_or_complete(self) -> Stack {
match self.pstack {
Some(parent_stack) => Stack::BuddingElement(
parent_stack.consume_element(self.element),
@ -357,14 +356,14 @@ impl<Ix: SymbolIndexSize> ElementStack<Ix> {
/// Push the provided [`Element`] onto the child list of the inner
/// [`Element`].
fn consume_element(mut self, child: Element<Ix>) -> Self {
fn consume_element(mut self, child: Element) -> Self {
self.element.children.push(Tree::Element(child));
self
}
/// Push the provided [`Attr`] onto the attribute list of the inner
/// [`Element`].
fn consume_attr(mut self, attr: Attr<Ix>) -> Self {
fn consume_attr(mut self, attr: Attr) -> Self {
self.element.attrs.push(attr);
self
}
@ -394,7 +393,7 @@ impl<Ix: SymbolIndexSize> ElementStack<Ix> {
/// For more information,
/// see the [module-level documentation](self).
#[derive(Debug, Eq, PartialEq)]
pub enum Stack<Ix: SymbolIndexSize> {
pub enum Stack {
/// Empty stack.
Empty,
@ -402,29 +401,29 @@ pub enum Stack<Ix: SymbolIndexSize> {
///
/// (This is a tree IR,
/// so here's a plant pun).
BuddingElement(ElementStack<Ix>),
BuddingElement(ElementStack),
/// A completed [`Element`].
///
/// This should be consumed and emitted.
ClosedElement(Element<Ix>),
ClosedElement(Element),
/// An attribute is awaiting its value,
/// after which it will be attached to an element.
AttrName(ElementStack<Ix>, QName<Ix>, Span),
AttrName(ElementStack, QName, Span),
/// An attribute whose value is being constructed of value fragments,
/// after which it will be attached to an element.
AttrFragments(ElementStack<Ix>, AttrParts<Ix>),
AttrFragments(ElementStack, AttrParts),
}
impl<Ix: SymbolIndexSize> Default for Stack<Ix> {
impl Default for Stack {
fn default() -> Self {
Self::Empty
}
}
impl<Ix: SymbolIndexSize> Stack<Ix> {
impl Stack {
/// Attempt to open a new element.
///
/// If the stack is [`Self::Empty`],
@ -436,7 +435,7 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// being considered a completed [`Element`].
///
/// Attempting to open an element in any other context is an error.
fn open_element(self, name: QName<Ix>, span: Span) -> Result<Self, Ix> {
fn open_element(self, name: QName, span: Span) -> Result<Self> {
let element = Element::open(name, span);
Ok(Self::BuddingElement(ElementStack {
@ -462,11 +461,7 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// processed---that is,
/// the tree must be _balanced_.
/// An unbalanced tree results in a [`ParseError::UnbalancedTag`].
fn close_element(
self,
name: Option<QName<Ix>>,
span: Span,
) -> Result<Self, Ix> {
fn close_element(self, name: Option<QName>, span: Span) -> Result<Self> {
match self {
Self::BuddingElement(stack) => stack
.try_close(name, span)
@ -481,7 +476,7 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// An attribute begins with a [`QName`] representing its name.
/// It will be attached to a parent element after being closed with a
/// value via [`Stack::close_attr`].
fn open_attr(self, name: QName<Ix>, span: Span) -> Result<Self, Ix> {
fn open_attr(self, name: QName, span: Span) -> Result<Self> {
Ok(match self {
Self::BuddingElement(ele_stack) => {
Self::AttrName(ele_stack, name, span)
@ -501,11 +496,7 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// which is responsible for managing future fragments.
///
/// This will cause heap allocation.
fn push_attr_value(
self,
value: AttrValue<Ix>,
span: Span,
) -> Result<Self, Ix> {
fn push_attr_value(self, value: AttrValue, span: Span) -> Result<Self> {
Ok(match self {
Self::AttrName(ele_stack, name, open_span) => {
// This initial capacity can be adjusted after we observe
@ -532,7 +523,7 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// If the attribute is composed of fragments ([`Stack::AttrFragments`]),
/// this serves as the final fragment and will yield an
/// [`Attr::Extensible`] with no further processing.
fn close_attr(self, value: AttrValue<Ix>, span: Span) -> Result<Self, Ix> {
fn close_attr(self, value: AttrValue, span: Span) -> Result<Self> {
Ok(match self {
Self::AttrName(ele_stack, name, open_span) => {
Stack::BuddingElement(ele_stack.consume_attr(Attr::new(
@ -578,11 +569,11 @@ impl<Ix: SymbolIndexSize> Stack<Ix> {
/// except that a stack is needed to accumulate tokens until we can begin
/// emitting a tree.
#[derive(Debug, Default)]
pub struct ParserState<Ix: SymbolIndexSize> {
stack: Stack<Ix>,
pub struct ParserState {
stack: Stack,
}
impl<Ix: SymbolIndexSize> ParserState<Ix> {
impl ParserState {
/// Create state of a new parser that has not yet seen any input
/// tokens.
///
@ -614,7 +605,7 @@ impl<Ix: SymbolIndexSize> ParserState<Ix> {
///
/// See the [module-level documentation](self) for more information on
/// the implementation of the parser.
pub fn parse_token(&mut self, tok: Token<Ix>) -> Result<Parsed<Ix>, Ix> {
pub fn parse_token(&mut self, tok: Token) -> Result<Parsed> {
let stack = take(&mut self.stack);
match tok {
@ -632,7 +623,7 @@ impl<Ix: SymbolIndexSize> ParserState<Ix> {
}
/// Emit a completed object or store the current stack for further processing.
fn store_or_emit(&mut self, new_stack: Stack<Ix>) -> Parsed<Ix> {
fn store_or_emit(&mut self, new_stack: Stack) -> Parsed {
match new_stack {
Stack::ClosedElement(ele) => Parsed::Object(Tree::Element(ele)),
@ -645,23 +636,23 @@ impl<Ix: SymbolIndexSize> ParserState<Ix> {
}
/// Result of a XIR tree parsing operation.
pub type Result<T, Ix> = std::result::Result<T, ParseError<Ix>>;
pub type Result<T> = std::result::Result<T, ParseError>;
/// Parsing error from [`ParserState`].
#[derive(Debug, Eq, PartialEq)]
pub enum ParseError<Ix: SymbolIndexSize> {
pub enum ParseError {
/// The closing tag does not match the opening tag at the same level of
/// nesting.
UnbalancedTag {
open: (QName<Ix>, Span),
close: (QName<Ix>, Span),
open: (QName, Span),
close: (QName, Span),
},
/// Not yet implemented.
Todo(Token<Ix>, Stack<Ix>),
Todo(Token, Stack),
}
impl<Ix: SymbolIndexSize> Display for ParseError<Ix> {
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
// TODO: not a useful error because of symbols and missing span information
@ -695,12 +686,12 @@ impl<Ix: SymbolIndexSize> Display for ParseError<Ix> {
/// This has the same structure as [`Option`],
/// but is its own type to avoid confusion as to what this type may mean
/// when deeply nested within other types
/// (e.g. `Option<Result<Parsed<Ix>, ParserError>>` reads a bit better
/// than `Option<Result<Option<Tree<Ix>>, ParserError>>`).
/// (e.g. `Option<Result<Parsed, ParserError>>` reads a bit better
/// than `Option<Result<Option<Tree>, ParserError>>`).
#[derive(Debug, Eq, PartialEq)]
pub enum Parsed<Ix: SymbolIndexSize> {
pub enum Parsed {
/// Parsing of an object is complete.
Object(Tree<Ix>),
Object(Tree),
/// The parser needs more token data to emit an object
/// (the active context is not yet complete).
@ -724,15 +715,11 @@ pub enum Parsed<Ix: SymbolIndexSize> {
/// use tamer::ir::xir::tree::{ParserState, parse};
///# use tamer::ir::xir::Token;
///
///# type Ix = u16;
///# let token_stream: std::vec::IntoIter<Token<Ix>> = vec![].into_iter();
///# let token_stream: std::vec::IntoIter<Token> = vec![].into_iter();
/// // The above is equivalent to:
/// let parser = token_stream.scan(ParserState::new(), parse);
/// ```
pub fn parse<Ix: SymbolIndexSize>(
state: &mut ParserState<Ix>,
tok: Token<Ix>,
) -> Option<Result<Parsed<Ix>, Ix>> {
pub fn parse(state: &mut ParserState, tok: Token) -> Option<Result<Parsed>> {
Some(ParserState::parse_token(state, tok))
}
@ -756,14 +743,13 @@ pub fn parse<Ix: SymbolIndexSize>(
/// use tamer::ir::xir::tree::parser_from;
///# use tamer::ir::xir::Token;
///
///# type Ix = u16;
///# let token_stream: std::vec::IntoIter<Token<Ix>> = vec![].into_iter();
///# let token_stream: std::vec::IntoIter<Token> = vec![].into_iter();
/// // Lazily parse a stream of XIR tokens as an iterator.
/// let parser = parser_from(token_stream);
/// ```
pub fn parser_from<Ix: SymbolIndexSize>(
toks: impl Iterator<Item = Token<Ix>>,
) -> impl Iterator<Item = Result<Tree<Ix>, Ix>> {
pub fn parser_from(
toks: impl Iterator<Item = Token>,
) -> impl Iterator<Item = Result<Tree>> {
toks.scan(ParserState::new(), parse)
.filter_map(|parsed| match parsed {
Ok(Parsed::Object(tree)) => Some(Ok(tree)),

View File

@ -24,7 +24,7 @@
//! See [parent module](super) for additional documentation.
use super::{AttrValue, QName};
use crate::{span::Span, sym::SymbolIndexSize};
use crate::span::Span;
/// An attribute.
///
@ -36,12 +36,12 @@ use crate::{span::Span, sym::SymbolIndexSize};
/// If you do not care about the distinction between the two types,
/// use the API provided by this enum for common functionality.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Attr<Ix: SymbolIndexSize> {
Simple(SimpleAttr<Ix>),
Extensible(AttrParts<Ix>),
pub enum Attr {
Simple(SimpleAttr),
Extensible(AttrParts),
}
impl<Ix: SymbolIndexSize> Attr<Ix> {
impl Attr {
/// Construct a new simple attribute with a name, value, and respective
/// [`Span`]s.
///
@ -49,11 +49,7 @@ impl<Ix: SymbolIndexSize> Attr<Ix> {
/// but it can be cheaply converted into [`Attr::Extensible`] via
/// [`Attr::parts`] or [`From`].
#[inline]
pub fn new(
name: QName<Ix>,
value: AttrValue<Ix>,
span: (Span, Span),
) -> Self {
pub fn new(name: QName, value: AttrValue, span: (Span, Span)) -> Self {
Self::Simple(SimpleAttr::new(name, value, span))
}
@ -66,7 +62,7 @@ impl<Ix: SymbolIndexSize> Attr<Ix> {
/// [`Span`] resolution and being zero-copy.
#[inline]
pub fn new_extensible_with_capacity(
name: QName<Ix>,
name: QName,
name_span: Span,
capacity: usize,
) -> Self {
@ -80,9 +76,9 @@ impl<Ix: SymbolIndexSize> Attr<Ix> {
/// or re-using them in conjunction with [`AttrParts::into_fragments`].
#[inline]
pub fn from_fragments(
name: QName<Ix>,
name: QName,
name_span: Span,
frags: Vec<(AttrValue<Ix>, Span)>,
frags: Vec<(AttrValue, Span)>,
) -> Self {
Self::Extensible(AttrParts {
name,
@ -101,7 +97,7 @@ impl<Ix: SymbolIndexSize> Attr<Ix> {
/// it will be converted into an extensible attribute with one value
/// fragment and then returned.
#[inline]
pub fn parts(self) -> AttrParts<Ix> {
pub fn parts(self) -> AttrParts {
match self {
Self::Simple(attr) => attr.into(),
Self::Extensible(parts) => parts,
@ -114,22 +110,18 @@ impl<Ix: SymbolIndexSize> Attr<Ix> {
/// This should be used in place of [`AttrParts`] whenever the attribute is
/// a simple [`QName`]/[`AttrValue`] pair.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SimpleAttr<Ix: SymbolIndexSize> {
name: QName<Ix>,
value: AttrValue<Ix>,
pub struct SimpleAttr {
name: QName,
value: AttrValue,
/// Spans for the attribute name and value respectively.
span: (Span, Span),
}
impl<Ix: SymbolIndexSize> SimpleAttr<Ix> {
impl SimpleAttr {
/// Construct a new simple attribute with a name, value, and respective
/// [`Span`]s.
#[inline]
pub fn new(
name: QName<Ix>,
value: AttrValue<Ix>,
span: (Span, Span),
) -> Self {
pub fn new(name: QName, value: AttrValue, span: (Span, Span)) -> Self {
Self { name, value, span }
}
}
@ -142,23 +134,23 @@ impl<Ix: SymbolIndexSize> SimpleAttr<Ix> {
/// 3. You need to parse a XIR stream with
/// [`Token::AttrValueFragment`](super::Token::AttrValueFragment).
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct AttrParts<Ix: SymbolIndexSize> {
name: QName<Ix>,
pub struct AttrParts {
name: QName,
name_span: Span,
/// Ordered value fragments and their associated [`Span`]s.
///
/// When writing,
/// fragments will be concatenated in order without any delimiters.
value_frags: Vec<(AttrValue<Ix>, Span)>,
value_frags: Vec<(AttrValue, Span)>,
}
impl<Ix: SymbolIndexSize> AttrParts<Ix> {
impl AttrParts {
/// Construct a new simple attribute with a name, value, and respective
/// [`Span`]s.
#[inline]
pub fn with_capacity(
name: QName<Ix>,
name: QName,
name_span: Span,
capacity: usize,
) -> Self {
@ -170,7 +162,7 @@ impl<Ix: SymbolIndexSize> AttrParts<Ix> {
}
}
impl<Ix: SymbolIndexSize> AttrParts<Ix> {
impl AttrParts {
/// Append a new value fragment and its associated span.
///
/// Value fragments are intended to be concatenated on write without a
@ -178,7 +170,7 @@ impl<Ix: SymbolIndexSize> AttrParts<Ix> {
/// and are associated with
/// [`Token::AttrValueFragment`](super::Token::AttrValueFragment).
#[inline]
pub fn push_value(&mut self, value: AttrValue<Ix>, span: Span) {
pub fn push_value(&mut self, value: AttrValue, span: Span) {
self.value_frags.push((value, span));
}
@ -189,7 +181,7 @@ impl<Ix: SymbolIndexSize> AttrParts<Ix> {
/// [`AttrParts`],
/// see [`into_fragments`](AttrParts::into_fragments).
#[inline]
pub fn value_fragments(&self) -> &Vec<(AttrValue<Ix>, Span)> {
pub fn value_fragments(&self) -> &Vec<(AttrValue, Span)> {
&self.value_frags
}
@ -199,13 +191,13 @@ impl<Ix: SymbolIndexSize> AttrParts<Ix> {
/// This allows the buffer to be re-used for future [`AttrParts`],
/// avoiding additional heap allocations.
#[inline]
pub fn into_fragments(self) -> Vec<(AttrValue<Ix>, Span)> {
pub fn into_fragments(self) -> Vec<(AttrValue, Span)> {
self.value_frags
}
}
impl<Ix: SymbolIndexSize> From<SimpleAttr<Ix>> for AttrParts<Ix> {
fn from(attr: SimpleAttr<Ix>) -> Self {
impl From<SimpleAttr> for AttrParts {
fn from(attr: SimpleAttr) -> Self {
Self {
name: attr.name,
name_span: attr.span.0,
@ -214,8 +206,8 @@ impl<Ix: SymbolIndexSize> From<SimpleAttr<Ix>> for AttrParts<Ix> {
}
}
impl<Ix: SymbolIndexSize> From<Attr<Ix>> for AttrParts<Ix> {
fn from(attr: Attr<Ix>) -> Self {
impl From<Attr> for AttrParts {
fn from(attr: Attr) -> Self {
match attr {
Attr::Simple(inner) => inner.into(),
Attr::Extensible(inner) => inner,
@ -232,30 +224,30 @@ impl<Ix: SymbolIndexSize> From<Attr<Ix>> for AttrParts<Ix> {
/// 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<Ix: SymbolIndexSize> {
attrs: Vec<Attr<Ix>>,
pub struct AttrList {
attrs: Vec<Attr>,
}
impl<Ix: SymbolIndexSize> AttrList<Ix> {
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<Ix>) {
pub fn push(&mut self, attr: Attr) {
self.attrs.push(attr)
}
}
impl<Ix: SymbolIndexSize> From<Vec<Attr<Ix>>> for AttrList<Ix> {
fn from(attrs: Vec<Attr<Ix>>) -> Self {
impl From<Vec<Attr>> for AttrList {
fn from(attrs: Vec<Attr>) -> Self {
AttrList { attrs }
}
}
impl<Ix: SymbolIndexSize, const N: usize> From<[Attr<Ix>; N]> for AttrList<Ix> {
fn from(attrs: [Attr<Ix>; N]) -> Self {
impl<const N: usize> From<[Attr; N]> for AttrList {
fn from(attrs: [Attr; N]) -> Self {
AttrList {
attrs: attrs.into(),
}
@ -268,8 +260,6 @@ mod test {
use super::*;
use crate::{convert::ExpectInto, sym::GlobalSymbolIntern};
type Ix = crate::global::ProgSymSize;
lazy_static! {
static ref S: Span =
Span::from_byte_interval((0, 0), "test case, 1".intern());
@ -282,7 +272,7 @@ mod test {
let name = "attr".unwrap_into();
let value = AttrValue::Escaped("value".intern());
let attr = SimpleAttr::<Ix> {
let attr = SimpleAttr {
name,
value,
span: (*S, *S2),
@ -310,8 +300,7 @@ mod test {
let value1 = AttrValue::Escaped("first".intern());
let value2 = AttrValue::Escaped("second".intern());
let mut attr =
Attr::<Ix>::new_extensible_with_capacity(name, *S, 2).parts();
let mut attr = Attr::new_extensible_with_capacity(name, *S, 2).parts();
attr.push_value(value1, *S);
attr.push_value(value2, *S2);
@ -325,12 +314,9 @@ mod test {
let value1 = AttrValue::Escaped("first".intern());
let value2 = AttrValue::Escaped("second".intern());
let attr = Attr::<Ix>::from_fragments(
name,
*S,
vec![(value1, *S), (value2, *S2)],
)
.parts();
let attr =
Attr::from_fragments(name, *S, vec![(value1, *S), (value2, *S2)])
.parts();
assert_eq!(&vec![(value1, *S), (value2, *S2)], attr.value_fragments());
}
@ -344,7 +330,7 @@ mod test {
let frags = vec![(value1, *S2), (value2, *S)];
let mut attr1 = Attr::<Ix>::from_fragments(name, *S, frags).parts();
let mut attr1 = Attr::from_fragments(name, *S, frags).parts();
attr1.push_value(value3, *S2);
// Notice that the value is owned, and so we can call

View File

@ -21,8 +21,6 @@ use super::*;
use crate::convert::ExpectInto;
use crate::sym::GlobalSymbolIntern;
type Ix = u16;
lazy_static! {
static ref S: Span =
Span::from_byte_interval((0, 0), "test case, 1".intern());
@ -37,7 +35,7 @@ mod tree {
#[test]
fn element_from_tree() {
let ele = Element::<Ix> {
let ele = Element {
name: "foo".unwrap_into(),
attrs: AttrList::new(),
children: vec![],
@ -55,8 +53,8 @@ fn empty_element_self_close_from_toks() {
let name = ("ns", "elem").unwrap_into();
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(name, *S),
Token::<Ix>::Close(None, *S2),
Token::Open(name, *S),
Token::Close(None, *S2),
]);
let expected = Element {
@ -83,8 +81,8 @@ fn empty_element_balanced_close_from_toks() {
let name = ("ns", "openclose").unwrap_into();
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(name, *S),
Token::<Ix>::Close(Some(name), *S2),
Token::Open(name, *S),
Token::Close(Some(name), *S2),
]);
let expected = Element {
@ -112,8 +110,8 @@ fn empty_element_unbalanced_close_from_toks() {
let close_name = "unbalanced_name".unwrap_into();
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(open_name, *S),
Token::<Ix>::Close(Some(close_name), *S2),
Token::Open(open_name, *S),
Token::Close(Some(close_name), *S2),
]);
let mut sut = toks.scan(ParserState::new(), parse);
@ -142,7 +140,7 @@ fn empty_element_with_attrs_from_toks() {
let val2c = AttrValue::Escaped("val2b".intern());
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(name, *S),
Token::Open(name, *S),
Token::AttrName(attr1, *S),
Token::AttrValue(val1, *S2),
Token::AttrName(attr2, *S),
@ -190,12 +188,12 @@ fn element_with_empty_sibling_children() {
let childb = "childb".unwrap_into();
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(parent, *S),
Token::<Ix>::Open(childa, *S),
Token::<Ix>::Close(None, *S2),
Token::<Ix>::Open(childb, *S),
Token::<Ix>::Close(None, *S2),
Token::<Ix>::Close(Some(parent), *S2),
Token::Open(parent, *S),
Token::Open(childa, *S),
Token::Close(None, *S2),
Token::Open(childb, *S),
Token::Close(None, *S2),
Token::Close(Some(parent), *S2),
]);
let expected = Element {
@ -233,12 +231,12 @@ fn element_with_child_with_attributes() {
let value = AttrValue::Escaped("attr value".into());
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(parent, *S),
Token::<Ix>::Open(child, *S),
Token::<Ix>::AttrName(attr, *S),
Token::<Ix>::AttrValue(value, *S2),
Token::<Ix>::Close(None, *S3),
Token::<Ix>::Close(Some(parent), *S3),
Token::Open(parent, *S),
Token::Open(child, *S),
Token::AttrName(attr, *S),
Token::AttrValue(value, *S2),
Token::Close(None, *S3),
Token::Close(Some(parent), *S3),
]);
let expected = Element {
@ -266,7 +264,7 @@ fn parser_from_filters_incomplete() {
let val = AttrValue::Escaped("val1".intern());
let toks = std::array::IntoIter::new([
Token::<Ix>::Open(name, *S),
Token::Open(name, *S),
Token::AttrName(attr, *S),
Token::AttrValue(val, *S2),
Token::Close(None, *S2),

View File

@ -22,7 +22,6 @@
use super::{Error as XirError, QName, Token};
use crate::ir::xir::{AttrValue, Text};
use crate::sym::GlobalSymbolResolve;
use crate::sym::SymbolIndexSize;
use std::io::{Error as IoError, Write};
use std::result;
@ -156,7 +155,7 @@ pub trait XmlWriter: Sized {
}
}
impl<Ix: SymbolIndexSize> XmlWriter for QName<Ix> {
impl XmlWriter for QName {
#[inline]
fn write<W: Write>(self, sink: &mut W, prev_state: WriterState) -> Result {
if let Some(prefix) = self.prefix() {
@ -169,7 +168,7 @@ impl<Ix: SymbolIndexSize> XmlWriter for QName<Ix> {
}
}
impl<Ix: SymbolIndexSize> XmlWriter for Token<Ix> {
impl XmlWriter for Token {
fn write<W: Write>(self, sink: &mut W, prev_state: WriterState) -> Result {
type S = WriterState; // More concise
@ -316,7 +315,7 @@ impl<Ix: SymbolIndexSize> XmlWriter for Token<Ix> {
}
}
impl<Ix: SymbolIndexSize, I: Iterator<Item = Token<Ix>>> XmlWriter for I {
impl<I: Iterator<Item = Token>> XmlWriter for I {
fn write<W: Write>(
mut self,
sink: &mut W,
@ -341,8 +340,6 @@ mod test {
type TestResult = std::result::Result<(), Error>;
type Ix = u16;
lazy_static! {
static ref S: Span =
Span::from_byte_interval((0, 0), "test case".intern());
@ -350,7 +347,7 @@ mod test {
#[test]
fn writes_beginning_node_tag_without_prefix() -> TestResult {
let name = QName::<Ix>::new_local("no-prefix".try_into()?);
let name = QName::new_local("no-prefix".try_into()?);
let result = Token::Open(name, *S).write_new(Default::default())?;
assert_eq!(result.0, b"<no-prefix");
@ -361,7 +358,7 @@ mod test {
#[test]
fn writes_beginning_node_tag_with_prefix() -> TestResult {
let name = QName::<Ix>::try_from(("prefix", "element-name"))?;
let name = QName::try_from(("prefix", "element-name"))?;
let result = Token::Open(name, *S).write_new(Default::default())?;
assert_eq!(result.0, b"<prefix:element-name");
@ -372,7 +369,7 @@ mod test {
#[test]
fn closes_open_node_when_opening_another() -> TestResult {
let name = QName::<Ix>::try_from(("p", "another-element"))?;
let name = QName::try_from(("p", "another-element"))?;
let result = Token::Open(name, *S).write_new(WriterState::NodeOpen)?;
assert_eq!(result.0, b"><p:another-element");
@ -383,8 +380,7 @@ mod test {
#[test]
fn closes_open_node_as_empty_element() -> TestResult {
let result =
Token::<Ix>::Close(None, *S).write_new(WriterState::NodeOpen)?;
let result = Token::Close(None, *S).write_new(WriterState::NodeOpen)?;
assert_eq!(result.0, b"/>");
assert_eq!(result.1, WriterState::NodeExpected);
@ -394,7 +390,7 @@ mod test {
#[test]
fn closing_tag_when_node_expected() -> TestResult {
let name = QName::<Ix>::try_from(("a", "closed-element"))?;
let name = QName::try_from(("a", "closed-element"))?;
let result = Token::Close(Some(name), *S)
.write_new(WriterState::NodeExpected)?;
@ -409,7 +405,7 @@ mod test {
// to explicitly support outputting malformed XML.
#[test]
fn closes_open_node_with_closing_tag() -> TestResult {
let name = QName::<Ix>::try_from(("b", "closed-element"))?;
let name = QName::try_from(("b", "closed-element"))?;
let result =
Token::Close(Some(name), *S).write_new(WriterState::NodeOpen)?;
@ -423,7 +419,7 @@ mod test {
// Intended for alignment of attributes, primarily.
#[test]
fn whitespace_within_open_node() -> TestResult {
let result = Token::<Ix>::Whitespace(Whitespace::try_from(" \t ")?, *S)
let result = Token::Whitespace(Whitespace::try_from(" \t ")?, *S)
.write_new(WriterState::NodeOpen)?;
assert_eq!(result.0, b" \t ");
@ -434,8 +430,8 @@ mod test {
#[test]
fn writes_attr_name_to_open_node() -> TestResult {
let name_ns = QName::<Ix>::try_from(("some", "attr"))?;
let name_local = QName::<Ix>::new_local("nons".try_into()?);
let name_ns = QName::try_from(("some", "attr"))?;
let name_local = QName::new_local("nons".try_into()?);
// Namespace prefix
let result =
@ -456,7 +452,7 @@ mod test {
fn writes_escaped_attr_value_when_adjacent_to_attr() -> TestResult {
// Just to be sure it's not trying to escape when we say it
// shouldn't, we include a character that must otherwise be escaped.
let value = AttrValue::<Ix>::Escaped("test \" escaped".intern());
let value = AttrValue::Escaped("test \" escaped".intern());
let result = Token::AttrValue(value, *S)
.write_new(WriterState::AttrNameAdjacent)?;
@ -469,8 +465,8 @@ mod test {
#[test]
fn writes_escaped_attr_value_consisting_of_fragments() -> TestResult {
let value_left = AttrValue::<Ix>::Escaped("left ".intern());
let value_right = AttrValue::<Ix>::Escaped("right".intern());
let value_left = AttrValue::Escaped("left ".intern());
let value_right = AttrValue::Escaped("right".intern());
let result = vec![
Token::AttrValueFragment(value_left, *S),
@ -489,7 +485,7 @@ mod test {
fn writes_escaped_text() -> TestResult {
// Just to be sure it's not trying to escape when we say it
// shouldn't, we include a character that must otherwise be escaped.
let text = Text::<Ix>::Escaped("test > escaped".intern());
let text = Text::Escaped("test > escaped".intern());
// When a node is expected.
let result =
@ -509,7 +505,7 @@ mod test {
fn writes_unescaped_data() -> TestResult {
// Just to be sure it's not trying to escape when we say it
// shouldn't, we include a character that must otherwise be escaped.
let text = Text::<Ix>::Unescaped("test > unescaped".intern());
let text = Text::Unescaped("test > unescaped".intern());
// When a node is expected.
let result =
@ -529,7 +525,7 @@ mod test {
fn writes_escaped_comment() -> TestResult {
// Just to be sure it's not trying to escape when we say it
// shouldn't, we include a character that must otherwise be escaped.
let comment = Text::<Ix>::Escaped("comment > escaped".intern());
let comment = Text::Escaped("comment > escaped".intern());
// When a node is expected.
let result =
@ -549,7 +545,7 @@ mod test {
#[test]
fn unsupported_transition_results_in_error() -> TestResult {
assert!(matches!(
Token::AttrValue(AttrValue::<Ix>::Escaped("".into()), *S)
Token::AttrValue(AttrValue::Escaped("".into()), *S)
.write(&mut vec![], WriterState::NodeExpected),
Err(Error::UnexpectedToken(_, WriterState::NodeExpected)),
));
@ -561,7 +557,7 @@ mod test {
// practice.
#[test]
fn test_valid_sequence_of_tokens() -> TestResult {
let root: QName<Ix> = ("r", "root").try_into()?;
let root: QName = ("r", "root").try_into()?;
let result = vec![
Token::Open(root, *S),

View File

@ -39,8 +39,7 @@ use std::fs;
use std::io::{BufReader, BufWriter};
use std::path::{Path, PathBuf};
type LinkerAsg =
DefaultAsg<IdentObject<global::ProgSymSize>, global::ProgIdentSize>;
type LinkerAsg = DefaultAsg<IdentObject, global::ProgIdentSize>;
type LinkerAsgBuilderState =
AsgBuilderState<FxBuildHasher, global::ProgIdentSize>;
@ -177,7 +176,7 @@ fn load_xmlo<'a, P: AsRef<Path>>(
let (path, file) = cfile.into();
let xmlo: XmloReader<_, _> = file.into();
let xmlo: XmloReader<_> = file.into();
let mut state = depgraph.import_xmlo(xmlo, state)?;
@ -201,7 +200,7 @@ fn load_xmlo<'a, P: AsRef<Path>>(
fn get_ident<'a>(
depgraph: &'a LinkerAsg,
name: SymbolId<global::ProgSymSize>,
) -> Result<&'a IdentObject<global::ProgSymSize>, String> {
) -> Result<&'a IdentObject, String> {
depgraph
.lookup(name)
.and_then(|id| depgraph.get(id))
@ -210,8 +209,8 @@ fn get_ident<'a>(
fn output_xmle<'a>(
depgraph: &'a LinkerAsg,
sorted: &mut Sections<'a, IdentObject<global::ProgSymSize>>,
name: SymbolId<global::ProgSymSize>,
sorted: &mut Sections<'a, IdentObject>,
name: SymbolId,
relroot: String,
output: &str,
) -> Result<(), Box<dyn Error>> {

View File

@ -33,7 +33,7 @@
//! use tamer::sym::GlobalSymbolIntern;
//! use std::io::Cursor;
//!
//! let sections = Sections::<IdentObject<_>>::new();
//! let sections = Sections::<IdentObject>::new();
//! let writer = Cursor::new(Vec::new());
//! let mut xmle_writer = XmleWriter::new(writer);
//! xmle_writer.write(&sections, "foo".intern(), &String::from(""));

View File

@ -18,7 +18,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::ir::asg::Sections;
use crate::sym::ProgSymbolId;
use crate::sym::SymbolId;
use quick_xml::Error as XmlError;
use std::io::{Error as IoError, Write};
use std::result;
@ -33,7 +33,7 @@ pub trait Writer<W: Write> {
fn write<T>(
&mut self,
sections: &Sections<T>,
name: ProgSymbolId,
name: SymbolId,
relroot: &str,
) -> Result<()>
where

View File

@ -18,11 +18,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use super::writer::{Result, WriterError};
use crate::global;
use crate::ir::asg::{
IdentKind, IdentObject, IdentObjectData, Sections, SectionsIter,
};
use crate::sym::{GlobalSymbolResolve, ProgSymbolId, SymbolId};
use crate::sym::{GlobalSymbolResolve, SymbolId};
use fxhash::FxHashSet;
#[cfg(test)]
use mock::MockXmlWriter as XmlWriter;
@ -37,8 +36,6 @@ pub struct XmleWriter<W: Write> {
writer: XmlWriter<W>,
}
type Ix = global::ProgSymSize;
impl<W: Write> XmleWriter<W> {
/// Create a new instance of `XmleWriter`
/// ```
@ -81,7 +78,7 @@ impl<W: Write> XmleWriter<W> {
///
/// let writer = Cursor::new(Vec::new());
/// let mut xmle_writer = XmleWriter::new(writer);
/// let sections = Sections::<IdentObject<_>>::new();
/// let sections = Sections::<IdentObject>::new();
/// let name = "foo".intern();
/// xmle_writer.write(
/// &sections,
@ -91,10 +88,10 @@ impl<W: Write> XmleWriter<W> {
/// let buf = xmle_writer.into_inner().into_inner();
/// assert!(!buf.is_empty(), "something was written to the buffer");
/// ```
pub fn write<T: IdentObjectData<Ix>>(
pub fn write<T: IdentObjectData>(
&mut self,
sections: &Sections<T>,
name: SymbolId<Ix>,
name: SymbolId,
relroot: &str,
) -> Result {
self.write_start_package(name, &relroot)?
@ -150,7 +147,7 @@ impl<W: Write> XmleWriter<W> {
/// `write_start_tag` directly.
fn write_start_package(
&mut self,
name: SymbolId<Ix>,
name: SymbolId,
relroot: &str,
) -> Result<&mut XmleWriter<W>> {
let name_str = name.lookup_str();
@ -191,7 +188,7 @@ impl<W: Write> XmleWriter<W> {
///
/// All the [`Sections`] found need to be written out using the `writer`
/// object.
fn write_sections<T: IdentObjectData<Ix>>(
fn write_sections<T: IdentObjectData>(
&mut self,
sections: &Sections<T>,
relroot: &str,
@ -301,11 +298,11 @@ impl<W: Write> XmleWriter<W> {
///
/// If a `map` object has a `from` attribute in its source, we need to
/// write them using the `writer`'s `write_event`.
fn write_froms<T: IdentObjectData<Ix>>(
fn write_froms<T: IdentObjectData>(
&mut self,
sections: &Sections<T>,
) -> Result<&mut XmleWriter<W>> {
let mut map_froms: FxHashSet<ProgSymbolId> = Default::default();
let mut map_froms: FxHashSet<SymbolId> = Default::default();
let map_iter = sections.iter_map();
@ -335,7 +332,7 @@ impl<W: Write> XmleWriter<W> {
///
/// Iterates through the parts of a `Section` and writes them using the
/// `writer`'s 'write_event`.
fn write_section<T: IdentObjectData<Ix>>(
fn write_section<T: IdentObjectData>(
&mut self,
idents: SectionsIter<T>,
) -> Result<&mut XmleWriter<W>> {

View File

@ -55,7 +55,7 @@
//! </package>"#;
//!
//! let xmlo = XmloReader::new(src_xmlo);
//! let mut asg = DefaultAsg::<IdentObject<_>, global::ProgIdentSize>::new();
//! let mut asg = DefaultAsg::<IdentObject>::new();
//!
//! let state = asg.import_xmlo(xmlo, AsgBuilderState::<FxBuildHasher, _>::new());
//!
@ -72,7 +72,7 @@ use crate::ir::asg::{
Asg, AsgError, IdentKind, IdentKindError, IdentObjectState, IndexType,
ObjectRef, Source,
};
use crate::sym::{GlobalSymbolResolve, SymbolId, SymbolIndexSize, SymbolStr};
use crate::sym::{GlobalSymbolResolve, SymbolId, SymbolStr};
use std::collections::HashSet;
use std::convert::TryInto;
use std::error::Error;
@ -105,7 +105,7 @@ pub type Result<S, Ix> =
pub struct AsgBuilderState<S, Ix>
where
S: BuildHasher,
Ix: IndexType + SymbolIndexSize,
Ix: IndexType,
{
/// Discovered roots.
///
@ -122,12 +122,12 @@ where
///
/// See [`AsgBuilder::import_xmlo`] for behavior when this value is
/// [`None`].
pub found: Option<HashSet<SymbolId<Ix>, S>>,
pub found: Option<HashSet<SymbolId, S>>,
/// Program name once discovered.
///
/// This will be set by the first package encountered.
pub name: Option<SymbolId<Ix>>,
pub name: Option<SymbolId>,
/// Relative path to project root once discovered.
///
@ -138,7 +138,7 @@ where
impl<S, Ix> AsgBuilderState<S, Ix>
where
S: BuildHasher + Default,
Ix: IndexType + SymbolIndexSize,
Ix: IndexType,
{
/// Create a new, empty state.
pub fn new() -> Self {
@ -162,9 +162,9 @@ where
/// See the [module-level documentation](self) for example usage.
pub trait AsgBuilder<O, S, Ix>
where
O: IdentObjectState<Ix, O>,
O: IdentObjectState<O>,
S: BuildHasher,
Ix: IndexType + SymbolIndexSize,
Ix: IndexType,
{
/// Import [`XmloResult`]s into an [`Asg`].
///
@ -178,21 +178,21 @@ where
/// Its initial value can be provided as [`Default::default`].
fn import_xmlo(
&mut self,
xmlo: impl Iterator<Item = XmloResult<XmloEvent<Ix>>>,
xmlo: impl Iterator<Item = XmloResult<XmloEvent>>,
state: AsgBuilderState<S, Ix>,
) -> Result<S, Ix>;
}
impl<O, S, Ix, G> AsgBuilder<O, S, Ix> for G
where
O: IdentObjectState<Ix, O>,
O: IdentObjectState<O>,
S: BuildHasher + Default,
Ix: IndexType + SymbolIndexSize,
Ix: IndexType,
G: Asg<O, Ix>,
{
fn import_xmlo(
&mut self,
mut xmlo: impl Iterator<Item = XmloResult<XmloEvent<Ix>>>,
mut xmlo: impl Iterator<Item = XmloResult<XmloEvent>>,
mut state: AsgBuilderState<S, Ix>,
) -> Result<S, Ix> {
let mut elig = None;
@ -223,7 +223,7 @@ where
let extern_ = attrs.extern_;
let kindval = (&attrs).try_into()?;
let mut src: Source<Ix> = attrs.into();
let mut src: Source = attrs.into();
// Existing convention is to omit @src of local package
// (in this case, the program being linked)
@ -362,7 +362,7 @@ mod test {
use std::collections::hash_map::RandomState;
type SutIx = u16;
type Sut<'i> = DefaultAsg<IdentObject<SutIx>, SutIx>;
type Sut<'i> = DefaultAsg<IdentObject, SutIx>;
type SutState<'i> = AsgBuilderState<RandomState, SutIx>;
#[test]

View File

@ -54,7 +54,7 @@
//! use tamer::global;
//! use tamer::ir::legacyir::SymType;
//! use tamer::obj::xmlo::{XmloEvent, XmloReader};
//! use tamer::sym::{GlobalSymbolIntern, GlobalSymbolResolve, PkgSymbolId};
//! use tamer::sym::{GlobalSymbolIntern, GlobalSymbolResolve};
//!
//! let xmlo = br#"<package name="foo">
//! <preproc:symtable>
@ -78,7 +78,7 @@
//! </preproc:fragments>
//! </package>"#;
//!
//! let mut reader = XmloReader::<_, global::PkgSymSize>::new(xmlo as &[u8]);
//! let mut reader = XmloReader::<_>::new(xmlo as &[u8]);
//!
//! let mut pkgname = None;
//! let mut syms = Vec::new();
@ -138,8 +138,7 @@
use crate::ir::legacyir::{PackageAttrs, SymAttrs, SymType};
use crate::sym::{
GlobalSymbolInternUnchecked, GlobalSymbolResolve, SymbolId,
SymbolIndexSize, SymbolStr,
GlobalSymbolInternUnchecked, GlobalSymbolResolve, SymbolId, SymbolStr,
};
#[cfg(test)]
use crate::test::quick_xml::MockBytesStart as BytesStart;
@ -180,10 +179,9 @@ pub type XmloResult<T> = Result<T, XmloError>;
///
/// See [module-level documentation](self) for more information and
/// examples.
pub struct XmloReader<B, Ix>
pub struct XmloReader<B>
where
B: BufRead,
Ix: SymbolIndexSize,
{
/// Source `xmlo` reader.
reader: XmlReader<B>,
@ -207,13 +205,12 @@ where
///
/// This is known after processing the root `package` element,
/// provided that it's a proper root node.
pkg_name: Option<SymbolId<Ix>>,
pkg_name: Option<SymbolId>,
}
impl<B, Ix> XmloReader<B, Ix>
impl<B> XmloReader<B>
where
B: BufRead,
Ix: SymbolIndexSize,
{
/// Construct a new reader.
pub fn new(reader: B) -> Self {
@ -253,7 +250,7 @@ where
/// See private methods for more information.
///
/// TODO: Augment failures with context
pub fn read_event<'a>(&mut self) -> XmloResult<XmloEvent<Ix>> {
pub fn read_event<'a>(&mut self) -> XmloResult<XmloEvent> {
// Just to cut down on peak memory usage, cleaning up after a
// previous run. This does not affect behavior.
self.buffer.clear();
@ -354,10 +351,10 @@ where
/// parsed.
fn process_package<'a>(
ele: &'a BytesStart<'a>,
) -> XmloResult<PackageAttrs<Ix>> {
) -> XmloResult<PackageAttrs> {
let mut program = false;
let mut elig: Option<SymbolId<Ix>> = None;
let mut name: Option<SymbolId<Ix>> = None;
let mut elig: Option<SymbolId> = None;
let mut name: Option<SymbolId> = None;
let mut relroot: Option<String> = None;
for attr in ele.attributes().with_checks(false).filter_map(Result::ok) {
@ -409,10 +406,10 @@ where
/// ======
/// - [`XmloError::UnassociatedSym`] if missing `preproc:sym/@name`.
fn process_sym<'a>(
pkg_name: &Option<SymbolId<Ix>>,
pkg_name: &Option<SymbolId>,
ele: &'a BytesStart<'a>,
) -> XmloResult<XmloEvent<Ix>> {
let mut name: Option<SymbolId<Ix>> = None;
) -> XmloResult<XmloEvent> {
let mut name: Option<SymbolId> = None;
let mut sym_attrs = SymAttrs::default();
for attr in ele.attributes().with_checks(false).filter_map(Result::ok) {
@ -506,7 +503,7 @@ where
fn process_map_from<'a>(
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
) -> XmloResult<Vec<SymbolId<Ix>>> {
) -> XmloResult<Vec<SymbolId>> {
let mut froms = Vec::new();
loop {
@ -568,7 +565,7 @@ where
ele: &'a BytesStart<'a>,
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
) -> XmloResult<XmloEvent<Ix>> {
) -> XmloResult<XmloEvent> {
let name = ele
.attributes()
.with_checks(false)
@ -642,7 +639,7 @@ where
ele: &'a BytesStart<'a>,
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
) -> XmloResult<XmloEvent<Ix>> {
) -> XmloResult<XmloEvent> {
let mut src_attrs = ele.attributes();
let mut filtered = src_attrs.with_checks(false).filter_map(Result::ok);
@ -687,12 +684,11 @@ where
}
}
impl<B, Ix> Iterator for XmloReader<B, Ix>
impl<B> Iterator for XmloReader<B>
where
B: BufRead,
Ix: SymbolIndexSize,
{
type Item = XmloResult<XmloEvent<Ix>>;
type Item = XmloResult<XmloEvent>;
/// Invoke [`XmloReader::read_event`] and yield the result via an
/// [`Iterator`] API.
@ -708,10 +704,9 @@ where
}
}
impl<B, Ix> From<B> for XmloReader<B, Ix>
impl<B> From<B> for XmloReader<B>
where
B: BufRead,
Ix: SymbolIndexSize,
{
fn from(buf: B) -> Self {
Self::new(buf)
@ -728,24 +723,24 @@ where
/// 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<Ix: SymbolIndexSize> {
pub enum XmloEvent {
/// Package declaration.
///
/// This contains data gathered from the root `lv:package` node.
Package(PackageAttrs<Ix>),
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<Ix>, SymAttrs<Ix>),
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<Ix>, Vec<SymbolId<Ix>>),
SymDeps(SymbolId, Vec<SymbolId>),
/// Text (compiled code) fragment for a given symbol.
///
@ -754,7 +749,7 @@ pub enum XmloEvent<Ix: SymbolIndexSize> {
/// 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<Ix>, SymbolId<Ix>),
Fragment(SymbolId, SymbolId),
/// End-of-header.
///

View File

@ -18,12 +18,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use super::*;
use crate::global;
use crate::ir::legacyir::{SymDtype, SymType};
use crate::sym::GlobalSymbolIntern;
use crate::test::quick_xml::*;
type Sut<B> = XmloReader<B, global::PkgIdentExprSize>;
type Sut<B> = XmloReader<B>;
macro_rules! xmlo_tests {
($(fn $fn:ident($sut:ident) $body:block)*) => {

View File

@ -171,8 +171,10 @@
//! Related Work
//! ============
//! This span is motivated by [rustc's compressed `Span`](rustc-span).
//! TAMER's span size relies on [`global::PkgSymSize`] being 16 bits in length,
//! which _should_ be a reasonable assumption.
//! TAMER's span size relies on 16 bits being sufficient for holding
//! interned paths,
//! which _should_ be a very reasonable assumption unless the interner
//! ends up being shared with too many different things.
//! If ever that assumption becomes violated,
//! and it is deemed that packages containing so many symbols should be permitted,
//! TAMER's [`Span`] can accommodate in a similar with to rustc's by
@ -181,10 +183,11 @@
//!
//! [rustc-span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html
use crate::{global, sym::SymbolId};
use std::convert::TryInto;
use crate::global;
use crate::sym::PkgSymbolId;
/// A symbol size sufficient for holding interned paths.
pub type PathSymbolId = SymbolId<u16>;
/// Description of a source location and byte interval for some object.
///
@ -351,22 +354,22 @@ impl<P: Into<PathIndex>> From<P> for Context {
/// An interned path.
///
/// This is interned as a string slice ([`PkgSymbolId`]),
/// This is interned as a string slice ([`SymbolId`]),
/// not a `PathBuf`.
/// Consequently,
/// it is not an `OsStr`.
///
/// This newtype emphasizes that it differs from typical symbol usage,
/// especially given that it'll always use the [`PkgSymbolId`] interner,
/// especially given that it'll always use the 16-bit interner,
/// _not_ necessarily whatever global interner is used for all other
/// symbols.
/// In the future,
/// these may be interned separately.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct PathIndex(PkgSymbolId);
pub struct PathIndex(PathSymbolId);
impl From<PkgSymbolId> for PathIndex {
fn from(sym: PkgSymbolId) -> Self {
impl From<PathSymbolId> for PathIndex {
fn from(sym: PathSymbolId) -> Self {
Self(sym)
}
}
@ -409,7 +412,7 @@ mod test {
#[test]
fn span_pack_le() {
let span =
Span::new(0xA3A2A1A0, 0xB1B0, PkgSymbolId::test_from_int(0xC1C0));
Span::new(0xA3A2A1A0, 0xB1B0, SymbolId::test_from_int(0xC1C0));
assert_eq!(
0xC1C0_A3A2A1A0_B1B0,

View File

@ -33,7 +33,7 @@
//! as documented in the [parent module](super).
//!
//! ```
//! use tamer::sym::{Interner, DefaultPkgInterner, SymbolId};
//! use tamer::sym::{DefaultProgInterner, Interner, SymbolId};
//!
//! // Inputs to be interned
//! let a = "foo";
@ -43,7 +43,7 @@
//!
//! // Interners employ interior mutability and so do not need to be
//! // declared `mut`
//! let interner = DefaultPkgInterner::new();
//! let interner = DefaultProgInterner::new();
//!
//! let (ia, ib, ic, id) = (
//! interner.intern(a),
@ -199,7 +199,7 @@ pub trait Interner<'i, Ix: SymbolIndexSize> {
///
/// See the [module-level documentation](self) for examples and more
/// information on how to use this interner.
pub struct ArenaInterner<'i, S, Ix>
pub struct ArenaInterner<'i, S, Ix = global::ProgSymSize>
where
S: BuildHasher + Default,
Ix: SymbolIndexSize,
@ -357,9 +357,10 @@ where
/// (which uses SipHash at the time of writing).
///
/// See intern benchmarks for a comparison.
pub type FxArenaInterner<'i, Ix> = ArenaInterner<'i, FxBuildHasher, Ix>;
pub type FxArenaInterner<'i, Ix = global::ProgSymSize> =
ArenaInterner<'i, FxBuildHasher, Ix>;
/// Recommended [`Interner`] and configuration.
/// Recommended [`Interner`] and configuration (size-agnostic).
///
/// The choice of this default relies on the assumption that
/// denial-of-service attacks against the hash function are not a
@ -367,21 +368,11 @@ pub type FxArenaInterner<'i, Ix> = ArenaInterner<'i, FxBuildHasher, Ix>;
///
/// For more information on the hashing algorithm,
/// see [`FxArenaInterner`].
pub type DefaultInterner<'i, Ix> = FxArenaInterner<'i, Ix>;
pub type DefaultInterner<'i, Ix = global::ProgSymSize> =
FxArenaInterner<'i, Ix>;
/// Interner for individual packages and their dependencies.
///
/// This type should be preferred to [`DefaultPkgInterner`] when only a
/// single package's symbols are being processed,
/// since it can be better packed into structs.
pub type DefaultPkgInterner<'i> = DefaultInterner<'i, global::PkgSymSize>;
/// Interner for entire programs.
///
/// This interner holds symbols with a larger underyling datatype than
/// [`DefaultPkgInterner`].
/// It is intended for use by linkers or anything else that needs to process
/// a large number of packages in a program simultaneously.
/// Recommended [`Interner`] and configuration for compilers and linkers
/// processing one or more packages.
pub type DefaultProgInterner<'i> = DefaultInterner<'i, global::ProgSymSize>;
// Note that these tests assert on standalone interners, not on the globals;
@ -390,7 +381,7 @@ pub type DefaultProgInterner<'i> = DefaultInterner<'i, global::ProgSymSize>;
mod test {
use super::*;
type Sut<'i> = DefaultInterner<'i, global::ProgSymSize>;
type Sut<'i> = DefaultInterner<'i>;
#[test]
fn recognizes_equal_strings() {

View File

@ -28,10 +28,9 @@
//! [Fx Hash][fxhash] hashing algorithm.
//! - [`DefaultInterner`] - The currently recommended intern pool
//! configuration for symbol interning (size-agnostic).
//! - [`DefaultPkgInterner`] - The currently recommended intern pool
//! configuration for individual packages and their imports.
//! - [`DefaultProgInterner`] - The currently recommended intern pool
//! configuration for all packages within a program.
//! - [`DefaultProgInterner`] - The currently recommended
//! general-purpose intern pool configuration for compilers and
//! linkers processing symbols from one or more packages.
//!
//! Interners represent symbols as integer values which allows for `O(1)`
//! comparison of any arbitrary interned value,
@ -46,11 +45,10 @@
//! [arena]: bumpalo
//!
//! ```
//! use tamer::sym::{GlobalSymbolIntern, GlobalSymbolResolve, PkgSymbolId};
//! use tamer::sym::{GlobalSymbolIntern, GlobalSymbolResolve, SymbolId};
//!
//! // Interns are represented by `SymbolId`. You should choose one of
//! // `ProgSymbolId` or `PkgSymbolId`, unless both must be supported.
//! let foo: PkgSymbolId = "foo".intern();
//! // Interns are represented by `SymbolId`.
//! let foo: SymbolId = "foo".intern();
//! assert_eq!(foo, foo);
//!
//! // Interning the same string twice returns the same intern
@ -64,7 +62,7 @@
//! assert_ne!(foo, "bar".intern());
//!
//! // Interned slices can be looked up by their symbol id.
//! assert_eq!(&"foo", &foo.lookup_str());
//! assert_eq!("foo", foo.lookup_str().as_str());
//! ```
//!
//! What Is String Interning?
@ -144,42 +142,25 @@
//! Symbol Index Sizes
//! ------------------
//! [`SymbolId`] is generic over [`SymbolIndexSize`],
//! which is implemented for
//! [`global::PkgSymSize`](crate::global::PkgSymSize) and
//! [`global::ProgSymSize`](crate::global::ProgSymSize).
//! This allows the compiler---which processes far less data than the
//! linker---to use a smaller index size.
//! This is desirable for certain core data structures,
//! like spans,
//! which try to pack a lot of information into 64-bit structures.
//! defaulting to[`global::ProgSymSize`](crate::global::ProgSymSize).
//! The generic size allows for specialized interners in situations where a
//! a larger index size is undesirable,
//! such as [`Span`](crate::span::Span),
//! which tries to pack a lot of information into 64-bit structures.
//!
//! But the cost is that of another trait bound on any systems that must
//! accommodate any [`SymbolIndexSize`]
//! Systems should therefore favor one of these two types if they are not
//! shared between e.g. compilers and linkers:
//!
//! - [`PkgSymbolId`] for individual packages and their imports; and
//! - [`ProgSymbolId`] for all packages in a program.
//!
//! Note that _it is not permissable to cast between different index sizes_!
//! Even though a [`PkgSymbolId`] could fit within the index size of a
//! [`ProgSymbolId`],
//! for example,
//! they use _different_ interners with their own distinct index
//! sets.
//! A system should avoid using multiple interners at the same time,
//! and trait bounds will make such a mistake painfully obvious.
//! Note that _it is not permissable to cast between different index sizes_
//! because they use _different_ interners with their own distinct index
//! sets.
//!
//! Global Interners
//! ----------------
//! TAMER offers two thread-local global interners that intern strings with
//! a `'static` lifetime,
//! simplifying the handling of lifetimes;
//! they produce symbols of type [`PkgSymbolId`] and [`ProgSymbolId`]
//! and are intended for packages and entire programs respectively.
//! they produce 16-bit and 32-bit symbols.
//! These interners are lazily initialized on first use.
//! Symbols from the two interners cannot be mixed;
//! you must use the largest [`SymbolIndexSize`] needed.
//! Symbols from the two interners are independently allocated cannot be
//! mixed.
//!
//! Global interners were introduced because symbols are used by virtually
//! every part of the system,
@ -360,10 +341,10 @@ mod symbol;
pub use prefill::{st, StaticSymbolId};
pub use interner::{
ArenaInterner, DefaultInterner, DefaultPkgInterner, DefaultProgInterner,
FxArenaInterner, Interner,
ArenaInterner, DefaultInterner, DefaultProgInterner, FxArenaInterner,
Interner,
};
pub use symbol::{
GlobalSymbolIntern, GlobalSymbolInternUnchecked, GlobalSymbolResolve,
PkgSymbolId, ProgSymbolId, SymbolId, SymbolIndexSize, SymbolStr,
SymbolId, SymbolIndexSize, SymbolStr,
};

View File

@ -60,19 +60,6 @@ impl StaticSymbolId {
})
}
/// Cast static symbol into a [`SymbolId`] suitable for the global
/// package-level interner.
///
/// This is safe since global interners will always contain this
/// symbol before it can be read.
pub const fn as_pkg_sym(self) -> SymbolId<global::PkgSymSize> {
SymbolId(unsafe {
<global::PkgSymSize as SymbolIndexSize>::NonZero::new_unchecked(
self.0 as global::PkgSymSize,
)
})
}
pub const fn as_usize(self) -> usize {
self.0 as usize
}
@ -84,12 +71,6 @@ impl From<StaticSymbolId> for SymbolId<global::ProgSymSize> {
}
}
impl From<StaticSymbolId> for SymbolId<global::PkgSymSize> {
fn from(st: StaticSymbolId) -> Self {
st.as_pkg_sym()
}
}
/// Generate a newtype containing a [`StaticSymbolId`] that derefs to its
/// inner value.
macro_rules! static_symbol_newtype {
@ -139,7 +120,7 @@ macro_rules! static_symbol_newtypes {
}
}
/// Generate symbols of size [`global::ProgSymSize`] for preinterned strings.
/// Generate symbols for preinterned strings.
///
/// These symbols,
/// rather than being generated by the global internment system,
@ -304,45 +285,25 @@ static_symbols! {
#[cfg(test)]
mod test {
use super::st;
use crate::{
global,
sym::{GlobalSymbolIntern, SymbolId},
};
use crate::sym::{GlobalSymbolIntern, SymbolId};
macro_rules! global_sanity_check {
($name:ident, $ix:ty, $method:ident) => {
#[test]
fn $name() {
type Ix = $ix;
#[test]
fn global_sanity_check() {
// If we _don't_ prefill, make sure we're not starting at the first
// offset when interning, otherwise it'll look correct.
let new: SymbolId = "force offset".intern();
// If we _don't_ prefill, make sure we're not starting at the first
// offset when interning, otherwise it'll look correct.
let new: SymbolId<Ix> = "force offset".intern();
assert!(
new.as_usize() > st::END_STATIC.as_usize(),
"a new global symbol allocation was not > END_STATIC, \
indicating that prefill is not working!"
);
assert!(
new.as_usize() > st::END_STATIC.as_usize(),
"a new global symbol allocation was not > END_STATIC, \
indicating that prefill is not working!"
);
// Further sanity check to make sure indexes align as expected,
// not that you wouldn't otherwise notice that the whole system is
// broken, but this ought to offer a more direct hint as to what
// went wrong.
assert_eq!(st::True.$method(), "true".intern());
assert_eq!(st::False.$method(), "false".intern());
}
};
// Further sanity check to make sure indexes align as expected,
// not that you wouldn't otherwise notice that the whole system is
// broken, but this ought to offer a more direct hint as to what
// went wrong.
assert_eq!(st::True.as_prog_sym(), "true".intern());
assert_eq!(st::False.as_prog_sym(), "false".intern());
}
global_sanity_check!(
global_sanity_check_prog,
global::ProgSymSize,
as_prog_sym
);
global_sanity_check!(
global_sanity_check_pkg,
global::PkgSymSize,
as_pkg_sym
);
}

View File

@ -21,7 +21,7 @@
//!
//! See the [parent module](super) for more information.
use super::{DefaultPkgInterner, DefaultProgInterner, Interner};
use super::{DefaultInterner, Interner};
use crate::global;
use std::convert::{TryFrom, TryInto};
use std::fmt::{self, Debug, Display};
@ -32,10 +32,6 @@ use std::thread::LocalKey;
/// Unique symbol identifier produced by an [`Interner`].
///
/// Use one of [`PkgSymbolId`] or [`ProgSymbolId`] unless a generic size is
/// actually needed
/// (e.g. implementations shared between a compiler and linker).
///
/// This newtype helps to prevent other indexes from being used where a
/// symbol index is expected.
/// Note, however, that it provides no defense against mixing symbol indexes
@ -55,22 +51,11 @@ use std::thread::LocalKey;
/// see either [`GlobalSymbolResolve::lookup_str`] or
/// [`Interner::index_lookup`].
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SymbolId<Ix: SymbolIndexSize>(pub(super) Ix::NonZero);
pub struct SymbolId<Ix: SymbolIndexSize = global::ProgSymSize>(
pub(super) Ix::NonZero,
);
assert_eq_size!(Option<SymbolId<u16>>, SymbolId<u16>);
/// Identifier of a symbol within a single package.
///
/// This type should be preferred to [`ProgSymbolId`] when only a single
/// package's symbols are being processed.
pub type PkgSymbolId = SymbolId<global::PkgSymSize>;
/// Identifier of a symbol within an entire program.
///
/// This symbol type is preconfigured to accommodate a larger number of
/// symbols than [`PkgSymbolId`] and is suitable for use in a linker.
/// Use this type only when necessary.
pub type ProgSymbolId = SymbolId<global::ProgSymSize>;
impl<Ix: SymbolIndexSize> SymbolId<Ix> {
/// Construct index from an unchecked non-zero `u16` value.
///
@ -184,11 +169,11 @@ macro_rules! supported_symbol_index {
};
}
type StaticPkgInterner = DefaultPkgInterner<'static>;
type StaticProgInterner = DefaultProgInterner<'static>;
type Static16Interner = DefaultInterner<'static, u16>;
type Static32Interner = DefaultInterner<'static, u32>;
supported_symbol_index!(u16, NonZeroU16, StaticPkgInterner, INTERNER_PKG);
supported_symbol_index!(u32, NonZeroU32, StaticProgInterner, INTERNER_PROG);
supported_symbol_index!(u16, NonZeroU16, Static16Interner, INTERNER_PKG);
supported_symbol_index!(u32, NonZeroU32, Static32Interner, INTERNER_PROG);
/// A string retrieved from the intern pool using a [`SymbolId`].
///
@ -481,7 +466,7 @@ mod test {
#[test]
fn clone_uninterned() {
let sym: PkgSymbolId = "foo".clone_uninterned();
let sym: SymbolId = "foo".clone_uninterned();
assert_eq!("foo", sym.lookup_str());
}
}