tamer: ir::asg::object::IdentObject: Define methods from IdentObjectData

In particular, `name` needn't return an `Option`.  `fragment` also returns a
copy, since it's just a `SymbolId`.  (It really ought to be a newtype rather
than an alias, but we'll worry about that some other time.)

These changes allow us to remove some runtime panics.

DEV-10859
main
Mike Gerwitz 2021-10-14 14:36:44 -04:00
parent f055cb77c2
commit 739cf7e6eb
7 changed files with 104 additions and 78 deletions

View File

@ -313,7 +313,7 @@ mod object {
mod ident {
use super::*;
use tamer::ir::asg::{
IdentKind, IdentObject, IdentObjectData, IdentObjectState, Source,
IdentKind, IdentObject, IdentObjectState, Source,
};
use tamer::sym::GlobalSymbolIntern;

View File

@ -305,7 +305,7 @@ mod test {
None
}
fn fragment(&self) -> Option<&FragmentText> {
fn fragment(&self) -> Option<FragmentText> {
None
}

View File

@ -80,6 +80,44 @@ pub enum IdentObject {
IdentFragment(SymbolId, IdentKind, Source, FragmentText),
}
impl IdentObject {
pub fn name(&self) -> SymbolId {
match self {
Self::Missing(name)
| Self::Ident(name, _, _)
| Self::Extern(name, _, _)
| Self::IdentFragment(name, _, _, _) => *name,
}
}
pub fn kind(&self) -> Option<&IdentKind> {
match self {
Self::Missing(_) => None,
Self::Ident(_, kind, _)
| Self::Extern(_, kind, _)
| Self::IdentFragment(_, kind, _, _) => Some(kind),
}
}
pub fn src(&self) -> Option<&Source> {
match self {
Self::Missing(_) | Self::Extern(_, _, _) => None,
Self::Ident(_, _, src) | Self::IdentFragment(_, _, src, _) => {
Some(src)
}
}
}
pub fn fragment(&self) -> Option<FragmentText> {
match self {
Self::Missing(_) | Self::Ident(_, _, _) | Self::Extern(_, _, _) => {
None
}
Self::IdentFragment(_, _, _, text) => Some(*text),
}
}
}
/// Retrieve information about an [`IdentObject`].
///
/// APIs should adhere to this trait rather than a concrete object type such
@ -120,7 +158,7 @@ pub trait IdentObjectData {
///
/// If the object does not have an associated code fragment,
/// [`None`] is returned.
fn fragment(&self) -> Option<&FragmentText>;
fn fragment(&self) -> Option<FragmentText>;
/// IdentObject as an identifier ([`IdentObject`]).
///
@ -137,39 +175,20 @@ pub trait IdentObjectData {
impl IdentObjectData for IdentObject {
fn name(&self) -> Option<SymbolId> {
match self {
Self::Missing(name)
| Self::Ident(name, _, _)
| Self::Extern(name, _, _)
| Self::IdentFragment(name, _, _, _) => Some(*name),
}
Some(Self::name(self))
}
fn kind(&self) -> Option<&IdentKind> {
match self {
Self::Missing(_) => None,
Self::Ident(_, kind, _)
| Self::Extern(_, kind, _)
| Self::IdentFragment(_, kind, _, _) => Some(kind),
}
Self::kind(self)
}
fn src(&self) -> Option<&Source> {
match self {
Self::Missing(_) | Self::Extern(_, _, _) => None,
Self::Ident(_, _, src) | Self::IdentFragment(_, _, src, _) => {
Some(src)
}
}
Self::src(self)
}
fn fragment(&self) -> Option<&FragmentText> {
match self {
Self::Missing(_) | Self::Ident(_, _, _) | Self::Extern(_, _, _) => {
None
}
Self::IdentFragment(_, _, _, text) => Some(text),
}
fn fragment(&self) -> Option<FragmentText> {
// TODO: Get rid of the reference; the type is `Copy` now.
Self::fragment(self)
}
/// Expose underlying [`IdentObject`].
@ -372,9 +391,7 @@ impl IdentObjectState<IdentObject> for IdentObject {
}
_ => {
let err = TransitionError::Redeclare {
name: self.name().unwrap(),
};
let err = TransitionError::Redeclare { name: self.name() };
Err((self, err))
}
@ -406,11 +423,11 @@ impl IdentObjectState<IdentObject> for IdentObject {
src: Source,
) -> TransitionResult<IdentObject> {
match self.kind() {
None => Ok(IdentObject::Extern(self.name().unwrap(), kind, src)),
None => Ok(IdentObject::Extern(self.name(), kind, src)),
Some(cur_kind) => {
if cur_kind != &kind {
let err = TransitionError::ExternResolution {
name: self.name().unwrap(),
name: self.name(),
expected: kind.clone(),
given: cur_kind.clone(),
};
@ -708,22 +725,25 @@ mod test {
fn ident_object_name() {
let sym: SymbolId = "sym".intern();
assert_eq!(Some(sym), IdentObject::Missing(sym).name());
assert_eq!(
Some(sym),
IdentObjectData::name(&IdentObject::Missing(sym))
);
assert_eq!(
sym,
IdentObject::Ident(sym, IdentKind::Meta, Source::default())
.name()
);
assert_eq!(
Some(sym),
sym,
IdentObject::Extern(sym, IdentKind::Meta, Source::default())
.name()
);
assert_eq!(
Some(sym),
sym,
IdentObject::IdentFragment(
sym,
IdentKind::Meta,
@ -816,7 +836,7 @@ mod test {
);
assert_eq!(
Some(&text),
Some(text),
IdentObject::IdentFragment(
sym,
IdentKind::Meta,

View File

@ -26,7 +26,7 @@ use super::xmle::{
XmleSections,
};
use crate::global;
use crate::ir::asg::{Asg, DefaultAsg, IdentObject, IdentObjectData};
use crate::ir::asg::{Asg, DefaultAsg, IdentObject};
use crate::ir::xir::writer::XmlWriter;
use crate::obj::xmlo::{AsgBuilder, AsgBuilderState, XmloReader};
use crate::sym::SymbolId;
@ -82,20 +82,12 @@ pub fn xmle(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
let msg: Vec<String> = cycles
.into_iter()
.map(|cycle| {
let mut path: Vec<String> = cycle
let mut path = cycle
.into_iter()
.map(|obj| {
format!(
"{}",
depgraph
.get(obj)
.unwrap()
.name()
.unwrap()
.lookup_str(),
)
depgraph.get(obj).unwrap().name().lookup_str()
})
.collect();
.collect::<Vec<&str>>();
path.reverse();
path.push(path[0].clone());
@ -145,7 +137,7 @@ pub fn graphml(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
};
(
format!("{}", n.name().unwrap().lookup_str()),
n.name().lookup_str().into(),
n.kind().unwrap().as_sym(),
format!("{}", generated),
)

View File

@ -23,10 +23,7 @@
use super::section::{SectionsError, XmleSections};
use crate::{
ir::asg::{
Asg, BaseAsg, IdentKind, IdentObject, IdentObjectData, IndexType,
ObjectRef,
},
ir::asg::{Asg, BaseAsg, IdentKind, IdentObject, IndexType, ObjectRef},
sym::{st, GlobalSymbolResolve, SymbolId},
};
use petgraph::visit::DfsPostOrder;

View File

@ -27,28 +27,45 @@
//! necessary for execution.
use crate::ir::asg::{
IdentKind, IdentObject, IdentObjectData, IdentObjectState, UnresolvedError,
IdentKind, IdentObject, IdentObjectState, UnresolvedError,
};
use crate::sym::{GlobalSymbolResolve, SymbolId};
use crate::sym::SymbolId;
use fxhash::FxHashSet;
use std::mem::take;
use std::result::Result;
pub type PushResult<T = ()> = Result<T, SectionsError>;
/// Sections of a linked `xmle` file.
///
/// For more information on these sections,
/// see the [parent module](super).
pub trait XmleSections<'a> {
/// Push an object into the appropriate section.
///
/// Objects are expected to be properly sorted relative to their order
/// of execution so that their text fragments are placed in the
/// correct order in the final program text.
fn push(&mut self, ident: &'a IdentObject) -> PushResult;
/// Take the list of objects present in the linked file.
///
/// The order of these objects does not matter.
fn take_deps(&mut self) -> Vec<&'a IdentObject>;
fn take_static(&mut self) -> Vec<SymbolId>;
/// Take the ordered text fragments for the `map` section.
fn take_map(&mut self) -> Vec<SymbolId>;
/// Take the set of external identifiers mapped into this system.
fn take_map_froms(&mut self) -> FxHashSet<SymbolId>;
/// Take the ordered text fragments for the `retmap` section.
fn take_retmap(&mut self) -> Vec<SymbolId>;
/// Take the ordered text fragments for the `static` section.
fn take_static(&mut self) -> Vec<SymbolId>;
/// Take the ordered text fragments for the `exec` section.
fn take_exec(&mut self) -> Vec<SymbolId>;
}
@ -58,12 +75,24 @@ pub trait XmleSections<'a> {
/// see the [parent module](super).
#[derive(Debug, Default, PartialEq)]
pub struct Sections<'a> {
/// List of objects present in the linked file.
///
/// The order of these objects does not matter.
deps: Vec<&'a IdentObject>,
/// External identifiers mapped into this system.
map_froms: FxHashSet<SymbolId>,
/// Ordered text fragments of `map` section.
map: Vec<SymbolId>,
/// Order text fragments of `retmap` section.
retmap: Vec<SymbolId>,
/// Ordered text fragments of `static` section.
st: Vec<SymbolId>,
/// Ordered text fragments of `exec` section.
exec: Vec<SymbolId>,
}
@ -78,18 +107,12 @@ impl<'a> Sections<'a> {
}
impl<'a> XmleSections<'a> for Sections<'a> {
/// Push an object into the appropriate section.
///
/// Objects are expected to be properly sorted relative to their order
/// of execution so that their text fragments are placed in the
/// correct order in the final program text.
fn push(&mut self, ident: &'a IdentObject) -> PushResult {
self.deps.push(ident);
// TODO: This cannot happen, so use an API without Option.
let name = ident.name().expect("missing identifier name");
let frag = ident.fragment().map(|sym| *sym);
let name = ident.name();
let frag = ident.fragment();
match ident.resolved()?.kind() {
Some(kind) => match kind {
@ -131,13 +154,7 @@ impl<'a> XmleSections<'a> for Sections<'a> {
// compiler bug and there is no use in trying to be nice
// about a situation where something went terribly, horribly
// wrong.
return Err(SectionsError::MissingObjectKind(
ident
.name()
.map(|name| name.lookup_str())
.unwrap_or("<unknown>".into())
.into(),
));
return Err(SectionsError::MissingObjectKind(ident.name()));
}
}
@ -205,7 +222,7 @@ pub enum SectionsError {
/// sections.
/// It should never be the case that a resolved object has no kind,
/// so this likely represents a compiler bug.
MissingObjectKind(String),
MissingObjectKind(SymbolId),
}
impl From<UnresolvedError> for SectionsError {
@ -395,7 +412,7 @@ mod test {
($($name:ident),*) => {
vec![
$(&$name),*
].into_iter().map(|x| *x.fragment().unwrap()).collect::<Vec<SymbolId>>()
].into_iter().map(|x| x.fragment().unwrap()).collect::<Vec<SymbolId>>()
}
}

View File

@ -20,7 +20,7 @@
use super::*;
use crate::convert::ExpectInto;
use crate::ir::{
asg::{Dim, IdentKind, IdentObjectData, Source},
asg::{Dim, IdentKind, Source},
legacyir::SymDtype,
xir::{
pred::{not, open},
@ -256,7 +256,7 @@ fn test_writes_deps() -> TestResult {
assert_eq!(
attrs.find(QN_NAME).and_then(|a| a.value_atom()),
Some(AttrValue::Escaped(ident.name().unwrap())),
Some(AttrValue::Escaped(ident.name())),
);
assert_eq!(