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}