celestial_hub_compass/ast/
context.rs

1// A hash map of the variables by scope level in the parser.
2
3use std::collections::HashMap;
4
5use crate::ast::{Argument, VarType};
6
7use super::{Function, Statement, Variable};
8
9// A struct to hold the context of the parser.
10#[derive(Debug)]
11pub struct Context {
12  // The current scope level.
13  pub scope_level: usize,
14  // A hash map of the variables by scope level in the parser.
15  pub variables: HashMap<usize, Vec<Variable>>,
16
17  /// Function definitions
18  pub functions: HashMap<String, Function>,
19
20  pub optimization_level: u8,
21}
22
23impl Context {
24  pub fn new(optimization_level: u8) -> Self {
25    Self {
26      scope_level: 0,
27      optimization_level,
28      variables: HashMap::new(),
29      functions: HashMap::new(),
30    }
31  }
32
33  pub fn push_scope(&mut self) {
34    self.scope_level += 1;
35  }
36
37  pub fn pop_scope(&mut self) {
38    self.scope_level -= 1;
39  }
40
41  pub fn add_variable(&mut self, statement: Statement) {
42    let variable = statement.into();
43
44    if let Some(variables) = self.variables.get_mut(&self.scope_level) {
45      variables.push(variable);
46    } else {
47      self.variables.insert(self.scope_level, vec![variable]);
48    }
49  }
50
51  pub fn get_variable(&self, name: String) -> Option<&Variable> {
52    for scope in (0..=self.scope_level).rev() {
53      if let Some(variables) = self.variables.get(&scope) {
54        for variable in variables {
55          if variable.name == name {
56            return Some(variable);
57          }
58        }
59      }
60    }
61
62    None
63  }
64
65  pub fn add_function(&mut self, function: &Function) -> Result<(), String> {
66    if self.functions.contains_key(&function.name) {
67      return Err(format!("Function `{}` already defined", function.name));
68    }
69
70    self
71      .functions
72      .insert(function.name.clone(), function.clone());
73
74    Ok(())
75  }
76
77  pub fn get_function(&self, name: &str) -> Option<Function> {
78    self
79      .builtins()
80      .iter()
81      .find(|f| f.name == name)
82      .cloned()
83      .or_else(|| self.functions.get(name).cloned())
84  }
85
86  fn builtins(&self) -> Vec<Function> {
87    vec![
88      Function {
89        name: "write_string".to_string(),
90        body: vec![],
91        args: vec![Argument {
92          name: "message".to_string(),
93          var_type: VarType::Str,
94        }],
95        return_type: VarType::Void,
96        location: 0..0,
97        is_builtin: true,
98      },
99      Function {
100        name: "write_int".to_string(),
101        body: vec![],
102        args: vec![Argument {
103          name: "number".to_string(),
104          var_type: VarType::I32,
105        }],
106        return_type: VarType::Void,
107        location: 0..0,
108        is_builtin: true,
109      },
110      Function {
111        name: "read_int".to_string(),
112        body: vec![],
113        args: vec![],
114        return_type: VarType::I32,
115        location: 0..0,
116        is_builtin: true,
117      },
118      Function {
119        name: "read_string".to_string(),
120        body: vec![],
121        args: vec![Argument {
122          name: "size".to_string(),
123          var_type: VarType::U32,
124        }],
125        return_type: VarType::Str,
126        location: 0..0,
127        is_builtin: true,
128      },
129    ]
130  }
131}
132
133impl Default for Context {
134  fn default() -> Self {
135    Self::new(0)
136  }
137}
138
139impl From<Statement> for Variable {
140  fn from(statement: Statement) -> Self {
141    match statement {
142      Statement::VariableDeclaration(var) => var,
143      _ => panic!("Cannot convert statement to variable"),
144    }
145  }
146}