rune/compile/ir/
scopes.rs
1use crate::alloc::prelude::*;
2use crate::alloc::{self, HashMap};
3use crate::ast::Spanned;
4use crate::compile::{self, ErrorKind};
5use crate::hir;
6use crate::runtime::Value;
7
8pub(crate) struct MissingLocal(pub(crate) Box<str>);
10
11pub(crate) struct Scopes {
13 scopes: Vec<Scope>,
14}
15
16impl Scopes {
17 pub(crate) fn new() -> alloc::Result<Self> {
19 Ok(Self {
20 scopes: try_vec![Scope::default()],
21 })
22 }
23
24 pub(crate) fn clear_current(&mut self) -> Result<(), &'static str> {
26 let last = self
27 .scopes
28 .last_mut()
29 .ok_or("expected at least one scope")?;
30
31 last.locals.clear();
32 Ok(())
33 }
34
35 pub(crate) fn decl(&mut self, name: hir::Variable, value: Value) -> Result<(), ErrorKind> {
37 let last = self
38 .last_mut()
39 .ok_or_else(|| ErrorKind::msg("Expected at least one scope"))?;
40 last.locals.try_insert(name, value)?;
41 Ok(())
42 }
43
44 pub(crate) fn try_get(&self, name: &hir::Variable) -> Option<&Value> {
46 for scope in self.scopes.iter().rev() {
47 if let Some(current) = scope.locals.get(name) {
48 return Some(current);
49 }
50
51 if let ScopeKind::Isolate = scope.kind {
53 break;
54 }
55 }
56
57 None
58 }
59
60 pub(crate) fn get_name(
62 &self,
63 name: &hir::Variable,
64 span: &dyn Spanned,
65 ) -> compile::Result<&Value> {
66 for scope in self.scopes.iter().rev() {
67 if let Some(current) = scope.locals.get(name) {
68 return Ok(current);
69 }
70
71 if let ScopeKind::Isolate = scope.kind {
73 break;
74 }
75 }
76
77 Err(compile::Error::new(
78 span,
79 MissingLocal(name.try_to_string()?.try_into_boxed_str()?),
80 ))
81 }
82
83 pub(crate) fn get_name_mut(
85 &mut self,
86 name: &hir::Variable,
87 span: &dyn Spanned,
88 ) -> compile::Result<&mut Value> {
89 for scope in self.scopes.iter_mut().rev() {
90 if let Some(current) = scope.locals.get_mut(name) {
91 return Ok(current);
92 }
93
94 if let ScopeKind::Isolate = scope.kind {
96 break;
97 }
98 }
99
100 Err(compile::Error::new(
101 span,
102 MissingLocal(name.try_to_string()?.try_into_boxed_str()?),
103 ))
104 }
105
106 pub(crate) fn push(&mut self) -> alloc::Result<ScopeGuard> {
108 let length = self.scopes.len();
109 self.scopes.try_push(Scope::default())?;
110 Ok(ScopeGuard { length })
111 }
112
113 pub(crate) fn isolate(&mut self) -> alloc::Result<ScopeGuard> {
115 let length = self.scopes.len();
116 let scope = Scope {
117 kind: ScopeKind::Isolate,
118 ..Default::default()
119 };
120 self.scopes.try_push(scope)?;
121 Ok(ScopeGuard { length })
122 }
123
124 pub(crate) fn pop(&mut self, guard: ScopeGuard) -> Result<(), &'static str> {
125 if self.scopes.pop().is_none() {
126 return Err("expected at least one scope to pop");
127 }
128
129 if self.scopes.len() != guard.length {
130 return Err("scope length mismatch");
131 }
132
133 Ok(())
134 }
135
136 pub(crate) fn last_mut(&mut self) -> Option<&mut Scope> {
138 self.scopes.last_mut()
139 }
140}
141
142#[repr(transparent)]
143pub(crate) struct ScopeGuard {
144 length: usize,
145}
146
147#[derive(Debug, Clone, Copy)]
148enum ScopeKind {
149 None,
150 Isolate,
151}
152
153pub(crate) struct Scope {
154 kind: ScopeKind,
155 locals: HashMap<hir::Variable, Value>,
157}
158
159impl Default for Scope {
160 fn default() -> Self {
161 Self {
162 kind: ScopeKind::None,
163 locals: HashMap::new(),
164 }
165 }
166}