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