Skip to main content

datalog_structural_model/ir/
ground.rs

1//! Ground (variable-free) term and atom value forms.
2
3use std::fmt;
4
5use super::symbols::{ConstantSymbol, PredicateSymbol};
6
7/// Ground term — the value form of a [`Term`](super::term::Term)
8/// with all variables substituted. Used as the cell type inside
9/// tuples so an evaluator can store both flat
10/// constant-only facts and quoted-triple facts (TT1).
11///
12/// `Constant` corresponds to the
13/// [`Term::Constant`](super::term::Term::Constant) form;
14/// `TripleTerm` is the value form of
15/// [`Term::TripleTerm`](super::term::Term::TripleTerm) —
16/// a [`GroundAtom`] whose argument list contains only further
17/// `GroundTerm` values (no variables, recursively).
18///
19/// Total order: `Constant(_) < TripleTerm(_)`. Within each
20/// variant, the inner symbol or atom's lexicographic order
21/// determines the result. This is the determinism contract
22/// an evaluator can rely on when serialising grounded facts.
23#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
24pub enum GroundTerm {
25    /// Ground constant — the value form of
26    /// [`Term::Constant`](super::term::Term::Constant).
27    Constant(ConstantSymbol),
28    /// Ground quoted-triple term — the value form of
29    /// [`Term::TripleTerm`](super::term::Term::TripleTerm).
30    /// Contains a [`GroundAtom`] whose argument list contains
31    /// only further `GroundTerm` values; recursive nesting is
32    /// bounded by
33    /// [`MAX_TRIPLE_TERM_NESTING`](super::term::MAX_TRIPLE_TERM_NESTING)
34    /// (enforced at IR
35    /// [`Program::validate`](super::program::Program::validate)
36    /// time, before grounding).
37    TripleTerm(Box<GroundAtom>),
38}
39
40impl GroundTerm {
41    /// Construct a flat-constant ground term. Convenience for
42    /// the common case where the underlying value is a plain
43    /// [`ConstantSymbol`].
44    #[must_use]
45    pub fn constant(c: ConstantSymbol) -> Self {
46        Self::Constant(c)
47    }
48
49    /// Pull out the wrapped [`ConstantSymbol`] when this is the
50    /// constant form. Returns `None` for [`GroundTerm::TripleTerm`].
51    #[must_use]
52    pub fn as_constant(&self) -> Option<&ConstantSymbol> {
53        match self {
54            Self::Constant(c) => Some(c),
55            Self::TripleTerm(_) => None,
56        }
57    }
58}
59
60impl From<ConstantSymbol> for GroundTerm {
61    fn from(c: ConstantSymbol) -> Self {
62        Self::Constant(c)
63    }
64}
65
66/// Ground form of an [`Atom`](super::atom::Atom) — the value
67/// form with no variables anywhere in the argument tree. Used
68/// inside [`GroundTerm::TripleTerm`] so quoted-triple facts can
69/// be stored alongside flat facts in a fact set (TT1).
70#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
71pub struct GroundAtom {
72    /// Predicate of the ground atom.
73    pub predicate: PredicateSymbol,
74    /// Ground arguments in positional order.
75    pub args: Vec<GroundTerm>,
76}
77
78impl GroundAtom {
79    /// Arity of the ground atom.
80    #[must_use]
81    pub fn arity(&self) -> usize {
82        self.args.len()
83    }
84}
85
86/// Display a [`GroundTerm`]: constants as their raw symbol,
87/// quoted-triple terms as `<< s p o >>` per N-Triples-star
88/// syntax (mirroring [`Term`](super::term::Term)'s display
89/// contract).
90impl fmt::Display for GroundTerm {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        match self {
93            Self::Constant(c) => write!(f, "{}", c.as_str()),
94            Self::TripleTerm(atom) => {
95                if atom.args.len() == 2 {
96                    write!(
97                        f,
98                        "<< {} {} {} >>",
99                        atom.args[0],
100                        atom.predicate.as_str(),
101                        atom.args[1],
102                    )
103                } else {
104                    write!(f, "<< {atom} >>")
105                }
106            }
107        }
108    }
109}
110
111/// Display a [`GroundAtom`] as `predicate(arg_1, arg_2, …)`.
112/// Used by [`GroundTerm`]'s [`std::fmt::Display`] impl for non-2-arity
113/// triple-term values.
114impl fmt::Display for GroundAtom {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        write!(f, "{}(", self.predicate.as_str())?;
117        for (idx, arg) in self.args.iter().enumerate() {
118            if idx > 0 {
119                write!(f, ", ")?;
120            }
121            write!(f, "{arg}")?;
122        }
123        write!(f, ")")
124    }
125}