use super::compiled_shacl_error::CompiledShaclError;
use super::component_ir::ComponentIR;
use super::node_shape::NodeShapeIR;
use super::property_shape::PropertyShapeIR;
use super::target::CompiledTarget;
use crate::dependency_graph::{DependencyGraph, PosNeg};
use crate::reifier_info::ReifierInfo;
use crate::schema_ir::SchemaIR;
use crate::severity::CompiledSeverity;
use crate::shape_label_idx::ShapeLabelIdx;
use iri_s::IriS;
use rudof_rdf::rdf_core::{Rdf, SHACLPath, term::Object};
use shacl_ast::ShaclSchema;
use shacl_ast::shape::Shape;
use std::collections::HashSet;
use std::fmt::Display;
#[derive(Debug, Clone)]
pub enum ShapeIR {
NodeShape(Box<NodeShapeIR>),
PropertyShape(Box<PropertyShapeIR>),
}
impl ShapeIR {
pub fn deactivated(&self) -> bool {
match self {
ShapeIR::NodeShape(ns) => ns.deactivated(),
ShapeIR::PropertyShape(ps) => ps.deactivated(),
}
}
pub fn reifier_info(&self) -> Option<ReifierInfo> {
match self {
ShapeIR::NodeShape(_ns) => None,
ShapeIR::PropertyShape(ps) => ps.reifier_info(),
}
}
pub fn path(&self) -> Option<SHACLPath> {
match self {
ShapeIR::NodeShape(_) => None,
ShapeIR::PropertyShape(ps) => Some(ps.path().clone()),
}
}
pub fn show_severity(&self) -> String {
if let Some(severity) = self.severity().into() {
format!("(severity: {severity})")
} else {
"(severity: Violation)".to_string()
}
}
pub fn id(&self) -> &Object {
match self {
ShapeIR::NodeShape(ns) => ns.id(),
ShapeIR::PropertyShape(ps) => ps.id(),
}
}
pub fn targets(&self) -> &Vec<CompiledTarget> {
match self {
ShapeIR::NodeShape(ns) => ns.targets(),
ShapeIR::PropertyShape(ps) => ps.targets(),
}
}
pub fn components(&self) -> &Vec<ComponentIR> {
match self {
ShapeIR::NodeShape(ns) => ns.components(),
ShapeIR::PropertyShape(ps) => ps.components(),
}
}
pub fn property_shapes(&self) -> &Vec<ShapeLabelIdx> {
match self {
ShapeIR::NodeShape(ns) => ns.property_shapes(),
ShapeIR::PropertyShape(ps) => ps.property_shapes(),
}
}
pub fn path_str(&self) -> Option<String> {
match self {
ShapeIR::NodeShape(_) => None,
ShapeIR::PropertyShape(ps) => Some(ps.path().to_string()),
}
}
pub fn severity_iri(&self) -> IriS {
let iri_s: IriS = match self {
ShapeIR::NodeShape(ns) => ns.severity().iri(),
ShapeIR::PropertyShape(ps) => ps.severity().iri(),
};
iri_s
}
pub fn severity(&self) -> CompiledSeverity {
match self {
ShapeIR::NodeShape(ns) => ns.severity(),
ShapeIR::PropertyShape(ps) => ps.severity(),
}
}
pub fn compile<RDF: Rdf>(
shape: Shape<RDF>,
schema: &ShaclSchema<RDF>,
idx: &ShapeLabelIdx,
schema_ir: &mut SchemaIR,
) -> Result<ShapeLabelIdx, Box<CompiledShaclError>> {
let shape_ir = match shape {
Shape::NodeShape(node_shape) => {
let node_shape = NodeShapeIR::compile(node_shape, schema, schema_ir)?;
ShapeIR::NodeShape(Box::new(node_shape))
},
Shape::PropertyShape(property_shape) => {
let property_shape = PropertyShapeIR::compile(*property_shape, schema, schema_ir)?;
ShapeIR::PropertyShape(Box::new(property_shape))
},
};
let idx = schema_ir.add_shape(*idx, shape_ir)?;
Ok(idx)
}
pub(crate) fn add_edges(
&self,
shape_idx: ShapeLabelIdx,
dg: &mut DependencyGraph,
posneg: PosNeg,
schema_ir: &SchemaIR,
visited: &mut HashSet<ShapeLabelIdx>,
) {
match self {
ShapeIR::NodeShape(ns) => {
ns.add_edges(shape_idx, dg, posneg, schema_ir, visited);
},
ShapeIR::PropertyShape(ps) => {
ps.add_edges(shape_idx, dg, posneg, schema_ir, visited);
},
}
}
pub fn closed(&self) -> bool {
match self {
ShapeIR::NodeShape(ns) => ns.closed(),
ShapeIR::PropertyShape(ps) => ps.closed(),
}
}
pub fn allowed_properties(&self) -> HashSet<IriS> {
match self {
ShapeIR::NodeShape(ns) => ns.allowed_properties(),
ShapeIR::PropertyShape(ps) => ps.allowed_properties(),
}
}
}
impl Display for ShapeIR {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ShapeIR::NodeShape(_shape) => {
writeln!(f, "NodeShape")?;
},
ShapeIR::PropertyShape(shape) => {
writeln!(f, "PropertyShape")?;
writeln!(f, " path: {}", shape.path())?;
if let Some(reifier_info) = shape.reifier_info() {
writeln!(
f,
" reifier info: reification required: {}, reifier shapes: [{}]",
reifier_info.reification_required(),
reifier_info
.reifier_shape()
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(", ")
)?;
}
},
}
if self.deactivated() {
writeln!(f, " Deactivated: {}", self.deactivated())?;
}
if self.severity() != CompiledSeverity::Violation {
writeln!(f, " Severity: {}", self.severity())?;
}
if self.closed() {
writeln!(f, " closed: {}", self.closed())?;
}
let mut components = self.components().iter().peekable();
if components.peek().is_some() {
writeln!(f, " Components:")?;
for component in components {
writeln!(f, " - {component}")?;
}
}
let mut targets = self.targets().iter().peekable();
if targets.peek().is_some() {
writeln!(f, " Targets:")?;
for target in targets {
writeln!(f, " - {target}")?;
}
}
let mut property_shapes = self.property_shapes().iter().peekable();
if property_shapes.peek().is_some() {
writeln!(
f,
" Property Shapes: [{}]",
property_shapes.map(|ps| ps.to_string()).collect::<Vec<_>>().join(", ")
)?;
}
Ok(())
}
}