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
parent
ed245bb099
commit
e91aeef478
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(|| {
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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`].
|
||||
///
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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>> {
|
||||
|
|
|
@ -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(§ions, "foo".intern(), &String::from(""));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
/// §ions,
|
||||
|
@ -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>> {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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)*) => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue