TAMER: Symbol source data and metadata
parent
bcc2ab1221
commit
85a4934db5
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use super::graph::{Asg, AsgEdge, AsgError, AsgResult, Node, ObjectRef};
|
use super::graph::{Asg, AsgEdge, AsgError, AsgResult, Node, ObjectRef};
|
||||||
use super::ident::IdentKind;
|
use super::ident::IdentKind;
|
||||||
use super::object::{FragmentText, Object};
|
use super::object::{FragmentText, Object, Source};
|
||||||
use crate::sym::Symbol;
|
use crate::sym::Symbol;
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use petgraph::graph::{
|
use petgraph::graph::{
|
||||||
|
@ -125,13 +125,14 @@ where
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'i Symbol<'i>,
|
name: &'i Symbol<'i>,
|
||||||
kind: IdentKind,
|
kind: IdentKind,
|
||||||
|
src: Source<'i>,
|
||||||
) -> AsgResult<ObjectRef<Ix>> {
|
) -> AsgResult<ObjectRef<Ix>> {
|
||||||
// TODO: src check
|
// TODO: src check
|
||||||
if let Some(existing) = self.lookup(name) {
|
if let Some(existing) = self.lookup(name) {
|
||||||
return Ok(existing);
|
return Ok(existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = self.graph.add_node(Some(Object::Ident(name, kind)));
|
let node = self.graph.add_node(Some(Object::Ident(name, kind, src)));
|
||||||
|
|
||||||
self.index_identifier(name, node);
|
self.index_identifier(name, node);
|
||||||
|
|
||||||
|
@ -172,8 +173,8 @@ where
|
||||||
.expect("internal error: BaseAsg::set_fragment missing Node data");
|
.expect("internal error: BaseAsg::set_fragment missing Node data");
|
||||||
|
|
||||||
let result = match ty {
|
let result = match ty {
|
||||||
Object::Ident(sym, kind) => {
|
Object::Ident(sym, kind, src) => {
|
||||||
Ok(Object::IdentFragment(sym, kind, text))
|
Ok(Object::IdentFragment(sym, kind, src, text))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let err = Err(AsgError::BadFragmentDest(format!(
|
let err = Err(AsgError::BadFragmentDest(format!(
|
||||||
|
@ -287,18 +288,47 @@ mod test {
|
||||||
let syma = Symbol::new_dummy(SymbolIndex::from_u32(5), "syma");
|
let syma = Symbol::new_dummy(SymbolIndex::from_u32(5), "syma");
|
||||||
let symb = Symbol::new_dummy(SymbolIndex::from_u32(1), "symab");
|
let symb = Symbol::new_dummy(SymbolIndex::from_u32(1), "symab");
|
||||||
|
|
||||||
let nodea = sut.declare(&syma, IdentKind::Meta)?;
|
let nodea = sut.declare(
|
||||||
let nodeb = sut.declare(&symb, IdentKind::Worksheet)?;
|
&syma,
|
||||||
|
IdentKind::Meta,
|
||||||
|
Source {
|
||||||
|
desc: Some("a".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let nodeb = sut.declare(
|
||||||
|
&symb,
|
||||||
|
IdentKind::Worksheet,
|
||||||
|
Source {
|
||||||
|
desc: Some("b".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
assert_ne!(nodea, nodeb);
|
assert_ne!(nodea, nodeb);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(&Object::Ident(&syma, IdentKind::Meta)),
|
Some(&Object::Ident(
|
||||||
|
&syma,
|
||||||
|
IdentKind::Meta,
|
||||||
|
Source {
|
||||||
|
desc: Some("a".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)),
|
||||||
sut.get(nodea),
|
sut.get(nodea),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(&Object::Ident(&symb, IdentKind::Worksheet)),
|
Some(&Object::Ident(
|
||||||
|
&symb,
|
||||||
|
IdentKind::Worksheet,
|
||||||
|
Source {
|
||||||
|
desc: Some("b".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)),
|
||||||
sut.get(nodeb),
|
sut.get(nodeb),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -310,7 +340,14 @@ mod test {
|
||||||
let mut sut = Sut::with_capacity(0, 0);
|
let mut sut = Sut::with_capacity(0, 0);
|
||||||
|
|
||||||
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "lookup");
|
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "lookup");
|
||||||
let node = sut.declare(&sym, IdentKind::Meta)?;
|
let node = sut.declare(
|
||||||
|
&sym,
|
||||||
|
IdentKind::Meta,
|
||||||
|
Source {
|
||||||
|
generated: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
assert_eq!(Some(node), sut.lookup(&sym));
|
assert_eq!(Some(node), sut.lookup(&sym));
|
||||||
|
|
||||||
|
@ -335,10 +372,11 @@ mod test {
|
||||||
let mut sut = Sut::with_capacity(0, 0);
|
let mut sut = Sut::with_capacity(0, 0);
|
||||||
|
|
||||||
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "symdup");
|
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "symdup");
|
||||||
let node = sut.declare(&sym, IdentKind::Meta)?;
|
let node = sut.declare(&sym, IdentKind::Meta, Source::default())?;
|
||||||
|
|
||||||
// Same declaration a second time
|
// Same declaration a second time
|
||||||
let redeclare = sut.declare(&sym, IdentKind::Meta)?;
|
let redeclare =
|
||||||
|
sut.declare(&sym, IdentKind::Meta, Source::default())?;
|
||||||
|
|
||||||
assert_eq!(node, redeclare);
|
assert_eq!(node, redeclare);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -349,7 +387,11 @@ mod test {
|
||||||
let mut sut = Sut::with_capacity(0, 0);
|
let mut sut = Sut::with_capacity(0, 0);
|
||||||
|
|
||||||
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "tofrag");
|
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "tofrag");
|
||||||
let node = sut.declare(&sym, IdentKind::Meta)?;
|
let src = Source {
|
||||||
|
generated: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let node = sut.declare(&sym, IdentKind::Meta, src.clone())?;
|
||||||
|
|
||||||
let fragment = "a fragment".to_string();
|
let fragment = "a fragment".to_string();
|
||||||
let node_with_frag = sut.set_fragment(node, fragment.clone())?;
|
let node_with_frag = sut.set_fragment(node, fragment.clone())?;
|
||||||
|
@ -362,7 +404,7 @@ mod test {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(&Object::IdentFragment(&sym, IdentKind::Meta, fragment)),
|
Some(&Object::IdentFragment(&sym, IdentKind::Meta, src, fragment)),
|
||||||
sut.get(node)
|
sut.get(node)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -374,7 +416,7 @@ mod test {
|
||||||
let mut sut = Sut::with_capacity(0, 0);
|
let mut sut = Sut::with_capacity(0, 0);
|
||||||
|
|
||||||
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
|
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
|
||||||
let node = sut.declare(&sym, IdentKind::Meta)?;
|
let node = sut.declare(&sym, IdentKind::Meta, Source::default())?;
|
||||||
let fragment = "orig fragment".to_string();
|
let fragment = "orig fragment".to_string();
|
||||||
|
|
||||||
sut.set_fragment(node, fragment.clone())?;
|
sut.set_fragment(node, fragment.clone())?;
|
||||||
|
@ -391,7 +433,12 @@ mod test {
|
||||||
|
|
||||||
// Make sure we didn't leave the node in an inconsistent state
|
// Make sure we didn't leave the node in an inconsistent state
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(&Object::IdentFragment(&sym, IdentKind::Meta, fragment)),
|
Some(&Object::IdentFragment(
|
||||||
|
&sym,
|
||||||
|
IdentKind::Meta,
|
||||||
|
Default::default(),
|
||||||
|
fragment
|
||||||
|
)),
|
||||||
sut.get(node)
|
sut.get(node)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -405,8 +452,8 @@ mod test {
|
||||||
let sym = Symbol::new_dummy(SymbolIndex::from_u32(1), "sym");
|
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(1), "dep");
|
||||||
|
|
||||||
let symnode = sut.declare(&sym, IdentKind::Meta)?;
|
let symnode = sut.declare(&sym, IdentKind::Meta, Source::default())?;
|
||||||
let depnode = sut.declare(&dep, IdentKind::Meta)?;
|
let depnode = sut.declare(&dep, IdentKind::Meta, Source::default())?;
|
||||||
|
|
||||||
sut.add_dep(symnode, depnode);
|
sut.add_dep(symnode, depnode);
|
||||||
assert!(sut.has_dep(symnode, depnode));
|
assert!(sut.has_dep(symnode, depnode));
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
//! Abstract graph as the basis for concrete ASGs.
|
//! Abstract graph as the basis for concrete ASGs.
|
||||||
|
|
||||||
use super::ident::IdentKind;
|
use super::ident::IdentKind;
|
||||||
use super::object::{FragmentText, Object};
|
use super::object::{FragmentText, Object, Source};
|
||||||
use crate::sym::Symbol;
|
use crate::sym::Symbol;
|
||||||
use petgraph::graph::{IndexType, NodeIndex};
|
use petgraph::graph::{IndexType, NodeIndex};
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
@ -65,6 +65,7 @@ pub trait Asg<'i, Ix: IndexType> {
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'i Symbol<'i>,
|
name: &'i Symbol<'i>,
|
||||||
kind: IdentKind,
|
kind: IdentKind,
|
||||||
|
src: Source<'i>,
|
||||||
) -> AsgResult<ObjectRef<Ix>>;
|
) -> AsgResult<ObjectRef<Ix>>;
|
||||||
|
|
||||||
/// Declare an abstract identifier.
|
/// Declare an abstract identifier.
|
||||||
|
|
|
@ -150,6 +150,18 @@ impl<'i> TryFrom<SymAttrs<'i>> for IdentKind {
|
||||||
/// Certain [`IdentKind`] require that certain attributes be present,
|
/// Certain [`IdentKind`] require that certain attributes be present,
|
||||||
/// otherwise the conversion will fail.
|
/// otherwise the conversion will fail.
|
||||||
fn try_from(attrs: SymAttrs<'i>) -> Result<Self, Self::Error> {
|
fn try_from(attrs: SymAttrs<'i>) -> Result<Self, Self::Error> {
|
||||||
|
Self::try_from(&attrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i> TryFrom<&SymAttrs<'i>> for IdentKind {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
/// Attempt to raise [`SymAttrs`] into an [`IdentKind`].
|
||||||
|
///
|
||||||
|
/// Certain [`IdentKind`] require that certain attributes be present,
|
||||||
|
/// otherwise the conversion will fail.
|
||||||
|
fn try_from(attrs: &SymAttrs<'i>) -> Result<Self, Self::Error> {
|
||||||
let ty = attrs.ty.as_ref().ok_or("missing symbol type")?;
|
let ty = attrs.ty.as_ref().ok_or("missing symbol type")?;
|
||||||
|
|
||||||
macro_rules! ident {
|
macro_rules! ident {
|
||||||
|
@ -205,6 +217,27 @@ impl<'i> TryFrom<SymAttrs<'i>> for IdentKind {
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct Dim(u8);
|
pub struct Dim(u8);
|
||||||
|
|
||||||
|
/// Underlying datatype of identifier.
|
||||||
|
///
|
||||||
|
/// TODO: This will always be 0≤n≤9, so let's introduce a newtype for it.
|
||||||
|
impl AsRef<str> for Dim {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
match self.0 {
|
||||||
|
0 => &"0",
|
||||||
|
1 => &"1",
|
||||||
|
2 => &"2",
|
||||||
|
3 => &"3",
|
||||||
|
4 => &"4",
|
||||||
|
5 => &"5",
|
||||||
|
6 => &"6",
|
||||||
|
7 => &"7",
|
||||||
|
8 => &"8",
|
||||||
|
9 => &"9",
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Underlying datatype of identifier.
|
/// Underlying datatype of identifier.
|
||||||
pub type DataType = SymDtype;
|
pub type DataType = SymDtype;
|
||||||
|
|
||||||
|
@ -213,6 +246,16 @@ mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dim_to_str() {
|
||||||
|
// we'll just test high and low
|
||||||
|
let low: &str = Dim(0).as_ref();
|
||||||
|
let high: &str = Dim(9).as_ref();
|
||||||
|
|
||||||
|
assert_eq!("0", low);
|
||||||
|
assert_eq!("9", high);
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! test_kind {
|
macro_rules! test_kind {
|
||||||
($name:ident, $src:expr => $dest:expr) => {
|
($name:ident, $src:expr => $dest:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use tamer::global;
|
//! use tamer::global;
|
||||||
//! use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object};
|
//! use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object, Source};
|
||||||
//! use tamer::sym::{Interner, DefaultInterner};
|
//! use tamer::sym::{Interner, DefaultInterner};
|
||||||
//!
|
//!
|
||||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
//! let identa_sym = interner.intern("identa");
|
//! let identa_sym = interner.intern("identa");
|
||||||
//! let identb_sym = interner.intern("identb");
|
//! let identb_sym = interner.intern("identb");
|
||||||
//!
|
//!
|
||||||
//! let identa = asg.declare(identa_sym, IdentKind::Meta)?;
|
//! let identa = asg.declare(identa_sym, IdentKind::Meta, Source::default())?;
|
||||||
//! let identb = asg.declare_extern(identb_sym, IdentKind::Meta)?;
|
//! let identb = asg.declare_extern(identb_sym, IdentKind::Meta)?;
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(
|
//! assert_eq!(
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # use tamer::global;
|
//! # use tamer::global;
|
||||||
//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object, FragmentText};
|
//! # use tamer::ir::asg::{Asg, DefaultAsg, IdentKind, Object, FragmentText, Source};
|
||||||
//! # use tamer::sym::{Interner, DefaultInterner};
|
//! # use tamer::sym::{Interner, DefaultInterner};
|
||||||
//! #
|
//! #
|
||||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -111,13 +111,16 @@
|
||||||
//! # let interner = DefaultInterner::new();
|
//! # let interner = DefaultInterner::new();
|
||||||
//! #
|
//! #
|
||||||
//! // Fragments can be attached to resolved identifiers.
|
//! // Fragments can be attached to resolved identifiers.
|
||||||
//! let ident = asg.declare(interner.intern("ident"), IdentKind::Meta)?;
|
//! let ident = asg.declare(
|
||||||
|
//! interner.intern("ident"), IdentKind::Meta, Source::default()
|
||||||
|
//! )?;
|
||||||
//! asg.set_fragment(ident, FragmentText::from("test fragment"))?;
|
//! asg.set_fragment(ident, FragmentText::from("test fragment"))?;
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(
|
//! assert_eq!(
|
||||||
//! Some(&Object::IdentFragment(
|
//! Some(&Object::IdentFragment(
|
||||||
//! interner.intern("ident"),
|
//! interner.intern("ident"),
|
||||||
//! IdentKind::Meta,
|
//! IdentKind::Meta,
|
||||||
|
//! Source::default(),
|
||||||
//! FragmentText::from("test fragment"),
|
//! FragmentText::from("test fragment"),
|
||||||
//! )),
|
//! )),
|
||||||
//! asg.get(ident),
|
//! asg.get(ident),
|
||||||
|
@ -138,7 +141,7 @@ mod object;
|
||||||
|
|
||||||
pub use graph::{Asg, AsgResult, ObjectRef};
|
pub use graph::{Asg, AsgResult, ObjectRef};
|
||||||
pub use ident::IdentKind;
|
pub use ident::IdentKind;
|
||||||
pub use object::{FragmentText, Object};
|
pub use object::{FragmentText, Object, Source};
|
||||||
|
|
||||||
/// Default concrete ASG implementation.
|
/// Default concrete ASG implementation.
|
||||||
pub type DefaultAsg<'i, Ix> = base::BaseAsg<'i, Ix>;
|
pub type DefaultAsg<'i, Ix> = base::BaseAsg<'i, Ix>;
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
//! See [`super`] for available exports._
|
//! See [`super`] for available exports._
|
||||||
|
|
||||||
use super::ident::IdentKind;
|
use super::ident::IdentKind;
|
||||||
|
use crate::ir::legacyir::SymAttrs;
|
||||||
use crate::sym::Symbol;
|
use crate::sym::Symbol;
|
||||||
|
|
||||||
/// Type of object.
|
/// Type of object.
|
||||||
|
@ -38,15 +39,13 @@ use crate::sym::Symbol;
|
||||||
/// through [`Asg`][super::Asg]'s public API,
|
/// through [`Asg`][super::Asg]'s public API,
|
||||||
/// as it represents the absence of an object at that node within the
|
/// as it represents the absence of an object at that node within the
|
||||||
/// ASG.
|
/// ASG.
|
||||||
///
|
|
||||||
/// TODO: Source location (span; see Rustc).
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Object<'i> {
|
pub enum Object<'i> {
|
||||||
/// A resolved identifier.
|
/// A resolved identifier.
|
||||||
///
|
///
|
||||||
/// This represents an identifier that has been declared with certain
|
/// This represents an identifier that has been declared with certain
|
||||||
/// type information.
|
/// type information.
|
||||||
Ident(&'i Symbol<'i>, IdentKind),
|
Ident(&'i Symbol<'i>, IdentKind, Source<'i>),
|
||||||
|
|
||||||
/// An identifier that has not yet been resolved.
|
/// An identifier that has not yet been resolved.
|
||||||
///
|
///
|
||||||
|
@ -63,7 +62,7 @@ pub enum Object<'i> {
|
||||||
/// They are produced by the compiler and it is the job of the
|
/// They are produced by the compiler and it is the job of the
|
||||||
/// [linker][crate::ld] to put them into the correct order for the
|
/// [linker][crate::ld] to put them into the correct order for the
|
||||||
/// final executable.
|
/// final executable.
|
||||||
IdentFragment(&'i Symbol<'i>, IdentKind, FragmentText),
|
IdentFragment(&'i Symbol<'i>, IdentKind, Source<'i>, FragmentText),
|
||||||
|
|
||||||
/// The empty node (default value for indexer).
|
/// The empty node (default value for indexer).
|
||||||
///
|
///
|
||||||
|
@ -75,3 +74,87 @@ pub enum Object<'i> {
|
||||||
///
|
///
|
||||||
/// This represents the text associated with an identifier.
|
/// This represents the text associated with an identifier.
|
||||||
pub type FragmentText = String;
|
pub type FragmentText = String;
|
||||||
|
|
||||||
|
/// Metadata about the source of an object.
|
||||||
|
///
|
||||||
|
/// This contains information from the symbol table that does not belong on
|
||||||
|
/// [`IdentKind`],
|
||||||
|
/// since that stores _type_ information.
|
||||||
|
///
|
||||||
|
/// TODO: This does not currently store byte offsets within the source file
|
||||||
|
/// since the original XSLT-based compiler did not have that capability;
|
||||||
|
/// this will provide that information in the future.
|
||||||
|
#[derive(Debug, Default, PartialEq, Clone)]
|
||||||
|
pub struct Source<'i> {
|
||||||
|
/// The identifier from which this one is derived.
|
||||||
|
///
|
||||||
|
/// See [`IdentKind`] for more information on parents.
|
||||||
|
/// For example,
|
||||||
|
/// a [`IdentKind::Cgen`] always has a parent [`IdentKind::Class`].
|
||||||
|
pub parent: Option<&'i Symbol<'i>>,
|
||||||
|
|
||||||
|
/// Child identifier associated with this identifier.
|
||||||
|
///
|
||||||
|
/// For [`IdentKind::Class`],
|
||||||
|
/// this represents an associated [`IdentKind::Cgen`].
|
||||||
|
pub yields: Option<&'i Symbol<'i>>,
|
||||||
|
|
||||||
|
/// User-friendly identifier description.
|
||||||
|
///
|
||||||
|
/// This is used primarily by [`IdentKind::Class`] and
|
||||||
|
/// [`IdentKind::Gen`].
|
||||||
|
pub desc: Option<String>,
|
||||||
|
|
||||||
|
/// Whether this identifier was generated by the compiler.
|
||||||
|
///
|
||||||
|
/// A generated identifier is representative of an internal
|
||||||
|
/// implementation detail that should remain encapsulated from the
|
||||||
|
/// user and is subject to change over time.
|
||||||
|
///
|
||||||
|
/// Identifiers created by templates are not considered to be generated.
|
||||||
|
pub generated: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'i> From<SymAttrs<'i>> for Source<'i> {
|
||||||
|
/// Raise Legacy IR [`SymAttrs`].
|
||||||
|
///
|
||||||
|
/// This simply extracts a subset of fields from the source attributes.
|
||||||
|
fn from(attrs: SymAttrs<'i>) -> Self {
|
||||||
|
Source {
|
||||||
|
generated: attrs.generated,
|
||||||
|
parent: attrs.parent,
|
||||||
|
yields: attrs.yields,
|
||||||
|
desc: attrs.desc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::sym::SymbolIndex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn source_from_sym_attrs() {
|
||||||
|
let psym = Symbol::new_dummy(SymbolIndex::from_u32(1), "parent");
|
||||||
|
let ysym = Symbol::new_dummy(SymbolIndex::from_u32(2), "yields");
|
||||||
|
|
||||||
|
let attrs = SymAttrs {
|
||||||
|
generated: true,
|
||||||
|
parent: Some(&psym),
|
||||||
|
yields: Some(&ysym),
|
||||||
|
desc: Some("sym desc".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Source {
|
||||||
|
generated: attrs.generated,
|
||||||
|
parent: attrs.parent,
|
||||||
|
yields: attrs.yields,
|
||||||
|
desc: Some("sym desc".to_string()),
|
||||||
|
},
|
||||||
|
attrs.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -104,6 +104,33 @@ pub struct SymAttrs<'i> {
|
||||||
/// The linker (see [`crate::ld`]) is responsible for ensuring that the
|
/// The linker (see [`crate::ld`]) is responsible for ensuring that the
|
||||||
/// extern is satisfied and properly located in the final executable.
|
/// extern is satisfied and properly located in the final executable.
|
||||||
pub extern_: bool,
|
pub extern_: bool,
|
||||||
|
|
||||||
|
/// The identifier from which this one is derived.
|
||||||
|
///
|
||||||
|
/// For example,
|
||||||
|
/// [`SymType::Cgen`] has a parent [`SymType::Class`] and
|
||||||
|
/// [`SymType::Gen`] has a parent [`SymType::Rate`].
|
||||||
|
pub parent: Option<&'i Symbol<'i>>,
|
||||||
|
|
||||||
|
/// Whether this identifier was generated by the compiler.
|
||||||
|
///
|
||||||
|
/// A generated identifier is representative of an internal
|
||||||
|
/// implementation detail that should remain encapsulated from the
|
||||||
|
/// user and is subject to change over time.
|
||||||
|
///
|
||||||
|
/// Identifiers created by templates are not considered to be generated.
|
||||||
|
pub generated: bool,
|
||||||
|
|
||||||
|
/// Child identifier associated with this identifier.
|
||||||
|
///
|
||||||
|
/// For [`SymType::Class`],
|
||||||
|
/// this represents an associated [`SymType::Cgen`].
|
||||||
|
pub yields: Option<&'i Symbol<'i>>,
|
||||||
|
|
||||||
|
/// User-friendly identifier description.
|
||||||
|
///
|
||||||
|
/// This is used primarily by [`SymType::Class`] and [`SymType::Gen`].
|
||||||
|
pub desc: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Legacy symbol types.
|
/// Legacy symbol types.
|
||||||
|
|
|
@ -135,10 +135,12 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
|
||||||
|
|
||||||
let owned = attrs.src.is_none();
|
let owned = attrs.src.is_none();
|
||||||
|
|
||||||
let kind = attrs.try_into().map_err(|err| {
|
let kind = (&attrs).try_into().map_err(|err| {
|
||||||
format!("sym `{}` attrs error: {}", sym, err)
|
format!("sym `{}` attrs error: {}", sym, err)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let src = attrs.into();
|
||||||
|
|
||||||
// TODO: should probably track these down in the XSLT linker...
|
// TODO: should probably track these down in the XSLT linker...
|
||||||
match kind {
|
match kind {
|
||||||
Ok(kindval) => {
|
Ok(kindval) => {
|
||||||
|
@ -148,7 +150,7 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
|
||||||
|| sym.starts_with(":map:")
|
|| sym.starts_with(":map:")
|
||||||
|| sym.starts_with(":retmap:"));
|
|| sym.starts_with(":retmap:"));
|
||||||
|
|
||||||
let node = depgraph.declare(sym, kindval)?;
|
let node = depgraph.declare(sym, kindval, src)?;
|
||||||
|
|
||||||
if link_root {
|
if link_root {
|
||||||
roots.push(node);
|
roots.push(node);
|
||||||
|
|
|
@ -392,6 +392,28 @@ impl<'i, B: BufRead, I: Interner<'i>> XmloReader<'i, B, I> {
|
||||||
sym_attrs.extern_ = &*attr.value == b"true";
|
sym_attrs.extern_ = &*attr.value == b"true";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b"preproc:generated" => {
|
||||||
|
sym_attrs.generated = &*attr.value == b"true";
|
||||||
|
}
|
||||||
|
|
||||||
|
b"parent" => {
|
||||||
|
sym_attrs.parent = Some(unsafe {
|
||||||
|
interner.intern_utf8_unchecked(&attr.value)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
b"yields" => {
|
||||||
|
sym_attrs.yields = Some(unsafe {
|
||||||
|
interner.intern_utf8_unchecked(&attr.value)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
b"desc" => {
|
||||||
|
sym_attrs.desc = Some(unsafe {
|
||||||
|
String::from_utf8_unchecked(attr.value.to_vec())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// As this reader evolves, we may wish to provide an error
|
// As this reader evolves, we may wish to provide an error
|
||||||
// for unknown attributes so that we can be sure that we've
|
// for unknown attributes so that we can be sure that we've
|
||||||
// handled them all.
|
// handled them all.
|
||||||
|
@ -1411,6 +1433,21 @@ mod test {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parent: [parent="foo"] => SymAttrs {
|
||||||
|
parent: Some(interner.intern("foo")),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
yields: [yields="yield"] => SymAttrs {
|
||||||
|
yields: Some(interner.intern("yield")),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
desc: [desc="Description"] => SymAttrs {
|
||||||
|
desc: Some("Description".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
// Multiple attributes at once
|
// Multiple attributes at once
|
||||||
multi: [src="foo", type="class", dim="1", dtype="float", extern="true"]
|
multi: [src="foo", type="class", dim="1", dtype="float", extern="true"]
|
||||||
=> SymAttrs {
|
=> SymAttrs {
|
||||||
|
@ -1419,9 +1456,48 @@ mod test {
|
||||||
dim: Some(1),
|
dim: Some(1),
|
||||||
dtype: Some(SymDtype::Float),
|
dtype: Some(SymDtype::Float),
|
||||||
extern_: true,
|
extern_: true,
|
||||||
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// can't be tested using the above
|
||||||
|
#[test]
|
||||||
|
fn generated_true() -> XmloResult<()> {
|
||||||
|
let stub_data: &[u8] = &[];
|
||||||
|
let interner = DefaultInterner::new();
|
||||||
|
let mut sut = Sut::new(stub_data, &interner);
|
||||||
|
|
||||||
|
// See xmlo_tests macro for explanation
|
||||||
|
sut.seen_root = true;
|
||||||
|
|
||||||
|
sut.reader.next_event = Some(Box::new(|_, _| {
|
||||||
|
Ok(XmlEvent::Empty(MockBytesStart::new(
|
||||||
|
b"preproc:sym",
|
||||||
|
Some(MockAttributes::new(vec![
|
||||||
|
MockAttribute::new(b"name", b"generated_true"),
|
||||||
|
MockAttribute::new(b"preproc:generated", b"true"),
|
||||||
|
])),
|
||||||
|
)))
|
||||||
|
}));
|
||||||
|
|
||||||
|
let result = sut.read_event()?;
|
||||||
|
|
||||||
|
let expected_attrs = SymAttrs {
|
||||||
|
generated: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
XmloEvent::SymDecl(
|
||||||
|
interner.intern("generated_true"),
|
||||||
|
expected_attrs
|
||||||
|
),
|
||||||
|
result
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_on_non_ascii_dim() {
|
fn fails_on_non_ascii_dim() {
|
||||||
let stub_data: &[u8] = &[];
|
let stub_data: &[u8] = &[];
|
||||||
|
|
Loading…
Reference in New Issue