tamer: ld::xmle::lower: Extract sectioning into Sections

This is the appropriate place to be, now that we've begun narrowing the
types.  We'll be able to do so further; this is just the first step.

This does not yet move the tests, but the code is still tested because it's
tightly coupled with `sort`.  Those will move in the next commit(s).

DEV-10859
main
Mike Gerwitz 2021-10-12 12:14:24 -04:00
parent 08d92ca663
commit ea11cf1416
2 changed files with 114 additions and 69 deletions

View File

@ -21,13 +21,9 @@
//!
//! See the [parent module](super) for more information.
use super::Sections;
use crate::{
ir::asg::{
Asg, BaseAsg, IdentKind, IdentObject, IdentObjectData,
IdentObjectState, IndexType, ObjectRef, UnresolvedError,
},
sym::GlobalSymbolResolve,
use super::{section::SectionsError, Sections};
use crate::ir::asg::{
Asg, BaseAsg, IdentKind, IdentObject, IdentObjectData, IndexType, ObjectRef,
};
use petgraph::visit::DfsPostOrder;
@ -59,34 +55,8 @@ where
}
while let Some(index) = dfs.next(&asg.graph) {
let ident = asg.get(index).expect("missing node").resolved()?;
match ident.kind() {
Some(kind) => match kind {
IdentKind::Meta
| IdentKind::Worksheet
| IdentKind::Param(_, _)
| IdentKind::Type(_)
| IdentKind::Func(_, _)
| IdentKind::Const(_, _) => deps.st.push_body(ident),
IdentKind::MapHead | IdentKind::Map | IdentKind::MapTail => {
deps.map.push_body(ident)
}
IdentKind::RetMapHead
| IdentKind::RetMap
| IdentKind::RetMapTail => deps.retmap.push_body(ident),
_ => deps.rater.push_body(ident),
},
None => {
return Err(SortError::MissingObjectKind(
ident
.name()
.map(|name| format!("{}", name.lookup_str()))
.unwrap_or("<unknown>".into())
.into(),
))
}
}
let ident = asg.get(index).expect("missing node");
deps.push(ident)?;
}
Ok(deps)
@ -153,44 +123,23 @@ where
/// sorting process.
#[derive(Debug, PartialEq)]
pub enum SortError<Ix: IndexType> {
/// An unresolved object was encountered during sorting.
///
/// An unresolved object means that the graph has an incomplete picture
/// of the program,
/// and so sorting cannot be reliably performed.
/// Since all objects are supposed to be resolved prior to sorting,
/// this represents either a problem with the program being compiled
/// or a bug in the compiler itself.
UnresolvedObject(UnresolvedError),
/// The kind of an object encountered during sorting could not be
/// determined.
///
/// Sorting uses the object kind to place objects into their appropriate
/// sections.
/// It should never be the case that a resolved object has no kind,
/// so this likely represents a compiler bug.
MissingObjectKind(String),
/// Error while building [`Sections`].
SectionsError(SectionsError),
/// The graph has a cyclic dependency.
Cycles(Vec<Vec<ObjectRef<Ix>>>),
}
impl<Ix: IndexType> From<UnresolvedError> for SortError<Ix> {
fn from(err: UnresolvedError) -> Self {
Self::UnresolvedObject(err)
impl<Ix: IndexType> From<SectionsError> for SortError<Ix> {
fn from(err: SectionsError) -> Self {
Self::SectionsError(err)
}
}
impl<Ix: IndexType> std::fmt::Display for SortError<Ix> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::UnresolvedObject(err) => std::fmt::Display::fmt(err, fmt),
Self::MissingObjectKind(name) => write!(
fmt,
"internal error: missing object kind for object `{}` (this may be a compiler bug!)",
name,
),
Self::SectionsError(err) => err.fmt(fmt),
Self::Cycles(_) => write!(fmt, "cyclic dependencies"),
}
}
@ -198,10 +147,7 @@ impl<Ix: IndexType> std::fmt::Display for SortError<Ix> {
impl<Ix: IndexType> std::error::Error for SortError<Ix> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::UnresolvedObject(err) => Some(err),
_ => None,
}
None
}
}
@ -316,7 +262,9 @@ mod test {
match sort(&sut, &vec![sym_node]) {
Ok(_) => panic!("Unexpected success - dependency is not in graph"),
Err(SortError::UnresolvedObject(_)) => (),
Err(SortError::SectionsError(SectionsError::UnresolvedObject(
_,
))) => (),
bad => {
panic!("Incorrect error result when dependency is not in graph: {:?}", bad)
}

View File

@ -23,12 +23,15 @@
//! which places the relocatable object code fragments in the order
//! necessary for execution.
use crate::ir::asg::{IdentObject, IdentObjectData};
use crate::sym::SymbolId;
use crate::ir::asg::{
IdentKind, IdentObject, IdentObjectData, IdentObjectState, UnresolvedError,
};
use crate::sym::{GlobalSymbolResolve, SymbolId};
use fxhash::FxHashSet;
use std::collections::hash_set;
use std::iter::Chain;
use std::option;
use std::result::Result;
use std::slice::Iter;
/// A section of an [object file](crate::obj).
@ -116,6 +119,8 @@ impl<'a> Iterator for SectionIter<'a> {
}
}
pub type PushResult = Result<(), SectionsError>;
/// ASG objects organized into logical sections.
///
/// These sections may not necessarily correspond directly to sections of an
@ -141,6 +146,47 @@ impl<'a> 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 {
match ident.resolved()?.kind() {
Some(kind) => match kind {
IdentKind::Meta
| IdentKind::Worksheet
| IdentKind::Param(_, _)
| IdentKind::Type(_)
| IdentKind::Func(_, _)
| IdentKind::Const(_, _) => self.st.push_body(ident),
IdentKind::MapHead | IdentKind::Map | IdentKind::MapTail => {
self.map.push_body(ident)
}
IdentKind::RetMapHead
| IdentKind::RetMap
| IdentKind::RetMapTail => self.retmap.push_body(ident),
_ => self.rater.push_body(ident),
},
None => {
// TODO: This should not be possible; ensure that with types
// or turn this into a panic. It would certainly be 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(),
));
}
}
Ok(())
}
/// Construct an iterator over each of the individual sections in
/// arbitrary order.
///
@ -210,6 +256,57 @@ impl<'a> Sections<'a> {
}
}
/// Error during [`Sections`] building.
#[derive(Debug, PartialEq)]
pub enum SectionsError {
/// An unresolved object was encountered during sorting.
///
/// An unresolved object means that the graph has an incomplete picture
/// of the program,
/// and so sorting cannot be reliably performed.
/// Since all objects are supposed to be resolved prior to sorting,
/// this represents either a problem with the program being compiled
/// or a bug in the compiler itself.
UnresolvedObject(UnresolvedError),
/// The kind of an object encountered during sorting could not be
/// determined.
///
/// Sorting uses the object kind to place objects into their appropriate
/// sections.
/// It should never be the case that a resolved object has no kind,
/// so this likely represents a compiler bug.
MissingObjectKind(String),
}
impl From<UnresolvedError> for SectionsError {
fn from(err: UnresolvedError) -> Self {
Self::UnresolvedObject(err)
}
}
impl std::error::Error for SectionsError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::UnresolvedObject(err) => Some(err),
_ => None,
}
}
}
impl std::fmt::Display for SectionsError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::UnresolvedObject(err) => err.fmt(fmt),
Self::MissingObjectKind(name) => write!(
fmt,
"missing object kind for object `{}` (this may be a compiler bug!)",
name,
),
}
}
}
// Compose the chained iterator type for [`SectionsIter`].
// This could be further abstracted away,
// but it's likely that `Sections` will be simplified in the future.