tamer: Remove Ix generalization throughout system

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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