use alloc::boxed::Box;
use alloc::vec::Vec;
use vize_l0::{Span, id::NodeId, side_table::SideTable};
use crate::op::Region;
use crate::provenance::ProvenanceRecord;
use crate::scope::{ScopeFacts, ScopeTag};
use crate::walk::{NodeEvent, NodeLimit, NodeRef, PageWalk};
mod builder;
mod check;
pub(crate) use builder::ElementAllocation;
pub use builder::{Builder, ComponentBody, ComponentFactory, RegionBuilder};
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub struct ArtifactParts<'a> {
pub source: &'a str,
pub root: Region<'a>,
pub provenance: Vec<ProvenanceRecord>,
pub scopes: SideTable<ScopeFacts>,
}
#[derive(Debug)]
pub struct Artifact<'a> {
parts: ArtifactParts<'a>,
node_count: u32,
}
#[derive(Debug)]
pub struct RejectedArtifact<'a> {
pub error: ArtifactError,
pub parts: Box<ArtifactParts<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IfShape {
Empty,
LeadingElse,
NonTrailingElse,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ArtifactError {
SourceLimit,
NodeLimit,
UnfinishedOwner { node: NodeId },
BindingWithoutOwner { span: Span },
BindingAfterChild { node: NodeId, span: Span },
InvalidBindingName { node: NodeId, span: Span },
InvalidHandlerReference { node: NodeId, handler: NodeId },
InvalidOriginalForReference { node: NodeId, original: NodeId },
InvalidSpan { node: Option<NodeId>, span: Span },
OutsideOwner {
node: NodeId,
span: Span,
owner: Span,
},
InvalidIf { node: NodeId, shape: IfShape },
DanglingProvenance { record: usize, node: NodeId },
DanglingScope { node: NodeId },
InvalidScopeSite { node: NodeId },
MissingScope { node: NodeId },
InvalidJsSpan { node: NodeId, span: Span },
MismatchedJsSource { node: NodeId, span: Span },
InvalidScopeTag { node: NodeId, tag: ScopeTag },
}
impl<'a> Artifact<'a> {
pub fn try_new(parts: ArtifactParts<'a>) -> Result<Self, RejectedArtifact<'a>> {
match check::check(&parts) {
Ok(node_count) => Ok(Self { parts, node_count }),
Err(error) => Err(RejectedArtifact {
error,
parts: Box::new(parts),
}),
}
}
#[must_use]
pub fn source(&self) -> &'a str {
self.parts.source
}
#[must_use]
pub fn root(&self) -> &Region<'a> {
&self.parts.root
}
#[must_use]
pub fn node_count(&self) -> u32 {
self.node_count
}
#[must_use]
pub fn contains_node(&self, node: NodeId) -> bool {
node.index() < self.node_count
}
#[must_use]
pub fn scopes(&self) -> &SideTable<ScopeFacts> {
&self.parts.scopes
}
#[must_use]
pub fn provenance(&self) -> &[ProvenanceRecord] {
&self.parts.provenance
}
pub fn visit_nodes<'s>(
&'s self,
visit: &mut impl FnMut(NodeId, NodeRef<'s, 'a>),
) -> Result<(), NodeLimit> {
crate::walk::visit_nodes(&mut PageWalk::new(), &self.parts.root.ops, visit)
}
pub fn visit_events<'s>(
&'s self,
visit: &mut impl FnMut(NodeEvent<'s, 'a>),
) -> Result<(), NodeLimit> {
crate::walk::visit_events(&mut PageWalk::new(), &self.parts.root.ops, visit)
}
#[must_use]
pub fn into_parts(self) -> ArtifactParts<'a> {
self.parts
}
}