Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer/src
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-12 10:02:22 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-19 15:42:06 -0400
commitf20120787f7505d98296f933cc6dde134ca5ebba (patch)
tree05d83a0a9b27d3a58b9734e001d36988969a004b /tamer/src
parent3fe3fc4b84608045cc55fc350ede38c9b760ca04 (diff)
downloadtame-f20120787f7505d98296f933cc6dde134ca5ebba.tar.gz
tame-f20120787f7505d98296f933cc6dde134ca5ebba.tar.bz2
tame-f20120787f7505d98296f933cc6dde134ca5ebba.zip
TAMER: Extract identifier transitions into Object
The next commit will generalize this further. This moves logic out of BaseAsg so that we can implement more sophisticated transitions for compatability checks. The logic is still tested as part of BaseAsg; the next commit will change that as it's generalized further. * tamer/src/ir/asg/base.rs: Extract object transitions. * tamer/src/ir/asg/graph.rs (AsgError)[IncompatibleIdent]: New variant. (From<TransitionError> for AsgError): Basic type translation. * tamer/src/ir/asg/object.rs (TransitionResult): New type. (impl Object): Transition methods. (TransitionError): New enum.
Diffstat (limited to 'tamer/src')
-rw-r--r--tamer/src/ir/asg/base.rs103
-rw-r--r--tamer/src/ir/asg/graph.rs22
-rw-r--r--tamer/src/ir/asg/object.rs133
3 files changed, 183 insertions, 75 deletions
diff --git a/tamer/src/ir/asg/base.rs b/tamer/src/ir/asg/base.rs
index 387fdfe..e584ea1 100644
--- a/tamer/src/ir/asg/base.rs
+++ b/tamer/src/ir/asg/base.rs
@@ -144,32 +144,25 @@ where
kind: IdentKind,
src: Source<'i>,
) -> AsgResult<ObjectRef<Ix>> {
- // TODO: src check
if let Some(existing) = self.lookup(name) {
let node = self.graph.node_weight_mut(existing.0).unwrap();
- match node {
- Some(Object::Missing(_)) => {
- node.replace(Object::Ident(name, kind, src));
- return Ok(existing);
- }
- // TODO: no override-override
- Some(Object::Ident(_, _, orig_src))
- if orig_src.virtual_ && src.override_ =>
- {
- *orig_src = src;
- return Ok(existing);
- }
- // TODO: no override-override
- Some(Object::IdentFragment(_, _, orig_src, _))
- if orig_src.virtual_ && src.override_ =>
- {
- // clears fragment, which is no longer applicable
- node.replace(Object::Ident(name, kind, src));
- return Ok(existing);
- }
- _ => return Ok(existing),
- }
+ let obj = node.take().expect(&format!(
+ "internal error: missing object for {}",
+ name
+ ));
+
+ // TODO: test inconsistent state (fixed)
+ return obj
+ .redeclare(kind, src)
+ .and_then(|obj| {
+ node.replace(obj);
+ Ok(existing)
+ })
+ .or_else(|(orig, err)| {
+ node.replace(orig);
+ Err(err.into())
+ });
}
let node = self.graph.add_node(Some(Object::Ident(name, kind, src)));
@@ -212,56 +205,17 @@ where
.take()
.expect("internal error: BaseAsg::set_fragment missing Node data");
- let result = match ty {
- Object::Ident(sym, kind, src) => {
- Ok(Object::IdentFragment(sym, kind, src, text))
- }
- Object::IdentFragment(_, IdentKind::MapHead, _, _) => Ok(ty),
- Object::IdentFragment(_, IdentKind::MapTail, _, _) => Ok(ty),
- Object::IdentFragment(_, IdentKind::RetMapHead, _, _) => Ok(ty),
- Object::IdentFragment(_, IdentKind::RetMapTail, _, _) => Ok(ty),
- // TODO remove these ignores when fixed
- Object::IdentFragment(
- sym,
- IdentKind::Map,
- Source {
- virtual_: true,
- override_: true,
- ..
- },
- _,
- ) => {
- eprintln!(
- "ignoring virtual and overridden map object: {}",
- sym
- );
- Ok(ty)
- }
- Object::IdentFragment(
- sym,
- IdentKind::RetMap,
- Source {
- virtual_: true,
- override_: true,
- ..
- },
- _,
- ) => {
- eprintln!(
- "ignoring virtual and overridden retmap object: {}",
- sym
- );
- Ok(ty)
- }
- _ => Err(AsgError::BadFragmentDest(format!(
- "identifier is not a Object::Ident): {:?}",
- ty,
- ))),
- }?;
-
- node.replace(result);
-
- Ok(identi)
+ // Be sure to restore the previous node if the transition fails,
+ // otherwise we'll be left in an inconsistent internal state.
+ ty.set_fragment(text)
+ .and_then(|obj| {
+ node.replace(obj);
+ Ok(identi)
+ })
+ .or_else(|(orig, err)| {
+ node.replace(orig);
+ Err(err.into())
+ })
}
#[inline]
@@ -390,6 +344,7 @@ where
#[cfg(test)]
mod test {
+ use super::super::graph::AsgError;
use super::*;
use crate::sym::SymbolIndex;
@@ -699,7 +654,7 @@ mod test {
let mut sut = Sut::with_capacity(0, 0);
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
- let dep = Symbol::new_dummy(SymbolIndex::from_u32(1), "dep");
+ let dep = Symbol::new_dummy(SymbolIndex::from_u32(2), "dep");
let symnode = sut.declare(&sym, IdentKind::Meta, Source::default())?;
let depnode = sut.declare(&dep, IdentKind::Meta, Source::default())?;
diff --git a/tamer/src/ir/asg/graph.rs b/tamer/src/ir/asg/graph.rs
index 75d041c..58b5f91 100644
--- a/tamer/src/ir/asg/graph.rs
+++ b/tamer/src/ir/asg/graph.rs
@@ -20,7 +20,7 @@
//! Abstract graph as the basis for concrete ASGs.
use super::ident::IdentKind;
-use super::object::{FragmentText, Object, Source};
+use super::object::{FragmentText, Object, Source, TransitionError};
use super::Sections;
use crate::sym::Symbol;
use petgraph::graph::{IndexType, NodeIndex};
@@ -223,6 +223,14 @@ pub enum AsgError {
///
/// See [`Asg::set_fragment`] for more information.
BadFragmentDest(String),
+
+ /// An attempt to redeclare an identifier with additional information
+ /// has failed because the provided information was not compatible
+ /// with the original declaration.
+ ///
+ /// See [`Asg::declare`] for more information.
+ IncompatibleIdent(String),
+
/// The node was not expected in the current context
UnexpectedNode(String),
}
@@ -233,6 +241,9 @@ impl std::fmt::Display for AsgError {
Self::BadFragmentDest(msg) => {
write!(fmt, "bad fragment destination: {}", msg)
}
+ Self::IncompatibleIdent(msg) => {
+ write!(fmt, "identifier redeclaration failed: {}", msg)
+ }
Self::UnexpectedNode(msg) => {
write!(fmt, "unexpected node: {}", msg)
}
@@ -246,6 +257,15 @@ impl std::error::Error for AsgError {
}
}
+impl From<TransitionError> for AsgError {
+ fn from(e: TransitionError) -> Self {
+ match e {
+ TransitionError::Incompatible(msg) => Self::IncompatibleIdent(msg),
+ TransitionError::BadFragmentDest(msg) => Self::BadFragmentDest(msg),
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
diff --git a/tamer/src/ir/asg/object.rs b/tamer/src/ir/asg/object.rs
index b183234..8155e86 100644
--- a/tamer/src/ir/asg/object.rs
+++ b/tamer/src/ir/asg/object.rs
@@ -25,6 +25,10 @@
use super::ident::IdentKind;
use crate::ir::legacyir::SymAttrs;
use crate::sym::Symbol;
+use std::result::Result;
+
+pub type TransitionResult<'i> =
+ Result<Object<'i>, (Object<'i>, TransitionError)>;
/// Type of object.
///
@@ -71,6 +75,135 @@ pub enum Object<'i> {
IdentFragment(&'i Symbol<'i>, IdentKind, Source<'i>, FragmentText),
}
+impl<'i> Object<'i> {
+ /// Attempt to redeclare an identifier with additional information.
+ ///
+ /// _TODO: Compatibility information._
+ ///
+ /// The kind if 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(
+ mut self,
+ kind: IdentKind,
+ src: Source<'i>,
+ ) -> TransitionResult<'i> {
+ match self {
+ Object::Ident(_, _, ref mut orig_src)
+ if orig_src.virtual_ && src.override_ =>
+ {
+ *orig_src = src;
+ Ok(self)
+ }
+
+ // TODO: no override-override
+ Object::IdentFragment(name, _, orig_src, _)
+ if orig_src.virtual_ && src.override_ =>
+ {
+ // clears fragment, which is no longer applicable
+ Ok(Object::Ident(name, kind, src))
+ }
+
+ Object::Missing(name) | Object::Ident(name, _, _) => {
+ Ok(Object::Ident(name, kind, src))
+ }
+
+ // TODO: incompatible (check now-dangling commits)
+ _ => Ok(self),
+ }
+ }
+
+ /// 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> {
+ match self {
+ Object::Ident(sym, kind, src) => {
+ Ok(Object::IdentFragment(sym, kind, src, text))
+ }
+
+ Object::IdentFragment(_, IdentKind::MapHead, _, _)
+ | Object::IdentFragment(_, IdentKind::MapTail, _, _)
+ | Object::IdentFragment(_, IdentKind::RetMapHead, _, _)
+ | Object::IdentFragment(_, IdentKind::RetMapTail, _, _) => Ok(self),
+
+ // TODO remove these ignores when fixed
+ Object::IdentFragment(
+ sym,
+ IdentKind::Map,
+ Source {
+ virtual_: true,
+ override_: true,
+ ..
+ },
+ _,
+ ) => {
+ eprintln!(
+ "ignoring virtual and overridden map object: {}",
+ sym
+ );
+ Ok(self)
+ }
+ Object::IdentFragment(
+ sym,
+ IdentKind::RetMap,
+ Source {
+ virtual_: true,
+ override_: true,
+ ..
+ },
+ _,
+ ) => {
+ eprintln!(
+ "ignoring virtual and overridden retmap object: {}",
+ sym
+ );
+ Ok(self)
+ }
+
+ _ => {
+ let msg =
+ format!("identifier is not a Object::Ident): {:?}", self,);
+
+ Err((self, TransitionError::BadFragmentDest(msg)))
+ }
+ }
+ }
+}
+
+/// An error attempting to transition from one [`Object`] state to another.
+///
+/// TODO: Provide enough information to construct a useful message.
+#[derive(Debug, PartialEq)]
+pub enum TransitionError {
+ /// An attempt to redeclare an identifier with additional information
+ /// has failed because the provided information was not compatible
+ /// with the original declaration.
+ ///
+ /// See [`Object::redeclare`].
+ Incompatible(String),
+
+ /// The provided identifier is not in a state that is permitted to
+ /// receive a fragment.
+ ///
+ /// See [`Object::set_fragment`].
+ BadFragmentDest(String),
+}
+
+impl std::fmt::Display for TransitionError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
+ match self {
+ Self::Incompatible(msg) => {
+ write!(fmt, "object incompatible: {}", msg)
+ }
+
+ Self::BadFragmentDest(msg) => {
+ write!(fmt, "bad fragment destination: {}", msg)
+ }
+ }
+ }
+}
+
/// Compiled fragment for identifier.
///
/// This represents the text associated with an identifier.