diff --git a/.rev-xmle b/.rev-xmle
index 2253abf9..0a9afa0c 100644
--- a/.rev-xmle
+++ b/.rev-xmle
@@ -1,4 +1,4 @@
# This number is incremented for every linker change to force rebuilding
# of xmle files.
-2
+3
diff --git a/src/current/include/preproc/symtable.xsl b/src/current/include/preproc/symtable.xsl
index 9d219060..700f930e 100644
--- a/src/current/include/preproc/symtable.xsl
+++ b/src/current/include/preproc/symtable.xsl
@@ -514,10 +514,18 @@
-
+
-
+
+
+
+
+
+
diff --git a/tamer/src/ir/asg/base.rs b/tamer/src/ir/asg/base.rs
index f1868c3d..ed490f73 100644
--- a/tamer/src/ir/asg/base.rs
+++ b/tamer/src/ir/asg/base.rs
@@ -141,13 +141,29 @@ where
) -> AsgResult> {
// TODO: src check
if let Some(existing) = self.lookup(name) {
- match self.graph.node_weight_mut(existing.0) {
- Some(node @ Some(Object::Missing(_))) => {
+ 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);
}
- Some(_) => 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),
}
}
@@ -414,6 +430,81 @@ mod test {
Ok(())
}
+ // TODO: incompatible
+ #[test]
+ fn declare_override_virtual_ident() -> AsgResult<()> {
+ let mut sut = Sut::with_capacity(0, 0);
+
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "virtual");
+ let over_src = Symbol::new_dummy(SymbolIndex::from_u32(2), "src");
+
+ let virt_node = sut.declare(
+ &sym,
+ IdentKind::Meta,
+ Source {
+ virtual_: true,
+ ..Default::default()
+ },
+ )?;
+
+ let over_src = Source {
+ override_: true,
+ src: Some(&over_src),
+ ..Default::default()
+ };
+
+ let over_node = sut.declare(&sym, IdentKind::Meta, over_src.clone())?;
+
+ assert_eq!(virt_node, over_node);
+
+ assert_eq!(
+ sut.get(over_node),
+ Some(&Object::Ident(&sym, IdentKind::Meta, over_src,))
+ );
+
+ Ok(())
+ }
+
+ // TODO: incompatible
+ #[test]
+ fn declare_override_virtual_ident_fragment() -> AsgResult<()> {
+ let mut sut = Sut::with_capacity(0, 0);
+
+ let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "virtual");
+ let over_src = Symbol::new_dummy(SymbolIndex::from_u32(2), "src");
+
+ let virt_node = sut.declare(
+ &sym,
+ IdentKind::Meta,
+ Source {
+ virtual_: true,
+ ..Default::default()
+ },
+ )?;
+
+ sut.set_fragment(virt_node, FragmentText::from("remove me"))?;
+
+ let over_src = Source {
+ override_: true,
+ src: Some(&over_src),
+ ..Default::default()
+ };
+
+ let over_node = sut.declare(&sym, IdentKind::Meta, over_src.clone())?;
+
+ assert_eq!(virt_node, over_node);
+
+ // The act of overriding the node should have cleared any existing
+ // fragment, making way for a new fragment to take its place as soon
+ // as it is discovered. (So, back to an Object::Ident.)
+ assert_eq!(
+ sut.get(over_node),
+ Some(&Object::Ident(&sym, IdentKind::Meta, over_src,))
+ );
+
+ Ok(())
+ }
+
#[test]
fn add_fragment_to_ident() -> AsgResult<()> {
let mut sut = Sut::with_capacity(0, 0);
diff --git a/tamer/src/ir/asg/graph.rs b/tamer/src/ir/asg/graph.rs
index 7be76152..e2135e4a 100644
--- a/tamer/src/ir/asg/graph.rs
+++ b/tamer/src/ir/asg/graph.rs
@@ -61,6 +61,12 @@ pub trait Asg<'i, Ix: IndexType> {
/// [`Object::Extern`] into a [`Object::Ident`].
/// When this happens,
/// the extern is said to be _resolved_.
+ ///
+ /// 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.
fn declare(
&mut self,
name: &'i Symbol<'i>,
diff --git a/tamer/src/ir/asg/object.rs b/tamer/src/ir/asg/object.rs
index 1921111b..282834ac 100644
--- a/tamer/src/ir/asg/object.rs
+++ b/tamer/src/ir/asg/object.rs
@@ -33,9 +33,9 @@ use crate::sym::Symbol;
/// / \ \
/// / v v
/// ((Empty)) -> (Extern) -> ((Ident)) -> ((IdentFragment)).
-/// \ ^
-/// \ /
-/// `--------------------`
+/// \ ^ /
+/// \ / \ /
+/// `--------------------` `-----------'
/// ```
///
/// The [`Empty`][Object::Empty] state is never directly accessable
@@ -149,6 +149,22 @@ pub struct Source<'i> {
/// TODO: We have `parent`, `yields`, and `from`.
/// We should begin to consolodate.
pub from: Option>>,
+
+ /// Whether identifier is virtual (can be overridden).
+ ///
+ /// This feature adds complexity and will ideally be removed in the
+ /// future.
+ ///
+ /// See also [`override`][Source::override_].
+ pub virtual_: bool,
+
+ /// Whether identifier overrides a virtual identifier.
+ ///
+ /// This feature adds complexity and will ideally be removed in the
+ /// future.
+ ///
+ /// See also [`virtual_`][Source::virtual_].
+ pub override_: bool,
}
impl<'i> From> for Source<'i> {
@@ -164,6 +180,8 @@ impl<'i> From> for Source<'i> {
yields: attrs.yields,
desc: attrs.desc,
from: attrs.from,
+ virtual_: attrs.virtual_,
+ override_: attrs.override_,
}
}
}
@@ -189,6 +207,8 @@ mod test {
yields: Some(&ysym),
desc: Some("sym desc".to_string()),
from: Some(vec![&fsym]),
+ virtual_: true,
+ override_: true,
..Default::default()
};
@@ -201,6 +221,8 @@ mod test {
yields: attrs.yields,
desc: Some("sym desc".to_string()),
from: Some(vec![&fsym]),
+ virtual_: true,
+ override_: true,
},
attrs.into(),
);
diff --git a/tamer/src/ir/legacyir.rs b/tamer/src/ir/legacyir.rs
index be318b2e..bdf33a8e 100644
--- a/tamer/src/ir/legacyir.rs
+++ b/tamer/src/ir/legacyir.rs
@@ -158,6 +158,16 @@ pub struct SymAttrs<'i> {
/// - [`SymType::Func`] lists params in order (so that the compiler
/// knows application order).
pub from: Option>>,
+
+ /// Whether symbol can be overridden.
+ ///
+ /// See also [`override`][SymAttrs::override_].
+ pub virtual_: bool,
+
+ /// Whether symbol is an override of a virtual symbol.
+ ///
+ /// See also [`virtual`][SymAttrs::virtual_].
+ pub override_: bool,
}
/// Legacy symbol types.
diff --git a/tamer/src/obj/xmlo/reader.rs b/tamer/src/obj/xmlo/reader.rs
index 8264b147..dfc8d348 100644
--- a/tamer/src/obj/xmlo/reader.rs
+++ b/tamer/src/obj/xmlo/reader.rs
@@ -469,6 +469,14 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
});
}
+ b"virtual" => {
+ sym_attrs.virtual_ = &*attr.value == b"true";
+ }
+
+ b"isoverride" => {
+ sym_attrs.override_ = &*attr.value == b"true";
+ }
+
// As this reader evolves, we may wish to provide an error
// for unknown attributes so that we can be sure that we've
// handled them all.
@@ -1751,6 +1759,16 @@ mod test {
..Default::default()
}
+ r#virtual: [virtual="true"] => SymAttrs {
+ virtual_: true,
+ ..Default::default()
+ }
+
+ r#override: [isoverride="true"] => SymAttrs {
+ override_: true,
+ ..Default::default()
+ }
+
// Multiple attributes at once
multi: [src="foo", type="class", dim="1", dtype="float", extern="true"]
=> SymAttrs {