Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-14 00:10:03 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-24 09:56:20 -0400
commit5fb68f9b677dff593159a9986be8da7f72b16b0d (patch)
tree070b25bc22722a7088026a5f75c14d23c4806eb0 /tamer
parentf20120787f7505d98296f933cc6dde134ca5ebba (diff)
downloadtame-5fb68f9b677dff593159a9986be8da7f72b16b0d.tar.gz
tame-5fb68f9b677dff593159a9986be8da7f72b16b0d.tar.bz2
tame-5fb68f9b677dff593159a9986be8da7f72b16b0d.zip
TAMER: Make Asg generic over object
There's a lot here to make the object stored on the `Asg` generic. This introduces `ObjectState` for state transitions and `ObjectData` for pure data retrieval. This will allow not only for mocking, but will be useful to enforce compile-time restrictions on the type of objects expected by the linker vs. the compiler (e.g. the linker will not have expressions). This commit intentionally leaves the corresponding tests in their original location to prove that the functionality has not changed; they'll be moved in a future commit. This also leaves the names as "Object" to reduce the number the cognative overhead of this commit. It will be renamed to something like "IdentObject" in the near future to clarify the intent of the current object type and to open the way for expressions and a type that marries both of them in the future. Once all of this is done, we'll finally be able to make changes to the compatibility logic in state transitions to implement extern compatibility checks during resolution. DEV-7087
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/ir/asg/base.rs57
-rw-r--r--tamer/src/ir/asg/graph.rs64
-rw-r--r--tamer/src/ir/asg/mod.rs19
-rw-r--r--tamer/src/ir/asg/object.rs168
-rw-r--r--tamer/src/ir/asg/section.rs96
-rw-r--r--tamer/src/ld/poc.rs4
-rw-r--r--tamer/src/obj/xmle/writer/mod.rs4
-rw-r--r--tamer/src/obj/xmle/writer/writer.rs4
-rw-r--r--tamer/src/obj/xmle/writer/xmle.rs53
9 files changed, 311 insertions, 158 deletions
diff --git a/tamer/src/ir/asg/base.rs b/tamer/src/ir/asg/base.rs
index e584ea1..fbcf19a 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, Object, Source};
+use super::object::{FragmentText, ObjectData, ObjectState, Source};
use super::Sections;
use crate::sym::Symbol;
use fixedbitset::FixedBitSet;
@@ -42,9 +42,12 @@ use petgraph::visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable};
///
/// For more information,
/// see [`Asg`].
-pub struct BaseAsg<'i, Ix: IndexType> {
+pub struct BaseAsg<O, Ix>
+where
+ Ix: IndexType,
+{
/// Directed graph on which objects are stored.
- graph: DiGraph<Node<'i>, AsgEdge, Ix>,
+ graph: DiGraph<Node<O>, AsgEdge, Ix>,
/// Map of [`SymbolIndex`][crate::sym::SymbolIndex] to node indexes.
///
@@ -58,9 +61,10 @@ pub struct BaseAsg<'i, Ix: IndexType> {
empty_node: NodeIndex<Ix>,
}
-impl<'i, Ix> BaseAsg<'i, Ix>
+impl<'i, O, Ix> BaseAsg<O, Ix>
where
Ix: IndexType,
+ O: ObjectState<'i, O>,
{
/// Create an ASG with the provided initial capacity.
///
@@ -121,12 +125,14 @@ where
self.index[i] = node;
}
- /// Lookup `ident` or add an [`Object::Missing`] to the graph and
- /// return a reference to it.
+ /// Lookup `ident` or add a missing identifier to the graph and return a
+ /// reference to it.
+ ///
+ /// See [`ObjectState::missing`] for more information.
#[inline]
fn lookup_or_missing(&mut self, ident: &'i Symbol<'i>) -> ObjectRef<Ix> {
self.lookup(ident).unwrap_or_else(|| {
- let index = self.graph.add_node(Some(Object::Missing(ident)));
+ let index = self.graph.add_node(Some(O::missing(ident)));
self.index_identifier(ident, index);
ObjectRef(index)
@@ -134,9 +140,10 @@ where
}
}
-impl<'i, Ix> Asg<'i, Ix> for BaseAsg<'i, Ix>
+impl<'i, O, Ix> Asg<'i, O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType,
+ O: ObjectState<'i, O>,
{
fn declare(
&mut self,
@@ -165,7 +172,7 @@ where
});
}
- let node = self.graph.add_node(Some(Object::Ident(name, kind, src)));
+ let node = self.graph.add_node(Some(O::ident(name, kind, src)));
self.index_identifier(name, node);
@@ -178,9 +185,7 @@ where
expected_kind: IdentKind,
) -> AsgResult<ObjectRef<Ix>> {
// TODO: resolution!
- let node = self
- .graph
- .add_node(Some(Object::Extern(name, expected_kind)));
+ let node = self.graph.add_node(Some(O::extern_(name, expected_kind)));
self.index_identifier(name, node);
@@ -219,7 +224,7 @@ where
}
#[inline]
- fn get<I: Into<ObjectRef<Ix>>>(&self, index: I) -> Option<&Object<'i>> {
+ fn get<I: Into<ObjectRef<Ix>>>(&self, index: I) -> Option<&O> {
self.graph.node_weight(index.into().0).map(|node| {
node.as_ref()
.expect("internal error: BaseAsg::get missing Node data")
@@ -259,12 +264,13 @@ where
}
}
-impl<'a, 'i, Ix> SortableAsg<'a, 'i, Ix> for BaseAsg<'i, Ix>
+impl<'i, O, Ix> SortableAsg<'i, O, Ix> for BaseAsg<O, Ix>
where
Ix: IndexType,
+ O: ObjectData<'i> + ObjectState<'i, O>,
{
- fn sort(&'a self, roots: &[ObjectRef<Ix>]) -> AsgResult<Sections<'a, 'i>> {
- let mut deps: Sections = Sections::new();
+ fn sort(&'i self, roots: &[ObjectRef<Ix>]) -> AsgResult<Sections<'i, O>> {
+ let mut deps = Sections::new();
// This is technically a topological sort, but functions have
// cycles. Once we have more symbol metadata, we can filter them out
@@ -278,9 +284,8 @@ where
while let Some(index) = dfs.next(&self.graph) {
let ident = self.get(index).expect("missing node");
- match ident {
- Object::Ident(_, kind, _)
- | Object::IdentFragment(_, kind, _, _) => match kind {
+ match ident.kind() {
+ Some(kind) => match kind {
IdentKind::Meta => deps.meta.push_body(ident),
IdentKind::Worksheet => deps.worksheet.push_body(ident),
IdentKind::Param(_, _) => deps.params.push_body(ident),
@@ -294,10 +299,10 @@ where
| IdentKind::RetMapTail => deps.retmap.push_body(ident),
_ => deps.rater.push_body(ident),
},
- _ => {
+ None => {
return Err(AsgError::UnexpectedNode(format!(
"{:?}",
- ident
+ ident.ident()
)))
}
}
@@ -308,7 +313,7 @@ where
}
// TODO: encapsulate Petgraph API (N.B. this is untested!)
-impl<'i, Ix> Visitable for BaseAsg<'i, Ix>
+impl<'i, O, Ix> Visitable for BaseAsg<O, Ix>
where
Ix: IndexType,
{
@@ -323,7 +328,7 @@ where
}
}
-impl<'i, Ix> GraphBase for BaseAsg<'i, Ix>
+impl<'i, O, Ix> GraphBase for BaseAsg<O, Ix>
where
Ix: IndexType,
{
@@ -331,7 +336,7 @@ where
type EdgeId = EdgeIndex<Ix>;
}
-impl<'a, 'i, Ix> IntoNeighbors for &'a BaseAsg<'i, Ix>
+impl<'a, 'i, O, Ix> IntoNeighbors for &'a BaseAsg<O, Ix>
where
Ix: IndexType,
{
@@ -346,9 +351,11 @@ where
mod test {
use super::super::graph::AsgError;
use super::*;
+ use crate::ir::asg::Object;
use crate::sym::SymbolIndex;
- type Sut<'i> = BaseAsg<'i, u8>;
+ // TODO: mock Object
+ type Sut<'i> = BaseAsg<Object<'i>, u8>;
#[test]
fn create_with_capacity() {
diff --git a/tamer/src/ir/asg/graph.rs b/tamer/src/ir/asg/graph.rs
index 58b5f91..7aafeb6 100644
--- a/tamer/src/ir/asg/graph.rs
+++ b/tamer/src/ir/asg/graph.rs
@@ -20,24 +20,31 @@
//! Abstract graph as the basis for concrete ASGs.
use super::ident::IdentKind;
-use super::object::{FragmentText, Object, Source, TransitionError};
+use super::object::{
+ FragmentText, ObjectData, ObjectState, Source, TransitionError,
+};
use super::Sections;
use crate::sym::Symbol;
use petgraph::graph::{IndexType, NodeIndex};
use std::result::Result;
-/// An abstract semantic graph of [objects][Object].
+/// An abstract semantic graph of [objects][super::object].
///
/// This IR focuses on the definition and manipulation of objects and their
/// dependencies.
-/// See [`Object`] for a summary of valid object state transitions.
+/// See [`Object`](super::object::Object) for a summary of valid object
+/// state transitions.
///
/// Objects are never deleted from the graph,
/// so [`ObjectRef`]s will remain valid for the lifetime of the ASG.
///
/// For more information,
/// see the [module-level documentation][self].
-pub trait Asg<'i, Ix: IndexType> {
+pub trait Asg<'i, O, Ix>
+where
+ Ix: IndexType,
+ O: ObjectState<'i, O>,
+{
/// Declare a concrete identifier.
///
/// An identifier declaration is similar to a declaration in a header
@@ -54,22 +61,12 @@ pub trait Asg<'i, Ix: IndexType> {
/// then the operation will fail;
/// otherwise,
/// the existing identifier will be returned.
- /// A successful declaration will add a [`Object::Ident`] to the graph
- /// and return an [`ObjectRef`] reference.
- ///
- /// If an existing identifier is an extern (see
- /// [`Asg::declare_extern`]),
- /// then the declaration will be compared just the same,
- /// but the identifier will be converted from a
- /// [`Object::Extern`] into a [`Object::Ident`].
- /// When this happens,
- /// the extern is said to be _resolved_.
+ /// For more information on state transitions that can occur when
+ /// redeclaring an identifier that already exists,
+ /// see [`ObjectState::redeclare`].
///
- /// If a virtual identifier of type [`Object::IdentFragment`] is
- /// overridden,
- /// then its fragment is cleared
- /// (it returns to a [`Object::Ident`])
- /// to make way for the fragment of the override.
+ /// A successful declaration will add an identifier to the graph
+ /// and return an [`ObjectRef`] reference.
fn declare(
&mut self,
name: &'i Symbol<'i>,
@@ -81,7 +78,7 @@ pub trait Asg<'i, Ix: IndexType> {
///
/// An _extern_ declaration declares an identifier the same as
/// [`Asg::declare`],
- /// but instead as [`Object::Extern`].
+ /// but omits source information.
/// Externs are identifiers that are expected to be defined somewhere
/// else ("externally"),
/// and are resolved at [link-time][crate::ld].
@@ -93,6 +90,9 @@ pub trait Asg<'i, Ix: IndexType> {
/// the identifier will be immediately _resolved_ and the object
/// 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.
fn declare_extern(
&mut self,
name: &'i Symbol<'i>,
@@ -101,9 +101,9 @@ pub trait Asg<'i, Ix: IndexType> {
/// Set the fragment associated with a concrete identifier.
///
- /// This changes the type of the identifier from [`Object::Ident`]
- /// into [`Object::IdentFragment`],
- /// which is intended for use by the [linker][crate::ld].
+ /// Fragments are intended for use by the [linker][crate::ld].
+ /// For more information,
+ /// see [`ObjectState::set_fragment`].
fn set_fragment(
&mut self,
identi: ObjectRef<Ix>,
@@ -117,7 +117,7 @@ pub trait Asg<'i, Ix: IndexType> {
/// this should never fail so long as references are not shared
/// between multiple graphs.
/// It is nevertheless wrapped in an [`Option`] just in case.
- fn get<I: Into<ObjectRef<Ix>>>(&self, index: I) -> Option<&Object<'i>>;
+ fn get<I: Into<ObjectRef<Ix>>>(&self, index: I) -> Option<&O>;
/// Attempt to retrieve an identifier from the graph by name.
///
@@ -148,10 +148,10 @@ pub trait Asg<'i, Ix: IndexType> {
/// this method will add the dependency even if one or both of `ident`
/// or `dep` have not yet been declared.
/// In such a case,
- /// an [`Object::Missing`] will be added as a placeholder for the
- /// missing identifier,
+ /// 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.
///
/// References to both identifiers are returned in argument order.
fn add_dep_lookup(
@@ -165,8 +165,12 @@ pub trait Asg<'i, Ix: IndexType> {
///
/// Allow a graph to be partitioned into different [`Sections`] that can be
/// used as an `Intermediate Representation`.
-pub trait SortableAsg<'a, 'i, Ix: IndexType> {
- fn sort(&'a self, roots: &[ObjectRef<Ix>]) -> AsgResult<Sections<'a, 'i>>;
+pub trait SortableAsg<'i, O, Ix>
+where
+ O: ObjectData<'i>,
+ Ix: IndexType,
+{
+ fn sort(&'i self, roots: &[ObjectRef<Ix>]) -> AsgResult<Sections<'i, O>>;
}
/// A [`Result`] with a hard-coded [`AsgError`] error type.
@@ -175,7 +179,7 @@ pub trait SortableAsg<'a, 'i, Ix: IndexType> {
/// fail in error.
pub type AsgResult<T> = Result<T, AsgError>;
-/// Reference to an [object][Object] stored within the [`Asg`].
+/// Reference to an [object][super::object] stored within the [`Asg`].
///
/// Object references are integer offsets,
/// not pointers.
@@ -208,7 +212,7 @@ pub type AsgEdge = ();
///
/// Enclosed in an [`Option`] to permit moving owned values out of the
/// graph.
-pub type Node<'i> = Option<Object<'i>>;
+pub type Node<O> = Option<O>;
/// An error from an ASG operation.
///
diff --git a/tamer/src/ir/asg/mod.rs b/tamer/src/ir/asg/mod.rs
index 3f38fa2..3a88be3 100644
--- a/tamer/src/ir/asg/mod.rs
+++ b/tamer/src/ir/asg/mod.rs
@@ -67,7 +67,10 @@
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Be sure to choose size and initial capacities appropriate for your
//! // situation.
-//! let mut asg = DefaultAsg::<global::PkgIdentSize>::with_capacity(1024, 1024);
+//! let mut asg = DefaultAsg::<Object, global::PkgIdentSize>::with_capacity(
+//! 1024,
+//! 1024,
+//! );
//!
//! let interner = DefaultInterner::new();
//! let identa_sym = interner.intern("identa");
@@ -111,7 +114,10 @@
//! # use tamer::sym::{Interner, DefaultInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
-//! # let mut asg = DefaultAsg::<global::PkgIdentSize>::with_capacity(1024, 1024);
+//! # let mut asg = DefaultAsg::<Object, global::PkgIdentSize>::with_capacity(
+//! # 1024,
+//! # 1024,
+//! # );
//! # let interner = DefaultInterner::new();
//! #
//! let identa_sym = interner.intern("identa");
@@ -154,7 +160,10 @@
//! # use tamer::sym::{Interner, DefaultInterner};
//! #
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
-//! # let mut asg = DefaultAsg::<global::PkgIdentSize>::with_capacity(1024, 1024);
+//! # let mut asg = DefaultAsg::<Object, global::PkgIdentSize>::with_capacity(
+//! # 1024,
+//! # 1024,
+//! # );
//! # let interner = DefaultInterner::new();
//! #
//! // Fragments can be attached to resolved identifiers.
@@ -189,8 +198,8 @@ mod section;
pub use graph::{Asg, AsgError, AsgResult, ObjectRef, SortableAsg};
pub use ident::{Dim, IdentKind};
-pub use object::{FragmentText, Object, Source};
+pub use object::{FragmentText, Object, ObjectData, Source};
pub use section::{Section, SectionIterator, Sections};
/// Default concrete ASG implementation.
-pub type DefaultAsg<'i, Ix> = base::BaseAsg<'i, Ix>;
+pub type DefaultAsg<'i, O, Ix> = base::BaseAsg<O, Ix>;
diff --git a/tamer/src/ir/asg/object.rs b/tamer/src/ir/asg/object.rs
index 8155e86..acac0f2 100644
--- a/tamer/src/ir/asg/object.rs
+++ b/tamer/src/ir/asg/object.rs
@@ -27,8 +27,7 @@ use crate::ir::legacyir::SymAttrs;
use crate::sym::Symbol;
use std::result::Result;
-pub type TransitionResult<'i> =
- Result<Object<'i>, (Object<'i>, TransitionError)>;
+pub type TransitionResult<T> = Result<T, (T, TransitionError)>;
/// Type of object.
///
@@ -75,19 +74,165 @@ pub enum Object<'i> {
IdentFragment(&'i Symbol<'i>, IdentKind, Source<'i>, FragmentText),
}
-impl<'i> Object<'i> {
+/// Retrieve information about an [`Object`].
+///
+/// APIs should adhere to this trait rather than a concrete object type such
+/// as [`Object`];
+/// this allows other representations to be used,
+/// while still permitting the use of matching on [`Object`] through
+/// the use of [`ident`](ObjectData::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
+/// 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> {
+ /// Identifier name.
+ ///
+ /// If the object is not an identifier,
+ /// [`None`] is returned.
+ fn name(&self) -> Option<&'i Symbol<'i>>;
+
+ /// Identifier [`IdentKind`].
+ ///
+ /// If the object does not have a kind
+ /// (as is the case with [`Object::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`]),
+ /// [`None`] is returned.
+ fn src(&self) -> Option<&Source<'i>>;
+
+ /// Object as an identifier ([`Object`]).
+ ///
+ /// If the object is not or cannot be faithfully converted into an
+ /// [`Object`],
+ /// [`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>>;
+}
+
+impl<'i> ObjectData<'i> for Object<'i> {
+ fn name(&self) -> Option<&'i Symbol<'i>> {
+ match self {
+ Self::Missing(name)
+ | Self::Ident(name, _, _)
+ | Self::Extern(name, _)
+ | Self::IdentFragment(name, _, _, _) => Some(name),
+ }
+ }
+
+ fn kind(&self) -> Option<&IdentKind> {
+ match self {
+ Self::Missing(_) => None,
+ Self::Ident(_, kind, _)
+ | Self::Extern(_, kind)
+ | Self::IdentFragment(_, kind, _, _) => Some(kind),
+ }
+ }
+
+ fn src(&self) -> Option<&Source<'i>> {
+ match self {
+ Self::Missing(_) | Self::Extern(_, _) => None,
+ Self::Ident(_, _, src) | Self::IdentFragment(_, _, src, _) => {
+ Some(src)
+ }
+ }
+ }
+
+ /// Expose underlying [`Object`].
+ ///
+ /// 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.
+ #[inline]
+ fn ident(&self) -> Option<&Object<'i>> {
+ Some(&self)
+ }
+}
+
+/// Objects as a state machine.
+pub trait ObjectState<'i, T>
+where
+ T: ObjectState<'i, T>,
+{
+ /// Produce an object representing a missing identifier.
+ fn missing(ident: &'i Symbol<'i>) -> T;
+
+ /// Produce an object representing a concrete identifier.
+ fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> T;
+
+ /// Produce an object representing an extern.
+ fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> T;
+
+ /// Attempt to redeclare an identifier with additional information.
+ ///
+ /// For specific information on compatibility rules,
+ /// see implementers of this trait,
+ /// since rules may vary between implementations.
+ fn redeclare(self, kind: IdentKind, src: Source<'i>)
+ -> TransitionResult<T>;
+
+ /// Attach a code fragment (compiled text) to an identifier.
+ ///
+ /// This will fail if an identifier already has a fragment,
+ /// since only the owner of the identifier should be producing
+ /// compiled code.
+ /// Note, however, that an identifier's fragment may be cleared under
+ /// certain circumstances (such as symbol overrides),
+ /// making way for a new fragment to be set.
+ fn set_fragment(self, text: FragmentText) -> TransitionResult<T>;
+}
+
+impl<'i> ObjectState<'i, Object<'i>> for Object<'i> {
+ fn missing(ident: &'i Symbol<'i>) -> Self {
+ Object::Missing(ident)
+ }
+
+ fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> Self {
+ Object::Ident(name, kind, src)
+ }
+
+ fn extern_(name: &'i Symbol<'i>, kind: IdentKind) -> Self {
+ Object::Extern(name, kind)
+ }
+
/// Attempt to redeclare an identifier with additional information.
///
- /// _TODO: Compatibility information._
+ /// If an existing identifier is an [`Object::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_.
///
- /// The kind if identifier cannot change,
+ /// If a virtual identifier of type [`Object::IdentFragment`] is
+ /// overridden,
+ /// then its fragment is cleared
+ /// (it returns to a [`Object::Ident`])
+ /// to make way for the fragment of the override.
+ ///
+ /// The kind of identifier cannot change,
/// but the argument is provided here for convenience so that the
/// caller does not need to perform such a check itself.
- pub fn redeclare(
+ fn redeclare(
mut self,
kind: IdentKind,
src: Source<'i>,
- ) -> TransitionResult<'i> {
+ ) -> TransitionResult<Object<'i>> {
match self {
Object::Ident(_, _, ref mut orig_src)
if orig_src.virtual_ && src.override_ =>
@@ -113,10 +258,7 @@ impl<'i> Object<'i> {
}
}
- /// Attach a code fragment (compiled text) to an identifier.
- ///
- /// Only [`Object::Ident`] may receive a fragment.
- pub fn set_fragment(self, text: FragmentText) -> TransitionResult<'i> {
+ fn set_fragment(self, text: FragmentText) -> TransitionResult<Object<'i>> {
match self {
Object::Ident(sym, kind, src) => {
Ok(Object::IdentFragment(sym, kind, src, text))
@@ -180,13 +322,13 @@ pub enum TransitionError {
/// has failed because the provided information was not compatible
/// with the original declaration.
///
- /// See [`Object::redeclare`].
+ /// See [`ObjectState::redeclare`].
Incompatible(String),
/// The provided identifier is not in a state that is permitted to
/// receive a fragment.
///
- /// See [`Object::set_fragment`].
+ /// See [`ObjectState::set_fragment`].
BadFragmentDest(String),
}
diff --git a/tamer/src/ir/asg/section.rs b/tamer/src/ir/asg/section.rs
index 9ebaf9f..c4c40e3 100644
--- a/tamer/src/ir/asg/section.rs
+++ b/tamer/src/ir/asg/section.rs
@@ -17,31 +17,20 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-use crate::ir::asg::Object;
-
-type ObjectRef<'a, 'i> = &'a Object<'i>;
-pub type ObjectVec<'a, 'i> = Vec<ObjectRef<'a, 'i>>;
-
-/// A Section that needs to be written to the buffer
+/// A section of an [object file](crate::obj).
///
/// Most sections will only need a `body`, but some innlude `head` and `tail`
/// information. Rather than dealing with those differently, each `Section`
/// will have a `head` and `tail` that are empty by default.
#[derive(Clone, Debug, Default, PartialEq)]
-pub struct Section<'a, 'i> {
- head: ObjectVec<'a, 'i>,
- body: ObjectVec<'a, 'i>,
- tail: ObjectVec<'a, 'i>,
+pub struct Section<'a, T> {
+ head: Vec<&'a T>,
+ body: Vec<&'a T>,
+ tail: Vec<&'a T>,
}
-impl<'a, 'i> Section<'a, 'i> {
- /// Constructor for Sections
- ///
- /// ```
- /// use tamer::ir::asg::Section;
- ///
- /// let section = Section::new();
- /// ```
+impl<'a, T> Section<'a, T> {
+ /// New empty section.
pub fn new() -> Self {
Self {
head: Vec::new(),
@@ -61,18 +50,18 @@ impl<'a, 'i> Section<'a, 'i> {
}
/// Push an `Object` into a `Section`'s head
- pub fn push_head(&mut self, obj: ObjectRef<'a, 'i>) {
- self.head.push(&obj)
+ pub fn push_head(&mut self, obj: &'a T) {
+ self.head.push(obj)
}
/// Push an `Object` into a `Section`'s body
- pub fn push_body(&mut self, obj: ObjectRef<'a, 'i>) {
- self.body.push(&obj)
+ pub fn push_body(&mut self, obj: &'a T) {
+ self.body.push(obj)
}
/// Push an `Object` into a `Section`'s tail
- pub fn push_tail(&mut self, obj: ObjectRef<'a, 'i>) {
- self.tail.push(&obj)
+ pub fn push_tail(&mut self, obj: &'a T) {
+ self.tail.push(obj)
}
/// Merge the parts of a `Section` into one [`SectionIterator`]
@@ -99,7 +88,7 @@ impl<'a, 'i> Section<'a, 'i> {
/// assert_eq!(&obj, object);
/// }
/// ```
- pub fn iter(&self) -> SectionIterator {
+ pub fn iter(&self) -> SectionIterator<T> {
SectionIterator {
inner: Box::new(
self.head
@@ -115,12 +104,12 @@ impl<'a, 'i> Section<'a, 'i> {
/// Wrapper for an Iterator
///
/// This allows us to iterate over all parts of a [`Section`].
-pub struct SectionIterator<'a, 'i> {
- inner: Box<dyn Iterator<Item = &'a Object<'i>> + 'a>,
+pub struct SectionIterator<'a, T> {
+ inner: Box<dyn Iterator<Item = &'a T> + 'a>,
}
-impl<'a, 'i> Iterator for SectionIterator<'a, 'i> {
- type Item = &'a Object<'i>;
+impl<'a, T> Iterator for SectionIterator<'a, T> {
+ type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
@@ -132,25 +121,19 @@ impl<'a, 'i> Iterator for SectionIterator<'a, 'i> {
/// All the properties are public [`Section`] objects and will be accessed
/// directly by the the objects interacting with them.
#[derive(Debug, Default, PartialEq)]
-pub struct Sections<'a, 'i> {
- pub map: Section<'a, 'i>,
- pub retmap: Section<'a, 'i>,
- pub meta: Section<'a, 'i>,
- pub worksheet: Section<'a, 'i>,
- pub params: Section<'a, 'i>,
- pub types: Section<'a, 'i>,
- pub funcs: Section<'a, 'i>,
- pub rater: Section<'a, 'i>,
+pub struct Sections<'a, T> {
+ pub map: Section<'a, T>,
+ pub retmap: Section<'a, T>,
+ pub meta: Section<'a, T>,
+ pub worksheet: Section<'a, T>,
+ pub params: Section<'a, T>,
+ pub types: Section<'a, T>,
+ pub funcs: Section<'a, T>,
+ pub rater: Section<'a, T>,
}
-impl<'a, 'i> Sections<'a, 'i> {
- /// Constructor for Sections
- ///
- /// ```
- /// use tamer::ir::asg::Sections;
- ///
- /// let sections = Sections::new();
- /// ```
+impl<'a, T> Sections<'a, T> {
+ /// New collection of empty sections.
pub fn new() -> Self {
Self {
map: Section::new(),
@@ -168,6 +151,7 @@ impl<'a, 'i> Sections<'a, 'i> {
#[cfg(test)]
mod test {
use super::*;
+ use crate::ir::asg::Object;
use crate::sym::{Symbol, SymbolIndex};
lazy_static! {
@@ -175,9 +159,11 @@ mod test {
Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
}
+ type Sut<'a, 'i> = Section<'a, Object<'i>>;
+
#[test]
fn section_empty() {
- let section = Section::new();
+ let section = Sut::new();
assert!(section.head.is_empty());
assert!(section.body.is_empty());
@@ -186,7 +172,7 @@ mod test {
#[test]
fn section_head() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert!(section.head.is_empty());
@@ -198,7 +184,7 @@ mod test {
#[test]
fn section_body() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert!(section.body.is_empty());
@@ -211,7 +197,7 @@ mod test {
#[test]
fn section_tail() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert!(section.tail.is_empty());
@@ -223,7 +209,7 @@ mod test {
#[test]
fn section_len() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert_eq!(0, section.len());
@@ -237,7 +223,7 @@ mod test {
#[test]
fn section_is_empty_head() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert!(section.is_empty());
@@ -247,7 +233,7 @@ mod test {
#[test]
fn section_is_empty_body() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert!(section.is_empty());
@@ -257,7 +243,7 @@ mod test {
#[test]
fn section_is_empty_tail() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
assert!(section.is_empty());
@@ -267,7 +253,7 @@ mod test {
#[test]
fn section_iterator() {
- let mut section = Section::new();
+ let mut section = Sut::new();
let obj = Object::Missing(&SYM);
let expect = vec![&obj, &obj, &obj];
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index def7730..7ddfc36 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -34,8 +34,8 @@ use std::error::Error;
use std::fs;
use std::io::BufReader;
+type LinkerAsg<'i> = DefaultAsg<'i, Object<'i>, global::ProgIdentSize>;
type LinkerObjectRef = ObjectRef<global::ProgIdentSize>;
-type LinkerAsg<'i> = DefaultAsg<'i, global::ProgIdentSize>;
type LoadResult<'i> =
Result<Option<(Option<&'i Symbol<'i>>, Option<String>)>, Box<dyn Error>>;
@@ -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, 'i>,
+ sorted: &mut Sections<'a, Object<'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 43cc939..c3ca10b 100644
--- a/tamer/src/obj/xmle/writer/mod.rs
+++ b/tamer/src/obj/xmle/writer/mod.rs
@@ -29,14 +29,14 @@
//!
//! ```
//! use tamer::obj::xmle::writer::XmleWriter;
-//! use tamer::ir::asg::Sections;
+//! use tamer::ir::asg::{Object, 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::new();
+//! let sections = Sections::<Object>::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/writer.rs b/tamer/src/obj/xmle/writer/writer.rs
index 2e4c167..a1c4d05 100644
--- a/tamer/src/obj/xmle/writer/writer.rs
+++ b/tamer/src/obj/xmle/writer/writer.rs
@@ -30,9 +30,9 @@ pub type Result<T = ()> = result::Result<T, WriterError>;
///
/// This is used to take the [`Sections`] and write out the xmle files.
pub trait Writer<W: Write> {
- fn write(
+ fn write<T>(
&mut self,
- sections: &Sections,
+ sections: &Sections<T>,
name: Symbol,
relroot: &str,
) -> Result<()>
diff --git a/tamer/src/obj/xmle/writer/xmle.rs b/tamer/src/obj/xmle/writer/xmle.rs
index 2888d28..21948b4 100644
--- a/tamer/src/obj/xmle/writer/xmle.rs
+++ b/tamer/src/obj/xmle/writer/xmle.rs
@@ -18,7 +18,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use super::writer::{Result, WriterError};
-use crate::ir::asg::{IdentKind, Object, SectionIterator, Sections};
+use crate::ir::asg::{
+ IdentKind, Object, ObjectData, SectionIterator, Sections,
+};
use crate::sym::Symbol;
use fxhash::FxHashSet;
#[cfg(test)]
@@ -70,13 +72,12 @@ impl<W: Write> XmleWriter<W> {
/// ```
/// use std::io::Cursor;
/// use tamer::obj::xmle::writer::XmleWriter;
- /// use tamer::ir::asg::Sections;
- /// use tamer::sym::{Symbol, SymbolIndex};
- /// use tamer::sym::{DefaultInterner, Interner};
+ /// use tamer::ir::asg::{Sections, Object};
+ /// use tamer::sym::{Symbol, SymbolIndex, DefaultInterner, Interner};
///
/// let writer = Cursor::new(Vec::new());
/// let mut xmle_writer = XmleWriter::new(writer);
- /// let sections = Sections::new();
+ /// let sections = Sections::<Object>::new();
/// let a = "foo";
/// let interner = DefaultInterner::new();
/// let name = interner.intern(&a);
@@ -88,9 +89,9 @@ 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(
+ pub fn write<'i, T: ObjectData<'i>>(
&mut self,
- sections: &Sections,
+ sections: &Sections<T>,
name: &Symbol,
relroot: &str,
) -> Result {
@@ -191,9 +192,9 @@ impl<W: Write> XmleWriter<W> {
///
/// All the [`Sections`] found need to be written out using the `writer`
/// object.
- fn write_sections(
+ fn write_sections<'i, T: ObjectData<'i>>(
&mut self,
- sections: &Sections,
+ sections: &Sections<T>,
relroot: &str,
) -> Result<&mut XmleWriter<W>> {
let all = sections
@@ -207,7 +208,11 @@ impl<W: Write> XmleWriter<W> {
.chain(sections.funcs.iter())
.chain(sections.rater.iter());
- for ident in all {
+ for obj in all {
+ let ident = obj
+ .ident()
+ .expect("internal error: encountered non-identifier object");
+
match ident {
Object::Ident(sym, kind, src)
| Object::IdentFragment(sym, kind, src, _) => {
@@ -300,25 +305,21 @@ 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(
+ fn write_froms<'i, T: ObjectData<'i>>(
&mut self,
- sections: &Sections,
+ sections: &Sections<T>,
) -> Result<&mut XmleWriter<W>> {
let mut map_froms: FxHashSet<&str> = Default::default();
let map_iter = sections.map.iter();
for map_ident in map_iter {
- match map_ident {
- Object::Ident(_, _, src)
- | Object::IdentFragment(_, _, src, _) => {
- if let Some(froms) = &src.from {
- for from in froms {
- map_froms.insert(from);
- }
- }
+ let src = map_ident.src().expect("internal error: missing map src");
+
+ if let Some(froms) = &src.from {
+ for from in froms {
+ map_froms.insert(from);
}
- _ => unreachable!("filtered out during sorting"),
}
}
@@ -338,11 +339,15 @@ impl<W: Write> XmleWriter<W> {
///
/// Iterates through the parts of a `Section` and writes them using the
/// `writer`'s 'write_event`.
- fn write_section(
+ fn write_section<'i, T: ObjectData<'i>>(
&mut self,
- idents: SectionIterator,
+ idents: SectionIterator<T>,
) -> Result<&mut XmleWriter<W>> {
- for ident in idents {
+ for obj in idents {
+ let ident = obj
+ .ident()
+ .expect("internal error: encountered non-identifier object");
+
match ident {
Object::IdentFragment(_, _, _, frag) => {
self.writer.write_event(Event::Text(