datalog_structural_model/ir/
structural_term.rs1use super::{Atom, ConstantSymbol, GroundAtom, GroundTerm, MAX_TRIPLE_TERM_NESTING, Term};
3use std::{error::Error, fmt};
4
5#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
7#[serde(deny_unknown_fields)]
8pub enum TermShapeError {
9 TripleTermNestingExceeded {
11 depth: usize,
13 limit: usize,
15 },
16 InvalidSkolemArguments,
18}
19impl fmt::Display for TermShapeError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 Self::TripleTermNestingExceeded { depth, limit } => {
23 write!(f, "triple term depth {depth} exceeds limit {limit}")
24 }
25 Self::InvalidSkolemArguments => {
26 f.write_str("Skolem arguments must be variables or constants")
27 }
28 }
29 }
30}
31impl Error for TermShapeError {}
32impl Term {
33 pub fn try_triple_term(atom: Atom) -> Result<Self, TermShapeError> {
37 let term = Self::TripleTerm(Box::new(atom));
38 term.validate_structure()?;
39 Ok(term)
40 }
41 pub fn try_skolem(name: ConstantSymbol, args: Vec<Self>) -> Result<Self, TermShapeError> {
45 let term = Self::Skolem { name, args };
46 term.validate_structure()?;
47 Ok(term)
48 }
49 pub fn validate_structure(&self) -> Result<(), TermShapeError> {
54 let depth = self.nesting_depth();
55 if depth > MAX_TRIPLE_TERM_NESTING {
56 return Err(TermShapeError::TripleTermNestingExceeded {
57 depth,
58 limit: MAX_TRIPLE_TERM_NESTING,
59 });
60 }
61 match self {
62 Self::Variable(_) | Self::Constant(_) => {}
63 Self::TripleTerm(atom) => {
64 for term in &atom.terms {
65 term.validate_structure()?;
66 }
67 }
68 Self::Skolem { args, .. } => {
69 if args
70 .iter()
71 .any(|term| !matches!(term, Self::Variable(_) | Self::Constant(_)))
72 {
73 return Err(TermShapeError::InvalidSkolemArguments);
74 }
75 }
76 }
77 Ok(())
78 }
79}
80impl GroundTerm {
81 fn nesting_depth(&self) -> usize {
82 match self {
83 Self::Constant(_) => 0,
84 Self::TripleTerm(atom) => {
85 1 + atom.args.iter().map(Self::nesting_depth).max().unwrap_or(0)
86 }
87 }
88 }
89 pub fn try_triple_term(atom: GroundAtom) -> Result<Self, TermShapeError> {
93 let term = Self::TripleTerm(Box::new(atom));
94 term.validate_structure()?;
95 Ok(term)
96 }
97 pub fn validate_structure(&self) -> Result<(), TermShapeError> {
101 let depth = self.nesting_depth();
102 if depth > MAX_TRIPLE_TERM_NESTING {
103 return Err(TermShapeError::TripleTermNestingExceeded {
104 depth,
105 limit: MAX_TRIPLE_TERM_NESTING,
106 });
107 }
108 Ok(())
109 }
110}