2021-10-12 09:42:09 -04:00
|
|
|
// ASG lowering into xmle sections
|
|
|
|
//
|
2022-05-03 14:14:29 -04:00
|
|
|
// Copyright (C) 2014-2022 Ryan Specialty Group, LLC.
|
2021-10-12 09:42:09 -04:00
|
|
|
//
|
|
|
|
// This file is part of TAME.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2021-11-04 16:12:15 -04:00
|
|
|
//! Lowering of the [ASG](crate::asg) into `xmle` [`XmleSections`].
|
2021-10-12 09:42:09 -04:00
|
|
|
//!
|
|
|
|
//! See the [parent module](super) for more information.
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
use super::section::{SectionsError, XmleSections};
|
|
|
|
use crate::{
|
2022-05-11 16:38:59 -04:00
|
|
|
asg::{Asg, IdentKind, IdentObject, ObjectRef},
|
2021-10-14 12:37:32 -04:00
|
|
|
sym::{st, GlobalSymbolResolve, SymbolId},
|
2021-10-12 09:42:09 -04:00
|
|
|
};
|
|
|
|
use petgraph::visit::DfsPostOrder;
|
|
|
|
|
|
|
|
// Result of [`sort`].
|
2022-01-14 10:21:49 -05:00
|
|
|
pub type SortResult<T> = Result<T, SortError>;
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
/// Lower ASG into [`XmleSections`] by ordering relocatable text fragments.
|
2021-10-12 09:42:09 -04:00
|
|
|
///
|
|
|
|
/// This performs the equivalent of a topological sort,
|
|
|
|
/// although function cycles are permitted.
|
|
|
|
/// The actual operation performed is a post-order depth-first traversal.
|
2022-01-14 10:21:49 -05:00
|
|
|
pub fn sort<'a, S: XmleSections<'a>>(
|
2022-05-12 15:44:32 -04:00
|
|
|
asg: &'a Asg,
|
2022-01-14 10:21:49 -05:00
|
|
|
roots: &[ObjectRef],
|
2021-10-14 12:37:32 -04:00
|
|
|
mut dest: S,
|
2022-01-14 10:21:49 -05:00
|
|
|
) -> SortResult<S>
|
2021-10-12 09:42:09 -04:00
|
|
|
where
|
2021-10-14 12:37:32 -04:00
|
|
|
S: XmleSections<'a>,
|
2021-10-12 09:42:09 -04:00
|
|
|
{
|
|
|
|
// TODO: we should check for cycles as we sort (as the POC did).
|
|
|
|
check_cycles(asg)?;
|
|
|
|
|
|
|
|
// This is technically a topological sort, but functions have cycles.
|
|
|
|
let mut dfs = DfsPostOrder::empty(&asg.graph);
|
|
|
|
|
|
|
|
for index in roots {
|
|
|
|
dfs.stack.push((*index).into());
|
|
|
|
}
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
// These are always generated by the map compiler,
|
|
|
|
// but do not have edges that would allow them to be properly ordered
|
|
|
|
// (adding an edge to every map object would be wasteful).
|
|
|
|
dest.push(get_ident(asg, st::L_MAP_UUUHEAD))?;
|
|
|
|
dest.push(get_ident(asg, st::L_RETMAP_UUUHEAD))?;
|
|
|
|
|
2021-10-12 09:42:09 -04:00
|
|
|
while let Some(index) = dfs.next(&asg.graph) {
|
2021-10-12 12:14:24 -04:00
|
|
|
let ident = asg.get(index).expect("missing node");
|
2021-10-14 12:37:32 -04:00
|
|
|
dest.push(ident)?;
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
dest.push(get_ident(asg, st::L_MAP_UUUTAIL))?;
|
|
|
|
dest.push(get_ident(asg, st::L_RETMAP_UUUTAIL))?;
|
|
|
|
|
|
|
|
Ok(dest)
|
|
|
|
}
|
|
|
|
|
2022-05-12 15:44:32 -04:00
|
|
|
fn get_ident<'a, S>(depgraph: &'a Asg, name: S) -> &'a IdentObject
|
2021-10-14 12:37:32 -04:00
|
|
|
where
|
|
|
|
S: Into<SymbolId>,
|
|
|
|
{
|
|
|
|
let sym = name.into();
|
|
|
|
|
|
|
|
depgraph
|
|
|
|
.lookup(sym)
|
|
|
|
.and_then(|id| depgraph.get(id))
|
|
|
|
.expect(&format!(
|
|
|
|
"missing internal identifier: {}",
|
|
|
|
sym.lookup_str()
|
|
|
|
))
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Check graph for cycles
|
|
|
|
///
|
|
|
|
/// We want to catch any cycles before we start using the graph.
|
|
|
|
/// Unfortunately, we need to allow cycles for our [`IdentKind::Func`]
|
|
|
|
/// so we cannot use the typical algorithms in a straightforward manner.
|
|
|
|
///
|
|
|
|
/// We loop through all SCCs and check that they are not all functions. If
|
|
|
|
/// they are, we ignore the cycle, otherwise we will return an error.
|
2022-05-12 15:44:32 -04:00
|
|
|
fn check_cycles(asg: &Asg) -> SortResult<()> {
|
2021-10-12 09:42:09 -04:00
|
|
|
// While `tarjan_scc` does do a topological sort, it does not suit our
|
|
|
|
// needs because we need to filter out some allowed cycles. It would
|
|
|
|
// still be possible to use this, but we also need to only check nodes
|
|
|
|
// that are attached to our "roots". We are doing our own sort and as of
|
|
|
|
// the initial writing, this does not have a significant performance
|
|
|
|
// impact.
|
|
|
|
let sccs = petgraph::algo::tarjan_scc(&asg.graph);
|
|
|
|
|
|
|
|
let cycles: Vec<_> = sccs
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|scc| {
|
|
|
|
// For single-node SCCs, we just need to make sure they are
|
|
|
|
// not neighbors with themselves.
|
|
|
|
if scc.len() == 1
|
|
|
|
&& !asg.graph.neighbors(scc[0]).any(|nx| nx == scc[0])
|
|
|
|
{
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let is_all_funcs = scc.iter().all(|nx| {
|
2022-05-11 16:38:59 -04:00
|
|
|
let ident = asg.get(*nx).expect("missing node");
|
tamer: Use `..` for tuple unimportant variant matches
Tbh, I was unaware that this was supported by tuple variants until reading
over the Rustc source code for something. (Which I had previously read, but
I must have missed it.)
This is more proper, in the sense that in a lot of cases we not only care
about how many values a tuple has, but if we explicitly match on them using
`_`, then any time we modify the number of values, it would _break_ any code
doing so. Using this method, we improve maintainability by not causing
breakages under those circumstances.
But, consequently, it's important that we use this only when we _really_
don't care and don't want to be notified by the compiler.
I did not use `..` as a prefix, even where supported, because the intent is
to append additional information to tuples. Consequently, I also used `..`
in places where no additional fields currently exist, since they may in the
future (e.g. introducing `Span` for `IdentObject`).
2021-10-15 12:28:59 -04:00
|
|
|
matches!(ident.kind(), Some(IdentKind::Func(..)))
|
2021-10-12 09:42:09 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
if is_all_funcs {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let cycles =
|
|
|
|
scc.iter().map(|nx| ObjectRef::from(*nx)).collect();
|
|
|
|
Some(cycles)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
if cycles.is_empty() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(SortError::Cycles(cycles))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Error during graph sorting.
|
|
|
|
///
|
|
|
|
/// These errors reflect barriers to meaningfully understanding the
|
|
|
|
/// properties of the data in the graph with respect to sorting.
|
|
|
|
/// It does not represent bad underlying data that does not affect the
|
|
|
|
/// sorting process.
|
|
|
|
#[derive(Debug, PartialEq)]
|
2022-01-14 10:21:49 -05:00
|
|
|
pub enum SortError {
|
2021-10-14 12:37:32 -04:00
|
|
|
/// Error while lowering into [`XmleSections`].
|
2021-10-12 12:14:24 -04:00
|
|
|
SectionsError(SectionsError),
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
/// The graph has a cyclic dependency.
|
2022-01-14 10:21:49 -05:00
|
|
|
Cycles(Vec<Vec<ObjectRef>>),
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
impl From<SectionsError> for SortError {
|
2021-10-12 12:14:24 -04:00
|
|
|
fn from(err: SectionsError) -> Self {
|
|
|
|
Self::SectionsError(err)
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
impl std::fmt::Display for SortError {
|
2021-10-12 09:42:09 -04:00
|
|
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
match self {
|
2021-10-12 12:14:24 -04:00
|
|
|
Self::SectionsError(err) => err.fmt(fmt),
|
2021-10-12 09:42:09 -04:00
|
|
|
Self::Cycles(_) => write!(fmt, "cyclic dependencies"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
impl std::error::Error for SortError {
|
2021-10-12 09:42:09 -04:00
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
2021-10-12 12:14:24 -04:00
|
|
|
None
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::*;
|
|
|
|
use crate::{
|
2021-11-04 16:12:15 -04:00
|
|
|
asg::{Dim, FragmentText, IdentObject, Source},
|
2021-10-14 12:37:32 -04:00
|
|
|
ld::xmle::{section::PushResult, Sections},
|
2021-11-04 13:20:38 -04:00
|
|
|
obj::xmlo::SymDtype,
|
2021-10-12 10:31:01 -04:00
|
|
|
sym::GlobalSymbolIntern,
|
2021-10-12 09:42:09 -04:00
|
|
|
};
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
/// Create a graph with the expected {ret,}map head/tail identifiers.
|
2022-05-12 15:44:32 -04:00
|
|
|
fn make_asg() -> Asg {
|
|
|
|
let mut asg = Asg::new();
|
2021-10-14 12:37:32 -04:00
|
|
|
|
|
|
|
let text = "dummy fragment".intern();
|
|
|
|
|
|
|
|
asg.declare(
|
|
|
|
st::L_MAP_UUUHEAD.into(),
|
|
|
|
IdentKind::MapHead,
|
|
|
|
Default::default(),
|
|
|
|
)
|
|
|
|
.and_then(|id| asg.set_fragment(id, text))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
asg.declare(
|
|
|
|
st::L_MAP_UUUTAIL.into(),
|
|
|
|
IdentKind::MapTail,
|
|
|
|
Default::default(),
|
|
|
|
)
|
|
|
|
.and_then(|id| asg.set_fragment(id, text))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
asg.declare(
|
|
|
|
st::L_RETMAP_UUUHEAD.into(),
|
|
|
|
IdentKind::RetMapHead,
|
|
|
|
Default::default(),
|
|
|
|
)
|
|
|
|
.and_then(|id| asg.set_fragment(id, text))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
asg.declare(
|
|
|
|
st::L_RETMAP_UUUTAIL.into(),
|
|
|
|
IdentKind::RetMapTail,
|
|
|
|
Default::default(),
|
|
|
|
)
|
|
|
|
.and_then(|id| asg.set_fragment(id, text))
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
asg
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
// We care only about the order of pushes, not the sections they end
|
|
|
|
// up in.
|
|
|
|
struct StubSections<'a> {
|
|
|
|
pushed: Vec<&'a IdentObject>,
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
impl<'a> XmleSections<'a> for StubSections<'a> {
|
|
|
|
fn push(&mut self, ident: &'a IdentObject) -> PushResult {
|
|
|
|
self.pushed.push(ident);
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
fn take_deps(&mut self) -> Vec<&'a IdentObject> {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
fn take_static(&mut self) -> Vec<SymbolId> {
|
|
|
|
unimplemented!()
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
fn take_map(&mut self) -> Vec<SymbolId> {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
fn take_map_froms(&mut self) -> fxhash::FxHashSet<SymbolId> {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
fn take_retmap(&mut self) -> Vec<SymbolId> {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
fn take_exec(&mut self) -> Vec<SymbolId> {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
}
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
|
|
|
|
|
|
|
// Add them in an unsorted order.
|
|
|
|
let adep = asg
|
|
|
|
.declare("adep".into(), IdentKind::Meta, Default::default())
|
|
|
|
.unwrap();
|
|
|
|
let a = asg
|
|
|
|
.declare("a".into(), IdentKind::Meta, Default::default())
|
|
|
|
.unwrap();
|
|
|
|
let adepdep = asg
|
|
|
|
.declare("adepdep".into(), IdentKind::Meta, Default::default())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
asg.add_dep(a, adep);
|
|
|
|
asg.add_dep(adep, adepdep);
|
|
|
|
|
|
|
|
let sections =
|
|
|
|
sort(&asg, &vec![a], StubSections { pushed: Vec::new() })?;
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
sections.pushed,
|
|
|
|
vec![
|
|
|
|
// Static head
|
|
|
|
asg.lookup(st::L_MAP_UUUHEAD.into())
|
|
|
|
.and_then(|id| asg.get(id)),
|
|
|
|
asg.lookup(st::L_RETMAP_UUUHEAD.into())
|
|
|
|
.and_then(|id| asg.get(id)),
|
|
|
|
// Post-order
|
|
|
|
asg.get(adepdep),
|
|
|
|
asg.get(adep),
|
|
|
|
asg.get(a),
|
|
|
|
// Static tail
|
|
|
|
asg.lookup(st::L_MAP_UUUTAIL.into())
|
|
|
|
.and_then(|id| asg.get(id)),
|
|
|
|
asg.lookup(st::L_RETMAP_UUUTAIL.into())
|
|
|
|
.and_then(|id| asg.get(id)),
|
|
|
|
]
|
|
|
|
.into_iter()
|
|
|
|
.collect::<Option<Vec<_>>>()
|
|
|
|
.unwrap()
|
|
|
|
);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_missing_node() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
match sort(&asg, &vec![sym_node], Sections::new()) {
|
2021-10-12 09:42:09 -04:00
|
|
|
Ok(_) => panic!("Unexpected success - dependency is not in graph"),
|
2021-10-12 12:14:24 -04:00
|
|
|
Err(SortError::SectionsError(SectionsError::UnresolvedObject(
|
|
|
|
_,
|
|
|
|
))) => (),
|
2021-10-12 10:31:01 -04:00
|
|
|
bad => {
|
|
|
|
panic!("Incorrect error result when dependency is not in graph: {:?}", bad)
|
2021-10-12 09:42:09 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_no_roots_same_as_empty_graph() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg_nonempty_no_roots = make_asg();
|
|
|
|
|
|
|
|
// "empty" (it has the head/tail {ret,}map objects)
|
|
|
|
let asg_empty = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg_nonempty_no_roots.add_dep_lookup(sym, dep);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
assert_eq!(
|
|
|
|
sort(&asg_nonempty_no_roots, &vec![], Sections::new()),
|
|
|
|
sort(&asg_empty, &vec![], Sections::new())
|
|
|
|
);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_simple_cycle() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let dep_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
dep,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
|
|
|
let (_, _) = asg.add_dep_lookup(dep, sym);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
let expected: Vec<Vec<ObjectRef>> =
|
2021-10-12 09:42:09 -04:00
|
|
|
vec![vec![dep_node.into(), sym_node.into()]];
|
|
|
|
match result {
|
|
|
|
Ok(_) => panic!("sort did not detect cycle"),
|
|
|
|
Err(SortError::Cycles(scc)) => assert_eq!(expected, scc),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_two_simple_cycles() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let sym2 = "sym2".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
let dep2 = "dep2".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym2_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym2,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let dep_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
dep,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let dep2_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
dep2,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(dep_node, FragmentText::from("baz"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(dep2_node, FragmentText::from("huh"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
|
|
|
let (_, _) = asg.add_dep_lookup(dep, sym);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym2, dep2);
|
|
|
|
let (_, _) = asg.add_dep_lookup(dep2, sym2);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
let expected: Vec<Vec<ObjectRef>> = vec![
|
2021-10-12 09:42:09 -04:00
|
|
|
vec![dep_node.into(), sym_node.into()],
|
|
|
|
vec![dep2_node.into(), sym2_node.into()],
|
|
|
|
];
|
|
|
|
match result {
|
|
|
|
Ok(_) => panic!("sort did not detect cycle"),
|
|
|
|
Err(SortError::Cycles(scc)) => assert_eq!(expected, scc),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_no_cycle_with_edge_to_same_node() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let dep_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
dep,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
match result {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_cycle_with_a_few_steps() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym1 = "sym1".intern();
|
|
|
|
let sym2 = "sym2".intern();
|
|
|
|
let sym3 = "sym3".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym1_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym1,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym2_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym2,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym3_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym3,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
let expected: Vec<Vec<ObjectRef>> =
|
2021-10-12 09:42:09 -04:00
|
|
|
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
|
|
|
match result {
|
|
|
|
Ok(_) => panic!("sort did not detect cycle"),
|
|
|
|
Err(SortError::Cycles(scc)) => assert_eq!(expected, scc),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn graph_sort_cyclic_function_with_non_function_with_a_few_steps(
|
2022-01-14 10:21:49 -05:00
|
|
|
) -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym1 = "sym1".intern();
|
|
|
|
let sym2 = "sym2".intern();
|
|
|
|
let sym3 = "sym3".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym1_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym1,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym2_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym2,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym3_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym3,
|
|
|
|
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
let expected: Vec<Vec<ObjectRef>> =
|
2021-10-12 09:42:09 -04:00
|
|
|
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
|
|
|
match result {
|
|
|
|
Ok(_) => panic!("sort did not detect cycle"),
|
|
|
|
Err(SortError::Cycles(scc)) => assert_eq!(expected, scc),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_cyclic_bookended_by_functions() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym1 = "sym1".intern();
|
|
|
|
let sym2 = "sym2".intern();
|
|
|
|
let sym3 = "sym3".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym1_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym1,
|
|
|
|
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym2_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym2,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym3_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym3,
|
|
|
|
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
let expected: Vec<Vec<ObjectRef>> =
|
2021-10-12 09:42:09 -04:00
|
|
|
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
|
|
|
match result {
|
|
|
|
Ok(_) => panic!("sort did not detect cycle"),
|
|
|
|
Err(SortError::Cycles(scc)) => assert_eq!(expected, scc),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_cyclic_function_ignored() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym,
|
|
|
|
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let dep_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
dep,
|
|
|
|
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
|
|
|
let (_, _) = asg.add_dep_lookup(dep, sym);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
match result {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_cyclic_function_is_bookended() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym1 = "sym1".intern();
|
|
|
|
let sym2 = "sym2".intern();
|
|
|
|
let sym3 = "sym3".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym1_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym1,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym2_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym2,
|
|
|
|
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym3_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym3,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
|
|
|
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2022-01-14 10:21:49 -05:00
|
|
|
let expected: Vec<Vec<ObjectRef>> =
|
2021-10-12 09:42:09 -04:00
|
|
|
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
|
|
|
match result {
|
|
|
|
Ok(_) => panic!("sort did not detect cycle"),
|
|
|
|
Err(SortError::Cycles(scc)) => assert_eq!(expected, scc),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2022-01-14 10:21:49 -05:00
|
|
|
fn graph_sort_ignore_non_linked() -> SortResult<()> {
|
2021-10-14 12:37:32 -04:00
|
|
|
let mut asg = make_asg();
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
let sym = "sym".intern();
|
|
|
|
let dep = "dep".intern();
|
|
|
|
let ignored = "ignored".intern();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let sym_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
sym,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let dep_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
dep,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let ignored_node = asg
|
2021-10-12 09:42:09 -04:00
|
|
|
.declare(
|
|
|
|
ignored,
|
|
|
|
IdentKind::Tpl,
|
|
|
|
Source {
|
|
|
|
virtual_: true,
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
2021-10-14 12:37:32 -04:00
|
|
|
asg.set_fragment(ignored_node, FragmentText::from("baz"))
|
2021-10-12 09:42:09 -04:00
|
|
|
.unwrap();
|
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let (_, _) = asg.add_dep_lookup(sym, dep);
|
|
|
|
let (_, _) = asg.add_dep_lookup(ignored, sym);
|
2021-10-12 09:42:09 -04:00
|
|
|
|
2021-10-14 12:37:32 -04:00
|
|
|
let result = sort(&asg, &vec![sym_node], Sections::new());
|
2021-10-12 09:42:09 -04:00
|
|
|
|
|
|
|
match result {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => panic!("unexpected error: {}", e),
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|