[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.
master
Mike Gerwitz 2020-03-16 11:49:41 -04:00
parent 5fb68f9b67
commit f969877324
9 changed files with 671 additions and 298 deletions

View File

@ -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;
// TODO: mock Object
type Sut<'i> = BaseAsg<Object<'i>, u8>;
#[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
}
}
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())?;
let src = Source::default();
let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
// Same declaration a second time
let redeclare =
sut.declare(&sym, IdentKind::Meta, Source::default())?;
// 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())?;
// We don't care what the objects are for this test, just that the
// same node is referenced.
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 over_src = Source {
override_: true,
src: Some(&over_src),
..Default::default()
};
let over_node = sut.declare(&sym, IdentKind::Meta, over_src.clone())?;
assert_eq!(virt_node, over_node);
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)
);
let obj = sut.get(node).unwrap();
assert_eq!(Some((&sym, IdentKind::Meta, src,)), obj.given_ident);
assert_eq!(Some(fragment), obj.given_set_fragment);
Ok(())
}
fn add_ident_kind_ignores(
given: IdentKind,
expected: IdentKind,
) -> AsgResult<()> {
let mut sut = Sut::with_capacity(0, 0);
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)
);
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;
}

View File

@ -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)]

View File

@ -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.
@ -248,6 +255,13 @@ mod test {
use super::*;
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

View File

@ -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.

View File

@ -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");

View File

@ -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);

View File

@ -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,

View File

@ -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(""));

View File

@ -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)?;