tensorlogic_ir/
term.rs

1//! Terms: variables and constants.
2
3use serde::{Deserialize, Serialize};
4
5/// Type annotation for a term.
6#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub struct TypeAnnotation {
8    pub type_name: String,
9}
10
11impl TypeAnnotation {
12    pub fn new(type_name: impl Into<String>) -> Self {
13        TypeAnnotation {
14            type_name: type_name.into(),
15        }
16    }
17}
18
19#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub enum Term {
21    Var(String),
22    Const(String),
23    /// Typed term with explicit type annotation
24    Typed {
25        value: Box<Term>,
26        type_annotation: TypeAnnotation,
27    },
28}
29
30impl Term {
31    pub fn var(name: impl Into<String>) -> Self {
32        Term::Var(name.into())
33    }
34
35    pub fn constant(name: impl Into<String>) -> Self {
36        Term::Const(name.into())
37    }
38
39    /// Create a typed variable
40    pub fn typed_var(name: impl Into<String>, type_name: impl Into<String>) -> Self {
41        Term::Typed {
42            value: Box::new(Term::Var(name.into())),
43            type_annotation: TypeAnnotation::new(type_name),
44        }
45    }
46
47    /// Create a typed constant
48    pub fn typed_const(name: impl Into<String>, type_name: impl Into<String>) -> Self {
49        Term::Typed {
50            value: Box::new(Term::Const(name.into())),
51            type_annotation: TypeAnnotation::new(type_name),
52        }
53    }
54
55    /// Attach a type annotation to an existing term
56    pub fn with_type(self, type_name: impl Into<String>) -> Self {
57        Term::Typed {
58            value: Box::new(self),
59            type_annotation: TypeAnnotation::new(type_name),
60        }
61    }
62
63    pub fn is_var(&self) -> bool {
64        match self {
65            Term::Var(_) => true,
66            Term::Typed { value, .. } => value.is_var(),
67            _ => false,
68        }
69    }
70
71    pub fn is_const(&self) -> bool {
72        match self {
73            Term::Const(_) => true,
74            Term::Typed { value, .. } => value.is_const(),
75            _ => false,
76        }
77    }
78
79    pub fn name(&self) -> &str {
80        match self {
81            Term::Var(n) | Term::Const(n) => n,
82            Term::Typed { value, .. } => value.name(),
83        }
84    }
85
86    /// Get the type annotation if present
87    pub fn get_type(&self) -> Option<&TypeAnnotation> {
88        match self {
89            Term::Typed {
90                type_annotation, ..
91            } => Some(type_annotation),
92            _ => None,
93        }
94    }
95
96    /// Get the underlying untyped term
97    pub fn untyped(&self) -> &Term {
98        match self {
99            Term::Typed { value, .. } => value.untyped(),
100            term => term,
101        }
102    }
103}