datex_core/compiler/
scope.rs1use crate::ast::VariableKind;
2use crate::compiler::precompiler::{AstMetadata, PrecompilerScopeStack};
3use crate::compiler::{Variable, VariableRepresentation, context::VirtualSlot};
4use itertools::Itertools;
5use std::cell::RefCell;
6use std::collections::HashMap;
7use std::rc::Rc;
8
9#[derive(Debug, Clone, Default)]
10pub struct PrecompilerData {
11 pub ast_metadata: Rc<RefCell<AstMetadata>>,
13 pub precompiler_scope_stack: RefCell<PrecompilerScopeStack>,
15}
16
17#[derive(Debug, Clone)]
18pub struct CompilationScope {
19 variables: HashMap<String, Variable>,
21 parent_scope: Option<Box<CompilationScope>>,
23 external_parent_scope: Option<Box<CompilationScope>>,
25 next_slot_address: u32,
26
27 pub precompiler_data: Option<PrecompilerData>,
30 pub once: bool,
33 pub was_used: bool,
35}
36
37impl Default for CompilationScope {
38 fn default() -> Self {
39 CompilationScope {
40 variables: HashMap::new(),
41 parent_scope: None,
42 external_parent_scope: None,
43 next_slot_address: 0,
44 precompiler_data: Some(PrecompilerData::default()),
45 once: false,
46 was_used: false,
47 }
48 }
49}
50
51impl CompilationScope {
52 pub fn new(once: bool) -> CompilationScope {
53 CompilationScope {
54 once,
55 ..CompilationScope::default()
56 }
57 }
58
59 pub fn new_with_external_parent_scope(
60 parent_context: CompilationScope,
61 ) -> CompilationScope {
62 CompilationScope {
63 external_parent_scope: Some(Box::new(parent_context)),
64 ..CompilationScope::default()
65 }
66 }
67
68 pub fn has_external_parent_scope(&self) -> bool {
69 self.external_parent_scope.is_some()
70 }
71
72 pub fn register_variable_slot(&mut self, variable: Variable) {
73 self.variables.insert(variable.name.clone(), variable);
74 }
75
76 pub fn get_next_virtual_slot(&mut self) -> u32 {
77 let slot_address = self.next_slot_address;
78 self.next_slot_address += 1;
79 slot_address
80 }
81
82 pub fn resolve_variable_name_to_virtual_slot(
86 &self,
87 name: &str,
88 ) -> Option<(VirtualSlot, VariableKind)> {
89 if let Some(variable) = self.variables.get(name) {
90 let slot = match variable.representation {
91 VariableRepresentation::Constant(slot) => slot,
92 VariableRepresentation::VariableReference {
93 container_slot,
94 ..
95 } => container_slot,
96 VariableRepresentation::VariableSlot(slot) => slot,
97 };
98 Some((slot, variable.kind))
99 } else if let Some(external_parent) = &self.external_parent_scope {
100 external_parent
101 .resolve_variable_name_to_virtual_slot(name)
102 .map(|(virt_slot, var_type)| (virt_slot.downgrade(), var_type))
103 } else if let Some(parent) = &self.parent_scope {
104 parent.resolve_variable_name_to_virtual_slot(name)
105 } else {
106 None
107 }
108 }
109
110 pub fn push(self) -> CompilationScope {
112 CompilationScope {
113 next_slot_address: self.next_slot_address,
114 parent_scope: Some(Box::new(self)),
115 external_parent_scope: None,
116 variables: HashMap::new(),
117 precompiler_data: None,
118 once: true,
119 was_used: false,
120 }
121 }
122
123 pub fn pop(self) -> Option<(CompilationScope, Vec<VirtualSlot>)> {
126 if let Some(mut parent) = self.parent_scope {
127 parent.next_slot_address = self.next_slot_address;
129 Some((
130 *parent,
131 self.variables
132 .keys()
133 .flat_map(|k| self.variables[k].slots())
134 .collect::<Vec<_>>(),
135 ))
136 } else {
137 None
138 }
139 }
140
141 pub fn pop_external(self) -> Option<CompilationScope> {
142 self.external_parent_scope
143 .map(|external_parent| *external_parent)
144 }
145}