tamer: ld::xmle: Narrow Sections types
This moves the logic that sorts identifiers into sections into Sections itself, and introduces XmleSections to allow for mocking for testing. This then allows us to narrow the types significantly, eliminating some runtime checks. The types can be narrowed further, but I'll be limiting the work I'll be doing now; this'll be inevitably addressed as we use the ASG for the compiler. This also handles moving Sections tests, which was a TODO from the previous commit. DEV-10859main
parent
ea11cf1416
commit
f055cb77c2
|
@ -27,7 +27,7 @@ use test::Bencher;
|
|||
use tamer::ir::asg::{
|
||||
Asg, DataType, DefaultAsg, IdentKind, IdentObject, Source,
|
||||
};
|
||||
use tamer::ld::xmle::lower::sort;
|
||||
use tamer::ld::xmle::{lower::sort, Sections};
|
||||
use tamer::sym::{GlobalSymbolIntern, SymbolId};
|
||||
|
||||
type TestAsg = DefaultAsg<IdentObject>;
|
||||
|
@ -61,7 +61,7 @@ fn sort_1_with_1_000_existing_supernode(bench: &mut Bencher) {
|
|||
});
|
||||
|
||||
bench.iter(|| {
|
||||
drop(sort(&sut, &[root]));
|
||||
drop(sort(&sut, &[root], Sections::new()));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,6 @@ fn sort_1_with_1_000_existing_one_edge_per_node_one_path(bench: &mut Bencher) {
|
|||
let root = orefs[0];
|
||||
|
||||
bench.iter(|| {
|
||||
drop(sort(&sut, &[root]));
|
||||
drop(sort(&sut, &[root], Sections::new()));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -23,10 +23,7 @@
|
|||
use super::xmle::{
|
||||
lower::{sort, SortError},
|
||||
xir::lower_iter,
|
||||
Sections,
|
||||
};
|
||||
use crate::fs::{
|
||||
Filesystem, FsCanonicalizer, PathFile, VisitOnceFile, VisitOnceFilesystem,
|
||||
XmleSections,
|
||||
};
|
||||
use crate::global;
|
||||
use crate::ir::asg::{Asg, DefaultAsg, IdentObject, IdentObjectData};
|
||||
|
@ -34,6 +31,13 @@ use crate::ir::xir::writer::XmlWriter;
|
|||
use crate::obj::xmlo::{AsgBuilder, AsgBuilderState, XmloReader};
|
||||
use crate::sym::SymbolId;
|
||||
use crate::sym::{GlobalSymbolIntern, GlobalSymbolResolve};
|
||||
use crate::{
|
||||
fs::{
|
||||
Filesystem, FsCanonicalizer, PathFile, VisitOnceFile,
|
||||
VisitOnceFilesystem,
|
||||
},
|
||||
ld::xmle::Sections,
|
||||
};
|
||||
use fxhash::FxBuildHasher;
|
||||
use petgraph_graphml::GraphMl;
|
||||
use std::error::Error;
|
||||
|
@ -72,7 +76,7 @@ pub fn xmle(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
|
|||
.filter_map(|sym| depgraph.lookup(sym)),
|
||||
);
|
||||
|
||||
let mut sorted = match sort(&depgraph, &roots) {
|
||||
let sorted = match sort(&depgraph, &roots, Sections::new()) {
|
||||
Ok(sections) => sections,
|
||||
Err(SortError::Cycles(cycles)) => {
|
||||
let msg: Vec<String> = cycles
|
||||
|
@ -105,8 +109,7 @@ pub fn xmle(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
|
|||
};
|
||||
|
||||
output_xmle(
|
||||
&depgraph,
|
||||
&mut sorted,
|
||||
sorted,
|
||||
name.expect("missing root package name"),
|
||||
relroot.expect("missing root package relroot"),
|
||||
output,
|
||||
|
@ -200,46 +203,16 @@ fn load_xmlo<'a, P: AsRef<Path>>(
|
|||
Ok(state)
|
||||
}
|
||||
|
||||
fn get_ident<'a>(
|
||||
depgraph: &'a LinkerAsg,
|
||||
name: SymbolId<global::ProgSymSize>,
|
||||
) -> Result<&'a IdentObject, String> {
|
||||
depgraph
|
||||
.lookup(name)
|
||||
.and_then(|id| depgraph.get(id))
|
||||
.ok_or(format!("missing identifier: {}", name.lookup_str()))
|
||||
}
|
||||
|
||||
fn output_xmle<'a>(
|
||||
depgraph: &'a LinkerAsg,
|
||||
sorted: &mut Sections<'a>,
|
||||
fn output_xmle<'a, S: XmleSections<'a>>(
|
||||
sorted: S,
|
||||
name: SymbolId,
|
||||
relroot: SymbolId,
|
||||
output: &str,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
if !sorted.map.is_empty() {
|
||||
sorted
|
||||
.map
|
||||
.set_head(get_ident(depgraph, ":map:___head".intern())?);
|
||||
sorted
|
||||
.map
|
||||
.set_tail(get_ident(depgraph, ":map:___tail".intern())?);
|
||||
}
|
||||
|
||||
if !sorted.retmap.is_empty() {
|
||||
sorted
|
||||
.retmap
|
||||
.set_head(get_ident(depgraph, ":retmap:___head".intern())?);
|
||||
sorted
|
||||
.retmap
|
||||
.set_tail(get_ident(depgraph, ":retmap:___tail".intern())?);
|
||||
}
|
||||
|
||||
let file = fs::File::create(output)?;
|
||||
let mut buf = BufWriter::new(file);
|
||||
|
||||
lower_iter(&sorted, name, relroot).write(&mut buf, Default::default())?;
|
||||
|
||||
lower_iter(sorted, name, relroot).write(&mut buf, Default::default())?;
|
||||
buf.flush()?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -17,33 +17,37 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Lowering of the [ASG](crate::ir::asg) into `xmle` [`Sections`].
|
||||
//! Lowering of the [ASG](crate::ir::asg) into `xmle` [`XmleSections`].
|
||||
//!
|
||||
//! See the [parent module](super) for more information.
|
||||
|
||||
use super::{section::SectionsError, Sections};
|
||||
use crate::ir::asg::{
|
||||
Asg, BaseAsg, IdentKind, IdentObject, IdentObjectData, IndexType, ObjectRef,
|
||||
use super::section::{SectionsError, XmleSections};
|
||||
use crate::{
|
||||
ir::asg::{
|
||||
Asg, BaseAsg, IdentKind, IdentObject, IdentObjectData, IndexType,
|
||||
ObjectRef,
|
||||
},
|
||||
sym::{st, GlobalSymbolResolve, SymbolId},
|
||||
};
|
||||
use petgraph::visit::DfsPostOrder;
|
||||
|
||||
// Result of [`sort`].
|
||||
pub type SortResult<T, Ix> = Result<T, SortError<Ix>>;
|
||||
|
||||
/// Lower ASG into [`Sections`] by sorting relocatable text fragments.
|
||||
/// Lower ASG into [`XmleSections`] by ordering relocatable text fragments.
|
||||
///
|
||||
/// This performs the equivalent of a topological sort,
|
||||
/// although function cycles are permitted.
|
||||
/// The actual operation performed is a post-order depth-first traversal.
|
||||
pub fn sort<'a, Ix>(
|
||||
pub fn sort<'a, Ix, S: XmleSections<'a>>(
|
||||
asg: &'a BaseAsg<IdentObject, Ix>,
|
||||
roots: &[ObjectRef<Ix>],
|
||||
) -> SortResult<Sections<'a>, Ix>
|
||||
mut dest: S,
|
||||
) -> SortResult<S, Ix>
|
||||
where
|
||||
Ix: IndexType,
|
||||
S: XmleSections<'a>,
|
||||
{
|
||||
let mut deps = Sections::new();
|
||||
|
||||
// TODO: we should check for cycles as we sort (as the POC did).
|
||||
check_cycles(asg)?;
|
||||
|
||||
|
@ -54,12 +58,40 @@ where
|
|||
dfs.stack.push((*index).into());
|
||||
}
|
||||
|
||||
// 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))?;
|
||||
|
||||
while let Some(index) = dfs.next(&asg.graph) {
|
||||
let ident = asg.get(index).expect("missing node");
|
||||
deps.push(ident)?;
|
||||
dest.push(ident)?;
|
||||
}
|
||||
|
||||
Ok(deps)
|
||||
dest.push(get_ident(asg, st::L_MAP_UUUTAIL))?;
|
||||
dest.push(get_ident(asg, st::L_RETMAP_UUUTAIL))?;
|
||||
|
||||
Ok(dest)
|
||||
}
|
||||
|
||||
fn get_ident<'a, Ix, S>(
|
||||
depgraph: &'a BaseAsg<IdentObject, Ix>,
|
||||
name: S,
|
||||
) -> &'a IdentObject
|
||||
where
|
||||
Ix: IndexType,
|
||||
S: Into<SymbolId>,
|
||||
{
|
||||
let sym = name.into();
|
||||
|
||||
depgraph
|
||||
.lookup(sym)
|
||||
.and_then(|id| depgraph.get(id))
|
||||
.expect(&format!(
|
||||
"missing internal identifier: {}",
|
||||
sym.lookup_str()
|
||||
))
|
||||
}
|
||||
|
||||
/// Check graph for cycles
|
||||
|
@ -123,7 +155,7 @@ where
|
|||
/// sorting process.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SortError<Ix: IndexType> {
|
||||
/// Error while building [`Sections`].
|
||||
/// Error while lowering into [`XmleSections`].
|
||||
SectionsError(SectionsError),
|
||||
|
||||
/// The graph has a cyclic dependency.
|
||||
|
@ -156,95 +188,148 @@ mod test {
|
|||
use super::*;
|
||||
use crate::{
|
||||
ir::{
|
||||
asg::{DataType, Dim, FragmentText, IdentObject, Source},
|
||||
asg::{Dim, FragmentText, IdentObject, Source},
|
||||
legacyir::SymDtype,
|
||||
},
|
||||
ld::xmle::{section::PushResult, Sections},
|
||||
sym::GlobalSymbolIntern,
|
||||
};
|
||||
|
||||
type Sut = BaseAsg<IdentObject, u16>;
|
||||
type TestAsg = BaseAsg<IdentObject, u16>;
|
||||
|
||||
macro_rules! assert_section_sym {
|
||||
( $iterable:expr, $s:ident ) => {{
|
||||
let mut pos = 0;
|
||||
/// Create a graph with the expected {ret,}map head/tail identifiers.
|
||||
fn make_asg() -> TestAsg {
|
||||
let mut asg = TestAsg::new();
|
||||
|
||||
for obj in $iterable.iter() {
|
||||
let sym = obj.name().expect("missing object");
|
||||
assert_eq!($s.get(pos).map(|s| *s), Some(sym));
|
||||
let text = "dummy fragment".intern();
|
||||
|
||||
pos = pos + 1;
|
||||
}
|
||||
asg.declare(
|
||||
st::L_MAP_UUUHEAD.into(),
|
||||
IdentKind::MapHead,
|
||||
Default::default(),
|
||||
)
|
||||
.and_then(|id| asg.set_fragment(id, text))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(pos, $s.len());
|
||||
};};
|
||||
}
|
||||
asg.declare(
|
||||
st::L_MAP_UUUTAIL.into(),
|
||||
IdentKind::MapTail,
|
||||
Default::default(),
|
||||
)
|
||||
.and_then(|id| asg.set_fragment(id, text))
|
||||
.unwrap();
|
||||
|
||||
macro_rules! add_syms {
|
||||
($sut:ident, $base:expr, {$($dest:ident <- $name:ident: $kind:expr,)*}) => {
|
||||
$(
|
||||
let sym = stringify!($name).intern();
|
||||
asg.declare(
|
||||
st::L_RETMAP_UUUHEAD.into(),
|
||||
IdentKind::RetMapHead,
|
||||
Default::default(),
|
||||
)
|
||||
.and_then(|id| asg.set_fragment(id, text))
|
||||
.unwrap();
|
||||
|
||||
$sut.declare(sym, $kind, Source::default()).unwrap();
|
||||
let (_, _) = $sut.add_dep_lookup($base, sym);
|
||||
asg.declare(
|
||||
st::L_RETMAP_UUUTAIL.into(),
|
||||
IdentKind::RetMapTail,
|
||||
Default::default(),
|
||||
)
|
||||
.and_then(|id| asg.set_fragment(id, text))
|
||||
.unwrap();
|
||||
|
||||
$dest.push(sym);
|
||||
)*
|
||||
};
|
||||
asg
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graph_sort() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
// We care only about the order of pushes, not the sections they end
|
||||
// up in.
|
||||
struct StubSections<'a> {
|
||||
pushed: Vec<&'a IdentObject>,
|
||||
}
|
||||
|
||||
let mut st = vec![];
|
||||
let mut map = vec![];
|
||||
let mut retmap = vec![];
|
||||
impl<'a> XmleSections<'a> for StubSections<'a> {
|
||||
fn push(&mut self, ident: &'a IdentObject) -> PushResult {
|
||||
self.pushed.push(ident);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let base = "sym1".intern();
|
||||
let base_node = sut
|
||||
.declare(base, IdentKind::Map, Source::default())
|
||||
fn take_deps(&mut self) -> Vec<&'a IdentObject> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn take_static(&mut self) -> Vec<SymbolId> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn take_map(&mut self) -> Vec<SymbolId> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn take_map_froms(&mut self) -> fxhash::FxHashSet<SymbolId> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn take_retmap(&mut self) -> Vec<SymbolId> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn take_exec(&mut self) -> Vec<SymbolId> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
add_syms!(sut, base, {
|
||||
st <- meta1: IdentKind::Meta,
|
||||
st <- work1: IdentKind::Worksheet,
|
||||
st <- const1: IdentKind::Const(Dim::from_u8(0), DataType::Float),
|
||||
map <- map1: IdentKind::MapHead,
|
||||
map <- map2: IdentKind::Map,
|
||||
map <- map3: IdentKind::MapTail,
|
||||
retmap <- retmap1: IdentKind::RetMapHead,
|
||||
retmap <- retmap2: IdentKind::RetMap,
|
||||
retmap <- retmap3: IdentKind::RetMapTail,
|
||||
retmap <- retmap4: IdentKind::RetMapTail,
|
||||
retmap <- retmap5: IdentKind::RetMap,
|
||||
map <- map4: IdentKind::MapHead,
|
||||
map <- map5: IdentKind::Map,
|
||||
st <- meta2: IdentKind::Meta,
|
||||
st <- work2: IdentKind::Worksheet,
|
||||
map <- map6: IdentKind::MapTail,
|
||||
retmap <- retmap6: IdentKind::RetMapHead,
|
||||
st <- const2: IdentKind::Const(Dim::from_u8(2), DataType::Float),
|
||||
});
|
||||
asg.add_dep(a, adep);
|
||||
asg.add_dep(adep, adepdep);
|
||||
|
||||
map.push(base);
|
||||
let sections =
|
||||
sort(&asg, &vec![a], StubSections { pushed: Vec::new() })?;
|
||||
|
||||
let sections = sort(&sut, &vec![base_node])?;
|
||||
|
||||
assert_section_sym!(sections.st, st);
|
||||
assert_section_sym!(sections.map, map);
|
||||
assert_section_sym!(sections.retmap, retmap);
|
||||
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()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graph_sort_missing_node() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let dep = "dep".intern();
|
||||
|
||||
let sym_node = sut
|
||||
let sym_node = asg
|
||||
.declare(
|
||||
sym,
|
||||
IdentKind::Tpl,
|
||||
|
@ -255,12 +340,12 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = asg.add_dep_lookup(sym, dep);
|
||||
|
||||
match sort(&sut, &vec![sym_node]) {
|
||||
match sort(&asg, &vec![sym_node], Sections::new()) {
|
||||
Ok(_) => panic!("Unexpected success - dependency is not in graph"),
|
||||
Err(SortError::SectionsError(SectionsError::UnresolvedObject(
|
||||
_,
|
||||
|
@ -274,29 +359,33 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn graph_sort_no_roots() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
fn graph_sort_no_roots_same_as_empty_graph() -> SortResult<(), u16> {
|
||||
let mut asg_nonempty_no_roots = make_asg();
|
||||
|
||||
// "empty" (it has the head/tail {ret,}map objects)
|
||||
let asg_empty = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let dep = "dep".intern();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
asg_nonempty_no_roots.add_dep_lookup(sym, dep);
|
||||
|
||||
let sections = sort(&sut, &vec![])?;
|
||||
|
||||
assert_eq!(Sections::new(), sections);
|
||||
assert_eq!(
|
||||
sort(&asg_nonempty_no_roots, &vec![], Sections::new()),
|
||||
sort(&asg_empty, &vec![], Sections::new())
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graph_sort_simple_cycle() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let dep = "dep".intern();
|
||||
|
||||
let sym_node = sut
|
||||
let sym_node = asg
|
||||
.declare(
|
||||
sym,
|
||||
IdentKind::Tpl,
|
||||
|
@ -307,7 +396,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let dep_node = sut
|
||||
let dep_node = asg
|
||||
.declare(
|
||||
dep,
|
||||
IdentKind::Tpl,
|
||||
|
@ -318,15 +407,15 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = sut.add_dep_lookup(dep, sym);
|
||||
let (_, _) = asg.add_dep_lookup(sym, dep);
|
||||
let (_, _) = asg.add_dep_lookup(dep, sym);
|
||||
|
||||
let result = sort(&sut, &vec![sym_node]);
|
||||
let result = sort(&asg, &vec![sym_node], Sections::new());
|
||||
|
||||
let expected: Vec<Vec<ObjectRef<u16>>> =
|
||||
vec![vec![dep_node.into(), sym_node.into()]];
|
||||
|
@ -341,14 +430,14 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_two_simple_cycles() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let sym2 = "sym2".intern();
|
||||
let dep = "dep".intern();
|
||||
let dep2 = "dep2".intern();
|
||||
|
||||
let sym_node = sut
|
||||
let sym_node = asg
|
||||
.declare(
|
||||
sym,
|
||||
IdentKind::Tpl,
|
||||
|
@ -359,7 +448,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym2_node = sut
|
||||
let sym2_node = asg
|
||||
.declare(
|
||||
sym2,
|
||||
IdentKind::Tpl,
|
||||
|
@ -370,7 +459,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let dep_node = sut
|
||||
let dep_node = asg
|
||||
.declare(
|
||||
dep,
|
||||
IdentKind::Tpl,
|
||||
|
@ -381,7 +470,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let dep2_node = sut
|
||||
let dep2_node = asg
|
||||
.declare(
|
||||
dep2,
|
||||
IdentKind::Tpl,
|
||||
|
@ -392,21 +481,21 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
sut.set_fragment(dep_node, FragmentText::from("baz"))
|
||||
asg.set_fragment(dep_node, FragmentText::from("baz"))
|
||||
.unwrap();
|
||||
sut.set_fragment(dep2_node, FragmentText::from("huh"))
|
||||
asg.set_fragment(dep2_node, FragmentText::from("huh"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = sut.add_dep_lookup(dep, sym);
|
||||
let (_, _) = sut.add_dep_lookup(sym2, dep2);
|
||||
let (_, _) = sut.add_dep_lookup(dep2, sym2);
|
||||
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);
|
||||
|
||||
let result = sort(&sut, &vec![sym_node]);
|
||||
let result = sort(&asg, &vec![sym_node], Sections::new());
|
||||
|
||||
let expected: Vec<Vec<ObjectRef<u16>>> = vec![
|
||||
vec![dep_node.into(), sym_node.into()],
|
||||
|
@ -423,12 +512,12 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_no_cycle_with_edge_to_same_node() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let dep = "dep".intern();
|
||||
|
||||
let sym_node = sut
|
||||
let sym_node = asg
|
||||
.declare(
|
||||
sym,
|
||||
IdentKind::Tpl,
|
||||
|
@ -439,7 +528,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let dep_node = sut
|
||||
let dep_node = asg
|
||||
.declare(
|
||||
dep,
|
||||
IdentKind::Tpl,
|
||||
|
@ -450,15 +539,15 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = asg.add_dep_lookup(sym, dep);
|
||||
let (_, _) = asg.add_dep_lookup(sym, dep);
|
||||
|
||||
let result = sort(&sut, &vec![sym_node]);
|
||||
let result = sort(&asg, &vec![sym_node], Sections::new());
|
||||
|
||||
match result {
|
||||
Ok(_) => (),
|
||||
|
@ -470,13 +559,13 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_cycle_with_a_few_steps() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym1 = "sym1".intern();
|
||||
let sym2 = "sym2".intern();
|
||||
let sym3 = "sym3".intern();
|
||||
|
||||
let sym1_node = sut
|
||||
let sym1_node = asg
|
||||
.declare(
|
||||
sym1,
|
||||
IdentKind::Tpl,
|
||||
|
@ -487,7 +576,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym2_node = sut
|
||||
let sym2_node = asg
|
||||
.declare(
|
||||
sym2,
|
||||
IdentKind::Tpl,
|
||||
|
@ -498,7 +587,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym3_node = sut
|
||||
let sym3_node = asg
|
||||
.declare(
|
||||
sym3,
|
||||
IdentKind::Tpl,
|
||||
|
@ -509,18 +598,18 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = sut.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = sut.add_dep_lookup(sym3, sym1);
|
||||
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
||||
|
||||
let result = sort(&sut, &vec![sym1_node]);
|
||||
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
||||
|
||||
let expected: Vec<Vec<ObjectRef<u16>>> =
|
||||
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
||||
|
@ -536,13 +625,13 @@ mod test {
|
|||
#[test]
|
||||
fn graph_sort_cyclic_function_with_non_function_with_a_few_steps(
|
||||
) -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym1 = "sym1".intern();
|
||||
let sym2 = "sym2".intern();
|
||||
let sym3 = "sym3".intern();
|
||||
|
||||
let sym1_node = sut
|
||||
let sym1_node = asg
|
||||
.declare(
|
||||
sym1,
|
||||
IdentKind::Tpl,
|
||||
|
@ -553,7 +642,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym2_node = sut
|
||||
let sym2_node = asg
|
||||
.declare(
|
||||
sym2,
|
||||
IdentKind::Tpl,
|
||||
|
@ -564,7 +653,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym3_node = sut
|
||||
let sym3_node = asg
|
||||
.declare(
|
||||
sym3,
|
||||
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
||||
|
@ -575,18 +664,18 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = sut.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = sut.add_dep_lookup(sym3, sym1);
|
||||
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
||||
|
||||
let result = sort(&sut, &vec![sym1_node]);
|
||||
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
||||
|
||||
let expected: Vec<Vec<ObjectRef<u16>>> =
|
||||
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
||||
|
@ -601,13 +690,13 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_cyclic_bookended_by_functions() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym1 = "sym1".intern();
|
||||
let sym2 = "sym2".intern();
|
||||
let sym3 = "sym3".intern();
|
||||
|
||||
let sym1_node = sut
|
||||
let sym1_node = asg
|
||||
.declare(
|
||||
sym1,
|
||||
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
||||
|
@ -618,7 +707,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym2_node = sut
|
||||
let sym2_node = asg
|
||||
.declare(
|
||||
sym2,
|
||||
IdentKind::Tpl,
|
||||
|
@ -629,7 +718,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym3_node = sut
|
||||
let sym3_node = asg
|
||||
.declare(
|
||||
sym3,
|
||||
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
||||
|
@ -640,18 +729,18 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = sut.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = sut.add_dep_lookup(sym3, sym1);
|
||||
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
||||
|
||||
let result = sort(&sut, &vec![sym1_node]);
|
||||
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
||||
|
||||
let expected: Vec<Vec<ObjectRef<u16>>> =
|
||||
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
||||
|
@ -666,12 +755,12 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_cyclic_function_ignored() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let dep = "dep".intern();
|
||||
|
||||
let sym_node = sut
|
||||
let sym_node = asg
|
||||
.declare(
|
||||
sym,
|
||||
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
||||
|
@ -682,7 +771,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let dep_node = sut
|
||||
let dep_node = asg
|
||||
.declare(
|
||||
dep,
|
||||
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
||||
|
@ -693,15 +782,15 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = sut.add_dep_lookup(dep, sym);
|
||||
let (_, _) = asg.add_dep_lookup(sym, dep);
|
||||
let (_, _) = asg.add_dep_lookup(dep, sym);
|
||||
|
||||
let result = sort(&sut, &vec![sym_node]);
|
||||
let result = sort(&asg, &vec![sym_node], Sections::new());
|
||||
|
||||
match result {
|
||||
Ok(_) => (),
|
||||
|
@ -713,13 +802,13 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_cyclic_function_is_bookended() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym1 = "sym1".intern();
|
||||
let sym2 = "sym2".intern();
|
||||
let sym3 = "sym3".intern();
|
||||
|
||||
let sym1_node = sut
|
||||
let sym1_node = asg
|
||||
.declare(
|
||||
sym1,
|
||||
IdentKind::Tpl,
|
||||
|
@ -730,7 +819,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym2_node = sut
|
||||
let sym2_node = asg
|
||||
.declare(
|
||||
sym2,
|
||||
IdentKind::Func(Dim::default(), SymDtype::Empty),
|
||||
|
@ -741,7 +830,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let sym3_node = sut
|
||||
let sym3_node = asg
|
||||
.declare(
|
||||
sym3,
|
||||
IdentKind::Tpl,
|
||||
|
@ -752,18 +841,18 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym1_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(sym2_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
sut.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
asg.set_fragment(sym3_node, FragmentText::from("baz"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = sut.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = sut.add_dep_lookup(sym3, sym1);
|
||||
let (_, _) = asg.add_dep_lookup(sym1, sym2);
|
||||
let (_, _) = asg.add_dep_lookup(sym2, sym3);
|
||||
let (_, _) = asg.add_dep_lookup(sym3, sym1);
|
||||
|
||||
let result = sort(&sut, &vec![sym1_node]);
|
||||
let result = sort(&asg, &vec![sym1_node], Sections::new());
|
||||
|
||||
let expected: Vec<Vec<ObjectRef<u16>>> =
|
||||
vec![vec![sym3_node.into(), sym2_node.into(), sym1_node.into()]];
|
||||
|
@ -778,13 +867,13 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn graph_sort_ignore_non_linked() -> SortResult<(), u16> {
|
||||
let mut sut = Sut::new();
|
||||
let mut asg = make_asg();
|
||||
|
||||
let sym = "sym".intern();
|
||||
let dep = "dep".intern();
|
||||
let ignored = "ignored".intern();
|
||||
|
||||
let sym_node = sut
|
||||
let sym_node = asg
|
||||
.declare(
|
||||
sym,
|
||||
IdentKind::Tpl,
|
||||
|
@ -795,7 +884,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let dep_node = sut
|
||||
let dep_node = asg
|
||||
.declare(
|
||||
dep,
|
||||
IdentKind::Tpl,
|
||||
|
@ -806,7 +895,7 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let ignored_node = sut
|
||||
let ignored_node = asg
|
||||
.declare(
|
||||
ignored,
|
||||
IdentKind::Tpl,
|
||||
|
@ -817,17 +906,17 @@ mod test {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
sut.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
asg.set_fragment(sym_node, FragmentText::from("foo"))
|
||||
.unwrap();
|
||||
sut.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
asg.set_fragment(dep_node, FragmentText::from("bar"))
|
||||
.unwrap();
|
||||
sut.set_fragment(ignored_node, FragmentText::from("baz"))
|
||||
asg.set_fragment(ignored_node, FragmentText::from("baz"))
|
||||
.unwrap();
|
||||
|
||||
let (_, _) = sut.add_dep_lookup(sym, dep);
|
||||
let (_, _) = sut.add_dep_lookup(ignored, sym);
|
||||
let (_, _) = asg.add_dep_lookup(sym, dep);
|
||||
let (_, _) = asg.add_dep_lookup(ignored, sym);
|
||||
|
||||
let result = sort(&sut, &vec![sym_node]);
|
||||
let result = sort(&asg, &vec![sym_node], Sections::new());
|
||||
|
||||
match result {
|
||||
Ok(_) => (),
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
//! <l:static>
|
||||
//! function func_min(args,min1,min2) {return min1;}
|
||||
//! </l:static>
|
||||
//! <l:exec>C['CMP_OP_EQ'] = 1;</l:exec>
|
||||
//! <l:exec>A['foo']=E(A['bar']);</l:exec>
|
||||
//! </package>
|
||||
//! ```
|
||||
|
||||
|
@ -74,4 +74,4 @@ mod section;
|
|||
pub mod lower;
|
||||
pub mod xir;
|
||||
|
||||
pub use section::{Section, SectionIter, Sections, SectionsIter};
|
||||
pub use section::{Sections, XmleSections};
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
|
||||
//! Sections of a linked [`xmle`](super) object file.
|
||||
//!
|
||||
//! These sections are the result of [`sort`](super::lower::sort),
|
||||
//! An [`XmleSections`] object is responsible for placing provided
|
||||
//! identifiers into the appropriate section,
|
||||
//! but _it must be provided properly ordered data_.
|
||||
//! This ordering is the result of [`sort`](super::lower::sort),
|
||||
//! which places the relocatable object code fragments in the order
|
||||
//! necessary for execution.
|
||||
|
||||
|
@ -28,110 +31,40 @@ use crate::ir::asg::{
|
|||
};
|
||||
use crate::sym::{GlobalSymbolResolve, SymbolId};
|
||||
use fxhash::FxHashSet;
|
||||
use std::collections::hash_set;
|
||||
use std::iter::Chain;
|
||||
use std::option;
|
||||
use std::mem::take;
|
||||
use std::result::Result;
|
||||
use std::slice::Iter;
|
||||
|
||||
/// A section of an [object file](crate::obj).
|
||||
///
|
||||
/// Most sections will only need a `body`, but some innlude `head` and `tail`
|
||||
/// information. Rather than dealing with those differently, each `Section`
|
||||
/// will have a `head` and `tail` that are empty by default.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Section<'a> {
|
||||
head: Option<&'a IdentObject>,
|
||||
body: Vec<&'a IdentObject>,
|
||||
tail: Option<&'a IdentObject>,
|
||||
pub type PushResult<T = ()> = Result<T, SectionsError>;
|
||||
|
||||
pub trait XmleSections<'a> {
|
||||
fn push(&mut self, ident: &'a IdentObject) -> PushResult;
|
||||
|
||||
fn take_deps(&mut self) -> Vec<&'a IdentObject>;
|
||||
|
||||
fn take_static(&mut self) -> Vec<SymbolId>;
|
||||
|
||||
fn take_map(&mut self) -> Vec<SymbolId>;
|
||||
|
||||
fn take_map_froms(&mut self) -> FxHashSet<SymbolId>;
|
||||
|
||||
fn take_retmap(&mut self) -> Vec<SymbolId>;
|
||||
|
||||
fn take_exec(&mut self) -> Vec<SymbolId>;
|
||||
}
|
||||
|
||||
impl<'a> Section<'a> {
|
||||
/// New empty section.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
head: None,
|
||||
body: Vec::new(),
|
||||
tail: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the `Section` is empty
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.body.len() == 0
|
||||
}
|
||||
|
||||
/// Push an `IdentObject` into a `Section`'s head
|
||||
#[inline]
|
||||
pub fn set_head(&mut self, obj: &'a IdentObject) {
|
||||
self.head.replace(obj);
|
||||
}
|
||||
|
||||
/// Push an `IdentObject` into a `Section`'s body
|
||||
#[inline]
|
||||
pub fn push_body(&mut self, obj: &'a IdentObject) {
|
||||
self.body.push(obj)
|
||||
}
|
||||
|
||||
/// Push an `IdentObject` into a `Section`'s tail
|
||||
#[inline]
|
||||
pub fn set_tail(&mut self, obj: &'a IdentObject) {
|
||||
self.tail.replace(obj);
|
||||
}
|
||||
|
||||
/// Construct a new iterator visiting each head, body, and tail object
|
||||
/// in order.
|
||||
#[inline]
|
||||
pub fn iter(&self) -> SectionIter {
|
||||
SectionIter(
|
||||
self.head
|
||||
.iter()
|
||||
.chain(self.body.iter())
|
||||
.chain(self.tail.iter()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterator over the head, body, and tail of a [`Section`].
|
||||
/// Sections of a linked `xmle` file.
|
||||
///
|
||||
/// This iterator should be created with [`Section::iter`].
|
||||
///
|
||||
/// This hides the complex iterator type from callers.
|
||||
pub struct SectionIter<'a>(
|
||||
Chain<
|
||||
Chain<option::Iter<'a, &'a IdentObject>, Iter<'a, &'a IdentObject>>,
|
||||
option::Iter<'a, &'a IdentObject>,
|
||||
>,
|
||||
);
|
||||
|
||||
impl<'a> Iterator for SectionIter<'a> {
|
||||
type Item = &'a IdentObject;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.0.next().map(|x| *x)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let (low, high) = self.0.size_hint();
|
||||
(low, high.map(|x| x + 2))
|
||||
}
|
||||
}
|
||||
|
||||
pub type PushResult = Result<(), SectionsError>;
|
||||
|
||||
/// ASG objects organized into logical sections.
|
||||
///
|
||||
/// These sections may not necessarily correspond directly to sections of an
|
||||
/// [object file](crate::obj).
|
||||
// TODO: Remove pub
|
||||
/// For more information on these sections,
|
||||
/// see the [parent module](super).
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct Sections<'a> {
|
||||
pub map: Section<'a>,
|
||||
pub retmap: Section<'a>,
|
||||
pub st: Section<'a>,
|
||||
pub rater: Section<'a>,
|
||||
deps: Vec<&'a IdentObject>,
|
||||
map_froms: FxHashSet<SymbolId>,
|
||||
|
||||
map: Vec<SymbolId>,
|
||||
retmap: Vec<SymbolId>,
|
||||
st: Vec<SymbolId>,
|
||||
exec: Vec<SymbolId>,
|
||||
}
|
||||
|
||||
impl<'a> Sections<'a> {
|
||||
|
@ -139,34 +72,58 @@ impl<'a> Sections<'a> {
|
|||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: Section::new(),
|
||||
retmap: Section::new(),
|
||||
st: Section::new(),
|
||||
rater: Section::new(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn push(&mut self, ident: &'a IdentObject) -> PushResult {
|
||||
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);
|
||||
|
||||
match ident.resolved()?.kind() {
|
||||
Some(kind) => match kind {
|
||||
IdentKind::Cgen(_)
|
||||
| IdentKind::Gen(_, _)
|
||||
| IdentKind::Lparam(_, _) => {
|
||||
// These types do not have fragments.
|
||||
}
|
||||
IdentKind::Meta
|
||||
| IdentKind::Worksheet
|
||||
| IdentKind::Param(_, _)
|
||||
| IdentKind::Type(_)
|
||||
| IdentKind::Func(_, _)
|
||||
| IdentKind::Const(_, _) => self.st.push_body(ident),
|
||||
| IdentKind::Const(_, _) => {
|
||||
self.st.push(expect_frag(name, frag)?)
|
||||
}
|
||||
IdentKind::MapHead | IdentKind::Map | IdentKind::MapTail => {
|
||||
self.map.push_body(ident)
|
||||
self.map.push(expect_frag(name, frag)?);
|
||||
|
||||
if let Some(from) =
|
||||
ident.src().expect("missing map src").from
|
||||
{
|
||||
self.map_froms.insert(from);
|
||||
}
|
||||
}
|
||||
IdentKind::RetMapHead
|
||||
| IdentKind::RetMap
|
||||
| IdentKind::RetMapTail => self.retmap.push_body(ident),
|
||||
_ => self.rater.push_body(ident),
|
||||
| IdentKind::RetMapTail => {
|
||||
self.retmap.push(expect_frag(name, frag)?)
|
||||
}
|
||||
// TODO: Why do templates have fragments?
|
||||
IdentKind::Class(_) | IdentKind::Rate(_) | IdentKind::Tpl => {
|
||||
self.exec.push(expect_frag(name, frag)?)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// TODO: This should not be possible; ensure that with types
|
||||
|
@ -187,75 +144,44 @@ impl<'a> Sections<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Construct an iterator over each of the individual sections in
|
||||
/// arbitrary order.
|
||||
///
|
||||
/// Each individual section is ordered as stated in [`Section::iter`],
|
||||
/// but you should not rely on the order that the sections themselves
|
||||
/// appear in;
|
||||
/// they may change or be combined in the future.
|
||||
/// At the time of writing,
|
||||
/// they are chained in the same order in which they are defined
|
||||
/// on the [`Sections`] struct.
|
||||
#[inline]
|
||||
pub fn iter_all(&self) -> SectionsIter {
|
||||
SectionsIter(SectionsIterType::All(
|
||||
self.map
|
||||
.iter()
|
||||
.chain(self.retmap.iter())
|
||||
.chain(self.st.iter())
|
||||
.chain(self.rater.iter()),
|
||||
))
|
||||
fn take_deps(&mut self) -> Vec<&'a IdentObject> {
|
||||
take(&mut self.deps)
|
||||
}
|
||||
|
||||
/// Construct an iterator over the static sections in arbitrary order.
|
||||
///
|
||||
/// These sections contain fragments that do not depend on any external
|
||||
/// inputs and can therefore be executed a single time when the
|
||||
/// program is loaded into memory.
|
||||
///
|
||||
/// Each individual section is ordered as stated in [`Section::iter`],
|
||||
/// but you should not rely on the order that the sections themselves
|
||||
/// appear in;
|
||||
/// they may change or be combined in the future.
|
||||
#[inline]
|
||||
pub fn iter_static(&self) -> SectionsIter {
|
||||
SectionsIter(SectionsIterType::Single(self.st.iter()))
|
||||
fn take_static(&mut self) -> Vec<SymbolId> {
|
||||
take(&mut self.st)
|
||||
}
|
||||
|
||||
/// Construct an iterator over the map section.
|
||||
#[inline]
|
||||
pub fn iter_map(&self) -> SectionsIter {
|
||||
SectionsIter(SectionsIterType::Single(self.map.iter()))
|
||||
fn take_map(&mut self) -> Vec<SymbolId> {
|
||||
take(&mut self.map)
|
||||
}
|
||||
|
||||
/// Iterate over each unique map `from` entry.
|
||||
///
|
||||
/// Multiple mappings may reference the same source field,
|
||||
/// which would produce duplicate values if they are not filtered.
|
||||
#[inline]
|
||||
pub fn iter_map_froms_uniq(&self) -> hash_set::IntoIter<SymbolId> {
|
||||
self.iter_map()
|
||||
.filter_map(|ident| {
|
||||
ident.src().expect("internal error: missing map src").from
|
||||
})
|
||||
.collect::<FxHashSet<SymbolId>>()
|
||||
.into_iter()
|
||||
fn take_map_froms(&mut self) -> FxHashSet<SymbolId> {
|
||||
take(&mut < |