1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// A hash map of the variables by scope level in the parser.

use std::collections::HashMap;

use super::{Statement, Variable};

// A struct to hold the context of the parser.
#[derive(Debug)]
pub struct Context {
  // The current scope level.
  pub scope_level: usize,
  // A hash map of the variables by scope level in the parser.
  pub variables: HashMap<usize, Vec<Variable>>,
}

impl Context {
  pub fn new() -> Self {
    Self {
      scope_level: 0,
      variables: HashMap::new(),
    }
  }

  pub fn push_scope(&mut self) {
    self.scope_level += 1;
  }

  pub fn pop_scope(&mut self) {
    self.scope_level -= 1;
  }

  pub fn add_variable(&mut self, statement: Statement) {
    let variable = statement.into();

    if let Some(variables) = self.variables.get_mut(&self.scope_level) {
      variables.push(variable);
    } else {
      self.variables.insert(self.scope_level, vec![variable]);
    }
  }

  pub fn get_variable(&self, name: String) -> Option<&Variable> {
    for scope in (0..=self.scope_level).rev() {
      if let Some(variables) = self.variables.get(&scope) {
        for variable in variables {
          if variable.name == name {
            return Some(variable);
          }
        }
      }
    }

    None
  }
}

impl Default for Context {
  fn default() -> Self {
    Self::new()
  }
}

impl From<Statement> for Variable {
  fn from(statement: Statement) -> Self {
    match statement {
      Statement::VariableDeclaration(var) => var,
      _ => panic!("Cannot convert statement to variable"),
    }
  }
}