1use serde::{Deserialize, Serialize};
4
5use crate::parametric_types::ParametricType;
6
7#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct TypeAnnotation {
13 pub type_name: String,
14}
15
16impl TypeAnnotation {
17 pub fn new(type_name: impl Into<String>) -> Self {
18 TypeAnnotation {
19 type_name: type_name.into(),
20 }
21 }
22
23 pub fn to_parametric(&self) -> ParametricType {
25 ParametricType::concrete(&self.type_name)
26 }
27
28 pub fn from_parametric(ty: &ParametricType) -> Option<Self> {
30 match ty {
31 ParametricType::Concrete(name) => Some(TypeAnnotation::new(name.clone())),
32 _ => None, }
34 }
35}
36
37#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
38pub enum Term {
39 Var(String),
40 Const(String),
41 Typed {
43 value: Box<Term>,
44 type_annotation: TypeAnnotation,
45 },
46}
47
48impl Term {
49 pub fn var(name: impl Into<String>) -> Self {
50 Term::Var(name.into())
51 }
52
53 pub fn constant(name: impl Into<String>) -> Self {
54 Term::Const(name.into())
55 }
56
57 pub fn typed_var(name: impl Into<String>, type_name: impl Into<String>) -> Self {
59 Term::Typed {
60 value: Box::new(Term::Var(name.into())),
61 type_annotation: TypeAnnotation::new(type_name),
62 }
63 }
64
65 pub fn typed_const(name: impl Into<String>, type_name: impl Into<String>) -> Self {
67 Term::Typed {
68 value: Box::new(Term::Const(name.into())),
69 type_annotation: TypeAnnotation::new(type_name),
70 }
71 }
72
73 pub fn with_type(self, type_name: impl Into<String>) -> Self {
75 Term::Typed {
76 value: Box::new(self),
77 type_annotation: TypeAnnotation::new(type_name),
78 }
79 }
80
81 pub fn is_var(&self) -> bool {
82 match self {
83 Term::Var(_) => true,
84 Term::Typed { value, .. } => value.is_var(),
85 _ => false,
86 }
87 }
88
89 pub fn is_const(&self) -> bool {
90 match self {
91 Term::Const(_) => true,
92 Term::Typed { value, .. } => value.is_const(),
93 _ => false,
94 }
95 }
96
97 pub fn name(&self) -> &str {
98 match self {
99 Term::Var(n) | Term::Const(n) => n,
100 Term::Typed { value, .. } => value.name(),
101 }
102 }
103
104 pub fn get_type(&self) -> Option<&TypeAnnotation> {
106 match self {
107 Term::Typed {
108 type_annotation, ..
109 } => Some(type_annotation),
110 _ => None,
111 }
112 }
113
114 pub fn untyped(&self) -> &Term {
116 match self {
117 Term::Typed { value, .. } => value.untyped(),
118 term => term,
119 }
120 }
121}