Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-25 23:20:51 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-03-26 09:14:29 -0400
commit537d9e64afdeb6fe3624e23838ecde7309486b77 (patch)
treeac0f871abdd7473bf94dba4856c1b8005534fb64 /tamer
parentd6762ab54736091c12c924ae3ba94d70763ee6d1 (diff)
downloadtame-537d9e64afdeb6fe3624e23838ecde7309486b77.tar.gz
tame-537d9e64afdeb6fe3624e23838ecde7309486b77.tar.bz2
tame-537d9e64afdeb6fe3624e23838ecde7309486b77.zip
[DEV-7087] TAMER: ObjectState: Introduce extern transition
This is the first step in a more incremental refactoring that previous commits to undo the optional Source in `ObjectState::ident`. This provides an explicit transition to an extern, with the intent of requiring an initial missing state. This will simplify logic on the ASG. Note that the Source provided to this new method is not yet used. That too will come in a following commit and will represent the source of the defined extern rather than the concrete identifier.
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/ir/asg/base.rs8
-rw-r--r--tamer/src/ir/asg/object.rs98
2 files changed, 69 insertions, 37 deletions
diff --git a/tamer/src/ir/asg/base.rs b/tamer/src/ir/asg/base.rs
index 91a00b5..e156a77 100644
--- a/tamer/src/ir/asg/base.rs
+++ b/tamer/src/ir/asg/base.rs
@@ -464,6 +464,14 @@ mod test {
Ok(self)
}
+ fn extern_(
+ self,
+ _kind: IdentKind,
+ _src: Source<'i>,
+ ) -> TransitionResult<StubIdentObject<'i>> {
+ Ok(self)
+ }
+
fn set_fragment(
mut self,
text: FragmentText,
diff --git a/tamer/src/ir/asg/object.rs b/tamer/src/ir/asg/object.rs
index ef54713..0c0cc8d 100644
--- a/tamer/src/ir/asg/object.rs
+++ b/tamer/src/ir/asg/object.rs
@@ -206,6 +206,22 @@ where
src: Option<Source<'i>>,
) -> TransitionResult<T>;
+ /// Resolve identifier against an extern declaration.
+ ///
+ /// If the existing identifier has an assigned [`IdentKind`],
+ /// then it will be compared for equality against the given `kind`.
+ /// If it matches,
+ /// then the current identifier will be returned as-is.
+ /// This represents an extern resolution that occurs when a concrete
+ /// identifier is located before an extern that requires it,
+ /// or my represent a duplicate (but compatible) extern
+ /// declaration.
+ ///
+ /// If no kind is assigned (such as [`IdentObject::Missing`]),
+ /// then a new extern is produced.
+ /// See for example [`IdentObject::Extern`].
+ fn extern_(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,
@@ -257,23 +273,8 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
src: Option<Source<'i>>,
) -> TransitionResult<IdentObject<'i>> {
match src {
- None => match self.kind() {
- None => Ok(IdentObject::Extern(self.name().unwrap(), kind)),
- Some(cur_kind) => {
- if cur_kind != &kind {
- let err = TransitionError::ExternResolution {
- name: self.name().unwrap().to_string(),
- expected: kind.clone(),
- given: cur_kind.clone(),
- };
-
- return Err((self, err));
- }
-
- // Resolved successfully, so keep what we already have.
- Ok(self)
- }
- },
+ // TODO: remove
+ None => self.extern_(kind, Source::default()),
Some(new_src) => match self {
IdentObject::Ident(_, _, ref mut orig_src)
if orig_src.virtual_ && new_src.override_ =>
@@ -314,6 +315,30 @@ impl<'i> IdentObjectState<'i, IdentObject<'i>> for IdentObject<'i> {
}
}
+ fn extern_(
+ self,
+ kind: IdentKind,
+ _src: Source<'i>,
+ ) -> TransitionResult<IdentObject<'i>> {
+ match self.kind() {
+ None => Ok(IdentObject::Extern(self.name().unwrap(), kind)),
+ Some(cur_kind) => {
+ if cur_kind != &kind {
+ let err = TransitionError::ExternResolution {
+ name: self.name().unwrap().to_string(),
+ expected: kind.clone(),
+ given: cur_kind.clone(),
+ };
+
+ return Err((self, err));
+ }
+
+ // Resolved successfully, so keep what we already have.
+ Ok(self)
+ }
+ }
+ }
+
fn set_fragment(
self,
text: FragmentText,
@@ -709,10 +734,14 @@ mod test {
fn ident_object() {
let sym = symbol_dummy!(1, "missing");
let kind = IdentKind::Class(Dim::from_u8(1));
+ let src = Source {
+ desc: Some("extern".into()),
+ ..Default::default()
+ };
assert_eq!(
- IdentObject::Extern(&sym, kind.clone()),
- IdentObject::ident(&sym, kind.clone(), None),
+ Ok(IdentObject::Extern(&sym, kind.clone())),
+ IdentObject::missing(&sym).extern_(kind, src),
);
}
@@ -727,8 +756,9 @@ mod test {
};
// Compatible kind, should resolve.
- let result = IdentObject::ident(&sym, kind.clone(), None)
- .redeclare(kind.clone(), Some(src.clone()));
+ let result = IdentObject::missing(&sym)
+ .extern_(kind.clone(), Source::default())
+ .and_then(|o| o.redeclare(kind.clone(), Some(src.clone())));
assert_eq!(Ok(IdentObject::Ident(&sym, kind, src)), result,);
}
@@ -746,29 +776,19 @@ mod test {
// Compatible kind, should resolve.
let result =
IdentObject::ident(&sym, kind.clone(), Some(src.clone()))
- .redeclare(kind.clone(), None);
+ .extern_(kind.clone(), Source::default());
assert_eq!(Ok(IdentObject::Ident(&sym, kind, src)), result,);
}
#[test]
- fn redeclare_missing() {
- let sym = symbol_dummy!(1, "extern_missing");
- let kind = IdentKind::Class(Dim::from_u8(7));
-
- let result =
- IdentObject::missing(&sym).redeclare(kind.clone(), None);
-
- assert_eq!(Ok(IdentObject::Extern(&sym, kind)), result);
- }
-
- #[test]
fn redeclare_another_extern() {
let sym = symbol_dummy!(1, "extern_extern");
let kind = IdentKind::Class(Dim::from_u8(20));
- let result = IdentObject::ident(&sym, kind.clone(), None)
- .redeclare(kind.clone(), None);
+ let result = IdentObject::missing(&sym)
+ .extern_(kind.clone(), Source::default())
+ .and_then(|o| o.extern_(kind.clone(), Source::default()));
assert_eq!(Ok(IdentObject::Extern(&sym, kind)), result);
}
@@ -783,7 +803,9 @@ mod test {
..Default::default()
};
- let orig = IdentObject::ident(&sym, kind.clone(), None);
+ let orig = IdentObject::missing(&sym)
+ .extern_(kind.clone(), Source::default())
+ .unwrap();
// Incompatible kind
let kind_bad = IdentKind::Meta;
@@ -834,7 +856,9 @@ mod test {
// Extern with incompatible kind.
let kind_extern = IdentKind::Meta;
- let result = orig.clone().redeclare(kind_extern.clone(), None);
+ let result = orig
+ .clone()
+ .extern_(kind_extern.clone(), Source::default());
match result {
Err((given_orig, err @ _)) => {