Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-16 11:49:41 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-24 09:56:25 -0400
commitf969877324d5c4f5debb6646f4ff95667a92e04f (patch)
treeda79a68ca1968fd2a8c638270fe40bc8ed3c287c
parent5fb68f9b677dff593159a9986be8da7f72b16b0d (diff)
downloadtame-f969877324d5c4f5debb6646f4ff95667a92e04f.tar.gz
tame-f969877324d5c4f5debb6646f4ff95667a92e04f.tar.bz2
tame-f969877324d5c4f5debb6646f4ff95667a92e04f.zip
[DEV-7087] TAMER: {=>Ident}Object{,State,Data}
This is essential to clarify what exactly the different object types represent with the new generic abstractions. For example, we will have expressions as an object type.
-rw-r--r--tamer/src/ir/asg/base.rs324
-rw-r--r--tamer/src/ir/asg/graph.rs23
-rw-r--r--tamer/src/ir/asg/ident.rs18
-rw-r--r--tamer/src/ir/asg/mod.rs37
-rw-r--r--tamer/src/ir/asg/object.rs474
-rw-r--r--tamer/src/ir/asg/section.rs30
-rw-r--r--tamer/src/ld/poc.rs8
-rw-r--r--tamer/src/obj/xmle/writer/mod.rs6
-rw-r--r--tamer/src/obj/xmle/writer/xmle.rs45
9 files changed, 669 insertions, 296 deletions
diff --git a/tamer/src/ir/asg/base.rs b/tamer/src/ir/asg/base.rs
index fbcf19a..d4b03a0 100644
--- a/tamer/src/ir/asg/base.rs
+++ b/tamer/src/ir/asg/base.rs
@@ -23,7 +23,7 @@ use super::graph::{
Asg, AsgEdge, AsgError, AsgResult, Node, ObjectRef, SortableAsg,
};
use super::ident::IdentKind;
-use super::object::{FragmentText, ObjectData, ObjectState, Source};
+use super::object::{FragmentText, IdentObjectData, IdentObjectState, Source};
use super::Sections;
use crate::sym::Symbol;
use fixedbitset::FixedBitSet;
@@ -64,7 +64,7 @@ where
impl<'i, O, Ix> BaseAsg<O, Ix>
where
Ix: IndexType,
- O: ObjectState<'i, O>,
+ O: IdentObjectState<'i, O>,
{
/// Create an ASG with the provided initial capacity.
///
@@ -128,7 +128,7 @@ where
/// Lookup `ident` or add a missing identifier to the graph and return a
/// reference to it.
///
- /// See [`ObjectState::missing`] for more information.
+ /// See [`IdentObjectState::missing`] for more information.
#[inline]
fn lookup_or_missing(&mut self, ident: &'i Symbol<'i>) -> ObjectRef<Ix> {
self.lookup(ident).unwrap_or_else(|| {
@@ -143,7 +143,7 @@ where
impl<'i, O, Ix> Asg<'i, O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType,
- O: ObjectState<'i, O>,
+ O: IdentObjectState<'i, O>,
{
fn declare(
&mut self,
@@ -267,7 +267,7 @@ where
impl<'i, O, Ix> SortableAsg<'i, O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType,
- O: ObjectData<'i> + ObjectState<'i, O>,
+ O: IdentObjectData<'i> + IdentObjectState<'i, O>,
{
fn sort(&'i self, roots: &[ObjectRef<Ix>]) -> AsgResult<Sections<'i, O>> {
let mut deps = Sections::new();
@@ -302,7 +302,7 @@ where
None => {
return Err(AsgError::UnexpectedNode(format!(
"{:?}",
- ident.ident()
+ ident.as_ident()
)))
}
}
@@ -351,11 +351,99 @@ where
mod test {
use super::super::graph::AsgError;
use super::*;
- use crate::ir::asg::Object;
+ use crate::ir::asg::{Dim, IdentObject, TransitionError, TransitionResult};
use crate::sym::SymbolIndex;
+ use std::cell::RefCell;
+
+ #[derive(Debug, Default, PartialEq)]
+ struct StubIdentObject<'i> {
+ given_missing: Option<&'i Symbol<'i>>,
+ given_ident: Option<(&'i Symbol<'i>, IdentKind, Source<'i>)>,
+ given_extern: Option<(&'i Symbol<'i>, IdentKind)>,
+ given_redeclare: Option<(IdentKind, Source<'i>)>,
+ given_set_fragment: Option<FragmentText>,
+ fail_redeclare: RefCell<Option<TransitionError>>,
+ }
+
+ impl<'i> IdentObjectData<'i> for StubIdentObject<'i> {
+ fn name(&self) -> Option<&'i Symbol<'i>> {
+ self.given_missing
+ .or(self.given_ident.as_ref().map(|args| args.0))
+ .or(self.given_extern.as_ref().map(|args| args.0))
+ }
+
+ fn kind(&self) -> Option<&IdentKind> {
+ self.given_ident
+ .as_ref()
+ .map(|args| &args.1)
+ .or(self.given_extern.as_ref().map(|args| &args.1))
+ .or(self.given_redeclare.as_ref().map(|args| &args.0))
+ }
+
+ fn src(&self) -> Option<&Source<'i>> {
+ None
+ }
+
+ fn fragment(&self) -> Option<&FragmentText> {
+ None
+ }
+
+ fn as_ident(&self) -> Option<&IdentObject<'i>> {
+ None
+ }
+ }
- // TODO: mock Object
- type Sut<'i> = BaseAsg<Object<'i>, u8>;
+ impl<'i> IdentObjectState<'i, StubIdentObject<'i>> for StubIdentObject<'i> {
+ fn missing(ident: &'i Symbol<'i>) -> Self {
+ Self {
+ given_missing: Some(ident),
+ ..Default::default()
+ }
+ }
+
+ fn ident(
+ name: &'i Symbol<'i>,
+ kind: IdentKind,
+ src: Source<'i>,
+ ) -> Self {
+ Self {
+ given_ident: Some((name, kind, src)),
+ ..Default::default()
+ }
+ }
+
+ fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> Self {
+ Self {
+ given_extern: Some((name, kind)),
+ ..Default::default()
+ }
+ }
+
+ fn redeclare(
+ mut self,
+ kind: IdentKind,
+ src: Source<'i>,
+ ) -> TransitionResult<StubIdentObject<'i>> {
+ if self.fail_redeclare.borrow().is_some() {
+ let err = self.fail_redeclare.replace(None).unwrap();
+ return Err((self, err));
+ }
+
+ self.given_redeclare = Some((kind, src));
+ Ok(self)
+ }
+
+ fn set_fragment(
+ mut self,
+ text: FragmentText,
+ ) -> TransitionResult<StubIdentObject<'i>> {
+ self.given_set_fragment.replace(text);
+ Ok(self)
+ }
+ }
+
+ // TODO: mock IdentObject
+ type Sut<'i> = BaseAsg<StubIdentObject<'i>, u8>;
#[test]
fn create_with_capacity() {
@@ -404,7 +492,7 @@ mod test {
assert_ne!(nodea, nodeb);
assert_eq!(
- Some(&Object::Ident(
+ Some((
&syma,
IdentKind::Meta,
Source {
@@ -412,11 +500,11 @@ mod test {
..Default::default()
},
)),
- sut.get(nodea),
+ sut.get(nodea).unwrap().given_ident
);
assert_eq!(
- Some(&Object::Ident(
+ Some((
&symb,
IdentKind::Worksheet,
Source {
@@ -424,7 +512,7 @@ mod test {
..Default::default()
},
)),
- sut.get(nodeb),
+ sut.get(nodeb).unwrap().given_ident
);
Ok(())
@@ -456,100 +544,74 @@ mod test {
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "extern");
let node = sut.declare_extern(&sym, IdentKind::Meta)?;
- assert_eq!(Some(&Object::Extern(&sym, IdentKind::Meta)), sut.get(node),);
+ assert_eq!(
+ Some((&sym, IdentKind::Meta)),
+ sut.get(node).unwrap().given_extern,
+ );
Ok(())
}
- // TODO: incompatible
#[test]
- fn declare_returns_existing_compatible() -> AsgResult<()> {
+ fn declare_returns_existing() -> AsgResult<()> {
let mut sut = Sut::with_capacity(0, 0);
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "symdup");
- let node = sut.declare(&sym, IdentKind::Meta, Source::default())?;
-
- // Same declaration a second time
- let redeclare =
- sut.declare(&sym, IdentKind::Meta, Source::default())?;
-
- assert_eq!(node, redeclare);
- Ok(())
- }
-
- // TODO: incompatible
- #[test]
- fn declare_override_virtual_ident() -> AsgResult<()> {
- let mut sut = Sut::with_capacity(0, 0);
-
- let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "virtual");
- let over_src = Symbol::new_dummy(SymbolIndex::from_u32(2), "src");
-
- let virt_node = sut.declare(
- &sym,
- IdentKind::Meta,
- Source {
- virtual_: true,
- ..Default::default()
- },
- )?;
+ let src = Source::default();
+ let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
- let over_src = Source {
- override_: true,
- src: Some(&over_src),
+ // Remember that our stub does not care about compatibility.
+ let rekind = IdentKind::Class(Dim::from_u8(3));
+ let resrc = Source {
+ desc: Some("redeclare".into()),
..Default::default()
};
+ let redeclare = sut.declare(&sym, rekind.clone(), resrc.clone())?;
- let over_node = sut.declare(&sym, IdentKind::Meta, over_src.clone())?;
-
- assert_eq!(virt_node, over_node);
+ // We don't care what the objects are for this test, just that the
+ // same node is referenced.
+ assert_eq!(node, redeclare);
assert_eq!(
- sut.get(over_node),
- Some(&Object::Ident(&sym, IdentKind::Meta, over_src,))
+ Some((rekind, resrc)),
+ sut.get(node).unwrap().given_redeclare,
);
Ok(())
}
- // TODO: incompatible
+ // Builds upon declare_returns_existing.
#[test]
- fn declare_override_virtual_ident_fragment() -> AsgResult<()> {
+ fn declare_fails_if_transition_fails() -> AsgResult<()> {
let mut sut = Sut::with_capacity(0, 0);
- let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "virtual");
- let over_src = Symbol::new_dummy(SymbolIndex::from_u32(2), "src");
-
- let virt_node = sut.declare(
- &sym,
- IdentKind::Meta,
- Source {
- virtual_: true,
- ..Default::default()
- },
- )?;
-
- sut.set_fragment(virt_node, FragmentText::from("remove me"))?;
-
- let over_src = Source {
- override_: true,
- src: Some(&over_src),
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "symdup");
+ let src = Source {
+ desc: Some("orig".into()),
..Default::default()
};
- let over_node = sut.declare(&sym, IdentKind::Meta, over_src.clone())?;
+ // Set up an object to fail redeclaration.
+ let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
+ let obj = sut.get(node).unwrap();
+ let msg = String::from("test fail");
+ obj.fail_redeclare
+ .replace(Some(TransitionError::Incompatible(msg.clone())));
- assert_eq!(virt_node, over_node);
+ // Should invoke StubIdentObject::redeclare on the above `obj`.
+ let result = sut.declare(&sym, IdentKind::Meta, Source::default());
- // The act of overriding the node should have cleared any existing
- // fragment, making way for a new fragment to take its place as soon
- // as it is discovered. (So, back to an Object::Ident.)
- assert_eq!(
- sut.get(over_node),
- Some(&Object::Ident(&sym, IdentKind::Meta, over_src,))
- );
+ if let Err(err) = result {
+ // The node should have been restored.
+ let obj = sut.get(node).unwrap();
+ assert_eq!(src, obj.given_ident.as_ref().unwrap().2);
- Ok(())
+ assert_eq!(AsgError::IncompatibleIdent(msg), err);
+
+ Ok(())
+ } else {
+ panic!("failure expected: {:?}", result);
+ }
}
#[test]
@@ -573,88 +635,15 @@ mod test {
"fragment node does not match original node"
);
- assert_eq!(
- Some(&Object::IdentFragment(&sym, IdentKind::Meta, src, fragment)),
- sut.get(node)
- );
-
- Ok(())
- }
-
- fn add_ident_kind_ignores(
- given: IdentKind,
- expected: IdentKind,
- ) -> AsgResult<()> {
- let mut sut = Sut::with_capacity(0, 0);
+ let obj = sut.get(node).unwrap();
- let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "tofrag");
- let src = Source {
- generated: true,
- ..Default::default()
- };
-
- let node = sut.declare(&sym, given, src.clone())?;
-
- let fragment = "a fragment".to_string();
- let node_with_frag = sut.set_fragment(node, fragment.clone())?;
-
- // Attaching a fragment should _replace_ the node, not create a
- // new one
- assert_eq!(
- node, node_with_frag,
- "fragment node does not match original node"
- );
-
- assert_eq!(
- Some(&Object::IdentFragment(&sym, expected, src, fragment)),
- sut.get(node)
- );
+ assert_eq!(Some((&sym, IdentKind::Meta, src,)), obj.given_ident);
+ assert_eq!(Some(fragment), obj.given_set_fragment);
Ok(())
}
- #[test]
- fn add_fragment_to_ident_map_head() -> AsgResult<()> {
- add_ident_kind_ignores(IdentKind::MapHead, IdentKind::MapHead)
- }
-
- #[test]
- fn add_fragment_to_ident_map_tail() -> AsgResult<()> {
- add_ident_kind_ignores(IdentKind::MapTail, IdentKind::MapTail)
- }
-
- #[test]
- fn add_fragment_to_ident_retmap_head() -> AsgResult<()> {
- add_ident_kind_ignores(IdentKind::RetMapHead, IdentKind::RetMapHead)
- }
-
- #[test]
- fn add_fragment_to_ident_retmap_tail() -> AsgResult<()> {
- add_ident_kind_ignores(IdentKind::RetMapTail, IdentKind::RetMapTail)
- }
-
- #[test]
- fn add_fragment_to_fragment_fails() -> AsgResult<()> {
- let mut sut = Sut::with_capacity(0, 0);
-
- let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
- let node = sut.declare(&sym, IdentKind::Meta, Source::default())?;
- let fragment = "orig fragment".to_string();
-
- sut.set_fragment(node, fragment.clone())?;
-
- // Since it's already a fragment, this should fail.
- let err = sut
- .set_fragment(node, "replacement".to_string())
- .expect_err("Expected failure");
-
- match err {
- AsgError::BadFragmentDest(str) if str.contains("sym") => (),
- _ => panic!("expected AsgError::BadFragmentDest: {:?}", err),
- }
-
- Ok(())
- }
+ // TODO: fragment fail
#[test]
fn add_ident_dep_to_ident() -> AsgResult<()> {
@@ -704,8 +693,8 @@ mod test {
let (symnode, depnode) = sut.add_dep_lookup(&sym, &dep);
assert!(sut.has_dep(symnode, depnode));
- assert_eq!(Some(&Object::Missing(&sym)), sut.get(symnode));
- assert_eq!(Some(&Object::Missing(&dep)), sut.get(depnode));
+ assert_eq!(Some(&sym), sut.get(symnode).unwrap().given_missing);
+ assert_eq!(Some(&dep), sut.get(depnode).unwrap().given_missing);
Ok(())
}
@@ -721,7 +710,7 @@ mod test {
let (symnode, _) = sut.add_dep_lookup(&sym, &dep);
let src = Source {
- desc: Some("Tamer is NOT lamer.".to_string()),
+ desc: Some("redeclare missing".into()),
..Default::default()
};
@@ -730,10 +719,10 @@ mod test {
assert_eq!(symnode, declared);
- assert_eq!(
- Some(&Object::Ident(&sym, IdentKind::Meta, src)),
- sut.get(declared),
- );
+ let obj = sut.get(declared).unwrap();
+
+ assert_eq!(Some(&sym), obj.given_missing);
+ assert_eq!(Some((IdentKind::Meta, src)), obj.given_redeclare);
Ok(())
}
@@ -742,13 +731,8 @@ mod test {
( $iter:expr, $s:ident ) => {{
let mut pos = 0;
for obj in $iter {
- match obj {
- Object::Ident(sym, _, _)
- | Object::IdentFragment(sym, _, _, _) => {
- assert_eq!($s.get(pos), Some(*sym));
- }
- _ => panic!("unexpected object"),
- }
+ let sym = obj.name().expect("missing object");
+ assert_eq!($s.get(pos), Some(sym));
pos = pos + 1;
}
diff --git a/tamer/src/ir/asg/graph.rs b/tamer/src/ir/asg/graph.rs
index 7aafeb6..bf7d30c 100644
--- a/tamer/src/ir/asg/graph.rs
+++ b/tamer/src/ir/asg/graph.rs
@@ -21,7 +21,7 @@
use super::ident::IdentKind;
use super::object::{
- FragmentText, ObjectData, ObjectState, Source, TransitionError,
+ FragmentText, IdentObjectData, IdentObjectState, Source, TransitionError,
};
use super::Sections;
use crate::sym::Symbol;
@@ -32,8 +32,8 @@ use std::result::Result;
///
/// This IR focuses on the definition and manipulation of objects and their
/// dependencies.
-/// See [`Object`](super::object::Object) for a summary of valid object
-/// state transitions.
+/// See [`IdentObject`](super::object::IdentObject) for a summary of valid
+/// identifier object state transitions.
///
/// Objects are never deleted from the graph,
/// so [`ObjectRef`]s will remain valid for the lifetime of the ASG.
@@ -43,7 +43,7 @@ use std::result::Result;
pub trait Asg<'i, O, Ix>
where
Ix: IndexType,
- O: ObjectState<'i, O>,
+ O: IdentObjectState<'i, O>,
{
/// Declare a concrete identifier.
///
@@ -63,7 +63,7 @@ where
/// the existing identifier will be returned.
/// For more information on state transitions that can occur when
/// redeclaring an identifier that already exists,
- /// see [`ObjectState::redeclare`].
+ /// see [`IdentObjectState::redeclare`].
///
/// A successful declaration will add an identifier to the graph
/// and return an [`ObjectRef`] reference.
@@ -91,8 +91,9 @@ where
/// on the graph will not be altered.
/// Resolution will otherwise fail in error.
///
- /// See [`ObjectState::extern_`] and [`ObjectState::redeclare`] for more
- /// information on compatibility related to extern resolution.
+ /// See [`IdentObjectState::extern_`] and
+ /// [`IdentObjectState::redeclare`] for more information on
+ /// compatibility related to extern resolution.
fn declare_extern(
&mut self,
name: &'i Symbol<'i>,
@@ -103,7 +104,7 @@ where
///
/// Fragments are intended for use by the [linker][crate::ld].
/// For more information,
- /// see [`ObjectState::set_fragment`].
+ /// see [`IdentObjectState::set_fragment`].
fn set_fragment(
&mut self,
identi: ObjectRef<Ix>,
@@ -151,7 +152,7 @@ where
/// a missing identifier will be added as a placeholder,
/// allowing the ASG to be built with partial information as
/// identifiers continue to be discovered.
- /// See [`ObjectState::missing`] for more information.
+ /// See [`IdentObjectState::missing`] for more information.
///
/// References to both identifiers are returned in argument order.
fn add_dep_lookup(
@@ -167,7 +168,7 @@ where
/// used as an `Intermediate Representation`.
pub trait SortableAsg<'i, O, Ix>
where
- O: ObjectData<'i>,
+ O: IdentObjectData<'i>,
Ix: IndexType,
{
fn sort(&'i self, roots: &[ObjectRef<Ix>]) -> AsgResult<Sections<'i, O>>;
@@ -181,7 +182,7 @@ pub type AsgResult<T> = Result<T, AsgError>;
/// Reference to an [object][super::object] stored within the [`Asg`].
///
-/// Object references are integer offsets,
+/// IdentObject references are integer offsets,
/// not pointers.
/// See the [module-level documentation][self] for more information.
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
diff --git a/tamer/src/ir/asg/ident.rs b/tamer/src/ir/asg/ident.rs
index 29eeeca..6a66316 100644
--- a/tamer/src/ir/asg/ident.rs
+++ b/tamer/src/ir/asg/ident.rs
@@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//! Identifiers (a type of [object][super::object::Object]).
+//! Identifiers (a type of [object][super::object::IdentObject]).
use crate::ir::legacyir::{SymAttrs, SymDtype, SymType};
use std::convert::TryFrom;
@@ -29,7 +29,7 @@ use std::convert::TryFrom;
///
/// These are derived from [`legacyir::SymType`][crate::ir::legacyir::SymType]
/// and will be generalized in the future.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Clone)]
pub enum IdentKind {
/// Classification generator.
///
@@ -219,6 +219,13 @@ impl<'i> TryFrom<&SymAttrs<'i>> for IdentKind {
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct Dim(u8);
+impl Dim {
+ pub fn from_u8(value: u8) -> Self {
+ // TODO: 0≤n<10
+ Self(value)
+ }
+}
+
/// Underlying datatype of identifier.
///
/// TODO: This will always be 0≤n≤9, so let's introduce a newtype for it.
@@ -249,6 +256,13 @@ mod test {
use std::convert::TryInto;
#[test]
+ fn dim_from_u8() {
+ let n = 5u8;
+
+ assert_eq!(Dim(n), Dim::from_u8(n));
+ }
+
+ #[test]
fn dim_to_str() {
// we'll just test high and low
let low: &str = Dim(0).as_ref();
diff --git a/tamer/src/ir/asg/mod.rs b/tamer/src/ir/asg/mod.rs
index 3a88be3..a547463 100644
--- a/tamer/src/ir/asg/mod.rs
+++ b/tamer/src/ir/asg/mod.rs
@@ -37,7 +37,7 @@
//!
//! Graph Structure
//! ===============
-//! Each node (vector) in the graph represents an [object][Object],
+//! Each node (vector) in the graph represents an [object][IdentObject],
//! such as an identifier or an expression.
//! Each directed edge `(A->B)` represents that `A` depends upon `B`.
//!
@@ -51,7 +51,7 @@
//! [scc]: https://en.wikipedia.org/wiki/Strongly_connected_component
//!
//! Each object may have a number of valid states;
-//! see [`Object`] for valid object states and transitions.
+//! see [`IdentObject`] for valid object states and transitions.
//!
//!
//! How To Use
@@ -61,13 +61,13 @@
//!
//! ```
//! use tamer::global;
-//! use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object, Source};
+//! use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, IdentObject, Source};
//! use tamer::sym::{Interner, DefaultInterner};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Be sure to choose size and initial capacities appropriate for your
//! // situation.
-//! let mut asg = DefaultAsg::<Object, global::PkgIdentSize>::with_capacity(
+//! let mut asg = DefaultAsg::<IdentObject, global::PkgIdentSize>::with_capacity(
//! 1024,
//! 1024,
//! );
@@ -80,7 +80,7 @@
//! let identb = asg.declare_extern(identb_sym, IdentKind::Meta)?;
//!
//! assert_eq!(
-//! Some(&Object::Extern(identb_sym, IdentKind::Meta)),
+//! Some(&IdentObject::Extern(identb_sym, IdentKind::Meta)),
//! asg.get(identb),
//! );
//!
@@ -105,16 +105,16 @@
//! it is often the case that a dependency will have to be added to the
//! graph before it is resolved.
//! For example,
-//! [`Asg::add_dep_lookup`] will add an [`Object::Missing`] to the graph
+//! [`Asg::add_dep_lookup`] will add an [`IdentObject::Missing`] to the graph
//! if either identifier has not yet been declared.
//!
//! ```
//! # use tamer::global;
-//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object, FragmentText, Source};
+//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, IdentObject, FragmentText, Source};
//! # use tamer::sym::{Interner, DefaultInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
-//! # let mut asg = DefaultAsg::<Object, global::PkgIdentSize>::with_capacity(
+//! # let mut asg = DefaultAsg::<IdentObject, global::PkgIdentSize>::with_capacity(
//! # 1024,
//! # 1024,
//! # );
@@ -124,8 +124,8 @@
//! let identb_sym = interner.intern("identb");
//! let (identa, identb) = asg.add_dep_lookup(identa_sym, identb_sym);
//!
-//! assert_eq!(Some(&Object::Missing(identa_sym)), asg.get(identa));
-//! assert_eq!(Some(&Object::Missing(identb_sym)), asg.get(identb));
+//! assert_eq!(Some(&IdentObject::Missing(identa_sym)), asg.get(identa));
+//! assert_eq!(Some(&IdentObject::Missing(identb_sym)), asg.get(identb));
//!
//! // The identifiers returned above are proper objects on the graph.
//! assert_eq!(Some(identa), asg.lookup(identa_sym));
@@ -136,7 +136,7 @@
//! asg.declare(identa_sym, IdentKind::Meta, Source::default())?;
//!
//! assert_eq!(
-//! Some(&Object::Ident(identa_sym, IdentKind::Meta, Source::default())),
+//! Some(&IdentObject::Ident(identa_sym, IdentKind::Meta, Source::default())),
//! asg.get(identa),
//! );
//!
@@ -149,18 +149,18 @@
//! Fragments
//! ---------
//! A compiled fragment can be attached to any resolved identifier (see
-//! [`Object::Ident`]) using [`Asg::set_fragment`].
-//! Doing so changes the state of the identifier to [`Object::IdentFragment`],
+//! [`IdentObject::Ident`]) using [`Asg::set_fragment`].
+//! Doing so changes the state of the identifier to [`IdentObject::IdentFragment`],
//! and it is an error to attempt to overwrite that fragment once it is
//! set.
//!
//! ```
//! # use tamer::global;
-//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object, FragmentText, Source};
+//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, IdentObject, FragmentText, Source};
//! # use tamer::sym::{Interner, DefaultInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
-//! # let mut asg = DefaultAsg::<Object, global::PkgIdentSize>::with_capacity(
+//! # let mut asg = DefaultAsg::<IdentObject, global::PkgIdentSize>::with_capacity(
//! # 1024,
//! # 1024,
//! # );
@@ -173,7 +173,7 @@
//! asg.set_fragment(ident, FragmentText::from("test fragment"))?;
//!
//! assert_eq!(
-//! Some(&Object::IdentFragment(
+//! Some(&IdentObject::IdentFragment(
//! interner.intern("ident"),
//! IdentKind::Meta,
//! Source::default(),
@@ -198,7 +198,10 @@ mod section;
pub use graph::{Asg, AsgError, AsgResult, ObjectRef, SortableAsg};
pub use ident::{Dim, IdentKind};
-pub use object::{FragmentText, Object, ObjectData, Source};
+pub use object::{
+ FragmentText, IdentObject, IdentObjectData, Source, TransitionError,
+ TransitionResult,
+};
pub use section::{Section, SectionIterator, Sections};
/// Default concrete ASG implementation.
diff --git a/tamer/src/ir/asg/object.rs b/tamer/src/ir/asg/object.rs
index acac0f2..e516cfe 100644
--- a/tamer/src/ir/asg/object.rs
+++ b/tamer/src/ir/asg/object.rs
@@ -39,8 +39,8 @@ pub type TransitionResult<T> = Result<T, (T, TransitionError)>;
/// \ / \ /
/// `--------------------` `-----------'
/// ```
-#[derive(Debug, PartialEq)]
-pub enum Object<'i> {
+#[derive(Debug, PartialEq, Clone)]
+pub enum IdentObject<'i> {
/// An identifier is expected to be defined but is not yet available.
///
/// This variant contains the symbol representing the name of the
@@ -58,7 +58,7 @@ pub enum Object<'i> {
/// An identifier that has not yet been resolved.
///
- /// Externs are upgraded to [`Object::Ident`] once an identifier of
+ /// Externs are upgraded to [`IdentObject::Ident`] once an identifier of
/// the same name is loaded.
/// It is an error if the loaded identifier does not have a compatible
/// [`IdentKind`].
@@ -74,22 +74,22 @@ pub enum Object<'i> {
IdentFragment(&'i Symbol<'i>, IdentKind, Source<'i>, FragmentText),
}
-/// Retrieve information about an [`Object`].
+/// Retrieve information about an [`IdentObject`].
///
/// APIs should adhere to this trait rather than a concrete object type such
-/// as [`Object`];
+/// as [`IdentObject`];
/// this allows other representations to be used,
-/// while still permitting the use of matching on [`Object`] through
-/// the use of [`ident`](ObjectData::ident).
+/// while still permitting the use of matching on [`IdentObject`]
+/// through the use of [`ident`](IdentObjectState::ident).
///
/// Since an object implementing this trait may not be an identifier
/// (e.g. an expression),
-/// even [`name`](ObjectData::name)---which
-/// is used by all [`Object`] variants---returns
+/// even [`name`](IdentObjectData::name)---which
+/// is used by all [`IdentObject`] variants---returns
/// an [`Option`].
/// These methods also provide a convenient alternative to `match`ing on
/// data that may not be present in all variants.
-pub trait ObjectData<'i> {
+pub trait IdentObjectData<'i> {
/// Identifier name.
///
/// If the object is not an identifier,
@@ -99,31 +99,37 @@ pub trait ObjectData<'i> {
/// Identifier [`IdentKind`].
///
/// If the object does not have a kind
- /// (as is the case with [`Object::Missing`]),
+ /// (as is the case with [`IdentObject::Missing`]),
/// [`None`] is returned.
fn kind(&self) -> Option<&IdentKind>;
/// Identifier [`Source`].
///
/// If the object does not have source information
- /// (as is the case with [`Object::Extern`]),
+ /// (as is the case with [`IdentObject::Extern`]),
/// [`None`] is returned.
fn src(&self) -> Option<&Source<'i>>;
- /// Object as an identifier ([`Object`]).
+ /// Identifier [`FragmentText`].
+ ///
+ /// If the object does not have an associated code fragment,
+ /// [`None`] is returned.
+ fn fragment(&self) -> Option<&FragmentText>;
+
+ /// IdentObject as an identifier ([`IdentObject`]).
///
/// If the object is not or cannot be faithfully converted into an
- /// [`Object`],
+ /// [`IdentObject`],
/// [`None`] is returned.
/// For example,
/// expressions will always yield [`None`].
///
- /// This allows pattern matching on [`Object`] variants regardless of
- /// the underlying object type.
- fn ident(&self) -> Option<&Object<'i>>;
+ /// This allows pattern matching on [`IdentObject`] variants regardless
+ /// of the underlying object type.
+ fn as_ident(&self) -> Option<&IdentObject<'i>>;
}
-impl<'i> ObjectData<'i> for Object<'i> {
+impl<'i> IdentObjectData<'i> for IdentObject<'i> {
fn name(&self) -> Option<&'i Symbol<'i>> {
match self {
Self::Missing(name)
@@ -151,23 +157,33 @@ impl<'i> ObjectData<'i> for Object<'i> {
}
}
- /// Expose underlying [`Object`].
+ fn fragment(&self) -> Option<&FragmentText> {
+ match self {
+ Self::Missing(_) | Self::Ident(_, _, _) | Self::Extern(_, _) => {
+ None
+ }
+ Self::IdentFragment(_, _, _, text) => Some(text),
+ }
+ }
+
+ /// Expose underlying [`IdentObject`].
///
/// This will never be [`None`] for this implementation.
/// However,
- /// other [`ObjectData`] implementations may still result in [`None`],
- /// so it's important _not_ to rely on this as an excuse to be lazy
- /// with unwrapping.
+ /// other [`IdentObjectData`] implementations may still result in
+ /// [`None`],
+ /// so it's important _not_ to rely on this as an excuse to be lazy
+ /// with unwrapping.
#[inline]
- fn ident(&self) -> Option<&Object<'i>> {
+ fn as_ident(&self) -> Option<&IdentObject<'i>> {
Some(&self)
}
}
/// Objects as a state machine.
-pub trait ObjectState<'i, T>
+pub trait IdentObjectState<'i, T>
where
- T: ObjectState<'i, T>,
+ T: IdentObjectState<'i, T>,
{
/// Produce an object representing a missing identifier.
fn missing(ident: &'i Symbol<'i>) -> T;
@@ -197,32 +213,32 @@ where
fn set_fragment(self, text: FragmentText) -> TransitionResult<T>;
}
-impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
+impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn missing(ident: &'i Symbol<'i>) -> Self {
- Object::Missing(ident)
+ IdentObject::Missing(ident)
}
fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> Self {
- Object::Ident(name, kind, src)
+ IdentObject::Ident(name, kind, src)
}
fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> Self {
- Object::Extern(name, kind)
+ IdentObject::Extern(name, kind)
}
/// Attempt to redeclare an identifier with additional information.
///
- /// If an existing identifier is an [`Object::Extern`],
+ /// If an existing identifier is an [`IdentObject::Extern`],
/// then the declaration will be compared just the same,
/// but the identifier will be converted from an extern into an
/// identifier.
/// When this happens,
/// the extern is said to be _resolved_.
///
- /// If a virtual identifier of type [`Object::IdentFragment`] is
+ /// If a virtual identifier of type [`IdentObject::IdentFragment`] is
/// overridden,
/// then its fragment is cleared
- /// (it returns to a [`Object::Ident`])
+ /// (it returns to a [`IdentObject::Ident`])
/// to make way for the fragment of the override.
///
/// The kind of identifier cannot change,
@@ -232,9 +248,9 @@ impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
mut self,
kind: IdentKind,
src: Source<'i>,
- ) -> TransitionResult<Object<'i>> {
+ ) -> TransitionResult<IdentObject<'i>> {
match self {
- Object::Ident(_, _, ref mut orig_src)
+ IdentObject::Ident(_, _, ref mut orig_src)
if orig_src.virtual_ && src.override_ =>
{
*orig_src = src;
@@ -242,15 +258,15 @@ impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
}
// TODO: no override-override
- Object::IdentFragment(name, _, orig_src, _)
+ IdentObject::IdentFragment(name, _, orig_src, _)
if orig_src.virtual_ && src.override_ =>
{
// clears fragment, which is no longer applicable
- Ok(Object::Ident(name, kind, src))
+ Ok(IdentObject::Ident(name, kind, src))
}
- Object::Missing(name) | Object::Ident(name, _, _) => {
- Ok(Object::Ident(name, kind, src))
+ IdentObject::Missing(name) | IdentObject::Ident(name, _, _) => {
+ Ok(IdentObject::Ident(name, kind, src))
}
// TODO: incompatible (check now-dangling commits)
@@ -258,19 +274,24 @@ impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
}
}
- fn set_fragment(self, text: FragmentText) -> TransitionResult<Object<'i>> {
+ fn set_fragment(
+ self,
+ text: FragmentText,
+ ) -> TransitionResult<IdentObject<'i>> {
match self {
- Object::Ident(sym, kind, src) => {
- Ok(Object::IdentFragment(sym, kind, src, text))
+ IdentObject::Ident(sym, kind, src) => {
+ Ok(IdentObject::IdentFragment(sym, kind, src, text))
}
- Object::IdentFragment(_, IdentKind::MapHead, _, _)
- | Object::IdentFragment(_, IdentKind::MapTail, _, _)
- | Object::IdentFragment(_, IdentKind::RetMapHead, _, _)
- | Object::IdentFragment(_, IdentKind::RetMapTail, _, _) => Ok(self),
+ IdentObject::IdentFragment(_, IdentKind::MapHead, _, _)
+ | IdentObject::IdentFragment(_, IdentKind::MapTail, _, _)
+ | IdentObject::IdentFragment(_, IdentKind::RetMapHead, _, _)
+ | IdentObject::IdentFragment(_, IdentKind::RetMapTail, _, _) => {
+ Ok(self)
+ }
// TODO remove these ignores when fixed
- Object::IdentFragment(
+ IdentObject::IdentFragment(
sym,
IdentKind::Map,
Source {
@@ -286,7 +307,7 @@ impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
);
Ok(self)
}
- Object::IdentFragment(
+ IdentObject::IdentFragment(
sym,
IdentKind::RetMap,
Source {
@@ -304,8 +325,10 @@ impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
}
_ => {
- let msg =
- format!("identifier is not a Object::Ident): {:?}", self,);
+ let msg = format!(
+ "identifier is not a IdentObject::Ident): {:?}",
+ self,
+ );
Err((self, TransitionError::BadFragmentDest(msg)))
}
@@ -313,7 +336,8 @@ impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
}
}
-/// An error attempting to transition from one [`Object`] state to another.
+/// An error attempting to transition from one [`IdentObject`] state to
+/// another.
///
/// TODO: Provide enough information to construct a useful message.
#[derive(Debug, PartialEq)]
@@ -322,13 +346,13 @@ pub enum TransitionError {
/// has failed because the provided information was not compatible
/// with the original declaration.
///
- /// See [`ObjectState::redeclare`].
+ /// See [`IdentObjectState::redeclare`].
Incompatible(String),
/// The provided identifier is not in a state that is permitted to
/// receive a fragment.
///
- /// See [`ObjectState::set_fragment`].
+ /// See [`IdentObjectState::set_fragment`].
BadFragmentDest(String),
}
@@ -448,9 +472,355 @@ impl<'i> From<SymAttrs<'i>> for Source<'i> {
#[cfg(test)]
mod test {
+ use super::super::ident::Dim;
use super::*;
use crate::sym::SymbolIndex;
+ mod ident_object_data {
+ use super::*;
+
+ // Note that IdentObject has no variants capable of None
+ #[test]
+ fn ident_object_name() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
+
+ assert_eq!(Some(&sym), IdentObject::Missing(&sym).name());
+
+ assert_eq!(
+ Some(&sym),
+ IdentObject::Ident(&sym, IdentKind::Meta, Source::default())
+ .name()
+ );
+
+ assert_eq!(
+ Some(&sym),
+ IdentObject::Extern(&sym, IdentKind::Meta).name()
+ );
+
+ assert_eq!(
+ Some(&sym),
+ IdentObject::IdentFragment(
+ &sym,
+ IdentKind::Meta,
+ Source::default(),
+ FragmentText::default(),
+ )
+ .name()
+ );
+ }
+
+ #[test]
+ fn ident_object_kind() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
+ let kind = IdentKind::Class(Dim::from_u8(5));
+
+ assert_eq!(None, IdentObject::Missing(&sym).kind());
+
+ assert_eq!(
+ Some(&kind),
+ IdentObject::Ident(&sym, kind.clone(), Source::default())
+ .kind()
+ );
+
+ assert_eq!(
+ Some(&kind),
+ IdentObject::Extern(&sym, kind.clone()).kind()
+ );
+
+ assert_eq!(
+ Some(&kind),
+ IdentObject::IdentFragment(
+ &sym,
+ kind.clone(),
+ Source::default(),
+ FragmentText::default()
+ )
+ .kind()
+ );
+ }
+
+ #[test]
+ fn ident_object_src() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
+ let src = Source {
+ desc: Some("test source".into()),
+ ..Default::default()
+ };
+
+ assert_eq!(None, IdentObject::Missing(&sym).src());
+
+ assert_eq!(
+ Some(&src),
+ IdentObject::Ident(&sym, IdentKind::Meta, src.clone()).src()
+ );
+
+ assert_eq!(None, IdentObject::Extern(&sym, IdentKind::Meta).src());
+
+ assert_eq!(
+ Some(&src),
+ IdentObject::IdentFragment(
+ &sym,
+ IdentKind::Meta,
+ src.clone(),
+ FragmentText::default()
+ )
+ .src()
+ );
+ }
+
+ #[test]
+ fn ident_object_fragment() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
+ let text: FragmentText = "foo".into();
+
+ assert_eq!(None, IdentObject::Missing(&sym).fragment());
+
+ assert_eq!(
+ None,
+ IdentObject::Ident(&sym, IdentKind::Meta, Source::default())
+ .fragment()
+ );
+
+ assert_eq!(
+ None,
+ IdentObject::Extern(&sym, IdentKind::Meta).fragment()
+ );
+
+ assert_eq!(
+ Some(&text),
+ IdentObject::IdentFragment(
+ &sym,
+ IdentKind::Meta,
+ Source::default(),
+ text.clone(),
+ )
+ .fragment()
+ );
+ }
+
+ #[test]
+ fn ident_object_as_ident() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
+ let ident = IdentObject::Missing(&sym);
+
+ // Since we _are_ an IdentObject, we should return a reference
+ // to ourselves. We want this, not a clone.
+ assert!(std::ptr::eq(
+ &ident as *const _,
+ ident.as_ident().unwrap() as *const _,
+ ));
+ }
+ }
+
+ mod ident_object_state {
+ use super::*;
+
+ #[test]
+ fn ident_object_missing() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "missing");
+ assert_eq!(IdentObject::Missing(&sym), IdentObject::missing(&sym));
+ }
+
+ #[test]
+ fn ident_object_ident() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "missing");
+ let kind = IdentKind::Meta;
+ let src = Source {
+ desc: Some("ident ctor".into()),
+ ..Default::default()
+ };
+
+ assert_eq!(
+ IdentObject::Ident(&sym, kind.clone(), src.clone()),
+ IdentObject::ident(&sym, kind.clone(), src.clone()),
+ );
+ }
+
+ #[test]
+ fn ident_object_extern() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "missing");
+ let kind = IdentKind::Class(Dim::from_u8(1));
+
+ assert_eq!(
+ IdentObject::Extern(&sym, kind.clone()),
+ IdentObject::extern_(&sym, kind.clone()),
+ );
+ }
+
+ // TODO: incompatible
+ #[test]
+ fn redeclare_returns_existing_compatible() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "symdup");
+
+ let first =
+ IdentObject::ident(&sym, IdentKind::Meta, Source::default());
+
+ // Same declaration a second time
+ assert_eq!(
+ Ok(first.clone()),
+ first.clone().redeclare(
+ first.kind().unwrap().clone(),
+ first.src().unwrap().clone(),
+ )
+ );
+ }
+
+ #[test]
+ fn add_fragment_to_ident() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "tofrag");
+ let src = Source {
+ generated: true,
+ ..Default::default()
+ };
+
+ let kind = IdentKind::Meta;
+ let ident = IdentObject::ident(&sym, kind.clone(), src.clone());
+ let text = FragmentText::from("a fragment");
+ let ident_with_frag = ident.set_fragment(text.clone());
+
+ assert_eq!(
+ Ok(IdentObject::IdentFragment(&sym, kind, src, text)),
+ ident_with_frag,
+ );
+ }
+
+ #[test]
+ fn add_fragment_to_fragment_fails() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "badsym");
+ let ident =
+ IdentObject::ident(&sym, IdentKind::Meta, Source::default());
+
+ let ident_with_frag = ident
+ .set_fragment("orig fragment".into())
+ .expect("set_fragment failed");
+
+ // Since it's already a fragment, this should fail.
+ let err = ident_with_frag
+ .clone()
+ .set_fragment("replacement".to_string())
+ .expect_err("Expected failure");
+
+ match err {
+ (orig, TransitionError::BadFragmentDest(str))
+ if str.contains("badsym") =>
+ {
+ assert_eq!(ident_with_frag, orig);
+ }
+ _ => panic!(
+ "expected TransitionError::BadFragmentDest: {:?}",
+ err
+ ),
+ }
+ }
+
+ // TODO: incompatible
+ #[test]
+ fn declare_override_virtual_ident() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "virtual");
+ let over_src = Symbol::new_dummy(SymbolIndex::from_u32(2), "src");
+ let kind = IdentKind::Meta;
+
+ let virt = IdentObject::ident(
+ &sym,
+ kind.clone(),
+ Source {
+ virtual_: true,
+ ..Default::default()
+ },
+ );
+
+ let over_src = Source {
+ override_: true,
+ src: Some(&over_src),
+ ..Default::default()
+ };
+
+ let result = virt.redeclare(kind.clone(), over_src.clone());
+
+ assert_eq!(Ok(IdentObject::Ident(&sym, kind, over_src)), result);
+ }
+
+ // TODO: incompatible
+ #[test]
+ fn declare_override_virtual_ident_fragment() {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "virtual");
+ let over_src = Symbol::new_dummy(SymbolIndex::from_u32(2), "src");
+ let kind = IdentKind::Meta;
+
+ let virt_src = Source {
+ virtual_: true,
+ ..Default::default()
+ };
+
+ let virt = IdentObject::ident(&sym, kind.clone(), virt_src.clone());
+ let text = FragmentText::from("remove me");
+ let virt_frag = virt.set_fragment(text.clone());
+
+ assert_eq!(
+ Ok(IdentObject::IdentFragment(
+ &sym,
+ kind.clone(),
+ virt_src,
+ text
+ )),
+ virt_frag,
+ );
+
+ let over_src = Source {
+ override_: true,
+ src: Some(&over_src),
+ ..Default::default()
+ };
+
+ let result =
+ virt_frag.unwrap().redeclare(kind.clone(), over_src.clone());
+
+ // The act of overriding the object should have cleared any
+ // existing fragment, making way for a new fragment to take its
+ // place as soon as it is discovered. (So, back to an
+ // IdentObject::Ident.)
+ assert_eq!(Ok(IdentObject::Ident(&sym, kind, over_src)), result);
+ }
+
+ fn add_ident_kind_ignores(given: IdentKind, expected: IdentKind) {
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "tofrag");
+ let src = Source {
+ generated: true,
+ ..Default::default()
+ };
+
+ let obj = IdentObject::ident(&sym, given, src.clone());
+
+ let fragment = "a fragment".to_string();
+ let obj_with_frag = obj.set_fragment(fragment.clone());
+
+ assert_eq!(
+ Ok(IdentObject::IdentFragment(&sym, expected, src, fragment)),
+ obj_with_frag,
+ );
+ }
+
+ #[test]
+ fn add_fragment_to_ident_map_head() {
+ add_ident_kind_ignores(IdentKind::MapHead, IdentKind::MapHead)
+ }
+
+ #[test]
+ fn add_fragment_to_ident_map_tail() {
+ add_ident_kind_ignores(IdentKind::MapTail, IdentKind::MapTail)
+ }
+
+ #[test]
+ fn add_fragment_to_ident_retmap_head() {
+ add_ident_kind_ignores(IdentKind::RetMapHead, IdentKind::RetMapHead)
+ }
+
+ #[test]
+ fn add_fragment_to_ident_retmap_tail() {
+ add_ident_kind_ignores(IdentKind::RetMapTail, IdentKind::RetMapTail)
+ }
+ }
+
#[test]
fn source_from_sym_attrs() {
let nsym = Symbol::new_dummy(SymbolIndex::from_u32(1), "name");
diff --git a/tamer/src/ir/asg/section.rs b/tamer/src/ir/asg/section.rs
index c4c40e3..839466e 100644
--- a/tamer/src/ir/asg/section.rs
+++ b/tamer/src/ir/asg/section.rs
@@ -49,17 +49,17 @@ impl<'a, T> Section<'a, T> {
self.len() == 0
}
- /// Push an `Object` into a `Section`'s head
+ /// Push an `IdentObject` into a `Section`'s head
pub fn push_head(&mut self, obj: &'a T) {
self.head.push(obj)
}
- /// Push an `Object` into a `Section`'s body
+ /// Push an `IdentObject` into a `Section`'s body
pub fn push_body(&mut self, obj: &'a T) {
self.body.push(obj)
}
- /// Push an `Object` into a `Section`'s tail
+ /// Push an `IdentObject` into a `Section`'s tail
pub fn push_tail(&mut self, obj: &'a T) {
self.tail.push(obj)
}
@@ -71,12 +71,12 @@ impl<'a, T> Section<'a, T> {
/// method allows us to access the iterator.
///
/// ```
- /// use tamer::ir::asg::{Object, Section};
+ /// use tamer::ir::asg::{IdentObject, Section};
/// use tamer::sym::{DefaultInterner, Interner};
///
/// let interner = DefaultInterner::new();
/// let mut section = Section::new();
- /// let obj = Object::Missing(interner.intern("ident"));
+ /// let obj = IdentObject::Missing(interner.intern("ident"));
/// let expect = vec![&obj, &obj, &obj];
///
/// section.push_head(&obj);
@@ -151,7 +151,7 @@ impl<'a, T> Sections<'a, T> {
#[cfg(test)]
mod test {
use super::*;
- use crate::ir::asg::Object;
+ use crate::ir::asg::IdentObject;
use crate::sym::{Symbol, SymbolIndex};
lazy_static! {
@@ -159,7 +159,7 @@ mod test {
Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
}
- type Sut<'a, 'i> = Section<'a, Object<'i>>;
+ type Sut<'a, 'i> = Section<'a, IdentObject<'i>>;
#[test]
fn section_empty() {
@@ -173,7 +173,7 @@ mod test {
#[test]
fn section_head() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert!(section.head.is_empty());
@@ -185,7 +185,7 @@ mod test {
#[test]
fn section_body() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert!(section.body.is_empty());
@@ -198,7 +198,7 @@ mod test {
#[test]
fn section_tail() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert!(section.tail.is_empty());
@@ -210,7 +210,7 @@ mod test {
#[test]
fn section_len() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert_eq!(0, section.len());
section.push_head(&obj);
@@ -224,7 +224,7 @@ mod test {
#[test]
fn section_is_empty_head() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert!(section.is_empty());
section.push_head(&obj);
@@ -234,7 +234,7 @@ mod test {
#[test]
fn section_is_empty_body() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert!(section.is_empty());
section.push_body(&obj);
@@ -244,7 +244,7 @@ mod test {
#[test]
fn section_is_empty_tail() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
assert!(section.is_empty());
section.push_tail(&obj);
@@ -254,7 +254,7 @@ mod test {
#[test]
fn section_iterator() {
let mut section = Sut::new();
- let obj = Object::Missing(&SYM);
+ let obj = IdentObject::Missing(&SYM);
let expect = vec![&obj, &obj, &obj];
section.push_head(&obj);
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index 7ddfc36..904d019 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -22,7 +22,7 @@
use crate::global;
use crate::ir::asg::{
- Asg, DefaultAsg, IdentKind, Object, ObjectRef, Sections, SortableAsg,
+ Asg, DefaultAsg, IdentKind, IdentObject, ObjectRef, Sections, SortableAsg,
Source,
};
use crate::obj::xmle::writer::XmleWriter;
@@ -34,7 +34,7 @@ use std::error::Error;
use std::fs;
use std::io::BufReader;
-type LinkerAsg<'i> = DefaultAsg<'i, Object<'i>, global::ProgIdentSize>;
+type LinkerAsg<'i> = DefaultAsg<'i, IdentObject<'i>, global::ProgIdentSize>;
type LinkerObjectRef = ObjectRef<global::ProgIdentSize>;
type LoadResult<'i> =
@@ -241,7 +241,7 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
fn get_ident<'a, 'i>(
depgraph: &'a LinkerAsg<'i>,
name: &'i Symbol<'i>,
-) -> Result<&'a Object<'i>, XmloError> {
+) -> Result<&'a IdentObject<'i>, XmloError> {
depgraph
.lookup(name)
.and_then(|id| depgraph.get(id))
@@ -251,7 +251,7 @@ fn get_ident<'a, 'i>(
fn output_xmle<'a, 'i, I: Interner<'i>>(
depgraph: &'a LinkerAsg<'i>,
interner: &'i I,
- sorted: &mut Sections<'a, Object<'i>>,
+ sorted: &mut Sections<'a, IdentObject<'i>>,
name: &'i Symbol<'i>,
relroot: String,
output: &str,
diff --git a/tamer/src/obj/xmle/writer/mod.rs b/tamer/src/obj/xmle/writer/mod.rs
index c3ca10b..992d3a8 100644
--- a/tamer/src/obj/xmle/writer/mod.rs
+++ b/tamer/src/obj/xmle/writer/mod.rs
@@ -1,4 +1,4 @@
-// Object file writer
+// IdentObject file writer
//
// Copyright (C) 2014-2020 Ryan Specialty Group, LLC.
//
@@ -29,14 +29,14 @@
//!
//! ```
//! use tamer::obj::xmle::writer::XmleWriter;
-//! use tamer::ir::asg::{Object, Sections};
+//! use tamer::ir::asg::{IdentObject, Sections};
//! use tamer::sym::{DefaultInterner, Interner, Symbol};
//! use std::io::Cursor;
//!
//! let interner = DefaultInterner::new();
//! let name = interner.intern(&String::from("foo"));
//!
-//! let sections = Sections::<Object>::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(""));
diff --git a/tamer/src/obj/xmle/writer/xmle.rs b/tamer/src/obj/xmle/writer/xmle.rs
index 21948b4..517abb2 100644
--- a/tamer/src/obj/xmle/writer/xmle.rs
+++ b/tamer/src/obj/xmle/writer/xmle.rs
@@ -19,7 +19,7 @@
use super::writer::{Result, WriterError};
use crate::ir::asg::{
- IdentKind, Object, ObjectData, SectionIterator, Sections,
+ IdentKind, IdentObject, IdentObjectData, SectionIterator, Sections,
};
use crate::sym::Symbol;
use fxhash::FxHashSet;
@@ -72,12 +72,12 @@ impl<W: Write> XmleWriter<W> {
/// ```
/// use std::io::Cursor;
/// use tamer::obj::xmle::writer::XmleWriter;
- /// use tamer::ir::asg::{Sections, Object};
+ /// use tamer::ir::asg::{Sections, IdentObject};
/// use tamer::sym::{Symbol, SymbolIndex, DefaultInterner, Interner};
///
/// let writer = Cursor::new(Vec::new());
/// let mut xmle_writer = XmleWriter::new(writer);
- /// let sections = Sections::<Object>::new();
+ /// let sections = Sections::<IdentObject>::new();
/// let a = "foo";
/// let interner = DefaultInterner::new();
/// let name = interner.intern(&a);
@@ -89,7 +89,7 @@ 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: ObjectData<'i>>(
+ pub fn write<'i, T: IdentObjectData<'i>>(
&mut self,
sections: &Sections<T>,
name: &Symbol,
@@ -192,7 +192,7 @@ impl<W: Write> XmleWriter<W> {
///
/// All the [`Sections`] found need to be written out using the `writer`
/// object.
- fn write_sections<'i, T: ObjectData<'i>>(
+ fn write_sections<'i, T: IdentObjectData<'i>>(
&mut self,
sections: &Sections<T>,
relroot: &str,
@@ -210,12 +210,12 @@ impl<W: Write> XmleWriter<W> {
for obj in all {
let ident = obj
- .ident()
+ .as_ident()
.expect("internal error: encountered non-identifier object");
match ident {
- Object::Ident(sym, kind, src)
- | Object::IdentFragment(sym, kind, src, _) => {
+ IdentObject::Ident(sym, kind, src)
+ | IdentObject::IdentFragment(sym, kind, src, _) => {
let name: &str = sym;
// this'll be formalized more sanely
@@ -305,7 +305,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: ObjectData<'i>>(
+ fn write_froms<'i, T: IdentObjectData<'i>>(
&mut self,
sections: &Sections<T>,
) -> Result<&mut XmleWriter<W>> {
@@ -339,26 +339,26 @@ 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: ObjectData<'i>>(
+ fn write_section<'i, T: IdentObjectData<'i>>(
&mut self,
idents: SectionIterator<T>,
) -> Result<&mut XmleWriter<W>> {
for obj in idents {
let ident = obj
- .ident()
+ .as_ident()
.expect("internal error: encountered non-identifier object");
match ident {
- Object::IdentFragment(_, _, _, frag) => {
+ IdentObject::IdentFragment(_, _, _, frag) => {
self.writer.write_event(Event::Text(
BytesText::from_plain_str(frag),
))?;
}
// Cgen, Gen, and Lparam are not expected to be present, so we
// can ignore them when we determeing when to return an Err.
- Object::Ident(_, IdentKind::Cgen(_), _)
- | Object::Ident(_, IdentKind::Gen(_, _), _)
- | Object::Ident(_, IdentKind::Lparam(_, _), _) => (),
+ IdentObject::Ident(_, IdentKind::Cgen(_), _)
+ | IdentObject::Ident(_, IdentKind::Gen(_, _), _)
+ | IdentObject::Ident(_, IdentKind::Lparam(_, _), _) => (),
obj => {
return Err(WriterError::ExpectedFragment(format!(
"fragment expected: {:?}",
@@ -509,7 +509,7 @@ mod test {
}));
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
- let obj = Object::IdentFragment(
+ let obj = IdentObject::IdentFragment(
&sym,
IdentKind::Meta,
Source::default(),
@@ -531,7 +531,7 @@ mod test {
}));
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
- let obj = Object::Ident(
+ let obj = IdentObject::Ident(
&sym,
IdentKind::Cgen(Dim::default()),
Source::default(),
@@ -552,7 +552,7 @@ mod test {
}));
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
- let obj = Object::Missing(&sym);
+ let obj = IdentObject::Missing(&sym);
let mut section = Section::new();
section.push_body(&obj);
@@ -592,7 +592,7 @@ mod test {
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "random_symbol");
let object =
- Object::Ident(&sym, IdentKind::Worksheet, Source::default());
+ IdentObject::Ident(&sym, IdentKind::Worksheet, Source::default());
let mut sections = Sections::new();
sections.map.push_body(&object);
sut.write_sections(&sections, &String::from(""))?;
@@ -662,7 +662,8 @@ mod test {
virtual_: true,
..Default::default()
};
- let object = Object::Ident(&nsym, IdentKind::Worksheet, attrs.into());
+ let object =
+ IdentObject::Ident(&nsym, IdentKind::Worksheet, attrs.into());
let mut sections = Sections::new();
sections.map.push_body(&object);
sut.write_sections(&sections, &String::from("root"))?;
@@ -696,7 +697,7 @@ mod test {
let mut src = Source::default();
src.from = Some(vec![&symb]);
- let object = Object::Ident(&sym, IdentKind::Worksheet, src);
+ let object = IdentObject::Ident(&sym, IdentKind::Worksheet, src);
let mut sections = Sections::new();
sections.map.push_body(&object);
sut.write_froms(&sections)?;
@@ -715,7 +716,7 @@ mod test {
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "random_symbol");
let object =
- Object::Ident(&sym, IdentKind::Worksheet, Source::default());
+ IdentObject::Ident(&sym, IdentKind::Worksheet, Source::default());
let mut sections = Sections::new();
sections.map.push_body(&object);
sut.write_froms(&sections)?;