datex_core/compiler/
scope.rs1use crate::ast::expressions::VariableKind;
2use crate::collections::HashMap;
3use crate::compiler::precompiler::precompiled_ast::RichAst;
4use crate::compiler::precompiler::scope_stack::PrecompilerScopeStack;
5use crate::compiler::{Variable, VariableRepresentation, context::VirtualSlot};
6use crate::runtime::execution::context::ExecutionMode;
7use core::cell::RefCell;
8
9#[derive(Debug, Default, Clone)]
10pub struct PrecompilerData {
11 pub rich_ast: RichAst,
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 execution_mode: ExecutionMode,
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 execution_mode: ExecutionMode::Static,
46 was_used: false,
47 }
48 }
49}
50
51impl CompilationScope {
52 pub fn new(execution_mode: ExecutionMode) -> CompilationScope {
53 CompilationScope {
54 execution_mode,
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 mark_as_last_execution(&mut self) {
69 match self.execution_mode {
70 ExecutionMode::Static => {
71 panic!(
72 "mark_as_last_execution can only be called for Unbounded execution modes"
73 );
74 }
75 ExecutionMode::Unbounded { .. } => {
76 self.execution_mode =
77 ExecutionMode::Unbounded { has_next: false };
78 }
79 _ => {}
80 }
81 }
82
83 pub fn has_external_parent_scope(&self) -> bool {
84 self.external_parent_scope.is_some()
85 }
86
87 pub fn register_variable_slot(&mut self, variable: Variable) {
88 self.variables.insert(variable.name.clone(), variable);
89 }
90
91 pub fn get_next_virtual_slot(&mut self) -> u32 {
92 let slot_address = self.next_slot_address;
93 self.next_slot_address += 1;
94 slot_address
95 }
96
97 pub fn resolve_variable_name_to_virtual_slot(
101 &self,
102 name: &str,
103 ) -> Option<(VirtualSlot, VariableKind)> {
104 if let Some(variable) = self.variables.get(name) {
105 let slot = match variable.representation {
106 VariableRepresentation::Constant(slot) => slot,
107 VariableRepresentation::VariableReference {
108 container_slot,
109 ..
110 } => container_slot,
111 VariableRepresentation::VariableSlot(slot) => slot,
112 };
113 Some((slot, variable.kind))
114 } else if let Some(external_parent) = &self.external_parent_scope {
115 external_parent
116 .resolve_variable_name_to_virtual_slot(name)
117 .map(|(virt_slot, var_type)| (virt_slot.downgrade(), var_type))
118 } else if let Some(parent) = &self.parent_scope {
119 parent.resolve_variable_name_to_virtual_slot(name)
120 } else {
121 None
122 }
123 }
124
125 pub fn push(self) -> CompilationScope {
127 CompilationScope {
128 next_slot_address: self.next_slot_address,
129 parent_scope: Some(Box::new(self)),
130 external_parent_scope: None,
131 variables: HashMap::new(),
132 precompiler_data: None,
133 execution_mode: ExecutionMode::Static,
134 was_used: false,
135 }
136 }
137
138 pub fn pop(self) -> Option<(CompilationScope, Vec<VirtualSlot>)> {
141 if let Some(mut parent) = self.parent_scope {
142 parent.next_slot_address = self.next_slot_address;
144 Some((
145 *parent,
146 self.variables
147 .keys()
148 .flat_map(|k| self.variables[k].slots())
149 .collect::<Vec<_>>(),
150 ))
151 } else {
152 None
153 }
154 }
155
156 pub fn pop_external(self) -> Option<CompilationScope> {
157 self.external_parent_scope
158 .map(|external_parent| *external_parent)
159 }
160}