tamer: Remove default SymbolIndex (et al) index type

Oh boy.  What a mess of a change.

This demonstrates some significant issues we have with Symbol.  I had
originally modelled the system a bit after Rustc's, but deviated in certain
regards:

  1. This has a confurable base type to enable better packing without bit
     twiddling and potentially unsafe tricks I'd rather avoid unless
     necessary; and
  2. The lifetime is not static, and there is no global, singleton interner;
     and
  3. I pass around references to a Symbol rather than passing around an
     index into an interner.

For #3---this is done because there's no singleton interner and therefore
resolving a symbol requires a direct reference to an available interner.  It
also wasn't clear to me (and still isn't, in fact) whether more than one
interner may be used for different contexts.

But, that doesn't preclude removing lifetimes and just passing around
indexes; in fact, I plan to do this in the frontend where the parser and
such will have direct interner access and can therefore just look up based
on a symbol index.  We could reserve references for situations where
exposing an interner would be undesirable.

Anyway, more to come...
main
Mike Gerwitz 2021-07-29 14:26:40 -04:00
parent e6ad2be5b9
commit 0fc8a1a4df
18 changed files with 463 additions and 341 deletions

9
tamer/Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
@ -273,6 +275,12 @@ dependencies = [
"serde",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.73"
@ -298,6 +306,7 @@ dependencies = [
"petgraph-graphml",
"predicates",
"quick-xml",
"static_assertions",
]
[[package]]

View File

@ -29,12 +29,13 @@ predicates = "1"
[dependencies]
bumpalo = ">= 2.6.0"
fxhash = ">= 0.2.1"
petgraph = ">= 0.4.13"
petgraph = "0.5.1" # TODO: petgraph-graphml holds this back
quick-xml = ">= 0.17.0"
getopts = "0.2"
exitcode = "1.1.2"
lazy_static = ">= 1.4.0"
petgraph-graphml = ">= 2.0.1"
static_assertions = ">= 1.1.0"
# Feature flags can be specified using `./configure FEATURES=foo,bar,baz`.
#

View File

@ -19,6 +19,9 @@
//! Base concrete [`Asg`] implementation.
use std::convert::TryInto;
use std::fmt::Debug;
use super::graph::{
Asg, AsgEdge, AsgResult, IndexType, Node, ObjectRef, SortableAsg,
SortableAsgError, SortableAsgResult,
@ -28,7 +31,7 @@ use super::object::{
FragmentText, IdentObjectData, IdentObjectState, Source, TransitionResult,
};
use super::Sections;
use crate::sym::Symbol;
use crate::sym::{Symbol, SymbolIndexSize};
use petgraph::graph::{DiGraph, Graph, NodeIndex};
use petgraph::visit::DfsPostOrder;
@ -44,7 +47,7 @@ use petgraph::visit::DfsPostOrder;
/// see [`Asg`].
pub struct BaseAsg<O, Ix>
where
Ix: IndexType,
Ix: IndexType + SymbolIndexSize,
{
/// Directed graph on which objects are stored.
graph: DiGraph<Node<O>, AsgEdge, Ix>,
@ -63,8 +66,9 @@ where
impl<'i, O, Ix> BaseAsg<O, Ix>
where
Ix: IndexType,
O: IdentObjectState<'i, O> + IdentObjectData<'i>,
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectState<'i, Ix, O> + IdentObjectData<'i, Ix>,
{
/// Create a new ASG.
///
@ -114,7 +118,11 @@ where
/// Panics
/// ======
/// Will panic if unable to allocate more space for the index.
fn index_identifier(&mut self, name: &'i Symbol<'i>, node: NodeIndex<Ix>) {
fn index_identifier(
&mut self,
name: &'i Symbol<'i, Ix>,
node: NodeIndex<Ix>,
) {
let i: usize = name.index().into();
if i >= self.index.len() {
@ -137,7 +145,10 @@ where
/// reference to it.
///
/// See [`IdentObjectState::declare`] for more information.
fn lookup_or_missing(&mut self, ident: &'i Symbol<'i>) -> ObjectRef<Ix> {
fn lookup_or_missing(
&mut self,
ident: &'i Symbol<'i, Ix>,
) -> ObjectRef<Ix> {
self.lookup(ident).unwrap_or_else(|| {
let index = self.graph.add_node(Some(O::declare(ident)));
@ -157,7 +168,7 @@ where
/// value on transition failure.
fn with_ident_lookup<F>(
&mut self,
name: &'i Symbol<'i>,
name: &'i Symbol<'i, Ix>,
f: F,
) -> AsgResult<ObjectRef<Ix>>
where
@ -202,23 +213,24 @@ where
impl<'i, O, Ix> Asg<'i, O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType,
O: IdentObjectState<'i, O> + IdentObjectData<'i>,
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectState<'i, Ix, O> + IdentObjectData<'i, Ix>,
{
fn declare(
&mut self,
name: &'i Symbol<'i>,
name: &'i Symbol<'i, Ix>,
kind: IdentKind,
src: Source<'i>,
src: Source<'i, Ix>,
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident_lookup(name, |obj| obj.resolve(kind, src))
}
fn declare_extern(
&mut self,
name: &'i Symbol<'i>,
name: &'i Symbol<'i, Ix>,
kind: IdentKind,
src: Source<'i>,
src: Source<'i, Ix>,
) -> AsgResult<ObjectRef<Ix>> {
self.with_ident_lookup(name, |obj| obj.extern_(kind, src))
}
@ -240,7 +252,7 @@ where
}
#[inline]
fn lookup(&self, name: &'i Symbol<'i>) -> Option<ObjectRef<Ix>> {
fn lookup(&self, name: &'i Symbol<'i, Ix>) -> Option<ObjectRef<Ix>> {
let i: usize = name.index().into();
self.index
@ -261,8 +273,8 @@ where
fn add_dep_lookup(
&mut self,
ident: &'i Symbol<'i>,
dep: &'i Symbol<'i>,
ident: &'i Symbol<'i, Ix>,
dep: &'i Symbol<'i, Ix>,
) -> (ObjectRef<Ix>, ObjectRef<Ix>) {
let identi = self.lookup_or_missing(ident);
let depi = self.lookup_or_missing(dep);
@ -276,8 +288,9 @@ where
impl<'i, O, Ix> SortableAsg<'i, O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType,
O: IdentObjectData<'i> + IdentObjectState<'i, O>,
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectData<'i, Ix> + IdentObjectState<'i, Ix, O>,
{
fn sort(
&'i self,
@ -339,8 +352,9 @@ where
/// they are, we ignore the cycle, otherwise we will return an error.
fn check_cycles<'i, O, Ix>(asg: &BaseAsg<O, Ix>) -> SortableAsgResult<(), Ix>
where
Ix: IndexType,
O: IdentObjectData<'i> + IdentObjectState<'i, O>,
Ix: IndexType + SymbolIndexSize,
<Ix as TryInto<usize>>::Error: Debug,
O: IdentObjectData<'i, Ix> + IdentObjectState<'i, Ix, 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
@ -395,11 +409,13 @@ mod test {
use crate::sym::SymbolIndex;
use std::cell::RefCell;
type Ix = u8;
#[derive(Debug, Default, PartialEq)]
struct StubIdentObject<'i> {
given_declare: Option<&'i Symbol<'i>>,
given_extern: Option<(IdentKind, Source<'i>)>,
given_resolve: Option<(IdentKind, Source<'i>)>,
given_declare: Option<&'i Symbol<'i, Ix>>,
given_extern: Option<(IdentKind, Source<'i, Ix>)>,
given_resolve: Option<(IdentKind, Source<'i, Ix>)>,
given_set_fragment: Option<FragmentText>,
fail_redeclare: RefCell<Option<TransitionError>>,
fail_extern: RefCell<Option<TransitionError>>,
@ -407,8 +423,8 @@ mod test {
fail_resolved: RefCell<Option<UnresolvedError>>,
}
impl<'i> IdentObjectData<'i> for StubIdentObject<'i> {
fn name(&self) -> Option<&'i Symbol<'i>> {
impl<'i> IdentObjectData<'i, Ix> for StubIdentObject<'i> {
fn name(&self) -> Option<&'i Symbol<'i, Ix>> {
self.given_declare
}
@ -416,7 +432,7 @@ mod test {
self.given_resolve.as_ref().map(|args| &args.0)
}
fn src(&self) -> Option<&Source<'i>> {
fn src(&self) -> Option<&Source<'i, Ix>> {
None
}
@ -424,13 +440,13 @@ mod test {
None
}
fn as_ident(&self) -> Option<&IdentObject<'i>> {
fn as_ident(&self) -> Option<&IdentObject<'i, Ix>> {
None
}
}
impl<'i> IdentObjectState<'i, StubIdentObject<'i>> for StubIdentObject<'i> {
fn declare(ident: &'i Symbol<'i>) -> Self {
impl<'i> IdentObjectState<'i, Ix, StubIdentObject<'i>> for StubIdentObject<'i> {
fn declare(ident: &'i Symbol<'i, Ix>) -> Self {
Self {
given_declare: Some(ident),
..Default::default()
@ -440,7 +456,7 @@ mod test {
fn resolve(
mut self,
kind: IdentKind,
src: Source<'i>,
src: Source<'i, Ix>,
) -> TransitionResult<StubIdentObject<'i>> {
if self.fail_redeclare.borrow().is_some() {
let err = self.fail_redeclare.replace(None).unwrap();
@ -462,7 +478,7 @@ mod test {
fn extern_(
mut self,
kind: IdentKind,
src: Source<'i>,
src: Source<'i, Ix>,
) -> TransitionResult<StubIdentObject<'i>> {
if self.fail_extern.borrow().is_some() {
let err = self.fail_extern.replace(None).unwrap();
@ -512,8 +528,8 @@ mod test {
// index to create a gap, and then use an index within that gap
// to ensure that it's not considered an already-defined
// identifier.
let syma = symbol_dummy!(5, "syma");
let symb = symbol_dummy!(1, "symab");
let syma = symbol_dummy!(5u8, "syma");
let symb = symbol_dummy!(1u8, "symab");
let nodea = sut.declare(
&syma,
@ -566,7 +582,7 @@ mod test {
fn lookup_by_symbol() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "lookup");
let sym = symbol_dummy!(1u8, "lookup");
let node = sut.declare(
&sym,
IdentKind::Meta,
@ -585,7 +601,7 @@ mod test {
fn declare_returns_existing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symdup");
let sym = symbol_dummy!(1u8, "symdup");
let src = Source::default();
let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
@ -611,7 +627,7 @@ mod test {
fn declare_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symdup");
let sym = symbol_dummy!(1u8, "symdup");
let src = Source {
desc: Some("orig".into()),
..Default::default()
@ -647,7 +663,7 @@ mod test {
fn declare_extern_returns_existing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symext");
let sym = symbol_dummy!(1u8, "symext");
let src = Source::default();
let node = sut.declare_extern(&sym, IdentKind::Meta, src.clone())?;
@ -673,7 +689,7 @@ mod test {
fn declare_extern_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "symdup");
let sym = symbol_dummy!(1u8, "symdup");
let src = Source {
desc: Some("orig".into()),
..Default::default()
@ -713,7 +729,7 @@ mod test {
fn add_fragment_to_ident() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "tofrag");
let sym = symbol_dummy!(1u8, "tofrag");
let src = Source {
generated: true,
..Default::default()
@ -743,7 +759,7 @@ mod test {
fn add_fragment_to_ident_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "failfrag");
let sym = symbol_dummy!(1u8, "failfrag");
let src = Source {
generated: true,
..Default::default()
@ -777,8 +793,8 @@ mod test {
fn add_ident_dep_to_ident() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym = symbol_dummy!(1u8, "sym");
let dep = symbol_dummy!(2u8, "dep");
let symnode = sut.declare(&sym, IdentKind::Meta, Source::default())?;
let depnode = sut.declare(&dep, IdentKind::Meta, Source::default())?;
@ -798,8 +814,8 @@ mod test {
fn add_dep_lookup_existing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym = symbol_dummy!(1u8, "sym");
let dep = symbol_dummy!(2u8, "dep");
let _ = sut.declare(&sym, IdentKind::Meta, Source::default())?;
let _ = sut.declare(&dep, IdentKind::Meta, Source::default())?;
@ -814,8 +830,8 @@ mod test {
fn add_dep_lookup_missing() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym = symbol_dummy!(1u8, "sym");
let dep = symbol_dummy!(2u8, "dep");
// both of these are missing
let (symnode, depnode) = sut.add_dep_lookup(&sym, &dep);
@ -831,8 +847,8 @@ mod test {
fn declare_return_missing_symbol() -> AsgResult<()> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym = symbol_dummy!(1u8, "sym");
let dep = symbol_dummy!(2u8, "dep");
// both of these are missing, see add_dep_lookup_missing
let (symnode, _) = sut.add_dep_lookup(&sym, &dep);
@ -895,7 +911,7 @@ mod test {
let mut retmap = vec![];
let mut consts = vec![];
let base = symbol_dummy!(1, "sym1");
let base = symbol_dummy!(1u8, "sym1");
let base_node = sut
.declare(&base, IdentKind::Map, Source::default())
.unwrap();
@ -938,8 +954,8 @@ mod test {
fn graph_sort_missing_node() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym = symbol_dummy!(1u8, "sym");
let dep = symbol_dummy!(2u8, "dep");
let sym_node = sut
.declare(
@ -972,8 +988,8 @@ mod test {
fn graph_sort_no_roots() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "sym");
let dep = symbol_dummy!(2, "dep");
let sym = symbol_dummy!(1u8, "sym");
let dep = symbol_dummy!(2u8, "dep");
let (_, _) = sut.add_dep_lookup(&sym, &dep);
@ -988,8 +1004,8 @@ mod test {
fn graph_sort_simple_cycle() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(2, "sym");
let dep = symbol_dummy!(3, "dep");
let sym = symbol_dummy!(2u8, "sym");
let dep = symbol_dummy!(3u8, "dep");
let sym_node = sut
.declare(
@ -1038,10 +1054,10 @@ mod test {
fn graph_sort_two_simple_cycles() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(2, "sym");
let sym2 = symbol_dummy!(3, "sym2");
let dep = symbol_dummy!(4, "dep");
let dep2 = symbol_dummy!(5, "dep2");
let sym = symbol_dummy!(2u8, "sym");
let sym2 = symbol_dummy!(3u8, "sym2");
let dep = symbol_dummy!(4u8, "dep");
let dep2 = symbol_dummy!(5u8, "dep2");
let sym_node = sut
.declare(
@ -1121,8 +1137,8 @@ mod test {
{
let mut sut = Sut::new();
let sym = symbol_dummy!(2, "sym");
let dep = symbol_dummy!(3, "dep");
let sym = symbol_dummy!(2u8, "sym");
let dep = symbol_dummy!(3u8, "dep");
let sym_node = sut
.declare(
@ -1168,9 +1184,9 @@ mod test {
fn graph_sort_cycle_with_a_few_steps() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = symbol_dummy!(1, "sym1");
let sym2 = symbol_dummy!(2, "sym2");
let sym3 = symbol_dummy!(3, "sym3");
let sym1 = symbol_dummy!(1u8, "sym1");
let sym2 = symbol_dummy!(2u8, "sym2");
let sym3 = symbol_dummy!(3u8, "sym3");
let sym1_node = sut
.declare(
@ -1234,9 +1250,9 @@ mod test {
) -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = symbol_dummy!(1, "sym1");
let sym2 = symbol_dummy!(2, "sym2");
let sym3 = symbol_dummy!(3, "sym3");
let sym1 = symbol_dummy!(1u8, "sym1");
let sym2 = symbol_dummy!(2u8, "sym2");
let sym3 = symbol_dummy!(3u8, "sym3");
let sym1_node = sut
.declare(
@ -1299,9 +1315,9 @@ mod test {
fn graph_sort_cyclic_bookended_by_functions() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = symbol_dummy!(1, "sym1");
let sym2 = symbol_dummy!(2, "sym2");
let sym3 = symbol_dummy!(3, "sym3");
let sym1 = symbol_dummy!(1u8, "sym1");
let sym2 = symbol_dummy!(2u8, "sym2");
let sym3 = symbol_dummy!(3u8, "sym3");
let sym1_node = sut
.declare(
@ -1364,8 +1380,8 @@ mod test {
fn graph_sort_cyclic_function_ignored() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(2, "sym");
let dep = symbol_dummy!(3, "dep");
let sym = symbol_dummy!(2u8, "sym");
let dep = symbol_dummy!(3u8, "dep");
let sym_node = sut
.declare(
@ -1411,9 +1427,9 @@ mod test {
fn graph_sort_cyclic_function_is_bookended() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym1 = symbol_dummy!(1, "sym1");
let sym2 = symbol_dummy!(2, "sym2");
let sym3 = symbol_dummy!(3, "sym3");
let sym1 = symbol_dummy!(1u8, "sym1");
let sym2 = symbol_dummy!(2u8, "sym2");
let sym3 = symbol_dummy!(3u8, "sym3");
let sym1_node = sut
.declare(
@ -1476,9 +1492,9 @@ mod test {
fn graph_sort_ignore_non_linked() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(2, "sym");
let dep = symbol_dummy!(3, "dep");
let ignored = symbol_dummy!(4, "ignored");
let sym = symbol_dummy!(2u8, "sym");
let dep = symbol_dummy!(3u8, "dep");
let ignored = symbol_dummy!(4u8, "ignored");
let sym_node = sut
.declare(
@ -1538,7 +1554,7 @@ mod test {
fn graph_sort_fail_unresolved() -> SortableAsgResult<(), u8> {
let mut sut = Sut::new();
let sym = symbol_dummy!(1, "unresolved");
let sym = symbol_dummy!(1u8, "unresolved");
let node = sut
.declare(&sym, IdentKind::Meta, Default::default())
.unwrap();

View File

@ -25,7 +25,7 @@ use super::object::{
UnresolvedError,
};
use super::Sections;
use crate::sym::Symbol;
use crate::sym::{Symbol, SymbolIndexSize};
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<'i, O, Ix>
where
Ix: IndexType,
O: IdentObjectState<'i, O>,
Ix: IndexType + SymbolIndexSize,
O: IdentObjectState<'i, Ix, O>,
{
/// Declare a concrete identifier.
///
@ -84,9 +84,9 @@ where
/// and return an [`ObjectRef`] reference.
fn declare(
&mut self,
name: &'i Symbol<'i>,
name: &'i Symbol<'i, Ix>,
kind: IdentKind,
src: Source<'i>,
src: Source<'i, Ix>,
) -> AsgResult<ObjectRef<Ix>>;
/// Declare an abstract identifier.
@ -111,9 +111,9 @@ where
/// compatibility related to extern resolution.
fn declare_extern(
&mut self,
name: &'i Symbol<'i>,
name: &'i Symbol<'i, Ix>,
kind: IdentKind,
src: Source<'i>,
src: Source<'i, Ix>,
) -> AsgResult<ObjectRef<Ix>>;
/// Set the fragment associated with a concrete identifier.
@ -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: &'i Symbol<'i>) -> Option<ObjectRef<Ix>>;
fn lookup(&self, name: &'i Symbol<'i, Ix>) -> 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: &'i Symbol<'i>,
dep: &'i Symbol<'i>,
ident: &'i Symbol<'i, Ix>,
dep: &'i Symbol<'i, Ix>,
) -> (ObjectRef<Ix>, ObjectRef<Ix>);
}
@ -184,8 +184,8 @@ where
/// used as an `Intermediate Representation`.
pub trait SortableAsg<'i, O, Ix>
where
O: IdentObjectData<'i>,
Ix: IndexType,
O: IdentObjectData<'i, Ix>,
Ix: IndexType + SymbolIndexSize,
{
/// Sort graph into [`Sections`].
///

View File

@ -20,6 +20,7 @@
//! Identifiers (a type of [object][super::object::IdentObject]).
use crate::ir::legacyir::{SymAttrs, SymDtype, SymType};
use crate::sym::SymbolIndexSize;
use std::convert::TryFrom;
use std::error::Error;
@ -208,26 +209,32 @@ impl std::fmt::Display for IdentKind {
}
}
impl<'i> TryFrom<SymAttrs<'i>> for IdentKind {
impl<'i, Ix> TryFrom<SymAttrs<'i, Ix>> for IdentKind
where
Ix: SymbolIndexSize,
{
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<'i>) -> Result<Self, Self::Error> {
fn try_from(attrs: SymAttrs<'i, Ix>) -> Result<Self, Self::Error> {
Self::try_from(&attrs)
}
}
impl<'i> TryFrom<&SymAttrs<'i>> for IdentKind {
impl<'i, Ix> TryFrom<&SymAttrs<'i, Ix>> for IdentKind
where
Ix: SymbolIndexSize,
{
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<'i>) -> Result<Self, Self::Error> {
fn try_from(attrs: &SymAttrs<'i, Ix>) -> Result<Self, Self::Error> {
let ty = attrs.ty.as_ref().ok_or(Self::Error::MissingType)?;
macro_rules! ident {
@ -353,6 +360,8 @@ mod test {
use super::*;
use std::convert::TryInto;
type Ix = u8;
#[test]
fn dim_from_u8() {
let n = 5u8;
@ -376,7 +385,7 @@ mod test {
fn $name() {
assert_eq!(
Ok($dest),
SymAttrs {
SymAttrs::<Ix> {
ty: Some($src),
..Default::default()
}
@ -392,7 +401,7 @@ mod test {
assert_eq!(
Ok($dest(Dim(dim))),
SymAttrs {
SymAttrs::<Ix> {
ty: Some($src),
dim: Some(dim),
..Default::default()
@ -401,7 +410,7 @@ mod test {
);
// no dim
let result = IdentKind::try_from(SymAttrs {
let result = IdentKind::try_from(SymAttrs::<Ix> {
ty: Some($src),
..Default::default()
})
@ -418,7 +427,7 @@ mod test {
assert_eq!(
Ok($dest(dtype)),
SymAttrs {
SymAttrs::<Ix> {
ty: Some($src),
dtype: Some(dtype),
..Default::default()
@ -427,7 +436,7 @@ mod test {
);
// no dtype
let result = IdentKind::try_from(SymAttrs {
let result = IdentKind::try_from(SymAttrs::<Ix> {
ty: Some($src),
..Default::default()
})
@ -445,7 +454,7 @@ mod test {
assert_eq!(
Ok($dest(Dim(dim), dtype)),
SymAttrs {
SymAttrs::<Ix> {
ty: Some($src),
dim: Some(dim),
dtype: Some(dtype),
@ -455,7 +464,7 @@ mod test {
);
// no dim
let dim_result = IdentKind::try_from(SymAttrs {
let dim_result = IdentKind::try_from(SymAttrs::<Ix> {
ty: Some($src),
dtype: Some(dtype),
..Default::default()
@ -465,7 +474,7 @@ mod test {
assert_eq!(IdentKindError::MissingDim, dim_result);
// no dtype
let dtype_result = IdentKind::try_from(SymAttrs {
let dtype_result = IdentKind::try_from(SymAttrs::<Ix> {
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, DefaultInterner};
//! use tamer::sym::{Interner, DefaultPkgInterner};
//!
//! # 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<_>, global::PkgIdentSize>::with_capacity(
//! 1024,
//! 1024,
//! );
//!
//! let interner = DefaultInterner::new();
//! let interner = DefaultPkgInterner::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, DefaultInterner};
//! # use tamer::sym::{Interner, DefaultPkgInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let mut asg = DefaultAsg::<IdentObject, global::PkgIdentSize>::with_capacity(
//! # let mut asg = DefaultAsg::<IdentObject<_>, global::PkgIdentSize>::with_capacity(
//! # 1024,
//! # 1024,
//! # );
//! # let interner = DefaultInterner::new();
//! # let interner = DefaultPkgInterner::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, DefaultInterner};
//! # use tamer::sym::{Interner, DefaultPkgInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let mut asg = DefaultAsg::<IdentObject, global::PkgIdentSize>::with_capacity(
//! # let mut asg = DefaultAsg::<IdentObject<_>, global::PkgIdentSize>::with_capacity(
//! # 1024,
//! # 1024,
//! # );
//! # let interner = DefaultInterner::new();
//! # let interner = DefaultPkgInterner::new();
//! #
//! // Fragments can be attached to resolved identifiers.
//! let ident = asg.declare(

View File

@ -24,7 +24,7 @@
use super::ident::IdentKind;
use crate::ir::legacyir::SymAttrs;
use crate::sym::Symbol;
use crate::sym::{Symbol, SymbolIndexSize};
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<'i> {
pub enum IdentObject<'i, Ix: SymbolIndexSize> {
/// 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<'i> {
/// By defining an object as missing,
/// this allows the graph to be built incrementally as objects are
/// discovered.
Missing(&'i Symbol<'i>),
Missing(&'i Symbol<'i, Ix>),
/// A resolved identifier.
///
/// This represents an identifier that has been declared with certain
/// type information.
Ident(&'i Symbol<'i>, IdentKind, Source<'i>),
Ident(&'i Symbol<'i, Ix>, IdentKind, Source<'i, Ix>),
/// An identifier that has not yet been resolved.
///
@ -68,7 +68,7 @@ pub enum IdentObject<'i> {
/// Once resolved, however,
/// the source will instead represent the location of the concrete
/// identifier.
Extern(&'i Symbol<'i>, IdentKind, Source<'i>),
Extern(&'i Symbol<'i, Ix>, IdentKind, Source<'i, Ix>),
/// Identifier with associated text.
///
@ -77,7 +77,7 @@ pub enum IdentObject<'i> {
/// 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(&'i Symbol<'i>, IdentKind, Source<'i>, FragmentText),
IdentFragment(&'i Symbol<'i, Ix>, IdentKind, Source<'i, Ix>, FragmentText),
}
/// Retrieve information about an [`IdentObject`].
@ -95,12 +95,12 @@ pub enum IdentObject<'i> {
/// 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<'i> {
pub trait IdentObjectData<'i, Ix: SymbolIndexSize> {
/// Identifier name.
///
/// If the object is not an identifier,
/// [`None`] is returned.
fn name(&self) -> Option<&'i Symbol<'i>>;
fn name(&self) -> Option<&'i Symbol<'i, Ix>>;
/// Identifier [`IdentKind`].
///
@ -114,7 +114,7 @@ pub trait IdentObjectData<'i> {
/// If the object does not have source information
/// (as is the case with [`IdentObject::Extern`]),
/// [`None`] is returned.
fn src(&self) -> Option<&Source<'i>>;
fn src(&self) -> Option<&Source<'i, Ix>>;
/// Identifier [`FragmentText`].
///
@ -132,10 +132,10 @@ pub trait IdentObjectData<'i> {
///
/// This allows pattern matching on [`IdentObject`] variants regardless
/// of the underlying object type.
fn as_ident(&self) -> Option<&IdentObject<'i>>;
fn as_ident(&self) -> Option<&IdentObject<'i, Ix>>;
}
impl<'i> std::fmt::Display for IdentObject<'i> {
impl<'i, Ix: SymbolIndexSize> std::fmt::Display for IdentObject<'i, Ix> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.name() {
Some(n) => write!(f, "{}", n),
@ -144,8 +144,11 @@ impl<'i> std::fmt::Display for IdentObject<'i> {
}
}
impl<'i> IdentObjectData<'i> for IdentObject<'i> {
fn name(&self) -> Option<&'i Symbol<'i>> {
impl<'i, Ix> IdentObjectData<'i, Ix> for IdentObject<'i, Ix>
where
Ix: SymbolIndexSize,
{
fn name(&self) -> Option<&'i Symbol<'i, Ix>> {
match self {
Self::Missing(name)
| Self::Ident(name, _, _)
@ -163,7 +166,7 @@ impl<'i> IdentObjectData<'i> for IdentObject<'i> {
}
}
fn src(&self) -> Option<&Source<'i>> {
fn src(&self) -> Option<&Source<'i, Ix>> {
match self {
Self::Missing(_) | Self::Extern(_, _, _) => None,
Self::Ident(_, _, src) | Self::IdentFragment(_, _, src, _) => {
@ -190,27 +193,32 @@ impl<'i> IdentObjectData<'i> for IdentObject<'i> {
/// so it's important _not_ to rely on this as an excuse to be lazy
/// with unwrapping.
#[inline]
fn as_ident(&self) -> Option<&IdentObject<'i>> {
fn as_ident(&self) -> Option<&IdentObject<'i, Ix>> {
Some(&self)
}
}
/// Objects as a state machine.
pub trait IdentObjectState<'i, T>
pub trait IdentObjectState<'i, Ix, T>
where
T: IdentObjectState<'i, T>,
T: IdentObjectState<'i, Ix, T>,
Ix: SymbolIndexSize,
{
/// Produce an object representing a missing identifier.
///
/// This is the base state for all identifiers.
fn declare(ident: &'i Symbol<'i>) -> T;
fn declare(ident: &'i Symbol<'i, Ix>) -> 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<'i>) -> TransitionResult<T>;
fn resolve(
self,
kind: IdentKind,
src: Source<'i, Ix>,
) -> TransitionResult<T>;
/// Assertion to return self if identifier is resolved,
/// otherwise failing with [`UnresolvedError`].
@ -244,7 +252,11 @@ 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<'i>) -> TransitionResult<T>;
fn extern_(
self,
kind: IdentKind,
src: Source<'i, Ix>,
) -> TransitionResult<T>;
/// Attach a code fragment (compiled text) to an identifier.
///
@ -257,8 +269,12 @@ where
fn set_fragment(self, text: FragmentText) -> TransitionResult<T>;
}
impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn declare(ident: &'i Symbol<'i>) -> Self {
impl<'i, Ix> IdentObjectState<'i, Ix, IdentObject<'i, Ix>>
for IdentObject<'i, Ix>
where
Ix: SymbolIndexSize,
{
fn declare(ident: &'i Symbol<'i, Ix>) -> Self {
IdentObject::Missing(ident)
}
@ -293,8 +309,8 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn resolve(
self,
kind: IdentKind,
mut src: Source<'i>,
) -> TransitionResult<IdentObject<'i>> {
mut src: Source<'i, Ix>,
) -> TransitionResult<IdentObject<'i, Ix>> {
match self {
IdentObject::Ident(name, ref orig_kind, ref orig_src)
| IdentObject::IdentFragment(
@ -390,7 +406,7 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
}
}
fn resolved(&self) -> Result<&IdentObject<'i>, UnresolvedError> {
fn resolved(&self) -> Result<&IdentObject<'i, Ix>, UnresolvedError> {
match self {
IdentObject::Missing(name) => Err(UnresolvedError::Missing {
name: name.to_string(),
@ -412,8 +428,8 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn extern_(
self,
kind: IdentKind,
src: Source<'i>,
) -> TransitionResult<IdentObject<'i>> {
src: Source<'i, Ix>,
) -> TransitionResult<IdentObject<'i, Ix>> {
match self.kind() {
None => Ok(IdentObject::Extern(self.name().unwrap(), kind, src)),
Some(cur_kind) => {
@ -436,7 +452,7 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn set_fragment(
self,
text: FragmentText,
) -> TransitionResult<IdentObject<'i>> {
) -> TransitionResult<IdentObject<'i, Ix>> {
match self {
IdentObject::Ident(sym, kind, src) => {
Ok(IdentObject::IdentFragment(sym, kind, src, text))
@ -621,26 +637,26 @@ pub type FragmentText = String;
/// 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<'i> {
pub struct Source<'i, Ix: SymbolIndexSize> {
/// Name of package containing reference to this object.
pub pkg_name: Option<&'i Symbol<'i>>,
pub pkg_name: Option<&'i Symbol<'i, Ix>>,
/// Relative path to the source of this object,
/// if not present in the current package.
pub src: Option<&'i Symbol<'i>>,
pub src: Option<&'i Symbol<'i, Ix>>,
/// 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<&'i Symbol<'i>>,
pub parent: Option<&'i Symbol<'i, Ix>>,
/// Child identifier associated with this identifier.
///
/// For [`IdentKind::Class`],
/// this represents an associated [`IdentKind::Cgen`].
pub yields: Option<&'i Symbol<'i>>,
pub yields: Option<&'i Symbol<'i, Ix>>,
/// User-friendly identifier description.
///
@ -668,7 +684,7 @@ pub struct Source<'i> {
///
/// TODO: We have `parent`, `yields`, and `from`.
/// We should begin to consolodate.
pub from: Option<Vec<&'i Symbol<'i>>>,
pub from: Option<Vec<&'i Symbol<'i, Ix>>>,
/// Whether identifier is virtual (can be overridden).
///
@ -687,11 +703,14 @@ pub struct Source<'i> {
pub override_: bool,
}
impl<'i> From<SymAttrs<'i>> for Source<'i> {
impl<'i, Ix> From<SymAttrs<'i, Ix>> for Source<'i, Ix>
where
Ix: SymbolIndexSize,
{
/// Raise Legacy IR [`SymAttrs`].
///
/// This simply extracts a subset of fields from the source attributes.
fn from(attrs: SymAttrs<'i>) -> Self {
fn from(attrs: SymAttrs<'i, Ix>) -> Self {
Source {
pkg_name: attrs.pkg_name,
src: attrs.src,
@ -718,7 +737,7 @@ mod test {
// Note that IdentObject has no variants capable of None
#[test]
fn ident_object_name() {
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
assert_eq!(Some(&sym), IdentObject::Missing(&sym).name());
@ -748,7 +767,7 @@ mod test {
#[test]
fn ident_object_kind() {
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let kind = IdentKind::Class(Dim::from_u8(5));
assert_eq!(None, IdentObject::Missing(&sym).kind());
@ -779,7 +798,7 @@ mod test {
#[test]
fn ident_object_src() {
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let src = Source {
desc: Some("test source".into()),
..Default::default()
@ -811,7 +830,7 @@ mod test {
#[test]
fn ident_object_fragment() {
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let text: FragmentText = "foo".into();
assert_eq!(None, IdentObject::Missing(&sym).fragment());
@ -842,7 +861,7 @@ mod test {
#[test]
fn ident_object_as_ident() {
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let ident = IdentObject::Missing(&sym);
// Since we _are_ an IdentObject, we should return a reference
@ -859,13 +878,13 @@ mod test {
#[test]
fn ident_object_missing() {
let sym = symbol_dummy!(1, "missing");
let sym = symbol_dummy!(1u8, "missing");
assert_eq!(IdentObject::Missing(&sym), IdentObject::declare(&sym));
}
#[test]
fn resolved_on_missing() {
let sym = symbol_dummy!(1, "missing");
let sym = symbol_dummy!(1u8, "missing");
let result = IdentObject::declare(&sym)
.resolved()
@ -881,7 +900,7 @@ mod test {
#[test]
fn ident_object_ident() {
let sym = symbol_dummy!(1, "ident");
let sym = symbol_dummy!(1u8, "ident");
let kind = IdentKind::Meta;
let src = Source {
desc: Some("ident ctor".into()),
@ -898,7 +917,7 @@ mod test {
#[test]
fn resolved_on_ident() {
let sym = symbol_dummy!(1, "ident resolve");
let sym = symbol_dummy!(1u8, "ident resolve");
let kind = IdentKind::Meta;
let src = Source {
desc: Some("ident ctor".into()),
@ -921,7 +940,7 @@ mod test {
// packages have the same local symbol.
#[test]
fn ident_object_redeclare_same_src() {
let sym = symbol_dummy!(1, "redecl");
let sym = symbol_dummy!(1u8, "redecl");
let kind = IdentKind::Meta;
let src = Source::default();
@ -951,7 +970,7 @@ mod test {
#[test]
fn ident_object() {
let sym = symbol_dummy!(1, "extern");
let sym = symbol_dummy!(1u8, "extern");
let kind = IdentKind::Class(Dim::from_u8(1));
let src = Source {
desc: Some("extern".into()),
@ -966,9 +985,9 @@ mod test {
#[test]
fn resolved_on_extern() {
let sym = symbol_dummy!(1, "extern resolved");
let sym = symbol_dummy!(1u8, "extern resolved");
let kind = IdentKind::Class(Dim::from_u8(1));
let pkg_name = symbol_dummy!(2, "pkg/name");
let pkg_name = symbol_dummy!(2u8, "pkg/name");
let src = Source {
pkg_name: Some(&pkg_name),
desc: Some("extern".into()),
@ -1033,7 +1052,7 @@ mod test {
// Extern first, then identifier
#[test]
fn redeclare_compatible_resolves() {
let sym = symbol_dummy!(1, "extern_re_pre");
let sym = symbol_dummy!(1u8, "extern_re_pre");
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("okay".into()),
@ -1051,7 +1070,7 @@ mod test {
// Identifier first, then extern
#[test]
fn redeclare_compatible_resolves_post() {
let sym = symbol_dummy!(1, "extern_re_post");
let sym = symbol_dummy!(1u8, "extern_re_post");
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("okay".into()),
@ -1068,7 +1087,7 @@ mod test {
#[test]
fn redeclare_another_extern() {
let sym = symbol_dummy!(1, "extern_extern");
let sym = symbol_dummy!(1u8, "extern_extern");
let kind = IdentKind::Class(Dim::from_u8(20));
let src_first = Source {
desc: Some("first src".into()),
@ -1094,7 +1113,7 @@ mod test {
// Extern first, then identifier
#[test]
fn redeclare_post_incompatible_kind() {
let sym = symbol_dummy!(1, "extern_re_bad_post");
let sym = symbol_dummy!(1u8, "extern_re_bad_post");
let kind = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("bad kind".into()),
@ -1138,7 +1157,7 @@ mod test {
// Identifier first, then extern
#[test]
fn redeclare_pre_incompatible_kind() {
let sym = symbol_dummy!(1, "extern_re_bad_pre");
let sym = symbol_dummy!(1u8, "extern_re_bad_pre");
let kind_given = IdentKind::Class(Dim::from_u8(10));
let src = Source {
desc: Some("bad kind".into()),
@ -1184,7 +1203,7 @@ mod test {
#[test]
fn add_fragment_to_ident() {
let sym = symbol_dummy!(1, "tofrag");
let sym = symbol_dummy!(1u8, "tofrag");
let src = Source {
generated: true,
..Default::default()
@ -1205,7 +1224,7 @@ mod test {
#[test]
fn resolved_on_fragment() {
let sym = symbol_dummy!(1, "tofrag resolved");
let sym = symbol_dummy!(1u8, "tofrag resolved");
let src = Source {
generated: true,
..Default::default()
@ -1226,7 +1245,7 @@ mod test {
#[test]
fn add_fragment_to_fragment_fails() {
let sym = symbol_dummy!(1, "badsym");
let sym = symbol_dummy!(1u8, "badsym");
let ident = IdentObject::declare(&sym)
.resolve(IdentKind::Meta, Source::default())
.unwrap();
@ -1259,8 +1278,8 @@ mod test {
#[test]
fn declare_virtual_ident_first() {
let sym = symbol_dummy!(1, "virtual");
let over_src = symbol_dummy!(2, "src");
let sym = symbol_dummy!(1u8, "virtual");
let over_src = symbol_dummy!(2u8, "src");
let kind = IdentKind::Meta;
let virt = IdentObject::declare(&sym)
@ -1298,8 +1317,8 @@ mod test {
// Override is encountered before the virtual
#[test]
fn declare_virtual_ident_after_override() {
let sym = symbol_dummy!(1, "virtual_second");
let virt_src = symbol_dummy!(2, "virt_src");
let sym = symbol_dummy!(1u8, "virtual_second");
let virt_src = symbol_dummy!(2u8, "virt_src");
let kind = IdentKind::Meta;
let over_src = Source {
@ -1336,7 +1355,7 @@ mod test {
#[test]
fn declare_override_non_virtual() {
let sym = symbol_dummy!(1, "non_virtual");
let sym = symbol_dummy!(1u8, "non_virtual");
let kind = IdentKind::Meta;
let non_virt = IdentObject::declare(&sym)
@ -1390,8 +1409,8 @@ mod test {
#[test]
fn declare_virtual_ident_incompatible_kind() {
let sym = symbol_dummy!(1, "virtual");
let src_sym = symbol_dummy!(2, "src");
let sym = symbol_dummy!(1u8, "virtual");
let src_sym = symbol_dummy!(2u8, "src");
let kind = IdentKind::Meta;
let virt = IdentObject::declare(&sym)
@ -1450,8 +1469,8 @@ mod test {
// fragment to be cleared to make way for the new fragment.
#[test]
fn declare_override_virtual_ident_fragment_virtual_first() {
let sym = symbol_dummy!(1, "virtual");
let over_src = symbol_dummy!(2, "src");
let sym = symbol_dummy!(1u8, "virtual");
let over_src = symbol_dummy!(2u8, "src");
let kind = IdentKind::Meta;
// Remember: override is going to come first...
@ -1523,8 +1542,8 @@ mod test {
// precedence over the override.
#[test]
fn declare_override_virtual_ident_fragment_override_first() {
let sym = symbol_dummy!(1, "virtual");
let over_src = symbol_dummy!(2, "src");
let sym = symbol_dummy!(1u8, "virtual");
let over_src = symbol_dummy!(2u8, "src");
let kind = IdentKind::Meta;
let virt_src = Source {
@ -1569,8 +1588,8 @@ mod test {
#[test]
fn declare_override_virtual_ident_fragment_incompatible_type() {
let sym = symbol_dummy!(1, "virtual");
let over_src = symbol_dummy!(2, "src");
let sym = symbol_dummy!(1u8, "virtual");
let over_src = symbol_dummy!(2u8, "src");
let kind = IdentKind::Meta;
let virt_src = Source {
@ -1627,7 +1646,7 @@ mod test {
}
fn add_ident_kind_ignores(given: IdentKind, expected: IdentKind) {
let sym = symbol_dummy!(1, "tofrag");
let sym = symbol_dummy!(1u8, "tofrag");
let src = Source {
generated: true,
..Default::default()
@ -1669,11 +1688,11 @@ mod test {
#[test]
fn source_from_sym_attrs() {
let nsym = symbol_dummy!(1, "name");
let ssym = symbol_dummy!(2, "src");
let psym = symbol_dummy!(3, "parent");
let ysym = symbol_dummy!(4, "yields");
let fsym = symbol_dummy!(5, "from");
let nsym = symbol_dummy!(1u8, "name");
let ssym = symbol_dummy!(2u8, "src");
let psym = symbol_dummy!(3u8, "parent");
let ysym = symbol_dummy!(4u8, "yields");
let fsym = symbol_dummy!(5u8, "from");
let attrs = SymAttrs {
pkg_name: Some(&nsym),

View File

@ -72,9 +72,9 @@ impl<'a, T> Section<'a, T> {
///
/// ```
/// use tamer::ir::asg::{IdentObject, Section};
/// use tamer::sym::{DefaultInterner, Interner};
/// use tamer::sym::{DefaultPkgInterner, Interner};
///
/// let interner = DefaultInterner::new();
/// let interner = DefaultPkgInterner::new();
/// let mut section = Section::new();
/// let obj = IdentObject::Missing(interner.intern("ident"));
/// let expect = vec![&obj, &obj, &obj];
@ -157,10 +157,10 @@ mod test {
use crate::sym::{Symbol, SymbolIndex};
lazy_static! {
static ref SYM: Symbol<'static> = symbol_dummy!(1, "sym");
static ref SYM: Symbol<'static, u16> = symbol_dummy!(1, "sym");
}
type Sut<'a, 'i> = Section<'a, IdentObject<'i>>;
type Sut<'a, 'i> = Section<'a, IdentObject<'i, u16>>;
#[test]
fn section_empty() {

View File

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

View File

@ -30,7 +30,7 @@ use crate::ir::asg::{
};
use crate::obj::xmle::writer::XmleWriter;
use crate::obj::xmlo::{AsgBuilder, AsgBuilderState, XmloReader};
use crate::sym::{DefaultInterner, Interner, Symbol};
use crate::sym::{DefaultInterner, DefaultProgInterner, Interner, Symbol};
use fxhash::FxBuildHasher;
use petgraph_graphml::GraphMl;
use std::error::Error;
@ -38,7 +38,8 @@ use std::fs;
use std::io::BufReader;
use std::path::{Path, PathBuf};
type LinkerAsg<'i> = DefaultAsg<'i, IdentObject<'i>, global::ProgIdentSize>;
type LinkerAsg<'i> =
DefaultAsg<'i, IdentObject<'i, global::ProgSymSize>, global::ProgIdentSize>;
type LinkerAsgBuilderState<'i> =
AsgBuilderState<'i, FxBuildHasher, global::ProgIdentSize>;
@ -112,7 +113,7 @@ pub fn xmle(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
pub fn graphml(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
let mut fs = VisitOnceFilesystem::new();
let mut depgraph = LinkerAsg::with_capacity(65536, 65536);
let interner = DefaultInterner::new();
let interner = DefaultProgInterner::new();
let _ = load_xmlo(
package_path,
@ -162,7 +163,7 @@ pub fn graphml(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
Ok(())
}
fn load_xmlo<'a, 'i, I: Interner<'i>, P: AsRef<Path>>(
fn load_xmlo<'a, 'i, I: Interner<'i, global::ProgSymSize>, P: AsRef<Path>>(
path_str: P,
fs: &mut VisitOnceFilesystem<FsCanonicalizer, FxBuildHasher>,
depgraph: &mut LinkerAsg<'i>,
@ -176,7 +177,7 @@ fn load_xmlo<'a, 'i, I: Interner<'i>, P: AsRef<Path>>(
let (path, file) = cfile.into();
let xmlo: XmloReader<'_, _, _> = (file, interner).into();
let xmlo: XmloReader<'_, _, _, _> = (file, interner).into();
let mut state = depgraph.import_xmlo(xmlo, state)?;
@ -198,19 +199,19 @@ fn load_xmlo<'a, 'i, I: Interner<'i>, P: AsRef<Path>>(
fn get_ident<'a, 'i>(
depgraph: &'a LinkerAsg<'i>,
name: &'i Symbol<'i>,
) -> Result<&'a IdentObject<'i>, String> {
name: &'i Symbol<'i, global::ProgSymSize>,
) -> Result<&'a IdentObject<'i, global::ProgSymSize>, String> {
depgraph
.lookup(name)
.and_then(|id| depgraph.get(id))
.ok_or(format!("missing identifier: {}", name))
}
fn output_xmle<'a, 'i, I: Interner<'i>>(
fn output_xmle<'a, 'i, I: Interner<'i, global::ProgSymSize>>(
depgraph: &'a LinkerAsg<'i>,
interner: &'i I,
sorted: &mut Sections<'a, IdentObject<'i>>,
name: &'i Symbol<'i>,
sorted: &mut Sections<'a, IdentObject<'i, global::ProgSymSize>>,
name: &'i Symbol<'i, global::ProgSymSize>,
relroot: String,
output: &str,
) -> Result<(), Box<dyn Error>> {

View File

@ -26,6 +26,8 @@ pub mod global;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate static_assertions;
#[macro_use]
pub mod sym;

View File

@ -30,13 +30,13 @@
//! ```
//! use tamer::obj::xmle::writer::XmleWriter;
//! use tamer::ir::asg::{IdentObject, Sections};
//! use tamer::sym::{DefaultInterner, Interner, Symbol};
//! use tamer::sym::{DefaultProgInterner, Interner, Symbol};
//! use std::io::Cursor;
//!
//! let interner = DefaultInterner::new();
//! let interner = DefaultProgInterner::new();
//! let name = interner.intern(&String::from("foo"));
//!
//! let sections = Sections::<IdentObject>::new();
//! let sections = Sections::<IdentObject<_>>::new();
//! let writer = Cursor::new(Vec::new());
//! let mut xmle_writer = XmleWriter::new(writer);
//! xmle_writer.write(&sections, name, &String::from(""));

View File

@ -18,7 +18,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::ir::asg::Sections;
use crate::sym::Symbol;
use crate::sym::ProgSymbol as Symbol;
use quick_xml::Error as XmlError;
use std::io::{Error as IoError, Write};
use std::result;

View File

@ -21,7 +21,7 @@ use super::writer::{Result, WriterError};
use crate::ir::asg::{
IdentKind, IdentObject, IdentObjectData, SectionIterator, Sections,
};
use crate::sym::Symbol;
use crate::sym::{Symbol, SymbolIndexSize};
use fxhash::FxHashSet;
#[cfg(test)]
use mock::MockXmlWriter as XmlWriter;
@ -73,13 +73,13 @@ impl<W: Write> XmleWriter<W> {
/// use std::io::Cursor;
/// use tamer::obj::xmle::writer::XmleWriter;
/// use tamer::ir::asg::{Sections, IdentObject};
/// use tamer::sym::{Symbol, SymbolIndex, DefaultInterner, Interner};
/// use tamer::sym::{Symbol, SymbolIndex, DefaultProgInterner, Interner};
///
/// let writer = Cursor::new(Vec::new());
/// let mut xmle_writer = XmleWriter::new(writer);
/// let sections = Sections::<IdentObject>::new();
/// let sections = Sections::<IdentObject<_>>::new();
/// let a = "foo";
/// let interner = DefaultInterner::new();
/// let interner = DefaultProgInterner::new();
/// let name = interner.intern(&a);
/// xmle_writer.write(
/// &sections,
@ -89,10 +89,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<'i, T: IdentObjectData<'i>>(
pub fn write<'i, Ix: SymbolIndexSize, T: IdentObjectData<'i, Ix>>(
&mut self,
sections: &Sections<T>,
name: &Symbol,
name: &Symbol<'i, Ix>,
relroot: &str,
) -> Result {
self.write_start_package(name, &relroot)?
@ -152,9 +152,9 @@ impl<W: Write> XmleWriter<W> {
///
/// The `package` element's opening tag needs attributes, so it cannot use
/// `write_start_tag` directly.
fn write_start_package(
fn write_start_package<Ix: SymbolIndexSize>(
&mut self,
name: &Symbol,
name: &Symbol<Ix>,
relroot: &str,
) -> Result<&mut XmleWriter<W>> {
let root =
@ -193,7 +193,7 @@ impl<W: Write> XmleWriter<W> {
///
/// All the [`Sections`] found need to be written out using the `writer`
/// object.
fn write_sections<'i, T: IdentObjectData<'i>>(
fn write_sections<'i, Ix: SymbolIndexSize, T: IdentObjectData<'i, Ix>>(
&mut self,
sections: &Sections<T>,
relroot: &str,
@ -309,7 +309,7 @@ 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<'i, T: IdentObjectData<'i>>(
fn write_froms<'i, Ix: SymbolIndexSize, T: IdentObjectData<'i, Ix>>(
&mut self,
sections: &Sections<T>,
) -> Result<&mut XmleWriter<W>> {
@ -343,7 +343,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<'i, T: IdentObjectData<'i>>(
fn write_section<'i, Ix: SymbolIndexSize, T: IdentObjectData<'i, Ix>>(
&mut self,
idents: SectionIterator<T>,
) -> Result<&mut XmleWriter<W>> {
@ -457,7 +457,7 @@ mod test {
_ => panic!("did not match expected event"),
}));
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
sut.write_start_package(&sym, &String::from(""))?;
@ -512,7 +512,7 @@ mod test {
_ => panic!("did not trigger event"),
}));
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let obj = IdentObject::IdentFragment(
&sym,
IdentKind::Meta,
@ -534,7 +534,7 @@ mod test {
panic!("callback should not have been called");
}));
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let obj = IdentObject::Ident(
&sym,
IdentKind::Cgen(Dim::default()),
@ -555,7 +555,7 @@ mod test {
panic!("callback should not have been called");
}));
let sym = symbol_dummy!(1, "sym");
let sym = symbol_dummy!(1u8, "sym");
let obj = IdentObject::Missing(&sym);
let mut section = Section::new();
@ -594,7 +594,7 @@ mod test {
_ => panic!("unexpected event"),
}));
let sym = symbol_dummy!(1, "random_symbol");
let sym = symbol_dummy!(1u8, "random_symbol");
let object =
IdentObject::Ident(&sym, IdentKind::Worksheet, Source::default());
let mut sections = Sections::new();
@ -649,11 +649,11 @@ mod test {
_ => panic!("unexpected event"),
}));
let nsym = symbol_dummy!(1, "name");
let ssym = symbol_dummy!(2, "src");
let psym = symbol_dummy!(3, "parent");
let ysym = symbol_dummy!(4, "yields");
let fsym = symbol_dummy!(5, "from");
let nsym = symbol_dummy!(1u8, "name");
let ssym = symbol_dummy!(2u8, "src");
let psym = symbol_dummy!(3u8, "parent");
let ysym = symbol_dummy!(4u8, "yields");
let fsym = symbol_dummy!(5u8, "from");
let attrs = SymAttrs {
pkg_name: Some(&nsym),
@ -696,8 +696,8 @@ mod test {
_ => panic!("unexpected event"),
}));
let sym = symbol_dummy!(1, "source symbol");
let symb = symbol_dummy!(2, "dest symbol");
let sym = symbol_dummy!(1u8, "source symbol");
let symb = symbol_dummy!(2u8, "dest symbol");
let mut src = Source::default();
src.from = Some(vec![&symb]);
@ -717,7 +717,7 @@ mod test {
_ => panic!("unexpected write"),
}));
let sym = symbol_dummy!(1, "random_symbol");
let sym = symbol_dummy!(1u8, "random_symbol");
let object =
IdentObject::Ident(&sym, IdentKind::Worksheet, Source::default());

View File

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

View File

@ -29,7 +29,10 @@
//! the former is more akin to an identifier.
//!
//! For more information on `xmlo` files,
//! see the [parent crate][super].
//! see the [parent crate][super].A
//!
//! This reader will be used by both the compiler and linker,
//! and so its [`Symbol`] type is generalized.
//!
//!
//! How To Use
@ -52,7 +55,7 @@
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! use tamer::obj::xmlo::{XmloEvent, XmloReader};
//! use tamer::ir::legacyir::SymType;
//! use tamer::sym::{DefaultInterner, Interner};
//! use tamer::sym::{DefaultPkgInterner, Interner};
//!
//! let xmlo = br#"<package name="foo">
//! <preproc:symtable>
@ -76,7 +79,7 @@
//! </preproc:fragments>
//! </package>"#;
//!
//! let interner = DefaultInterner::new();
//! let interner = DefaultPkgInterner::new();
//! let mut reader = XmloReader::new(xmlo as &[u8], &interner);
//!
//! let mut pkgname = None;
@ -132,7 +135,7 @@
//! ```
use crate::ir::legacyir::{PackageAttrs, SymAttrs, SymType};
use crate::sym::{Interner, Symbol};
use crate::sym::{Interner, Symbol, SymbolIndexSize};
#[cfg(test)]
use crate::test::quick_xml::MockBytesStart as BytesStart;
#[cfg(test)]
@ -172,10 +175,11 @@ pub type XmloResult<T> = Result<T, XmloError>;
///
/// See [module-level documentation](self) for more information and
/// examples.
pub struct XmloReader<'i, B, I>
pub struct XmloReader<'i, B, I, Ix>
where
B: BufRead,
I: Interner<'i>,
I: Interner<'i, Ix>,
Ix: SymbolIndexSize,
{
/// Source `xmlo` reader.
reader: XmlReader<B>,
@ -202,10 +206,15 @@ where
///
/// This is known after processing the root `package` element,
/// provided that it's a proper root node.
pkg_name: Option<&'i Symbol<'i>>,
pkg_name: Option<&'i Symbol<'i, Ix>>,
}
impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
impl<'i, B, I, Ix> XmloReader<'i, B, I, Ix>
where
B: BufRead,
I: Interner<'i, Ix>,
Ix: SymbolIndexSize,
{
/// Construct a new reader.
pub fn new(reader: B, interner: &'i I) -> Self {
let mut reader = XmlReader::from_reader(reader);
@ -245,7 +254,7 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
/// See private methods for more information.
///
/// TODO: Augment failures with context
pub fn read_event<'a>(&mut self) -> XmloResult<XmloEvent<'i>> {
pub fn read_event<'a>(&mut self) -> XmloResult<XmloEvent<'i, Ix>> {
let event = self.reader.read_event(&mut self.buffer)?;
// Ensure that the first encountered node is something we expect
@ -346,10 +355,10 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
fn process_package<'a>(
ele: &'a BytesStart<'a>,
interner: &'i I,
) -> XmloResult<PackageAttrs<'i>> {
) -> XmloResult<PackageAttrs<'i, Ix>> {
let mut program = false;
let mut elig: Option<&'i Symbol<'i>> = None;
let mut name: Option<&'i Symbol<'i>> = None;
let mut elig: Option<&'i Symbol<'i, Ix>> = None;
let mut name: Option<&'i Symbol<'i, Ix>> = None;
let mut relroot: Option<String> = None;
for attr in ele.attributes().with_checks(false).filter_map(Result::ok) {
@ -403,11 +412,11 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
/// ======
/// - [`XmloError::UnassociatedSym`] if missing `preproc:sym/@name`.
fn process_sym<'a>(
pkg_name: &Option<&'i Symbol<'i>>,
pkg_name: &Option<&'i Symbol<'i, Ix>>,
ele: &'a BytesStart<'a>,
interner: &'i I,
) -> XmloResult<XmloEvent<'i>> {
let mut name: Option<&'i Symbol<'i>> = None;
) -> XmloResult<XmloEvent<'i, Ix>> {
let mut name: Option<&'i Symbol<'i, Ix>> = None;
let mut sym_attrs = SymAttrs::default();
for attr in ele.attributes().with_checks(false).filter_map(Result::ok) {
@ -507,7 +516,7 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
interner: &'i I,
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
) -> XmloResult<Vec<&'i Symbol<'i>>> {
) -> XmloResult<Vec<&'i Symbol<'i, Ix>>> {
let mut froms = Vec::new();
loop {
@ -571,7 +580,7 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
interner: &'i I,
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
) -> XmloResult<XmloEvent<'i>> {
) -> XmloResult<XmloEvent<'i, Ix>> {
let name = ele
.attributes()
.with_checks(false)
@ -641,7 +650,7 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
interner: &'i I,
reader: &mut XmlReader<B>,
buffer: &mut Vec<u8>,
) -> XmloResult<XmloEvent<'i>> {
) -> XmloResult<XmloEvent<'i, Ix>> {
let mut src_attrs = ele.attributes();
let mut filtered = src_attrs.with_checks(false).filter_map(Result::ok);
@ -685,12 +694,13 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
}
}
impl<'i, B, I> Iterator for XmloReader<'i, B, I>
impl<'i, B, I, Ix> Iterator for XmloReader<'i, B, I, Ix>
where
B: BufRead,
I: Interner<'i>,
I: Interner<'i, Ix>,
Ix: SymbolIndexSize,
{
type Item = XmloResult<XmloEvent<'i>>;
type Item = XmloResult<XmloEvent<'i, Ix>>;
/// Invoke [`XmloReader::read_event`] and yield the result via an
/// [`Iterator`] API.
@ -706,10 +716,11 @@ where
}
}
impl<'i, B, I> From<(B, &'i I)> for XmloReader<'i, B, I>
impl<'i, B, I, Ix> From<(B, &'i I)> for XmloReader<'i, B, I, Ix>
where
B: BufRead,
I: Interner<'i>,
I: Interner<'i, Ix>,
Ix: SymbolIndexSize,
{
fn from(args: (B, &'i I)) -> Self {
Self::new(args.0, args.1)
@ -726,24 +737,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<'i> {
pub enum XmloEvent<'i, Ix: SymbolIndexSize> {
/// Package declaration.
///
/// This contains data gathered from the root `lv:package` node.
Package(PackageAttrs<'i>),
Package(PackageAttrs<'i, Ix>),
/// Symbol declaration.
///
/// This represents an entry in the symbol table,
/// which includes a symbol along with its variable metadata as
/// [`SymAttrs`].
SymDecl(&'i Symbol<'i>, SymAttrs<'i>),
SymDecl(&'i Symbol<'i, Ix>, SymAttrs<'i, Ix>),
/// Dependencies of a given symbol.
///
/// Note that, for simplicity, an owned vector is returned rather than a
/// slice into an internal buffer.
SymDeps(&'i Symbol<'i>, Vec<&'i Symbol<'i>>),
SymDeps(&'i Symbol<'i, Ix>, Vec<&'i Symbol<'i, Ix>>),
/// Text (compiled code) fragment for a given symbol.
///
@ -752,7 +763,7 @@ pub enum XmloEvent<'i> {
/// 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(&'i Symbol<'i>, String),
Fragment(&'i Symbol<'i, Ix>, String),
/// End-of-header.
///

View File

@ -22,7 +22,7 @@ use crate::ir::legacyir::{SymDtype, SymType};
use crate::sym::DefaultInterner;
use crate::test::quick_xml::*;
type Sut<'i, B, I> = XmloReader<'i, B, I>;
type Sut<'i, B, I> = XmloReader<'i, B, I, u16>;
macro_rules! xmlo_tests {
($(fn $fn:ident($sut:ident, $interner:ident) $body:block)*) => {

View File

@ -70,10 +70,10 @@
//!
//! // Each symbol has an associated, densely-packed integer value
//! // that can be used for indexing
//! assert_eq!(SymbolIndex::from_int(1), ia.index());
//! assert_eq!(SymbolIndex::from_int(1), ib.index());
//! assert_eq!(SymbolIndex::from_int(2), ic.index());
//! assert_eq!(SymbolIndex::from_int(1), id.index());
//! assert_eq!(SymbolIndex::from_int(1u16), ia.index());
//! assert_eq!(SymbolIndex::from_int(1u16), ib.index());
//! assert_eq!(SymbolIndex::from_int(2u16), ic.index());
//! assert_eq!(SymbolIndex::from_int(1u16), id.index());
//!
//! // Symbols can also be looked up by index.
//! assert_eq!(Some(ia), interner.index_lookup(ia.index()));
@ -235,7 +235,7 @@
//! - Rustc identifies symbols by integer value encapsulated within a
//! `Symbol`.
//! - Rustc's [`newtype_index!` macro][rustc-nt] uses
//! [`global::NonZeroProgSymSize`] so that [`Option`] uses no
//! [`NonZeroU32`] so that [`Option`] uses no
//! additional space (see [pull request `53315`][rustc-nt-pr]).
//! - Differences between TAMER and Rustc's implementations are outlined
//! above.
@ -273,7 +273,7 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::hash::BuildHasher;
use std::num::{NonZeroU16, NonZeroU32};
use std::num::{NonZeroU16, NonZeroU32, NonZeroU8};
use std::ops::Deref;
use std::{fmt, fmt::Debug};
@ -288,14 +288,13 @@ use std::{fmt, fmt::Debug};
/// between multiple [`Interner`]s.
///
/// The index `0` is never valid because of
/// [`SupportedSymbolIndex::NonZero`],
/// [`SymbolIndexSize::NonZero`],
/// which allows us to have `Option<SymbolIndex>` at no space cost.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SymbolIndex<Ix: SupportedSymbolIndex = global::ProgSymSize>(
Ix::NonZero,
);
pub struct SymbolIndex<Ix: SymbolIndexSize>(Ix::NonZero);
assert_eq_size!(Option<Symbol<u16>>, Symbol<u16>);
impl<Ix: SupportedSymbolIndex> SymbolIndex<Ix> {
impl<Ix: SymbolIndexSize> SymbolIndex<Ix> {
/// Construct index from a non-zero `u16` value.
///
/// Panics
@ -334,7 +333,7 @@ impl<Ix: SupportedSymbolIndex> SymbolIndex<Ix> {
}
}
impl<Ix: SupportedSymbolIndex> From<SymbolIndex<Ix>> for usize
impl<Ix: SymbolIndexSize> From<SymbolIndex<Ix>> for usize
where
<Ix as TryInto<usize>>::Error: Debug,
{
@ -343,7 +342,7 @@ where
}
}
impl<'i, Ix: SupportedSymbolIndex> From<&Symbol<'i, Ix>> for SymbolIndex<Ix> {
impl<'i, Ix: SymbolIndexSize> From<&Symbol<'i, Ix>> for SymbolIndex<Ix> {
fn from(sym: &Symbol<'i, Ix>) -> Self {
sym.index()
}
@ -356,7 +355,7 @@ impl<'i, Ix: SupportedSymbolIndex> From<&Symbol<'i, Ix>> for SymbolIndex<Ix> {
/// primitive type has to be explicitly accounted for.
///
/// This trait must be implemented on a primitive type like [`u16`].
pub trait SupportedSymbolIndex:
pub trait SymbolIndexSize:
Sized
+ Copy
+ Debug
@ -389,7 +388,7 @@ pub trait SupportedSymbolIndex:
macro_rules! supported_symbol_index {
($prim:ty, $nonzero:ty, $dummy:ident) => {
impl SupportedSymbolIndex for $prim {
impl SymbolIndexSize for $prim {
type NonZero = $nonzero;
fn dummy_sym() -> &'static Symbol<'static, Self> {
@ -411,6 +410,7 @@ macro_rules! supported_symbol_index {
};
}
supported_symbol_index!(u8, NonZeroU8, DUMMY_SYM_8);
supported_symbol_index!(u16, NonZeroU16, DUMMY_SYM_16);
supported_symbol_index!(u32, NonZeroU32, DUMMY_SYM_32);
@ -439,15 +439,25 @@ supported_symbol_index!(u32, NonZeroU32, DUMMY_SYM_32);
/// whose lifetime is that of the [`Interner`]'s underlying data store.
/// Dereferencing the symbol will expose the underlying slice.
#[derive(Copy, Clone, Debug)]
pub struct Symbol<'i, Ix = global::ProgSymSize>
where
Ix: SupportedSymbolIndex,
{
pub struct Symbol<'i, Ix: SymbolIndexSize> {
index: SymbolIndex<Ix>,
str: &'i str,
}
impl<'i, Ix: SupportedSymbolIndex> Symbol<'i, Ix> {
/// Interned string within a single package.
///
/// This type should be preferred to [`ProgSymbol`] when only a single
/// package's symbols are being processed.
pub type PkgSymbol<'i> = Symbol<'i, global::PkgSymSize>;
/// Interned string within an entire program.
///
/// This symbol type is preconfigured to accommodate a larger number of
/// symbols than [`PkgSymbol`] and is situable for use in a linker.
/// Use this type only when necessary.
pub type ProgSymbol<'i> = Symbol<'i, global::ProgSymSize>;
impl<'i, Ix: SymbolIndexSize> Symbol<'i, Ix> {
/// Construct a new interned value.
///
/// _This must only be done by an [`Interner`]._
@ -486,16 +496,16 @@ impl<'i, Ix: SupportedSymbolIndex> Symbol<'i, Ix> {
}
}
impl<'i> PartialEq for Symbol<'i> {
impl<'i, Ix: SymbolIndexSize> PartialEq for Symbol<'i, Ix> {
fn eq(&self, other: &Self) -> bool {
std::ptr::eq(self as *const _, other as *const _)
|| std::ptr::eq(self.str.as_ptr(), other.str.as_ptr())
}
}
impl<'i> Eq for Symbol<'i> {}
impl<'i, Ix: SymbolIndexSize> Eq for Symbol<'i, Ix> {}
impl<'i> Deref for Symbol<'i> {
impl<'i, Ix: SymbolIndexSize> Deref for Symbol<'i, Ix> {
type Target = str;
/// Dereference to interned string slice.
@ -507,7 +517,7 @@ impl<'i> Deref for Symbol<'i> {
}
}
impl<'i> fmt::Display for Symbol<'i> {
impl<'i, Ix: SymbolIndexSize> fmt::Display for Symbol<'i, Ix> {
/// Display name of underlying string.
///
/// Since symbols contain pointers to their interned slices,
@ -518,6 +528,15 @@ impl<'i> fmt::Display for Symbol<'i> {
}
lazy_static! {
/// Dummy 8-bit [`Symbol`] for use at index `0`.
///
/// A symbol must never have an index of `0`,
/// so this can be used as a placeholder.
/// The chosen [`SymbolIndex`] here does not matter since this will
/// never be referenced.
static ref DUMMY_SYM_8: Symbol<'static, u8> =
Symbol::new(SymbolIndex::from_int(1), "!BADSYMREF!");
/// Dummy 16-bit [`Symbol`] for use at index `0`.
///
/// A symbol must never have an index of `0`,
@ -551,10 +570,7 @@ lazy_static! {
/// [`contains`](Interner::contains).
///
/// See the [module-level documentation](self) for an example.
pub trait Interner<'i, Ix = global::ProgSymSize>
where
Ix: SupportedSymbolIndex,
{
pub trait Interner<'i, Ix: SymbolIndexSize> {
/// Intern a string slice or return an existing [`Symbol`].
///
/// If the provided string has already been interned,
@ -635,10 +651,10 @@ where
///
/// See the [module-level documentation](self) for examples and more
/// information on how to use this interner.
pub struct ArenaInterner<'i, S, Ix = global::ProgSymSize>
pub struct ArenaInterner<'i, S, Ix>
where
S: BuildHasher + Default,
Ix: SupportedSymbolIndex,
Ix: SymbolIndexSize,
{
/// String and [`Symbol`] storage.
arena: Bump,
@ -661,7 +677,7 @@ where
impl<'i, S, Ix> ArenaInterner<'i, S, Ix>
where
S: BuildHasher + Default,
Ix: SupportedSymbolIndex,
Ix: SymbolIndexSize,
{
/// Initialize a new interner with no initial capacity.
///
@ -707,7 +723,7 @@ where
impl<'i, S, Ix> Interner<'i, Ix> for ArenaInterner<'i, S, Ix>
where
S: BuildHasher + Default,
Ix: SupportedSymbolIndex,
Ix: SymbolIndexSize,
<Ix as TryFrom<usize>>::Error: Debug,
{
fn intern(&'i self, value: &str) -> &'i Symbol<'i, Ix> {
@ -792,8 +808,22 @@ pub type FxArenaInterner<'i, Ix> = ArenaInterner<'i, FxBuildHasher, Ix>;
///
/// For more information on the hashing algorithm,
/// see [`FxArenaInterner`].
pub type DefaultInterner<'i, Ix = global::ProgSymSize> =
FxArenaInterner<'i, Ix>;
pub type DefaultInterner<'i, Ix> = 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.
pub type DefaultProgInterner<'i> = DefaultInterner<'i, global::ProgSymSize>;
/// Concisely define dummy symbols for testing.
#[cfg(test)]
@ -810,28 +840,16 @@ mod test {
mod symbol {
use super::*;
/// Option<Symbol> should have no space cost.
#[test]
fn symbol_index_option_no_cost() {
use std::mem::size_of;
assert_eq!(
size_of::<Option<Symbol>>(),
size_of::<Symbol>(),
"Option<Symbol> should be the same size as Symbol"
);
}
#[test]
fn self_compares_eq() {
let sym = Symbol::new(SymbolIndex::from_int(1), "str");
let sym = Symbol::new(SymbolIndex::from_int(1u16), "str");
assert_eq!(&sym, &sym);
}
#[test]
fn copy_compares_equal() {
let sym = Symbol::new(SymbolIndex::from_int(1), "str");
let sym = Symbol::new(SymbolIndex::from_int(1u16), "str");
let cpy = sym;
assert_eq!(sym, cpy);
@ -841,8 +859,8 @@ mod test {
// used as a unique identifier across different interners.
#[test]
fn same_index_different_slices_compare_unequal() {
let a = Symbol::new(SymbolIndex::from_int(1), "a");
let b = Symbol::new(SymbolIndex::from_int(1), "b");
let a = Symbol::new(SymbolIndex::from_int(1u16), "a");
let b = Symbol::new(SymbolIndex::from_int(1u16), "b");
assert_ne!(a, b);
}
@ -858,15 +876,15 @@ mod test {
fn different_index_same_slices_compare_equal() {
let slice = "str";
let a = Symbol::new(SymbolIndex::from_int(1), slice);
let b = Symbol::new(SymbolIndex::from_int(2), slice);
let a = Symbol::new(SymbolIndex::from_int(1u16), slice);
let b = Symbol::new(SymbolIndex::from_int(2u16), slice);
assert_eq!(a, b);
}
#[test]
fn cloned_symbols_compare_equal() {
let sym = Symbol::new(SymbolIndex::from_int(1), "foo");
let sym = Symbol::new(SymbolIndex::from_int(1u16), "foo");
assert_eq!(sym, sym.clone());
}
@ -876,7 +894,8 @@ mod test {
#[test]
fn ref_can_be_used_as_string_slice() {
let slice = "str";
let sym_slice: &str = &Symbol::new(SymbolIndex::from_int(1), slice);
let sym_slice: &str =
&Symbol::new(SymbolIndex::from_int(1u16), slice);
assert_eq!(slice, sym_slice);
}
@ -898,7 +917,7 @@ mod test {
#[test]
fn displays_as_interned_value() {
let sym = Symbol::new(SymbolIndex::from_int(1), "foo");
let sym = Symbol::new(SymbolIndex::from_int(1u16), "foo");
assert_eq!(format!("{}", sym), sym.str);
}
@ -907,7 +926,7 @@ mod test {
mod interner {
use super::*;
type Sut<'i> = DefaultInterner<'i>;
type Sut<'i> = DefaultInterner<'i, global::ProgSymSize>;
#[test]
fn recognizes_equal_strings() {