From 6c1e6d6bfa9e87327347fbe8a7ae35ae7c3fc5d0 Mon Sep 17 00:00:00 2001 From: numzero Date: Sat, 19 Apr 2025 12:03:10 +0300 Subject: [PATCH] ugh, variance... --- src/twopass.rs | 57 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/src/twopass.rs b/src/twopass.rs index 18f85ea..37b3ae3 100644 --- a/src/twopass.rs +++ b/src/twopass.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{cell::RefCell, collections::HashMap}; use crate::ast; @@ -53,27 +53,62 @@ struct Call { args: Vec, } -#[derive(Debug)] -struct BuildContext<'a> { - parent: Option<&'a mut BuildContext<'a>>, +#[derive(Debug, Clone, Default)] +struct Scope { upvalues: Vec<(ast::Ident, Ident)>, scope: HashMap, } +impl Scope { + fn new_toplevel() -> Self { + Self { + upvalues: vec![("_ENV".to_string(), Ident::Local(0))], + scope: [("_ENV".to_string(), Ident::Upvalue(0))] + .into_iter() + .collect(), + } + } +} + +#[derive(Debug)] +struct BuildContext<'a> { + parent: Option<&'a BuildContext<'a>>, // mustn't be &mut because of variance + scope: RefCell, +} + impl BuildContext<'_> { - fn request(&mut self, name: &ast::Ident) -> Option { - if let Some(ident) = self.scope.get(name) { + fn request(&self, name: &ast::Ident) -> Option { + let mut scope = self.scope.borrow_mut(); + if let Some(ident) = scope.scope.get(name) { return Some(*ident); } - if let Some(ident) = self.parent.as_mut()?.request(name) { - let index = self.upvalues.len(); - self.upvalues.push((name.clone(), ident)); - return Some(Ident::Upvalue(index)); + if let Some(ident) = self.parent.as_ref()?.request(name) { + let index = scope.upvalues.len(); + scope.upvalues.push((name.clone(), ident)); + let ident = Ident::Upvalue(index); + scope.scope.insert(name.clone(), ident); + return Some(ident); } None } } -pub fn build(code: ast::Function) -> Function { +fn build_in_scope(parent: &BuildContext<'_>, code: ast::Function) -> Function { + let scope = BuildContext { + parent: Some(parent), + scope: Default::default(), + }; + if false { + build_in_scope(&scope, code.clone()); + build_in_scope(&scope, code.clone()); + } todo!() } + +pub fn build(code: ast::Function) -> Function { + let mut root = BuildContext { + parent: None, + scope: RefCell::new(Scope::new_toplevel()), + }; + build_in_scope(&mut root, code) +}