patch_prolog_shared/
term.rs1use crate::atom::AtomId;
8
9pub type VarId = u32;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub enum FirstArgKey {
14 Atom(AtomId),
15 Integer(i64),
16 Functor(AtomId, usize), }
18
19#[derive(Debug, Clone, PartialEq)]
21pub enum Term {
22 Atom(AtomId),
23 Var(VarId),
24 Integer(i64),
25 Float(f64),
26 Compound { functor: AtomId, args: Vec<Term> },
27 List { head: Box<Term>, tail: Box<Term> },
28}
29
30impl Term {
31 pub fn functor_arity(&self) -> Option<(AtomId, usize)> {
36 match self {
37 Term::Atom(id) => Some((*id, 0)),
38 Term::Compound { functor, args } => Some((*functor, args.len())),
39 _ => None,
40 }
41 }
42
43 pub fn first_arg_key(&self) -> Option<FirstArgKey> {
45 let first = match self {
46 Term::Compound { args, .. } if !args.is_empty() => &args[0],
47 _ => return None,
48 };
49 match first {
50 Term::Atom(id) => Some(FirstArgKey::Atom(*id)),
51 Term::Integer(n) => Some(FirstArgKey::Integer(*n)),
52 Term::Compound { functor, args } => Some(FirstArgKey::Functor(*functor, args.len())),
53 _ => None, }
55 }
56
57 pub fn is_var(&self) -> bool {
59 matches!(self, Term::Var(_))
60 }
61}
62
63#[derive(Debug, Clone, PartialEq)]
66pub struct Clause {
67 pub head: Term,
68 pub body: Vec<Term>,
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_term_functor_arity() {
77 let atom = Term::Atom(0);
78 assert_eq!(atom.functor_arity(), Some((0, 0)));
79
80 let compound = Term::Compound {
81 functor: 1,
82 args: vec![Term::Atom(2), Term::Var(0)],
83 };
84 assert_eq!(compound.functor_arity(), Some((1, 2)));
85
86 let var = Term::Var(0);
87 assert_eq!(var.functor_arity(), None);
88
89 let int = Term::Integer(42);
90 assert_eq!(int.functor_arity(), None);
91 }
92
93 #[test]
94 fn test_first_arg_key() {
95 let t = Term::Compound {
97 functor: 0,
98 args: vec![Term::Atom(1)],
99 };
100 assert_eq!(t.first_arg_key(), Some(FirstArgKey::Atom(1)));
101
102 let t = Term::Compound {
104 functor: 0,
105 args: vec![Term::Integer(42)],
106 };
107 assert_eq!(t.first_arg_key(), Some(FirstArgKey::Integer(42)));
108
109 let t = Term::Compound {
111 functor: 0,
112 args: vec![Term::Var(0)],
113 };
114 assert_eq!(t.first_arg_key(), None);
115
116 let t = Term::Atom(0);
118 assert_eq!(t.first_arg_key(), None);
119 }
120
121 #[test]
122 fn test_clause_construction() {
123 let clause = Clause {
124 head: Term::Compound {
125 functor: 0,
126 args: vec![Term::Atom(1), Term::Var(0)],
127 },
128 body: vec![Term::Compound {
129 functor: 2,
130 args: vec![Term::Var(0)],
131 }],
132 };
133 assert_eq!(clause.body.len(), 1);
134 assert_eq!(clause.head.functor_arity(), Some((0, 2)));
135 }
136}