1use crate::language::{InternSymbol, Access};
4use crate::parser::stmt::Label;
5use crate::debug::symbol::DebugSymbol;
6use crate::codegen::JumpSite;
7use crate::codegen::opcodes::{LocalIndex, UpvalueIndex};
8use crate::codegen::funproto::UpvalueTarget;
9use crate::codegen::errors::CompileResult;
10
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub(super) enum LocalName {
14 Symbol(InternSymbol),
16
17 Receiver, NArgs, Anonymous, }
25
26
27#[derive(Debug, Clone)]
28pub(super) struct Local {
29 mode: Access,
30 name: LocalName,
31 index: LocalIndex,
32 captured: bool, }
34
35impl Local {
36 pub(super) fn mode(&self) -> Access { self.mode }
37 pub(super) fn name(&self) -> LocalName { self.name }
38 pub(super) fn index(&self) -> LocalIndex { self.index }
39 pub(super) fn captured(&self) -> bool { self.captured }
40}
41
42#[derive(Clone, Copy)]
43pub(super) enum InsertLocal {
44 CreateNew(LocalIndex),
45 HideExisting(LocalIndex),
46}
47
48impl From<InsertLocal> for LocalIndex {
49 fn from(result: InsertLocal) -> Self {
50 match result {
51 InsertLocal::CreateNew(local_index) => local_index,
52 InsertLocal::HideExisting(local_index) => local_index,
53 }
54 }
55}
56
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub(super) enum ScopeTag {
60 Block,
61 Loop,
62 Branch,
63 Function,
64 Global,
65 Temporary,
66}
67
68impl ScopeTag {
69 fn accepts_control_flow(&self, control_flow: ControlFlowTarget) -> bool {
70 match self {
71 Self::Block => matches!(control_flow,
72 ControlFlowTarget::Break(..)
73 ),
74
75 Self::Loop => matches!(control_flow,
76 ControlFlowTarget::Break(..) | ControlFlowTarget::Continue(..)
77 ),
78
79 _ => false,
80 }
81 }
82
83 fn hide_from_nro(&self) -> bool {
84 match self {
85 Self::Temporary => true,
86 _ => false,
87 }
88 }
89
90 pub(super) fn is_expr_block(&self) -> bool {
91 match self {
92 Self::Block | Self:: Branch => true,
93 _ => false,
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99pub(super) enum ControlFlowTarget {
100 Break(Option<Label>),
101 Continue(Option<Label>),
102}
103
104impl ControlFlowTarget {
105 pub(super) fn label(&self) -> Option<&Label> {
106 match self {
107 Self::Break(label) => label.as_ref(),
108 Self::Continue(label) => label.as_ref(),
109 }
110 }
111}
112
113#[derive(Debug, Default)]
115struct ControlFlowTracker {
116 label: Option<Label>,
117 continue_sites: Vec<JumpSite>,
118 break_sites: Vec<JumpSite>,
119}
120
121impl ControlFlowTracker {
122 fn new(label: Option<Label>) -> Self {
123 Self {
124 label,
125 continue_sites: Vec::new(),
126 break_sites: Vec::new(),
127 }
128 }
129}
130
131#[derive(Debug)]
132pub(super) struct Scope {
133 tag: ScopeTag,
134 depth: usize,
135 symbol: Option<DebugSymbol>,
136 prev_index: Option<LocalIndex>,
137 locals: Vec<Local>,
138 control_flow: ControlFlowTracker,
139}
140
141impl Scope {
142 pub(super) fn tag(&self) -> ScopeTag {
143 self.tag
144 }
145
146 pub(super) fn depth(&self) -> usize {
147 self.depth
148 }
149
150 pub(super) fn locals(&self) -> &[Local] {
151 self.locals.as_slice()
152 }
153
154 pub(super) fn debug_symbol(&self) -> Option<&DebugSymbol> {
155 self.symbol.as_ref()
156 }
157
158 pub(super) fn register_continue(&mut self, continue_site: JumpSite) {
159 self.control_flow.continue_sites.push(continue_site)
160 }
161
162 pub(super) fn continue_sites(&self) -> &[JumpSite] {
163 &self.control_flow.continue_sites
164 }
165
166 pub(super) fn register_break(&mut self, break_site: JumpSite) {
167 self.control_flow.break_sites.push(break_site)
168 }
169
170 pub(super) fn break_sites(&self) -> &[JumpSite] {
171 &self.control_flow.break_sites
172 }
173
174 fn control_flow_mut(&mut self) -> &mut ControlFlowTracker {
175 &mut self.control_flow
176 }
177
178 fn last_index(&self) -> Option<LocalIndex> {
179 self.locals.last().map_or(self.prev_index, |local| Some(local.index))
180 }
181
182 fn find_local(&self, name: &LocalName) -> Option<&Local> {
183 if matches!(name, LocalName::Anonymous) {
184 return None; }
186 self.locals.iter().find(|local| local.name == *name)
187 }
188
189 fn find_local_mut(&mut self, name: &LocalName) -> Option<&mut Local> {
190 if matches!(name, LocalName::Anonymous) {
191 return None; }
193 self.locals.iter_mut().find(|local| local.name == *name)
194 }
195
196 fn push_local(&mut self, mode: Access, name: LocalName) -> CompileResult<&Local> {
197 let index = self.last_index().map_or(
198 Ok(0),
199 |index| index.checked_add(1)
200 .ok_or("local variable limit reached")
201 )?;
202
203 let local = Local {
204 mode, name, index,
205 captured: false,
206 };
207
208 self.locals.push(local);
209 Ok(self.locals.last().unwrap())
210 }
211
212 fn insert_local(&mut self, mode: Access, name: LocalName) -> CompileResult<InsertLocal> {
213 if self.tag.hide_from_nro() {
215 debug_assert!(name == LocalName::Anonymous);
216 }
217
218 if let Some(mut local) = self.find_local_mut(&name) {
220 (*local).mode = mode; Ok(InsertLocal::HideExisting(local.index))
222 } else {
223 let local = self.push_local(mode, name)?;
224 Ok(InsertLocal::CreateNew(local.index))
225 }
226 }
227}
228
229
230#[derive(Debug)]
231struct NestedScopes {
232 toplevel: Scope,
233 nested: Vec<Scope>,
234}
235
236impl NestedScopes {
237 fn new(symbol: Option<&DebugSymbol>, tag: ScopeTag, label: Option<Label>) -> Self {
238 let toplevel = Scope {
239 tag,
240 depth: 0,
241 prev_index: None,
242 symbol: symbol.copied(),
243 locals: Vec::new(),
244 control_flow: ControlFlowTracker::new(label),
245 };
246
247 Self {
248 toplevel,
249 nested: Vec::new(),
250 }
251 }
252
253 fn is_nested(&self) -> bool {
254 !self.nested.is_empty()
255 }
256
257 fn current_scope(&self) -> &Scope {
258 self.nested.last().unwrap_or(&self.toplevel)
259 }
260
261 fn current_scope_mut(&mut self) -> &mut Scope {
262 self.nested.last_mut().unwrap_or(&mut self.toplevel)
263 }
264
265 fn push_scope(&mut self, symbol: Option<&DebugSymbol>, label: Option<Label>, tag: ScopeTag) {
266 let current_scope = self.current_scope();
267
268 let scope = Scope {
269 tag,
270 depth: current_scope.depth() + 1,
271 prev_index: current_scope.last_index(),
272 symbol: symbol.copied(),
273 locals: Vec::new(),
274 control_flow: ControlFlowTracker::new(label),
275 };
276
277 self.nested.push(scope);
278 }
279
280 fn pop_scope(&mut self) -> Scope {
281 self.nested.pop().expect("pop toplevel scope")
282 }
283
284 fn iter_nro(&self) -> impl Iterator<Item=&Scope> {
286 self.nested.iter().rev()
287 .chain(std::iter::once(&self.toplevel))
288 .filter(|scope| !scope.tag().hide_from_nro())
289 }
290
291 fn iter_nro_mut(&mut self) -> impl Iterator<Item=&mut Scope> {
292 self.nested.iter_mut().rev()
293 .chain(std::iter::once(&mut self.toplevel))
294 .filter(|scope| !scope.tag().hide_from_nro())
295 }
296}
297
298
299#[derive(Debug, Clone)]
300pub(super) struct Upvalue {
301 mode: Access,
302 name: LocalName,
303 index: UpvalueIndex,
304 target: UpvalueTarget,
305}
306
307impl Upvalue {
308 pub(super) fn mode(&self) -> Access { self.mode }
309 pub(super) fn name(&self) -> LocalName { self.name }
310 pub(super) fn index(&self) -> UpvalueIndex { self.index }
311 pub(super) fn target(&self) -> UpvalueTarget { self.target }
312}
313
314
315#[derive(Debug)]
316pub(super) struct CallFrame {
317 scopes: NestedScopes,
318 upvalues: Vec<Upvalue>,
319}
320
321impl CallFrame {
322 fn new(symbol: Option<&DebugSymbol>) -> Self {
323 Self {
324 scopes: NestedScopes::new(symbol, ScopeTag::Function, None),
325 upvalues: Vec::new(),
326 }
327 }
328
329 pub(super) fn upvalues(&self) -> &[Upvalue] { self.upvalues.as_slice() }
330
331 pub(super) fn iter_locals(&self) -> impl Iterator<Item=&Local> {
332 self.scopes().iter_nro().flat_map(|scope| scope.locals().iter())
333 }
334
335 fn scopes(&self) -> &NestedScopes { &self.scopes }
336
337 fn scopes_mut(&mut self) -> &mut NestedScopes { &mut self.scopes }
338
339 fn find_upval(&self, name: &LocalName) -> Option<&Upvalue> {
340 self.upvalues.iter().find(|upval| upval.name == *name)
341 }
342
343 fn create_upval_for_local(&mut self, local: &mut Local) -> CompileResult<&Upvalue> {
344 let index = UpvalueIndex::try_from(self.upvalues.len())
345 .map_err(|_| "upvalue limit reached")?;
346
347 let upval = Upvalue {
348 index,
349 mode: local.mode,
350 name: local.name,
351 target: UpvalueTarget::Local(local.index),
352 };
353 self.upvalues.push(upval);
354
355 local.captured = true;
356
357 Ok(self.upvalues.last().unwrap())
358 }
359
360 fn create_upval_for_upval(&mut self, upval: &Upvalue) -> CompileResult<&Upvalue> {
361 let index = UpvalueIndex::try_from(self.upvalues.len())
362 .map_err(|_| "upvalue limit reached")?;
363
364 let upval = Upvalue {
365 index,
366 mode: upval.mode,
367 name: upval.name,
368 target: UpvalueTarget::Upvalue(upval.index),
369 };
370
371 self.upvalues.push(upval);
372
373 Ok(self.upvalues.last().unwrap())
374 }
375}
376
377
378#[derive(Debug)]
379pub(super) struct ScopeTracker {
380 toplevel: NestedScopes,
381 frames: Vec<CallFrame>,
382}
383
384impl ScopeTracker {
385 pub(super) fn new() -> Self {
386 Self {
387 toplevel: NestedScopes::new(None, ScopeTag::Global, None),
388 frames: Vec::new(),
389 }
390 }
391
392 pub(super) fn is_global_scope(&self) -> bool {
393 self.get_current_scope(true).tag() == ScopeTag::Global
395 }
396
397 pub(super) fn is_temporary_scope(&self) -> bool {
398 self.local_scopes().current_scope().tag() == ScopeTag::Temporary
399 }
400
401 pub(super) fn is_call_frame(&self) -> bool {
402 !self.frames.is_empty()
403 }
404
405 pub(super) fn push_frame(&mut self, symbol: Option<&DebugSymbol>) {
406 self.frames.push(CallFrame::new(symbol))
407 }
408
409 pub(super) fn pop_frame(&mut self) -> CallFrame {
410 self.frames.pop().expect("pop empty frames")
411 }
412
413 fn local_scopes(&self) -> &NestedScopes {
414 self.frames.last()
415 .map_or(&self.toplevel, |frame| frame.scopes())
416 }
417
418 fn local_scopes_mut(&mut self) -> &mut NestedScopes {
419 self.frames.last_mut()
420 .map_or(&mut self.toplevel, |frame| frame.scopes_mut())
421 }
422
423 fn get_current_scope(&self, ignore_temp: bool) -> &Scope {
424 if ignore_temp {
425 self.local_scopes()
426 .iter_nro().next()
427 .expect("empty nro")
428 } else {
429 self.local_scopes().current_scope()
430 }
431 }
432
433 fn get_current_scope_mut(&mut self, ignore_temp: bool) -> &mut Scope {
434 if ignore_temp {
435 self.local_scopes_mut()
436 .iter_nro_mut().next()
437 .expect("empty nro")
438 } else {
439 self.local_scopes_mut().current_scope_mut()
440 }
441 }
442
443 pub(super) fn push_scope(&mut self, symbol: Option<&DebugSymbol>, label: Option<Label>, tag: ScopeTag) -> &mut Scope {
446 let local_scope = self.local_scopes_mut();
447 local_scope.push_scope(symbol, label, tag);
448 local_scope.current_scope_mut()
449 }
450
451 pub(super) fn pop_scope(&mut self) -> Scope {
452 let scope = self.local_scopes_mut().pop_scope();
453 scope
454 }
455
456 pub(super) fn insert_local(&mut self, mode: Access, name: LocalName) -> CompileResult<InsertLocal> {
459 self.get_current_scope_mut(name != LocalName::Anonymous)
460 .insert_local(mode, name)
461 }
462
463 pub(super) fn resolve_local(&self, name: &LocalName) -> Option<&Local> {
464 self.local_scopes()
465 .iter_nro().find_map(|scope| scope.find_local(name))
466 }
467
468 pub(super) fn resolve_or_create_upval(&mut self, name: &LocalName) -> CompileResult<Option<&Upvalue>> {
471 if self.frames.is_empty() {
472 return Ok(None);
473 }
474
475 let frame_idx = self.frames.len() - 1;
476 let upval = self.resolve_upval_helper(name, frame_idx)?
477 .map(|idx| &self.frames.last().unwrap().upvalues[usize::from(idx)]);
478
479 Ok(upval)
480 }
481
482 fn resolve_upval_helper(&mut self, name: &LocalName, frame_idx: usize) -> CompileResult<Option<UpvalueIndex>> {
484 {
485 let (current_frame, enclosing_frame) = Self::get_frames_mut(&mut self.frames, frame_idx);
486
487 if let Some(upval) = current_frame.find_upval(name) {
489 return Ok(Some(upval.index));
490 }
491
492 let enclosing = enclosing_frame.map_or(&mut self.toplevel, |frame| frame.scopes_mut());
494 if let Some(local) = enclosing.iter_nro_mut().find_map(|scope| scope.find_local_mut(name)) {
495 return Ok(Some(current_frame.create_upval_for_local(local)?.index));
496 }
497 }
498
499 if frame_idx > 0 {
501 if let Some(upval_idx) = self.resolve_upval_helper(name, frame_idx-1)? {
502 let (current_frame, enclosing_frame) = Self::get_frames_mut(&mut self.frames, frame_idx);
503 if let Some(enclosing_frame) = enclosing_frame {
504 let upval = &enclosing_frame.upvalues()[usize::from(upval_idx)];
505
506 return Ok(Some(current_frame.create_upval_for_upval(upval)?.index));
507 }
508 }
509 }
510
511 Ok(None)
512 }
513
514 fn get_frames_mut(frames: &mut [CallFrame], frame_idx: usize) -> (&mut CallFrame, Option<&mut CallFrame>) {
516 let (frames, _) = frames.split_at_mut(frame_idx + 1);
517 let (current_frame, frames) = frames.split_last_mut().unwrap();
518 let enclosing_frame = frames.split_last_mut().map(|(last, _)| last);
519 (current_frame, enclosing_frame)
520 }
521
522 pub(super) fn resolve_control_flow(&self, target: ControlFlowTarget) -> Option<&Scope> {
526 self.local_scopes()
527 .iter_nro()
528 .find_map(|scope| {
529 if scope.tag().accepts_control_flow(target) {
530 if target.label().is_none() || target.label() == scope.control_flow.label.as_ref() {
531 return Some(scope)
532 }
533 }
534 None
535 })
536 }
537
538 pub(super) fn iter_scopes(&self) -> impl Iterator<Item=&Scope> {
539 self.local_scopes().iter_nro()
540 }
541
542 pub(super) fn iter_scopes_mut(&mut self) -> impl Iterator<Item=&mut Scope> {
543 self.local_scopes_mut().iter_nro_mut()
544 }
545}