From 7d6168fdaeef77f13f3435bb30a65f62aa58842c Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Fri, 30 May 2025 18:29:04 +0800 Subject: [PATCH] feat: ir env (WIP) --- Cargo.lock | 7 + Cargo.toml | 1 + src/builtins/mod.rs | 9 +- src/env.rs | 17 +- src/ir.rs | 609 +++++++++++++++++++++++++++++++---------- src/jit/helpers.rs | 2 +- src/jit/test.rs | 2 +- src/stack.rs | 8 +- src/ty/internal/mod.rs | 2 +- src/vm/mod.rs | 7 +- 10 files changed, 500 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b93370a..2dc1b54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -334,6 +334,7 @@ dependencies = [ "inkwell", "itertools", "regex", + "replace_with", "rnix", "rpds", "rustyline", @@ -409,6 +410,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "replace_with" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884" + [[package]] name = "rnix" version = "0.12.0" diff --git a/Cargo.toml b/Cargo.toml index 75e3e5a..b280eab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,5 +30,6 @@ regex = "1.11" hashbrown = "0.15" inkwell = { version = "0.6.0", features = ["llvm18-1"] } gc-arena = { git = "https://github.com/kyren/gc-arena", rev = "d651e3b4363d525a2d502c2305bc73e291835c84", features= ["hashbrown"] } +replace_with = "0.1" rustyline = { version = "15.0", optional = true } diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index 9a0af14..66d33c1 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -1,11 +1,16 @@ use gc_arena::{Gc, Mutation}; use hashbrown::HashMap; -use crate::env::VmEnv; +use crate::env::{IrEnv, VmEnv}; use crate::ty::internal::{AttrSet, CoW, PrimOp, Value}; use crate::vm::VM; -pub fn env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> { +pub fn ir_env<'gc>(mc: &Mutation<'gc>) -> Gc<'gc, IrEnv<'gc>> { + // TODO: + IrEnv::new(Gc::new(mc, HashMap::new()), mc) +} + +pub fn vm_env<'gc>(vm: &VM, mc: &Mutation<'gc>) -> Gc<'gc, VmEnv<'gc>> { let primops = [ PrimOp::new("add", 2, |args, _, mc| { let Ok([mut first, second]): Result<[Value; 2], _> = args.try_into() else { diff --git a/src/env.rs b/src/env.rs index c5a8f62..9eb11b6 100644 --- a/src/env.rs +++ b/src/env.rs @@ -3,7 +3,7 @@ use std::hash::Hash; use gc_arena::{Collect, Gc, Mutation}; use hashbrown::HashMap; -use crate::ty::internal::Value; +use crate::{ir::Ir, ty::internal::Value}; #[derive(Collect)] #[collect(no_drop)] @@ -21,6 +21,7 @@ pub struct LetEnv<'gc, K: Hash + Eq + Collect<'gc>, V: Collect<'gc>> { } pub type VmEnv<'gc> = Env<'gc, usize, Value<'gc>>; +pub type IrEnv<'gc> = Env<'gc, usize, Ir>; #[derive(Default, Clone, Collect)] #[collect(no_drop)] @@ -62,13 +63,25 @@ impl<'gc, K: Hash + Eq + Clone + Collect<'gc>, V: Clone + Collect<'gc>> Env<'gc, ) } - pub fn lookup(&self, symbol: &K) -> Option<&V> { + pub fn lookup_slow(&self, symbol: &K) -> Option<&V> { if let Some(val) = self.let_.lookup(symbol) { return Some(val); } self.with.lookup(symbol) } + pub fn lookup_let(&self, symbol: &K) -> Option<&V> { + self.let_.lookup(symbol) + } + + pub fn lookup_with(&self, symbol: &K) -> Option<&V> { + self.with.lookup(symbol) + } + + pub fn has_with(&self) -> bool { + self.with.map.is_some() + } + pub fn enter_arg(self: Gc<'gc, Self>, ident: K, val: V, mc: &Mutation<'gc>) -> Gc<'gc, Self> { Gc::new( mc, diff --git a/src/ir.rs b/src/ir.rs index d1540b3..9c21cbb 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -1,34 +1,38 @@ -use derive_more::IsVariant; +use derive_more::{IsVariant, TryUnwrap, Unwrap}; +use gc_arena::{Arena, Collect, Gc, Mutation, Rootable}; use hashbrown::HashMap; use ecow::EcoString; +use replace_with::{replace_with, replace_with_or_abort}; use rnix::ast::{self, Expr}; +use crate::builtins::ir_env; use crate::compile::*; +use crate::env::IrEnv; use crate::error::*; use crate::ty::common as c; pub fn downgrade(expr: Expr) -> Result { - let mut ctx = DowngradeContext::new(); - let ir = expr.downgrade(&mut ctx)?; - Ok(Downgraded { - top_level: ir, - consts: ctx.consts.into(), - symbols: ctx.symbols, - symmap: ctx.symmap, - thunks: ctx.thunks.into(), - funcs: ctx.funcs.into(), + let mut arena: Arena]> = + Arena::new(|mc| DowngradeContext::new(mc)); + arena.mutate_root(|mc, ctx| { + let ir = expr.downgrade(ctx, mc)?; + let consts = std::mem::take(&mut ctx.consts).into(); + let symbols = std::mem::take(&mut ctx.symbols); + let symmap = std::mem::take(&mut ctx.symmap); + let thunks = std::mem::take(&mut ctx.thunks).into(); + let funcs = std::mem::take(&mut ctx.funcs).into(); + Ok(Downgraded { + top_level: ir, + consts, + symbols, + symmap, + thunks, + funcs, + }) }) } -trait Downcast -where - Self: Sized, -{ - fn downcast_ref(&self) -> Option<&T>; - fn downcast_mut(&mut self) -> Option<&mut T>; -} - macro_rules! ir { ( $( @@ -39,22 +43,55 @@ macro_rules! ir { ) ,*$(,)? ) => { - #[derive(Clone, Debug, IsVariant)] + #[derive(Clone, Debug, IsVariant, Unwrap, Collect)] + #[collect(require_static)] pub enum Ir { $( $ty($ty), )* } + #[derive(Debug, IsVariant, TryUnwrap)] + pub enum IrRef<'a> { + $( + $ty(&'a $ty), + )* + } + + #[derive(Debug, IsVariant, TryUnwrap)] + pub enum IrMut<'a> { + $( + $ty(&'a mut $ty), + )* + } + impl Ir { fn boxed(self) -> Box { Box::new(self) } + fn ok(self) -> Result { Ok(self) } - } + fn as_ref(&self) -> IrRef { + match self { + $(Ir::$ty(ir) => IrRef::$ty(ir),)* + } + } + + fn as_mut(&mut self) -> IrMut { + match self { + $(Ir::$ty(ir) => IrMut::$ty(ir),)* + } + } + + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + match self { + $(Ir::$ty(ir) => ir.resolve(ctx, mc),)* + } + } + } impl Compile for Ir { fn compile(self, ctx: &mut Compiler) { match self { @@ -67,7 +104,8 @@ macro_rules! ir { $( #[$($x)*] )* - #[derive(Clone, Debug)] + #[derive(Clone, Debug, Collect)] + #[collect(no_drop)] pub struct $ty { $( pub $name : $elemtype, @@ -79,21 +117,6 @@ macro_rules! ir { Ir::$ty(self) } } - - impl Downcast<$ty> for Ir { - fn downcast_ref(&self) -> Option<&$ty> { - match self { - Ir::$ty(value) => Some(value), - _ => None, - } - } - fn downcast_mut(&mut self) -> Option<&mut $ty> { - match self { - Ir::$ty(value) => Some(value), - _ => None, - } - } - } )* } } @@ -120,17 +143,38 @@ ir! { Path => { expr: Box }, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] pub struct DynamicAttrPair(pub Ir, pub Ir); -#[derive(Default)] -pub struct DowngradeContext { +pub struct DowngradeContext<'gc> { thunks: Vec, funcs: Vec, consts: Vec, constmap: HashMap, symbols: Vec, symmap: HashMap, + env: Gc<'gc, IrEnv<'gc>>, +} + +unsafe impl<'gc> Collect<'gc> for DowngradeContext<'gc> { + fn trace>(&self, cc: &mut T) { + self.env.trace(cc); + } +} + +impl<'gc> DowngradeContext<'gc> { + fn new(mc: &Mutation<'gc>) -> Self { + DowngradeContext { + thunks: Vec::default(), + funcs: Vec::default(), + consts: Vec::default(), + constmap: HashMap::default(), + symbols: Vec::default(), + symmap: HashMap::default(), + env: ir_env(mc), + } + } } pub struct Downgraded { @@ -142,11 +186,7 @@ pub struct Downgraded { pub funcs: Box<[Func]>, } -impl DowngradeContext { - fn new() -> DowngradeContext { - DowngradeContext::default() - } - +impl<'gc> DowngradeContext<'gc> { fn new_thunk(&mut self, thunk: Ir) -> Thunk { let idx = self.thunks.len(); self.thunks.push(thunk); @@ -181,6 +221,50 @@ impl DowngradeContext { self.symbols.len() - 1 } } + + fn enter_arg(&mut self, ident: usize, val: Ir, mc: &Mutation<'gc>) { + self.env = self.env.enter_arg(ident, val, mc) + } + + fn enter_let(&mut self, attrs: HashMap, mc: &Mutation<'gc>) { + self.env = self.env.enter_let(Gc::new(mc, attrs), mc) + } + + fn enter_with(&mut self, attrs: HashMap, mc: &Mutation<'gc>) { + self.env = self.env.enter_with(Gc::new(mc, attrs), mc) + } + + fn leave(&mut self) { + self.env = self.env.leave() + } + + fn lookup(&self, ident: usize) -> Result> { + self.env.lookup_let(&ident).map_or_else( + || { + Err(Error::DowngradeError(format!( + "{} not found", + &self.symbols[ident] + ))) + }, + |val| Ok(Some(val)), + ) + } + + fn resolve_func(&mut self, idx: usize) -> Result<()> { + self.funcs.get_mut(idx).map_or_else(|| unreachable!(), |func| { + *func = func.resolve()?; + Ok(()) + }) + } + + fn resolve_thunk(&mut self, idx: usize, mc: &Mutation<'gc>) -> Result<()> { + self.thunks.get_mut(idx).map_or_else(|| unreachable!(), |thunk| { + replace_with_or_abort(thunk, |thunk| { + thunk.resolve(self, mc) + }); + Ok(()) + }) + } } impl Attrs { @@ -192,11 +276,12 @@ impl Attrs { self.stcs .get_mut(&ident) .unwrap() - .downcast_mut() - .ok_or_else(|| { - Error::DowngradeError(format!( + .as_mut() + .try_unwrap_attrs() + .or_else(|_| { + Err(Error::DowngradeError(format!( r#""{ident}" already exsists in this set"# - )) + ))) }) .and_then(|attrs: &mut Attrs| attrs._insert(path, name, value)) } else { @@ -263,7 +348,7 @@ impl Attrs { Some(Attr::Str(ident)) => self .stcs .get(ident) - .and_then(|attrs| attrs.downcast_ref()) + .and_then(|attrs| attrs.as_ref().try_unwrap_attrs().ok()) .map_or(Some(false), |attrs: &Attrs| attrs._has_attr(path, name)), None => match name { Attr::Str(ident) => Some(self.stcs.get(&ident).is_some()), @@ -280,14 +365,32 @@ impl Attrs { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] pub enum Attr { Dynamic(Ir), Strs(ConcatStrings), Str(usize), } -#[derive(Clone, Debug)] +impl Attr { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + use Attr::*; + Ok(match self { + Dynamic(ir) => Dynamic(ir.resolve(ctx, mc)?), + other => other + }) + } +} + +impl Thunk { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + ctx.enter_with(attrs, mc); + } +} + +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] pub enum BinOpKind { Add, Sub, @@ -336,7 +439,8 @@ impl From for BinOpKind { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] pub enum UnOpKind { Neg, Not, @@ -351,12 +455,15 @@ impl From for UnOpKind { } } +#[derive(Collect)] +#[collect(no_drop)] pub struct Func { pub param: Param, pub body: Box, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] pub enum Param { Ident(usize), Formals { @@ -370,41 +477,52 @@ trait Downgrade where Self: Sized, { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result; + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result; } impl Downgrade for Expr { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { match self { - Expr::Apply(apply) => apply.downgrade(ctx), - Expr::Assert(assert) => assert.downgrade(ctx), + Expr::Apply(apply) => apply.downgrade(ctx, mc), + Expr::Assert(assert) => assert.downgrade(ctx, mc), Expr::Error(error) => Err(Error::DowngradeError(error.to_string())), - Expr::IfElse(ifelse) => ifelse.downgrade(ctx), - Expr::Select(select) => select.downgrade(ctx), - Expr::Str(str) => str.downgrade(ctx), - Expr::Path(path) => path.downgrade(ctx), - Expr::Literal(lit) => lit.downgrade(ctx), - Expr::Lambda(lambda) => lambda.downgrade(ctx), - Expr::LegacyLet(let_) => let_.downgrade(ctx), - Expr::LetIn(letin) => letin.downgrade(ctx), - Expr::List(list) => list.downgrade(ctx), - Expr::BinOp(op) => op.downgrade(ctx), - Expr::Paren(paren) => paren.expr().unwrap().downgrade(ctx), - Expr::Root(root) => root.expr().unwrap().downgrade(ctx), - Expr::AttrSet(attrs) => attrs.downgrade(ctx), - Expr::UnaryOp(op) => op.downgrade(ctx), - Expr::Ident(ident) => ident.downgrade(ctx), - Expr::With(with) => with.downgrade(ctx), - Expr::HasAttr(has) => has.downgrade(ctx), + Expr::IfElse(ifelse) => ifelse.downgrade(ctx, mc), + Expr::Select(select) => select.downgrade(ctx, mc), + Expr::Str(str) => str.downgrade(ctx, mc), + Expr::Path(path) => path.downgrade(ctx, mc), + Expr::Literal(lit) => lit.downgrade(ctx, mc), + Expr::Lambda(lambda) => lambda.downgrade(ctx, mc), + Expr::LegacyLet(let_) => let_.downgrade(ctx, mc), + Expr::LetIn(letin) => letin.downgrade(ctx, mc), + Expr::List(list) => list.downgrade(ctx, mc), + Expr::BinOp(op) => op.downgrade(ctx, mc), + Expr::Paren(paren) => paren.expr().unwrap().downgrade(ctx, mc), + Expr::Root(root) => root.expr().unwrap().downgrade(ctx, mc), + Expr::AttrSet(attrs) => attrs.downgrade(ctx, mc), + Expr::UnaryOp(op) => op.downgrade(ctx, mc), + Expr::Ident(ident) => ident.downgrade(ctx, mc), + Expr::With(with) => with.downgrade(ctx, mc), + Expr::HasAttr(has) => has.downgrade(ctx, mc), } } } impl Downgrade for ast::Assert { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { Assert { - assertion: self.condition().unwrap().downgrade(ctx)?.boxed(), - expr: self.body().unwrap().downgrade(ctx)?.boxed(), + assertion: self.condition().unwrap().downgrade(ctx, mc)?.boxed(), + expr: self.body().unwrap().downgrade(ctx, mc)?.boxed(), + } + .ir() + .ok() + } +} + +impl Assert { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + assertion: self.assertion.resolve(ctx, mc)?.boxed(), + expr: self.expr.resolve(ctx, mc)?.boxed(), } .ir() .ok() @@ -412,11 +530,23 @@ impl Downgrade for ast::Assert { } impl Downgrade for ast::IfElse { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { If { - cond: self.condition().unwrap().downgrade(ctx)?.boxed(), - consq: self.body().unwrap().downgrade(ctx)?.boxed(), - alter: self.else_body().unwrap().downgrade(ctx)?.boxed(), + cond: self.condition().unwrap().downgrade(ctx, mc)?.boxed(), + consq: self.body().unwrap().downgrade(ctx, mc)?.boxed(), + alter: self.else_body().unwrap().downgrade(ctx, mc)?.boxed(), + } + .ir() + .ok() + } +} + +impl If { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + If { + cond: self.cond.resolve(ctx, mc)?.boxed(), + consq: self.consq.resolve(ctx, mc)?.boxed(), + alter: self.alter.resolve(ctx, mc)?.boxed(), } .ir() .ok() @@ -424,13 +554,13 @@ impl Downgrade for ast::IfElse { } impl Downgrade for ast::Path { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { let parts = self .parts() .map(|part| match part { ast::InterpolPart::Literal(lit) => ctx.new_const(lit.to_string().into()).ir().ok(), ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(ctx) + interpol.expr().unwrap().downgrade(ctx, mc) } }) .collect::>>()?; @@ -448,15 +578,25 @@ impl Downgrade for ast::Path { } } +impl Path { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + expr: self.expr.resolve(ctx, mc)?.boxed(), + } + .ir() + .ok() + } +} + impl Downgrade for ast::Str { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { let parts = self .normalized_parts() .into_iter() .map(|part| match part { ast::InterpolPart::Literal(lit) => ctx.new_const(lit.into()).ir().ok(), ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(ctx) + interpol.expr().unwrap().downgrade(ctx, mc) } }) .collect::>>()?; @@ -468,8 +608,22 @@ impl Downgrade for ast::Str { } } +impl ConcatStrings { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + parts: self + .parts + .into_iter() + .map(|ir| ir.resolve(ctx, mc)) + .collect::>>()?, + } + .ir() + .ok() + } +} + impl Downgrade for ast::Literal { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, _: &Mutation<'gc>) -> Result { match self.kind() { ast::LiteralKind::Integer(int) => ctx.new_const(int.value().unwrap().into()), ast::LiteralKind::Float(float) => ctx.new_const(float.value().unwrap().into()), @@ -480,38 +634,88 @@ impl Downgrade for ast::Literal { } } +impl Const { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + self.ir().ok() + } +} + impl Downgrade for ast::Ident { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { - Var { - sym: ctx.new_sym(self.to_string()), + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, _: &Mutation<'gc>) -> Result { + let sym = ctx.new_sym(self.ident_token().unwrap().text()); + Var { sym }.ir().ok() + } +} + +impl Var { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + ctx.lookup(self.sym)? + .map_or(Var { ..self }.ir().ok(), |val| val.clone().ok()) + } +} + +impl Downgrade for ast::AttrSet { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let rec = self.rec_token().is_some(); + downgrade_has_entry(self, rec, ctx, mc).map(|attrs| attrs.ir()) + } +} + +impl Attrs { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + if self.rec { + todo!() + } else { + Self { + stcs: self + .stcs + .into_iter() + .map(|(k, v)| Ok((k, v.resolve(ctx, mc)?))) + .collect::>()?, + dyns: self + .dyns + .into_iter() + .map(|DynamicAttrPair(k, v)| { + Ok(DynamicAttrPair(k.resolve(ctx, mc)?, v.resolve(ctx, mc)?)) + }) + .collect::>()?, + rec: false, + } } .ir() .ok() } } -impl Downgrade for ast::AttrSet { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { - let rec = self.rec_token().is_some(); - downgrade_has_entry(self, rec, ctx).map(|attrs| attrs.ir()) - } -} - impl Downgrade for ast::List { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { let mut items = Vec::with_capacity(self.items().size_hint().0); for item in self.items() { - items.push(item.downgrade(ctx)?) + items.push(item.downgrade(ctx, mc)?) } List { items }.ir().ok() } } +impl List { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + items: self + .items + .into_iter() + .map(|item| item.resolve(ctx, mc)) + .collect::>()?, + } + .ir() + .ok() + } +} + impl Downgrade for ast::BinOp { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { BinOp { - lhs: self.lhs().unwrap().downgrade(ctx)?.boxed(), - rhs: self.rhs().unwrap().downgrade(ctx)?.boxed(), + lhs: self.lhs().unwrap().downgrade(ctx, mc)?.boxed(), + rhs: self.rhs().unwrap().downgrade(ctx, mc)?.boxed(), kind: self.operator().unwrap().into(), } .ir() @@ -519,10 +723,22 @@ impl Downgrade for ast::BinOp { } } +impl BinOp { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + lhs: self.lhs.resolve(ctx, mc)?.boxed(), + rhs: self.rhs.resolve(ctx, mc)?.boxed(), + ..self + } + .ir() + .ok() + } +} + impl Downgrade for ast::HasAttr { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { - let attrs = self.expr().unwrap().downgrade(ctx)?; - let path = downgrade_attrpath(self.attrpath().unwrap(), ctx)?; + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let attrs = self.expr().unwrap().downgrade(ctx, mc)?; + let path = downgrade_attrpath(self.attrpath().unwrap(), ctx, mc)?; HasAttr { lhs: attrs.boxed(), rhs: path, @@ -532,10 +748,21 @@ impl Downgrade for ast::HasAttr { } } +impl HasAttr { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + lhs: self.lhs.resolve(ctx, mc)?.boxed(), + rhs: self.rhs.into_iter().map(|attr| attr.resolve(ctx, mc)).collect::>()?, + } + .ir() + .ok() + } +} + impl Downgrade for ast::UnaryOp { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { UnOp { - rhs: self.expr().unwrap().downgrade(ctx)?.boxed(), + rhs: self.expr().unwrap().downgrade(ctx, mc)?.boxed(), kind: self.operator().unwrap().into(), } .ir() @@ -543,13 +770,24 @@ impl Downgrade for ast::UnaryOp { } } +impl UnOp { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + rhs: self.rhs.resolve(ctx, mc)?.boxed(), + ..self + } + .ir() + .ok() + } +} + impl Downgrade for ast::Select { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { Select { - expr: self.expr().unwrap().downgrade(ctx)?.boxed(), - attrpath: downgrade_attrpath(self.attrpath().unwrap(), ctx)?, + expr: self.expr().unwrap().downgrade(ctx, mc)?.boxed(), + attrpath: downgrade_attrpath(self.attrpath().unwrap(), ctx, mc)?, default: match self.default_expr() { - Some(default) => Some(default.downgrade(ctx)?.boxed()), + Some(default) => Some(default.downgrade(ctx, mc)?.boxed()), None => None, }, } @@ -558,12 +796,29 @@ impl Downgrade for ast::Select { } } +impl Select { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let default = if let Some(default) = self.default { + Some(default.resolve(ctx, mc)?.boxed()) + } else { + None + }; + Self { + expr: self.expr.resolve(ctx, mc)?.boxed(), + attrpath: self.attrpath.into_iter().map(|attr| attr.resolve(ctx, mc)).collect::>()?, + default + } + .ir() + .ok() + } +} + impl Downgrade for ast::LegacyLet { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { - let attrs = downgrade_has_entry(self, true, ctx)?; + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let attrs = downgrade_has_entry(self, true, ctx, mc)?; Select { expr: attrs.ir().boxed(), - attrpath: vec![Attr::Str(ctx.new_sym("body".to_string()))], + attrpath: vec![Attr::Str(ctx.new_sym("body"))], default: None, } .ir() @@ -572,59 +827,98 @@ impl Downgrade for ast::LegacyLet { } impl Downgrade for ast::LetIn { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { let body = self.body().unwrap(); - let attrs = downgrade_has_entry(self, true, ctx)?; - let expr = body.downgrade(ctx)?.boxed(); + let attrs = downgrade_has_entry(self, true, ctx, mc)?; + let expr = body.downgrade(ctx, mc)?.boxed(); Let { attrs, expr }.ir().ok() } } +impl Let { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let attrs = self.attrs.resolve(ctx, mc)?.unwrap_attrs(); + ctx.enter_let(attrs.stcs.clone(), mc); + let expr = self.expr.resolve(ctx, mc)?.boxed(); + ctx.leave(); + + Self { attrs, expr }.ir().ok() + } +} + impl Downgrade for ast::With { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { - let namespace = self.namespace().unwrap().downgrade(ctx)?; + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let namespace = self.namespace().unwrap().downgrade(ctx, mc)?; if let Ir::Attrs(attrs) = namespace { - let expr = self.body().unwrap().downgrade(ctx)?.boxed(); + let expr = self.body().unwrap().downgrade(ctx, mc)?.boxed(); Let { attrs, expr }.ir().ok() } else { let namespace = namespace.boxed(); - let expr = self.body().unwrap().downgrade(ctx)?.boxed(); + let expr = self.body().unwrap().downgrade(ctx, mc)?.boxed(); With { namespace, expr }.ir().ok() } } } +impl With { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let namespace = self.namespace.resolve(ctx, mc)?.boxed(); + ctx.enter_with(HashMap::new(), mc); + let expr = self.expr.resolve(ctx, mc)?.boxed(); + Self { namespace, expr }.ir().ok() + } +} + impl Downgrade for ast::Lambda { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { let body = self.body().unwrap(); - let param = downgrade_param(self.param().unwrap(), ctx)?; - let body = body.downgrade(ctx)?.boxed(); + let param = downgrade_param(self.param().unwrap(), ctx, mc)?; + let body = body.downgrade(ctx, mc)?.boxed(); ctx.new_func(Func { param, body }).ir().ok() } } impl Downgrade for ast::Apply { - fn downgrade(self, ctx: &mut DowngradeContext) -> Result { - let mut args = vec![self.argument().unwrap().downgrade(ctx)?]; + fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + let mut args = vec![self.argument().unwrap().downgrade(ctx, mc)?]; let mut func = self.lambda().unwrap(); while let ast::Expr::Apply(call) = func { func = call.lambda().unwrap(); - args.push(call.argument().unwrap().downgrade(ctx)?); + args.push(call.argument().unwrap().downgrade(ctx, mc)?); } - let func = func.downgrade(ctx)?.boxed(); + let func = func.downgrade(ctx, mc)?.boxed(); args.reverse(); Call { func, args }.ir().ok() } } -fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result { - match param { - ast::Param::IdentParam(ident) => Ok(Param::Ident(ctx.new_sym(ident.to_string()))), - ast::Param::Pattern(pattern) => downgrade_pattern(pattern, ctx), +impl Call { + fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result { + Self { + func: self.func.resolve(ctx, mc)?.boxed(), + args: self.args.into_iter().map(|arg| arg.resolve(ctx, mc)).collect::>()?, + } + .ir() + .ok() } } -fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Result { +fn downgrade_param<'gc>( + param: ast::Param, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, +) -> Result { + match param { + ast::Param::IdentParam(ident) => Ok(Param::Ident(ctx.new_sym(ident.to_string()))), + ast::Param::Pattern(pattern) => downgrade_pattern(pattern, ctx, mc), + } +} + +fn downgrade_pattern<'gc>( + pattern: ast::Pattern, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, +) -> Result { let formals = pattern .pat_entries() .map(|entry| { @@ -635,7 +929,7 @@ fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Resul entry .default() .unwrap() - .downgrade(ctx) + .downgrade(ctx, mc) .map(|ok| (ident, Some(ctx.new_thunk(ok)))) } }) @@ -651,10 +945,11 @@ fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Resul }) } -fn downgrade_has_entry( +fn downgrade_has_entry<'gc>( has_entry: impl ast::HasEntry, rec: bool, - ctx: &mut DowngradeContext, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, ) -> Result { let entires = has_entry.entries(); let mut attrs = Attrs { @@ -665,27 +960,30 @@ fn downgrade_has_entry( for entry in entires { match entry { - ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, ctx)?, - ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, ctx)?, + ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, ctx, mc)?, + ast::Entry::AttrpathValue(value) => { + downgrade_attrpathvalue(value, &mut attrs, ctx, mc)? + } } } Ok(attrs) } -fn downgrade_inherit( +fn downgrade_inherit<'gc>( inherit: ast::Inherit, stcs: &mut HashMap, - ctx: &mut DowngradeContext, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, ) -> Result<()> { let from = if let Some(from) = inherit.from() { - let from = from.expr().unwrap().downgrade(ctx)?; + let from = from.expr().unwrap().downgrade(ctx, mc)?; Some(ctx.new_thunk(from)) } else { None }; for attr in inherit.attrs() { - let ident = match downgrade_attr(attr, ctx)? { + let ident = match downgrade_attr(attr, ctx, mc)? { Attr::Str(ident) => ident, _ => { return Err(Error::DowngradeError( @@ -709,7 +1007,11 @@ fn downgrade_inherit( Ok(()) } -fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result { +fn downgrade_attr<'gc>( + attr: ast::Attr, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, +) -> Result { use ast::Attr::*; use ast::InterpolPart::*; match attr { @@ -722,7 +1024,7 @@ fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result { match parts.into_iter().next().unwrap() { Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident))), Interpolation(interpol) => { - Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?)) + Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx, mc)?)) } } } else { @@ -730,30 +1032,35 @@ fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result { .into_iter() .map(|part| match part { Literal(lit) => ctx.new_const(lit.into()).ir().ok(), - Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx), + Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx, mc), }) .collect::>>()?; Ok(Attr::Strs(ConcatStrings { parts })) } } - Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(ctx)?)), + Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(ctx, mc)?)), } } -fn downgrade_attrpath(attrpath: ast::Attrpath, ctx: &mut DowngradeContext) -> Result> { +fn downgrade_attrpath<'gc>( + attrpath: ast::Attrpath, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, +) -> Result> { attrpath .attrs() - .map(|attr| downgrade_attr(attr, ctx)) + .map(|attr| downgrade_attr(attr, ctx, mc)) .collect::>>() } -fn downgrade_attrpathvalue( +fn downgrade_attrpathvalue<'gc>( value: ast::AttrpathValue, attrs: &mut Attrs, - ctx: &mut DowngradeContext, + ctx: &mut DowngradeContext<'gc>, + mc: &Mutation<'gc>, ) -> Result<()> { - let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?; - let value = value.value().unwrap().downgrade(ctx)?; + let path = downgrade_attrpath(value.attrpath().unwrap(), ctx, mc)?; + let value = value.value().unwrap().downgrade(ctx, mc)?; let value = match value { x @ Ir::Const(_) => x, x => ctx.new_thunk(x).ir(), diff --git a/src/jit/helpers.rs b/src/jit/helpers.rs index 931fa12..867511e 100644 --- a/src/jit/helpers.rs +++ b/src/jit/helpers.rs @@ -350,7 +350,7 @@ extern "C" fn helper_call<'gc>( extern "C" fn helper_lookup(sym: usize, env: *const VmEnv) -> JITValue { let env = unsafe { env.as_ref() }.unwrap(); - let val: JITValue = env.lookup(&sym).unwrap().into(); + let val: JITValue = env.lookup_slow(&sym).unwrap().into(); val } diff --git a/src/jit/test.rs b/src/jit/test.rs index a238540..97c318c 100644 --- a/src/jit/test.rs +++ b/src/jit/test.rs @@ -10,7 +10,7 @@ use inkwell::context::Context; use ecow::EcoString; use rpds::vector_sync; -use crate::builtins::env; +use crate::builtins::vm_env; use crate::compile::compile; use crate::ir::downgrade; use crate::jit::JITContext; diff --git a/src/stack.rs b/src/stack.rs index ef391d2..c5b7fb4 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -16,7 +16,7 @@ macro_rules! into { } pub struct Stack { - items: [MaybeUninit; CAP], + items: Box<[MaybeUninit; CAP]>, top: usize, } @@ -37,7 +37,11 @@ impl Default for Stack { impl Stack { pub fn new() -> Self { Stack { - items: [const { MaybeUninit::uninit() }; CAP], + items: unsafe { + std::mem::transmute::>, Box<[MaybeUninit; CAP]>>( + Box::new_uninit(), + ) + }, top: 0, } } diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index 1e58b89..09e404e 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -608,7 +608,7 @@ impl<'gc> Thunk<'gc> { let _Thunk::Code(opcodes, env) = std::mem::replace(&mut *self.thunk.borrow_mut(mc), _Thunk::Suspended) else { - return Err(Error::EvalError("infinite recursion occured".into())); + return Err(Error::EvalError("infinite recursion encountered".into())); }; Ok((opcodes, env.unwrap())) } diff --git a/src/vm/mod.rs b/src/vm/mod.rs index f5faad0..f241a36 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -5,7 +5,7 @@ use hashbrown::{HashMap, HashSet}; use inkwell::context::Context; use itertools::Itertools; -use crate::builtins::env; +use crate::builtins::vm_env; use crate::bytecode::{BinOp, Func as F, OpCode, OpCodes, Program, UnOp}; use crate::env::VmEnv; use crate::error::*; @@ -22,7 +22,6 @@ use ecow::EcoString; mod test; const STACK_SIZE: usize = 8 * 1024 / size_of::(); -type GcArena = Arena GcRoot<'gc>]>; #[derive(Collect)] #[collect(require_static)] @@ -53,7 +52,7 @@ pub fn run(mut prog: Program) -> Result { vm, jit, stack: Stack::new(), - envs: vec![env(&vm, mc)], + envs: vec![vm_env(&vm, mc)], } }); prog.top_level.reverse(); @@ -331,7 +330,7 @@ fn single_op<'gc, const CAP: usize>( } OpCode::LookUp { sym } => { stack.push( - env.lookup(&sym) + env.lookup_slow(&sym) .ok_or_else(|| Error::EvalError(format!("{} not found", vm.get_sym(sym))))? .clone(), )?;