ugh, variance...

This commit is contained in:
numzero 2025-04-19 12:03:10 +03:00
parent c42a7b2251
commit 6c1e6d6bfa

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{cell::RefCell, collections::HashMap};
use crate::ast; use crate::ast;
@ -53,27 +53,62 @@ struct Call {
args: Vec<Expression>, args: Vec<Expression>,
} }
#[derive(Debug)] #[derive(Debug, Clone, Default)]
struct BuildContext<'a> { struct Scope {
parent: Option<&'a mut BuildContext<'a>>,
upvalues: Vec<(ast::Ident, Ident)>, upvalues: Vec<(ast::Ident, Ident)>,
scope: HashMap<ast::Ident, Ident>, scope: HashMap<ast::Ident, Ident>,
} }
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<Scope>,
}
impl BuildContext<'_> { impl BuildContext<'_> {
fn request(&mut self, name: &ast::Ident) -> Option<Ident> { fn request(&self, name: &ast::Ident) -> Option<Ident> {
if let Some(ident) = self.scope.get(name) { let mut scope = self.scope.borrow_mut();
if let Some(ident) = scope.scope.get(name) {
return Some(*ident); return Some(*ident);
} }
if let Some(ident) = self.parent.as_mut()?.request(name) { if let Some(ident) = self.parent.as_ref()?.request(name) {
let index = self.upvalues.len(); let index = scope.upvalues.len();
self.upvalues.push((name.clone(), ident)); scope.upvalues.push((name.clone(), ident));
return Some(Ident::Upvalue(index)); let ident = Ident::Upvalue(index);
scope.scope.insert(name.clone(), ident);
return Some(ident);
} }
None 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!() 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)
}