celestial_hub_compass/ast/
mod.rs

1use std::{ops::Range, str::FromStr};
2
3use lalrpop_util::ParseError;
4
5use crate::lexer::{tokens, ErrorTip, LexicalError};
6
7pub type Location = std::ops::Range<usize>;
8pub mod context;
9
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub enum VarType {
12  I8,
13  I16,
14  I32,
15  I64,
16  U8,
17  U16,
18  U32,
19  U64,
20  Bool,
21  F32,
22  F64,
23  Str,
24  Void,
25  Ptr,
26}
27
28impl std::fmt::Display for VarType {
29  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30    match self {
31      VarType::I8 => write!(f, "i8"),
32      VarType::I16 => write!(f, "i16"),
33      VarType::I32 => write!(f, "i32"),
34      VarType::I64 => write!(f, "i64"),
35      VarType::U8 => write!(f, "u8"),
36      VarType::U16 => write!(f, "u16"),
37      VarType::U32 => write!(f, "u32"),
38      VarType::U64 => write!(f, "u64"),
39      VarType::Bool => write!(f, "bool"),
40      VarType::F32 => write!(f, "f32"),
41      VarType::F64 => write!(f, "f64"),
42      VarType::Str => write!(f, "str"),
43      VarType::Void => write!(f, "void"),
44      VarType::Ptr => write!(f, "ptr"),
45    }
46  }
47}
48
49impl FromStr for VarType {
50  type Err = String;
51
52  fn from_str(s: &str) -> Result<Self, Self::Err> {
53    match s {
54      "i8" => Ok(VarType::I8),
55      "i16" => Ok(VarType::I16),
56      "i32" => Ok(VarType::I32),
57      "i64" => Ok(VarType::I64),
58      "u8" => Ok(VarType::U8),
59      "u16" => Ok(VarType::U16),
60      "u32" => Ok(VarType::U32),
61      "u64" => Ok(VarType::U64),
62      "bool" => Ok(VarType::Bool),
63      "f32" => Ok(VarType::F32),
64      "f64" => Ok(VarType::F64),
65      "str" => Ok(VarType::Str),
66      "ptr" => Ok(VarType::Ptr),
67      "void" => Ok(VarType::Void),
68      _ => Err(format!("Invalid type: {}", s)),
69    }
70  }
71}
72
73impl From<String> for VarType {
74  fn from(s: String) -> Self {
75    s.as_str().parse().unwrap()
76  }
77}
78
79impl From<VarType> for String {
80  fn from(value: VarType) -> Self {
81    match value {
82      VarType::I8 => "i8".to_string(),
83      VarType::I16 => "i16".to_string(),
84      VarType::I32 => "i32".to_string(),
85      VarType::I64 => "i64".to_string(),
86      VarType::U8 => "u8".to_string(),
87      VarType::U16 => "u16".to_string(),
88      VarType::U32 => "u32".to_string(),
89      VarType::U64 => "u64".to_string(),
90      VarType::Bool => "bool".to_string(),
91      VarType::F32 => "f32".to_string(),
92      VarType::F64 => "f64".to_string(),
93      VarType::Str => "str".to_string(),
94      VarType::Void => "void".to_string(),
95      VarType::Ptr => "ptr".to_string(),
96    }
97  }
98}
99
100#[derive(Clone, Debug, PartialEq)]
101pub enum Statement {
102  VariableDeclaration(Variable),
103
104  // if x op y goto L
105  ConditionalJump {
106    condition: Expr,
107    label: String,
108    location: Location,
109  },
110
111  // goto L
112  UnconditionalJump {
113    label: String,
114    location: Location,
115  },
116
117  // Label definition
118  Label {
119    name: String,
120    location: Location,
121  },
122
123  FunctionDefinition(Function),
124
125  // Store expression
126  Store {
127    at: Operand,
128    from: Operand,
129    location: Location,
130  },
131
132  Call(FunctionCall),
133
134  NoOperation,
135}
136
137#[derive(Clone, Debug, PartialEq)]
138pub struct FunctionCall {
139  pub name: String,
140  pub params: Vec<Operand>,
141  pub return_type: VarType,
142  pub location: Location,
143}
144
145#[derive(Clone, Debug, PartialEq)]
146pub struct Variable {
147  pub var_type: VarType,
148  pub name: String,
149  pub value: Expr,
150  pub location: Location,
151}
152
153#[derive(Clone, Debug, PartialEq)]
154pub struct Function {
155  pub name: String,
156  pub location: Location,
157  pub args: Vec<Argument>,
158  pub body: Vec<Statement>,
159  pub return_type: VarType,
160  pub is_builtin: bool,
161}
162
163// Expressions are statements that return a value, such as
164// function calls, arithmetic operations, literals, etc.
165#[derive(Clone, Debug, PartialEq)]
166pub enum Expr {
167  BinaryOperation(BinaryOperation),
168  FunctionCall(FunctionCall),
169  Operand(Operand),
170}
171
172// TODO: Impl get_type for Expr
173
174#[derive(Clone, Debug, PartialEq)]
175pub struct Return {
176  pub var_type: VarType,
177}
178
179#[derive(Clone, Debug, PartialEq)]
180pub struct Argument {
181  pub name: String,
182  pub var_type: VarType,
183}
184
185#[derive(Clone, Debug, PartialEq)]
186pub enum BinaryOperation {
187  Arithmetic {
188    lhs: Operand,
189    operator: Operator,
190    rhs: Operand,
191    operation_type: VarType,
192  },
193  Conditional {
194    lhs: Operand,
195    condition: Condition,
196    rhs: Operand,
197    operation_type: VarType,
198  },
199}
200
201#[derive(Clone, Debug, PartialEq)]
202pub enum Operand {
203  Identifier(String),
204  Dereference(String),
205  LiteralStr(String),
206  LiteralBool(bool),
207  LiteralI8(i8),
208  LiteralI16(i16),
209  LiteralI32(i32),
210  LiteralI64(i64),
211  LiteralU8(u8),
212  LiteralU16(u16),
213  LiteralU32(u32),
214  LiteralU64(u64),
215  LiteralF32(f32),
216  LiteralF64(f64),
217}
218
219impl Operand {
220  pub fn as_identifier(&self) -> Result<&str, String> {
221    Ok(match self {
222      Operand::Identifier(name) => name,
223      _ => return Err("Expected register, found immediate".to_string()),
224    })
225  }
226
227  pub fn as_immediate(&self) -> Result<i32, String> {
228    Ok(match self {
229      Operand::LiteralI8(val) => *val as i32,
230      Operand::LiteralI16(val) => *val as i32,
231      Operand::LiteralI32(val) => *val as i32,
232      Operand::LiteralI64(val) => *val as i32,
233      Operand::LiteralU8(val) => *val as i32,
234      Operand::LiteralU16(val) => *val as i32,
235      Operand::LiteralU32(val) => *val as i32,
236      Operand::LiteralU64(val) => *val as i32,
237      Operand::LiteralF32(val) => *val as i32,
238      Operand::LiteralF64(val) => *val as i32,
239      Operand::LiteralBool(val) => *val as i32,
240      _ => return Err("Expected immediate, found register".to_string()),
241    })
242  }
243
244  pub fn get_type(
245    &self,
246    context: &context::Context,
247    loc: Range<usize>,
248  ) -> Result<VarType, ParseError<usize, tokens::Token, LexicalError>> {
249    match self {
250      Operand::Identifier(variable_name) => {
251        let var = context
252          .get_variable(variable_name.clone())
253          .ok_or(ParseError::<usize, tokens::Token, LexicalError>::User {
254            error: LexicalError::UnknownVariable {
255              error: vec![ErrorTip {
256                message: format!("unknown variable `{}`", variable_name),
257                location: loc,
258              }],
259              help: None,
260            },
261          })?;
262
263        Ok(var.var_type)
264      }
265      Operand::LiteralStr(_) => Ok(VarType::Str),
266      Operand::LiteralU8(_) => Ok(VarType::U8),
267      Operand::LiteralU16(_) => Ok(VarType::U16),
268      Operand::LiteralU32(_) => Ok(VarType::U32),
269      Operand::LiteralU64(_) => Ok(VarType::U64),
270      Operand::LiteralI8(_) => Ok(VarType::I8),
271      Operand::LiteralI16(_) => Ok(VarType::I16),
272      Operand::LiteralI32(_) => Ok(VarType::I32),
273      Operand::LiteralI64(_) => Ok(VarType::I64),
274      Operand::LiteralBool(_) => Ok(VarType::Bool),
275      Operand::LiteralF32(_) => Ok(VarType::F32),
276      Operand::LiteralF64(_) => Ok(VarType::F64),
277      Operand::Dereference(_) => Ok(VarType::Ptr),
278    }
279  }
280}
281
282impl TryFrom<Operand> for VarType {
283  type Error = String;
284
285  fn try_from(operand: Operand) -> Result<Self, Self::Error> {
286    match operand {
287      Operand::Identifier(_) => Err("Cannot convert identifier to type".to_string()),
288      Operand::LiteralStr(_) => Ok(VarType::Str),
289      Operand::LiteralU8(_) => Ok(VarType::U8),
290      Operand::LiteralU16(_) => Ok(VarType::U16),
291      Operand::LiteralU32(_) => Ok(VarType::U32),
292      Operand::LiteralU64(_) => Ok(VarType::U64),
293      Operand::LiteralI8(_) => Ok(VarType::I8),
294      Operand::LiteralI16(_) => Ok(VarType::I16),
295      Operand::LiteralI32(_) => Ok(VarType::I32),
296      Operand::LiteralI64(_) => Ok(VarType::I64),
297      Operand::LiteralBool(_) => Ok(VarType::Bool),
298      Operand::LiteralF32(_) => Ok(VarType::F32),
299      Operand::LiteralF64(_) => Ok(VarType::F64),
300      Operand::Dereference(_) => Ok(VarType::Ptr),
301    }
302  }
303}
304
305impl std::fmt::Display for Operand {
306  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307    match self {
308      Operand::Identifier(name) => write!(f, "{}", name),
309      Operand::LiteralStr(value) => write!(f, "{}", value),
310      Operand::LiteralBool(value) => write!(f, "{}", value),
311      Operand::LiteralI8(value) => write!(f, "{}", value),
312      Operand::LiteralI16(value) => write!(f, "{}", value),
313      Operand::LiteralI32(value) => write!(f, "{}", value),
314      Operand::LiteralI64(value) => write!(f, "{}", value),
315      Operand::LiteralU8(value) => write!(f, "{}", value),
316      Operand::LiteralU16(value) => write!(f, "{}", value),
317      Operand::LiteralU32(value) => write!(f, "{}", value),
318      Operand::LiteralU64(value) => write!(f, "{}", value),
319      Operand::LiteralF32(value) => write!(f, "{}", value),
320      Operand::LiteralF64(value) => write!(f, "{}", value),
321      Operand::Dereference(value) => write!(f, "*{}", value),
322    }
323  }
324}
325
326#[derive(Clone, Debug, PartialEq)]
327pub enum Operator {
328  Add,
329  Sub,
330  Mul,
331  Div,
332}
333
334impl std::fmt::Display for Operator {
335  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336    match self {
337      Operator::Add => write!(f, "+"),
338      Operator::Sub => write!(f, "-"),
339      Operator::Mul => write!(f, "*"),
340      Operator::Div => write!(f, "/"),
341    }
342  }
343}
344
345#[derive(Clone, Debug, PartialEq)]
346pub enum Condition {
347  LessThan,
348  GreaterThan,
349  LessThanOrEqual,
350  GreaterThanOrEqual,
351  Equal,
352  NotEqual,
353  And,
354  Or,
355}