feat: ir env (WIP)

This commit is contained in:
2025-05-30 18:29:04 +08:00
parent c548c4c6ac
commit 7d6168fdae
10 changed files with 500 additions and 164 deletions

View File

@@ -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 {

View File

@@ -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,

609
src/ir.rs
View File

@@ -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<Downgraded> {
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<Rootable![DowngradeContext<'_>]> =
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<T: Sized>
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<Self> {
Box::new(self)
}
fn ok(self) -> Result<Self> {
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<Ir> {
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<Ir> },
}
#[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<Ir>,
funcs: Vec<Func>,
consts: Vec<c::Const>,
constmap: HashMap<c::Const, usize>,
symbols: Vec<EcoString>,
symmap: HashMap<EcoString, usize>,
env: Gc<'gc, IrEnv<'gc>>,
}
unsafe impl<'gc> Collect<'gc> for DowngradeContext<'gc> {
fn trace<T: gc_arena::collect::Trace<'gc>>(&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<usize, Ir>, mc: &Mutation<'gc>) {
self.env = self.env.enter_let(Gc::new(mc, attrs), mc)
}
fn enter_with(&mut self, attrs: HashMap<usize, Ir>, 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<Option<&Ir>> {
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<Attr> {
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<Attr> {
ctx.enter_with(attrs, mc);
}
}
#[derive(Clone, Debug, Collect)]
#[collect(require_static)]
pub enum BinOpKind {
Add,
Sub,
@@ -336,7 +439,8 @@ impl From<ast::BinOpKind> for BinOpKind {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Collect)]
#[collect(require_static)]
pub enum UnOpKind {
Neg,
Not,
@@ -351,12 +455,15 @@ impl From<ast::UnaryOpKind> for UnOpKind {
}
}
#[derive(Collect)]
#[collect(no_drop)]
pub struct Func {
pub param: Param,
pub body: Box<Ir>,
}
#[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<Ir>;
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir>;
}
impl Downgrade for Expr {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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::<Result<Vec<_>>>()?;
@@ -448,15 +578,25 @@ impl Downgrade for ast::Path {
}
}
impl Path {
fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
Self {
expr: self.expr.resolve(ctx, mc)?.boxed(),
}
.ir()
.ok()
}
}
impl Downgrade for ast::Str {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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::<Result<Vec<_>>>()?;
@@ -468,8 +608,22 @@ impl Downgrade for ast::Str {
}
}
impl ConcatStrings {
fn resolve<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
Self {
parts: self
.parts
.into_iter()
.map(|ir| ir.resolve(ctx, mc))
.collect::<Result<Vec<_>>>()?,
}
.ir()
.ok()
}
}
impl Downgrade for ast::Literal {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, _: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
self.ir().ok()
}
}
impl Downgrade for ast::Ident {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
Var {
sym: ctx.new_sym(self.to_string()),
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, _: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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<Ir> {
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<Ir> {
if self.rec {
todo!()
} else {
Self {
stcs: self
.stcs
.into_iter()
.map(|(k, v)| Ok((k, v.resolve(ctx, mc)?)))
.collect::<Result<_>>()?,
dyns: self
.dyns
.into_iter()
.map(|DynamicAttrPair(k, v)| {
Ok(DynamicAttrPair(k.resolve(ctx, mc)?, v.resolve(ctx, mc)?))
})
.collect::<Result<_>>()?,
rec: false,
}
}
.ir()
.ok()
}
}
impl Downgrade for ast::AttrSet {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
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<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
Self {
items: self
.items
.into_iter()
.map(|item| item.resolve(ctx, mc))
.collect::<Result<_>>()?,
}
.ir()
.ok()
}
}
impl Downgrade for ast::BinOp {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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<Ir> {
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<Ir> {
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<Ir> {
Self {
lhs: self.lhs.resolve(ctx, mc)?.boxed(),
rhs: self.rhs.into_iter().map(|attr| attr.resolve(ctx, mc)).collect::<Result<_>>()?,
}
.ir()
.ok()
}
}
impl Downgrade for ast::UnaryOp {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
Self {
rhs: self.rhs.resolve(ctx, mc)?.boxed(),
..self
}
.ir()
.ok()
}
}
impl Downgrade for ast::Select {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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::<Result<_>>()?,
default
}
.ir()
.ok()
}
}
impl Downgrade for ast::LegacyLet {
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let attrs = downgrade_has_entry(self, true, ctx)?;
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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<Ir> {
let namespace = self.namespace().unwrap().downgrade(ctx)?;
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
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<Ir> {
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Ir> {
let mut args = vec![self.argument().unwrap().downgrade(ctx)?];
fn downgrade<'gc>(self, ctx: &mut DowngradeContext<'gc>, mc: &Mutation<'gc>) -> Result<Ir> {
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<Param> {
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<Ir> {
Self {
func: self.func.resolve(ctx, mc)?.boxed(),
args: self.args.into_iter().map(|arg| arg.resolve(ctx, mc)).collect::<Result<_>>()?,
}
.ir()
.ok()
}
}
fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Result<Param> {
fn downgrade_param<'gc>(
param: ast::Param,
ctx: &mut DowngradeContext<'gc>,
mc: &Mutation<'gc>,
) -> Result<Param> {
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<Param> {
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<Attrs> {
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<usize, Ir>,
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<Attr> {
fn downgrade_attr<'gc>(
attr: ast::Attr,
ctx: &mut DowngradeContext<'gc>,
mc: &Mutation<'gc>,
) -> Result<Attr> {
use ast::Attr::*;
use ast::InterpolPart::*;
match attr {
@@ -722,7 +1024,7 @@ fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result<Attr> {
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<Attr> {
.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::<Result<Vec<_>>>()?;
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<Vec<Attr>> {
fn downgrade_attrpath<'gc>(
attrpath: ast::Attrpath,
ctx: &mut DowngradeContext<'gc>,
mc: &Mutation<'gc>,
) -> Result<Vec<Attr>> {
attrpath
.attrs()
.map(|attr| downgrade_attr(attr, ctx))
.map(|attr| downgrade_attr(attr, ctx, mc))
.collect::<Result<Vec<_>>>()
}
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(),

View File

@@ -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
}

View File

@@ -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;

View File

@@ -16,7 +16,7 @@ macro_rules! into {
}
pub struct Stack<T, const CAP: usize> {
items: [MaybeUninit<T>; CAP],
items: Box<[MaybeUninit<T>; CAP]>,
top: usize,
}
@@ -37,7 +37,11 @@ impl<T, const CAP: usize> Default for Stack<T, CAP> {
impl<T, const CAP: usize> Stack<T, CAP> {
pub fn new() -> Self {
Stack {
items: [const { MaybeUninit::uninit() }; CAP],
items: unsafe {
std::mem::transmute::<Box<MaybeUninit<[T; CAP]>>, Box<[MaybeUninit<T>; CAP]>>(
Box::new_uninit(),
)
},
top: 0,
}
}

View File

@@ -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()))
}

View File

@@ -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::<Value>();
type GcArena = Arena<Rootable!['gc => GcRoot<'gc>]>;
#[derive(Collect)]
#[collect(require_static)]
@@ -53,7 +52,7 @@ pub fn run(mut prog: Program) -> Result<p::Value> {
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(),
)?;