[DEV-7087] TAMER: Object{State,Data}: API representative of state transitions

The API now enforces beginning at Missing and transitioning through
states.  Methods have been renamed to reflect this.
master
Mike Gerwitz 2020-03-26 00:43:04 -04:00
parent d3ecd7b228
commit f44549d730
3 changed files with 80 additions and 92 deletions

View File

@ -130,10 +130,10 @@ where
/// Lookup `ident` or add a missing identifier to the graph and return a
/// reference to it.
///
/// See [`IdentObjectState::missing`] for more information.
/// See [`IdentObjectState::declare`] for more information.
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(O::missing(ident)));
let index = self.graph.add_node(Some(O::declare(ident)));
self.index_identifier(ident, index);
ObjectRef(index)
@ -237,7 +237,7 @@ where
kind: IdentKind,
src: Source<'i>,
) -> AsgResult<ObjectRef<Ix>, Ix> {
self.with_ident(name, |obj| obj.redeclare(kind, src))
self.with_ident(name, |obj| obj.resolve(kind, src))
}
fn declare_extern(
@ -418,10 +418,9 @@ mod test {
#[derive(Debug, Default, PartialEq)]
struct StubIdentObject<'i> {
given_missing: Option<&'i Symbol<'i>>,
given_ident: Option<(&'i Symbol<'i>, IdentKind, Source<'i>)>,
given_declare: Option<&'i Symbol<'i>>,
given_extern: Option<(IdentKind, Source<'i>)>,
given_redeclare: Option<(IdentKind, Source<'i>)>,
given_resolve: Option<(IdentKind, Source<'i>)>,
given_set_fragment: Option<FragmentText>,
fail_redeclare: RefCell<Option<TransitionError>>,
fail_extern: RefCell<Option<TransitionError>>,
@ -429,15 +428,11 @@ mod test {
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))
self.given_declare
}
fn kind(&self) -> Option<&IdentKind> {
self.given_ident
.as_ref()
.map(|args| &args.1)
.or(self.given_redeclare.as_ref().map(|args| &args.0))
self.given_resolve.as_ref().map(|args| &args.0)
}
fn src(&self) -> Option<&Source<'i>> {
@ -454,25 +449,14 @@ mod test {
}
impl<'i> IdentObjectState<'i, StubIdentObject<'i>> for StubIdentObject<'i> {
fn missing(ident: &'i Symbol<'i>) -> Self {
fn declare(ident: &'i Symbol<'i>) -> Self {
Self {
given_missing: Some(ident),
given_declare: 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 redeclare(
fn resolve(
mut self,
kind: IdentKind,
src: Source<'i>,
@ -482,7 +466,7 @@ mod test {
return Err((self, err));
}
self.given_redeclare = Some((kind, src));
self.given_resolve = Some((kind, src));
Ok(self)
}
@ -558,7 +542,7 @@ mod test {
assert_ne!(nodea, nodeb);
assert_eq!(Some(&syma), sut.get(nodea).unwrap().given_missing);
assert_eq!(Some(&syma), sut.get(nodea).unwrap().given_declare);
assert_eq!(
Some((
IdentKind::Meta,
@ -567,10 +551,10 @@ mod test {
..Default::default()
},
)),
sut.get(nodea).unwrap().given_redeclare
sut.get(nodea).unwrap().given_resolve
);
assert_eq!(Some(&symb), sut.get(nodeb).unwrap().given_missing);
assert_eq!(Some(&symb), sut.get(nodeb).unwrap().given_declare);
assert_eq!(
Some((
IdentKind::Worksheet,
@ -579,7 +563,7 @@ mod test {
..Default::default()
},
)),
sut.get(nodeb).unwrap().given_redeclare
sut.get(nodeb).unwrap().given_resolve
);
Ok(())
@ -624,10 +608,7 @@ mod test {
// same node is referenced.
assert_eq!(node, redeclare);
assert_eq!(
Some((rekind, resrc)),
sut.get(node).unwrap().given_redeclare,
);
assert_eq!(Some((rekind, resrc)), sut.get(node).unwrap().given_resolve,);
Ok(())
}
@ -655,7 +636,7 @@ mod test {
if let Err(err) = result {
// The node should have been restored.
let obj = sut.get(node).unwrap();
assert_eq!(src, obj.given_redeclare.as_ref().unwrap().1);
assert_eq!(src, obj.given_resolve.as_ref().unwrap().1);
assert_eq!(AsgError::ObjectTransition(terr), err);
@ -750,8 +731,8 @@ mod test {
let obj = sut.get(node).unwrap();
assert_eq!(Some(&sym), obj.given_missing);
assert_eq!(Some((IdentKind::Meta, src)), obj.given_redeclare);
assert_eq!(Some(&sym), obj.given_declare);
assert_eq!(Some((IdentKind::Meta, src)), obj.given_resolve);
assert_eq!(Some(fragment), obj.given_set_fragment);
Ok(())
@ -807,8 +788,8 @@ mod test {
let (symnode, depnode) = sut.add_dep_lookup(&sym, &dep);
assert!(sut.has_dep(symnode, depnode));
assert_eq!(Some(&sym), sut.get(symnode).unwrap().given_missing);
assert_eq!(Some(&dep), sut.get(depnode).unwrap().given_missing);
assert_eq!(Some(&sym), sut.get(symnode).unwrap().given_declare);
assert_eq!(Some(&dep), sut.get(depnode).unwrap().given_declare);
Ok(())
}
@ -835,8 +816,8 @@ mod test {
let obj = sut.get(declared).unwrap();
assert_eq!(Some(&sym), obj.given_missing);
assert_eq!(Some((IdentKind::Meta, src)), obj.given_redeclare);
assert_eq!(Some(&sym), obj.given_declare);
assert_eq!(Some((IdentKind::Meta, src)), obj.given_resolve);
Ok(())
}

View File

@ -73,7 +73,7 @@ where
///
/// For more information on state transitions that can occur when
/// redeclaring an identifier that already exists,
/// see [`IdentObjectState::redeclare`].
/// see [`IdentObjectState::resolve`].
///
/// A successful declaration will add an identifier to the graph
/// and return an [`ObjectRef`] reference.
@ -102,7 +102,7 @@ where
/// Resolution will otherwise fail in error.
///
/// See [`IdentObjectState::extern_`] and
/// [`IdentObjectState::redeclare`] for more information on
/// [`IdentObjectState::resolve`] for more information on
/// compatibility related to extern resolution.
fn declare_extern(
&mut self,
@ -163,7 +163,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 [`IdentObjectState::missing`] for more information.
/// See [`IdentObjectState::declare`] for more information.
///
/// References to both identifiers are returned in argument order.
fn add_dep_lookup(

View File

@ -80,7 +80,7 @@ pub enum IdentObject<'i> {
/// as [`IdentObject`];
/// this allows other representations to be used,
/// while still permitting the use of matching on [`IdentObject`]
/// through the use of [`ident`](IdentObjectState::ident).
/// through the use of [`ident`](IdentObjectData::as_ident).
///
/// Since an object implementing this trait may not be an identifier
/// (e.g. an expression),
@ -186,20 +186,19 @@ where
T: IdentObjectState<'i, T>,
{
/// Produce an object representing a missing identifier.
fn missing(ident: &'i Symbol<'i>) -> T;
///
/// This is the base state for all identifiers.
fn declare(ident: &'i Symbol<'i>) -> T;
/// Produce an object representing a concrete identifier.
fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> T;
/// Attempt to redeclare an identifier with additional information.
/// Attempt to transition to a concrete identifier.
///
/// For specific information on compatibility rules,
/// see implementers of this trait,
/// since rules may vary between implementations.
fn redeclare(self, kind: IdentKind, src: Source<'i>)
-> TransitionResult<T>;
fn resolve(self, kind: IdentKind, src: Source<'i>) -> TransitionResult<T>;
/// Resolve identifier against an extern declaration.
/// Resolve identifier against an extern declaration or produce an
/// extern.
///
/// If the existing identifier has an assigned [`IdentKind`],
/// then it will be compared for equality against the given `kind`.
@ -227,14 +226,10 @@ where
}
impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
fn missing(ident: &'i Symbol<'i>) -> Self {
fn declare(ident: &'i Symbol<'i>) -> Self {
IdentObject::Missing(ident)
}
fn ident(name: &'i Symbol<'i>, kind: IdentKind, src: Source<'i>) -> Self {
IdentObject::Ident(name, kind, src)
}
/// Attempt to redeclare an identifier with additional information.
///
/// If an existing identifier is an [`IdentObject::Extern`],
@ -253,7 +248,7 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
/// 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.
fn redeclare(
fn resolve(
mut self,
kind: IdentKind,
src: Source<'i>,
@ -393,7 +388,7 @@ pub enum TransitionError {
/// has failed because the provided information was not compatible
/// with the original declaration.
///
/// See [`IdentObjectState::redeclare`].
/// See [`IdentObjectState::resolve`].
Incompatible(String),
/// Extern resolution failure.
@ -691,7 +686,7 @@ mod test {
#[test]
fn ident_object_missing() {
let sym = symbol_dummy!(1, "missing");
assert_eq!(IdentObject::Missing(&sym), IdentObject::missing(&sym));
assert_eq!(IdentObject::Missing(&sym), IdentObject::declare(&sym));
}
#[test]
@ -705,7 +700,9 @@ mod test {
assert_eq!(
IdentObject::Ident(&sym, kind.clone(), src.clone()),
IdentObject::ident(&sym, kind.clone(), src.clone()),
IdentObject::declare(&sym)
.resolve(kind.clone(), src.clone())
.unwrap(),
);
}
@ -723,7 +720,7 @@ mod test {
assert_eq!(
Ok(IdentObject::Extern(&sym, kind.clone())),
IdentObject::missing(&sym).extern_(kind, src),
IdentObject::declare(&sym).extern_(kind, src),
);
}
@ -738,9 +735,9 @@ mod test {
};
// Compatible kind, should resolve.
let result = IdentObject::missing(&sym)
let result = IdentObject::declare(&sym)
.extern_(kind.clone(), Source::default())
.and_then(|o| o.redeclare(kind.clone(), src.clone()));
.and_then(|o| o.resolve(kind.clone(), src.clone()));
assert_eq!(Ok(IdentObject::Ident(&sym, kind, src)), result,);
}
@ -756,9 +753,9 @@ mod test {
};
// Compatible kind, should resolve.
let result =
IdentObject::ident(&sym, kind.clone(), src.clone())
.extern_(kind.clone(), Source::default());
let result = IdentObject::declare(&sym)
.resolve(kind.clone(), src.clone())
.and_then(|o| o.extern_(kind.clone(), Source::default()));
assert_eq!(Ok(IdentObject::Ident(&sym, kind, src)), result,);
}
@ -768,7 +765,7 @@ mod test {
let sym = symbol_dummy!(1, "extern_extern");
let kind = IdentKind::Class(Dim::from_u8(20));
let result = IdentObject::missing(&sym)
let result = IdentObject::declare(&sym)
.extern_(kind.clone(), Source::default())
.and_then(|o| o.extern_(kind.clone(), Source::default()));
@ -785,13 +782,13 @@ mod test {
..Default::default()
};
let orig = IdentObject::missing(&sym)
let orig = IdentObject::declare(&sym)
.extern_(kind.clone(), Source::default())
.unwrap();
// Incompatible kind
let kind_bad = IdentKind::Meta;
let result = orig.clone().redeclare(kind_bad.clone(), src);
let result = orig.clone().resolve(kind_bad.clone(), src);
match result {
Err((given_orig, err @ _)) => {
@ -829,8 +826,9 @@ mod test {
..Default::default()
};
let orig =
IdentObject::ident(&sym, kind_given.clone(), src.clone());
let orig = IdentObject::declare(&sym)
.resolve(kind_given.clone(), src.clone())
.unwrap();
// Extern with incompatible kind.
let kind_extern = IdentKind::Meta;
@ -870,13 +868,14 @@ mod test {
fn redeclare_returns_existing_compatible() {
let sym = symbol_dummy!(1, "symdup");
let first =
IdentObject::ident(&sym, IdentKind::Meta, Source::default());
let first = IdentObject::declare(&sym)
.resolve(IdentKind::Meta, Source::default())
.unwrap();
// Same declaration a second time
assert_eq!(
Ok(first.clone()),
first.clone().redeclare(
first.clone().resolve(
first.kind().unwrap().clone(),
first.src().unwrap().clone(),
)
@ -892,7 +891,9 @@ mod test {
};
let kind = IdentKind::Meta;
let ident = IdentObject::ident(&sym, kind.clone(), src.clone());
let ident = IdentObject::declare(&sym)
.resolve(kind.clone(), src.clone())
.unwrap();
let text = FragmentText::from("a fragment");
let ident_with_frag = ident.set_fragment(text.clone());
@ -905,8 +906,9 @@ mod test {
#[test]
fn add_fragment_to_fragment_fails() {
let sym = symbol_dummy!(1, "badsym");
let ident =
IdentObject::ident(&sym, IdentKind::Meta, Source::default());
let ident = IdentObject::declare(&sym)
.resolve(IdentKind::Meta, Source::default())
.unwrap();
let ident_with_frag = ident
.set_fragment("orig fragment".into())
@ -938,14 +940,15 @@ mod test {
let over_src = symbol_dummy!(2, "src");
let kind = IdentKind::Meta;
let virt = IdentObject::ident(
&sym,
kind.clone(),
Source {
virtual_: true,
..Default::default()
},
);
let virt = IdentObject::declare(&sym)
.resolve(
kind.clone(),
Source {
virtual_: true,
..Default::default()
},
)
.unwrap();
let over_src = Source {
override_: true,
@ -953,7 +956,7 @@ mod test {
..Default::default()
};
let result = virt.redeclare(kind.clone(), over_src.clone());
let result = virt.resolve(kind.clone(), over_src.clone());
assert_eq!(Ok(IdentObject::Ident(&sym, kind, over_src)), result);
}
@ -970,7 +973,9 @@ mod test {
..Default::default()
};
let virt = IdentObject::ident(&sym, kind.clone(), virt_src.clone());
let virt = IdentObject::declare(&sym)
.resolve(kind.clone(), virt_src.clone())
.unwrap();
let text = FragmentText::from("remove me");
let virt_frag = virt.set_fragment(text.clone());
@ -991,7 +996,7 @@ mod test {
};
let result =
virt_frag.unwrap().redeclare(kind.clone(), over_src.clone());
virt_frag.unwrap().resolve(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
@ -1007,7 +1012,9 @@ mod test {
..Default::default()
};
let obj = IdentObject::ident(&sym, given, src.clone());
let obj = IdentObject::declare(&sym)
.resolve(given, src.clone())
.unwrap();
let fragment = "a fragment".to_string();
let obj_with_frag = obj.set_fragment(fragment.clone());