1use lazy_static::lazy_static;
3use pulsar_utils::{id::Id, mutcell::MutCell};
4use std::{fmt::Display, hash::Hash};
5
6lazy_static! {
7 pub static ref UNIT_TYPE_CELL: TypeCell = TypeCell::new(Type::Unit);
8 pub static ref INT64_TYPE_CELL: TypeCell = TypeCell::new(Type::Int64);
9}
10
11pub const ARRAY_TYPE_UNKNOWN_SIZE: isize = -1;
12
13#[derive(Clone, Hash, PartialEq, Eq, Debug)]
14pub enum Type {
15 Unknown,
16 Unit,
17 Var(Id),
18 Name(String),
19 Int64,
20
21 Array(TypeCell, isize),
23
24 Function {
25 is_pure: bool,
26 args: Vec<Type>,
27 ret: Box<Type>
28 }
29}
30
31impl Type {
32 pub fn unwrap(self) -> Self {
33 match self {
34 Self::Unknown => panic!("Type::unwrap failed"),
35 other => other
36 }
37 }
38
39 pub fn is_known(self) -> bool {
40 !matches!(self, Self::Unknown)
41 }
42
43 pub fn make_unknown() -> TypeCell {
44 TypeCell::new(Self::Unknown)
45 }
46
47 pub fn int64_singleton() -> TypeCell {
48 INT64_TYPE_CELL.to_owned()
49 }
50
51 pub fn unit_singleton() -> TypeCell {
52 UNIT_TYPE_CELL.to_owned()
53 }
54
55 pub fn size(&self) -> usize {
58 match &self {
59 Type::Unknown => panic!("Type::Unknown does not have a size"),
60 Type::Unit => 0,
61 Type::Var(_) => {
62 panic!("Type::Var should have been resolved by type inference")
63 }
64 Type::Name(_) => todo!("Need to figure out user-defined types"),
65 Type::Int64 => 8,
66 Type::Array(element_type, element_count) => {
67 element_type.as_ref().size() * (*element_count as usize)
68 }
69 Type::Function {
70 is_pure: _,
71 args: _,
72 ret: _
73 } => 8
74 }
75 }
76
77 pub fn as_array_type(&self) -> (TypeCell, isize) {
78 match &self {
79 Self::Array(element_type, size) => (element_type.clone(), *size),
80 _ => panic!(
81 "{}",
82 format!(
83 "Type::as_array_type called on non-array type `{}`",
84 &self
85 )
86 )
87 }
88 }
89
90 pub fn mangle(&self) -> String {
91 match &self {
92 Type::Unknown | Type::Var(_) => panic!(),
93 Type::Unit => "u".into(),
94 Type::Name(name) => format!("{}{}", name.len(), name),
95 Type::Int64 => "q".into(),
96 Type::Array(element_type, count) => {
97 format!("A{}{}", count, element_type)
98 }
99 Type::Function {
100 is_pure: _,
101 args: _,
102 ret: _
103 } => todo!()
104 }
105 }
106}
107
108impl Display for Type {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 match self {
111 Self::Unknown => write!(f, "?"),
112 Self::Unit => write!(f, "Unit"),
113 Self::Var(var) => write!(f, "'t{}", var),
114 Self::Name(name) => write!(f, "{}", name),
115 Self::Int64 => write!(f, "Int64"),
116 Self::Array(tcell, size) => write!(
117 f,
118 "{}[{}]",
119 tcell,
120 if *size == ARRAY_TYPE_UNKNOWN_SIZE {
121 "?".into()
122 } else {
123 size.to_string()
124 }
125 ),
126 Self::Function { is_pure, args, ret } => write!(
127 f,
128 "{}({}) -> {}",
129 if *is_pure { "pure " } else { "" },
130 args.iter()
131 .map(|ty| ty.to_string())
132 .collect::<Vec<_>>()
133 .join(", "),
134 ret,
135 )
136 }
137 }
138}
139
140#[derive(Clone, PartialEq, Eq)]
141pub enum StmtTermination {
142 Terminal,
143 Nonterminal
144}
145
146impl Display for StmtTermination {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 match self {
149 Self::Terminal => "Terminal",
150 Self::Nonterminal => "Nonterminal"
151 }
152 .fmt(f)
153 }
154}
155
156#[derive(Clone, PartialEq, Eq)]
157pub struct StmtType {
158 pub termination: StmtTermination,
159 pub is_pure: bool,
160 is_unknown: bool
161}
162
163impl StmtType {
164 pub fn from(termination: StmtTermination, is_pure: bool) -> StmtType {
165 StmtType {
166 termination,
167 is_pure,
168 is_unknown: false
169 }
170 }
171
172 pub fn make_unknown() -> StmtTypeCell {
173 StmtTypeCell::new(StmtType {
174 termination: StmtTermination::Nonterminal,
175 is_pure: false,
176 is_unknown: true
177 })
178 }
179}
180
181impl Display for StmtType {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "{}", if self.is_pure { "Pure" } else { "Impure" })?;
184 write!(f, "{}", self.termination)
185 }
186}
187
188pub type TypeCell = MutCell<Type>;
189pub type StmtTypeCell = MutCell<StmtType>;