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