[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
parent
d3ecd7b228
commit
f44549d730
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue