diff --git a/src/bytecode.rs b/src/bytecode.rs index 17c311a..83b58ed 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -1,15 +1,15 @@ use ecow::EcoString; -use crate::ty::internal::Const; +use crate::ty::internal::{Const, Func}; type Slice = Box<[T]>; pub type ThunkIdx = usize; -pub type ConstIdx = usize; -pub type SymIdx = usize; +pub type FuncIdx = usize; pub type OpCodes = Slice; pub type Consts = Slice; pub type Thunks = Slice; +pub type Funcs = Slice; #[derive(Debug, Clone)] pub struct Thunk { @@ -34,16 +34,6 @@ pub enum OpCode { Call { arity: usize }, /// make a function Func { idx: ThunkIdx }, - /// push param `sym` into TOS - PushIdentParam { sym: EcoString }, - /// push formal param `sym` into TOS - PushFormalParam { sym: EcoString }, - /// push default formal param with thunkidx `idx` into TOS - PushDefaultParam { idx: ThunkIdx }, - /// TODO: - SetEllipsis, - /// TODO: - SetAlias { sym: EcoString }, /// consume 1 element, assert TOS is true Assert, @@ -118,4 +108,5 @@ pub enum UnOp { pub struct Program { pub top_level: OpCodes, pub thunks: Thunks, + pub funcs: Box<[Func]> } diff --git a/src/compile.rs b/src/compile.rs index 65aec36..f25a581 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,6 +1,7 @@ use crate::bytecode::*; use crate::ir; use crate::ty::internal::Const; +use crate::ty::internal::Func; pub struct Compiler { opcodes: Vec, @@ -16,6 +17,15 @@ pub fn compile(downgraded: ir::Downgraded) -> Program { opcodes: Compiler::new().compile(thunk), }) .collect(), + funcs: downgraded + .funcs + .into_iter() + .map(|func| Func { + env: None, + param: func.param.into(), + opcodes: Compiler::new().compile(*func.body) + }) + .collect() } } @@ -43,10 +53,6 @@ impl Compiler { self.opcodes[idx] = code; } - fn last(&self) -> Option { - self.opcodes.last().cloned() - } - fn pop(&mut self) -> Option { self.opcodes.pop() } @@ -393,31 +399,9 @@ impl Compile for ir::Assert { } } -impl Compile for ir::Func { +impl Compile for ir::LoadFunc { fn compile(self, comp: &mut Compiler) { - comp.push(OpCode::Func { idx: self.body.idx }); - use ir::Param::*; - match self.param { - Ident(sym) => comp.push(OpCode::PushIdentParam { sym }), - Formals { - formals, - ellipsis, - alias, - } => { - for (sym, default) in formals { - comp.push(OpCode::PushFormalParam { sym }); - if let Some(ir::Thunk { idx }) = default { - comp.push(OpCode::PushDefaultParam { idx }); - } - } - if ellipsis { - comp.push(OpCode::SetEllipsis); - } - if let Some(sym) = alias { - comp.push(OpCode::SetAlias { sym }); - } - } - } + comp.push(OpCode::Func { idx: self.idx }); } } diff --git a/src/ir.rs b/src/ir.rs index a13a43f..9267e95 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -3,18 +3,21 @@ use std::collections::HashMap; use ecow::EcoString; use rnix::ast::{self, Expr}; -use crate::bytecode::{ConstIdx, Consts, ThunkIdx}; +use crate::bytecode::{Consts, ThunkIdx, FuncIdx}; use crate::compile::*; +#[cfg(feature = "jit")] +use crate::jit::*; use crate::error::*; use crate::ty::internal as i; pub fn downgrade(expr: Expr) -> Result { - let mut state = DowngradeState::new(); - let ir = expr.downgrade(&mut state)?; + let mut ctx = DowngradeContext::new(); + let ir = expr.downgrade(&mut ctx)?; Ok(Downgraded { top_level: ir, - consts: state.consts.into(), - thunks: state.thunks.into(), + consts: ctx.consts.into(), + thunks: ctx.thunks.into(), + funcs: ctx.funcs.into() }) } @@ -24,7 +27,6 @@ where { fn downcast_ref(&self) -> Option<&T>; fn downcast_mut(&mut self) -> Option<&mut T>; - fn downcast(self) -> core::result::Result; } macro_rules! ir { @@ -54,9 +56,18 @@ macro_rules! ir { } impl Compile for Ir { - fn compile(self, state: &mut Compiler) { + fn compile(self, ctx: &mut Compiler) { match self { - $(Ir::$ty(ir) => ir.compile(state),)* + $(Ir::$ty(ir) => ir.compile(ctx),)* + } + } + } + + #[cfg(feature = "jit")] + impl CodeGen for Ir { + fn codegen(self, ctx: &JITContext<'_>) { + match self { + $(Ir::$ty(ir) => ir.codegen(ctx),)* } } } @@ -91,12 +102,6 @@ macro_rules! ir { _ => None, } } - fn downcast(self) -> core::result::Result<$ty, Self> { - match self { - Ir::$ty(value) => Ok(value), - _ => Err(self), - } - } } )* } @@ -110,7 +115,7 @@ ir! { UnOp => { rhs: Box, kind: UnOpKind }, Select => { expr: Box, attrpath: Vec, default: Option> }, If => { cond: Box, consq: Box, alter: Box }, - Func => { param: Param, body: Thunk }, + LoadFunc => { idx: FuncIdx }, Call => { func: Box, args: Vec }, Let => { attrs: Attrs, expr: Box }, @@ -127,25 +132,23 @@ ir! { #[derive(Clone, Debug)] pub struct DynamicAttrPair(pub Ir, pub Ir); -pub struct DowngradeState { +#[derive(Default)] +pub struct DowngradeContext { thunks: Vec, + funcs: Vec, consts: Vec, - consts_table: HashMap, } pub struct Downgraded { pub top_level: Ir, pub consts: Consts, pub thunks: Box<[Ir]>, + pub funcs: Box<[Func]> } -impl DowngradeState { - fn new() -> DowngradeState { - DowngradeState { - thunks: Vec::new(), - consts: Vec::new(), - consts_table: HashMap::new(), - } +impl DowngradeContext { + fn new() -> DowngradeContext { + DowngradeContext::default() } fn new_thunk(&mut self, thunk: Ir) -> Thunk { @@ -154,8 +157,10 @@ impl DowngradeState { Thunk { idx } } - fn lookup_thunk(&self, idx: ThunkIdx) -> &Ir { - self.thunks.get(idx).unwrap() + fn new_func(&mut self, func: Func) -> LoadFunc { + let idx = self.funcs.len(); + self.funcs.push(func); + LoadFunc { idx } } } @@ -169,7 +174,7 @@ impl Attrs { .get_mut(&ident) .unwrap() .downcast_mut() - .ok_or(Error::DowngradeError(format!( + .ok_or_else(|| Error::DowngradeError(format!( r#""{ident}" already exsists in this set"# ))) .and_then(|attrs: &mut Attrs| attrs._insert(path, name, value)) @@ -320,6 +325,11 @@ impl From for UnOpKind { } } +pub struct Func { + pub param: Param, + pub body: Box, +} + #[derive(Clone, Debug)] pub enum Param { Ident(EcoString), @@ -334,41 +344,41 @@ trait Downgrade where Self: Sized, { - fn downgrade(self, state: &mut DowngradeState) -> Result; + fn downgrade(self, ctx: &mut DowngradeContext) -> Result; } impl Downgrade for Expr { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { match self { - Expr::Apply(apply) => apply.downgrade(state), - Expr::Assert(assert) => assert.downgrade(state), + Expr::Apply(apply) => apply.downgrade(ctx), + Expr::Assert(assert) => assert.downgrade(ctx), Expr::Error(error) => Err(Error::DowngradeError(error.to_string())), - Expr::IfElse(ifelse) => ifelse.downgrade(state), - Expr::Select(select) => select.downgrade(state), - Expr::Str(str) => str.downgrade(state), - Expr::Path(path) => path.downgrade(state), - Expr::Literal(lit) => lit.downgrade(state), - Expr::Lambda(lambda) => lambda.downgrade(state), - Expr::LegacyLet(let_) => let_.downgrade(state), - Expr::LetIn(letin) => letin.downgrade(state), - Expr::List(list) => list.downgrade(state), - Expr::BinOp(op) => op.downgrade(state), - Expr::Paren(paren) => paren.expr().unwrap().downgrade(state), - Expr::Root(root) => root.expr().unwrap().downgrade(state), - Expr::AttrSet(attrs) => attrs.downgrade(state), - Expr::UnaryOp(op) => op.downgrade(state), - Expr::Ident(ident) => ident.downgrade(state), - Expr::With(with) => with.downgrade(state), - Expr::HasAttr(has) => has.downgrade(state), + 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), } } } impl Downgrade for ast::Assert { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { Assert { - assertion: self.condition().unwrap().downgrade(state)?.boxed(), - expr: self.body().unwrap().downgrade(state)?.boxed(), + assertion: self.condition().unwrap().downgrade(ctx)?.boxed(), + expr: self.body().unwrap().downgrade(ctx)?.boxed(), } .ir() .ok() @@ -376,11 +386,11 @@ impl Downgrade for ast::Assert { } impl Downgrade for ast::IfElse { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { If { - cond: self.condition().unwrap().downgrade(state)?.boxed(), - consq: self.body().unwrap().downgrade(state)?.boxed(), - alter: self.else_body().unwrap().downgrade(state)?.boxed(), + cond: self.condition().unwrap().downgrade(ctx)?.boxed(), + consq: self.body().unwrap().downgrade(ctx)?.boxed(), + alter: self.else_body().unwrap().downgrade(ctx)?.boxed(), } .ir() .ok() @@ -388,7 +398,7 @@ impl Downgrade for ast::IfElse { } impl Downgrade for ast::Path { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let parts = self .parts() .map(|part| match part { @@ -398,7 +408,7 @@ impl Downgrade for ast::Path { .ir() .ok(), ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(state) + interpol.expr().unwrap().downgrade(ctx) } }) .collect::>>()?; @@ -417,14 +427,14 @@ impl Downgrade for ast::Path { } impl Downgrade for ast::Str { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let parts = self .normalized_parts() .into_iter() .map(|part| match part { ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(), ast::InterpolPart::Interpolation(interpol) => { - interpol.expr().unwrap().downgrade(state) + interpol.expr().unwrap().downgrade(ctx) } }) .collect::>>()?; @@ -437,7 +447,7 @@ impl Downgrade for ast::Str { } impl Downgrade for ast::Literal { - fn downgrade(self, _state: &mut DowngradeState) -> Result { + fn downgrade(self, _ctx: &mut DowngradeContext) -> Result { match self.kind() { ast::LiteralKind::Integer(int) => Const { value: int.value().unwrap().into(), @@ -455,7 +465,7 @@ impl Downgrade for ast::Literal { } impl Downgrade for ast::Ident { - fn downgrade(self, _state: &mut DowngradeState) -> Result { + fn downgrade(self, _ctx: &mut DowngradeContext) -> Result { Var { sym: self.to_string().into(), } @@ -465,27 +475,27 @@ impl Downgrade for ast::Ident { } impl Downgrade for ast::AttrSet { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let rec = self.rec_token().is_some(); - downgrade_has_entry(self, rec, state).map(|attrs| attrs.ir()) + downgrade_has_entry(self, rec, ctx).map(|attrs| attrs.ir()) } } impl Downgrade for ast::List { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let mut items = Vec::with_capacity(self.items().size_hint().0); for item in self.items() { - items.push(item.downgrade(state)?) + items.push(item.downgrade(ctx)?) } List { items }.ir().ok() } } impl Downgrade for ast::BinOp { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { BinOp { - lhs: self.lhs().unwrap().downgrade(state)?.boxed(), - rhs: self.rhs().unwrap().downgrade(state)?.boxed(), + lhs: self.lhs().unwrap().downgrade(ctx)?.boxed(), + rhs: self.rhs().unwrap().downgrade(ctx)?.boxed(), kind: self.operator().unwrap().into(), } .ir() @@ -494,9 +504,9 @@ impl Downgrade for ast::BinOp { } impl Downgrade for ast::HasAttr { - fn downgrade(self, state: &mut DowngradeState) -> Result { - let attrs = self.expr().unwrap().downgrade(state)?; - let path = downgrade_attrpath(self.attrpath().unwrap(), state)?; + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + let attrs = self.expr().unwrap().downgrade(ctx)?; + let path = downgrade_attrpath(self.attrpath().unwrap(), ctx)?; if let Some(attrs) = Downcast::::downcast_ref(&attrs) { if let Some(res) = attrs.has_attr(&path) { return Const { value: res.into() }.ir().ok(); @@ -512,9 +522,9 @@ impl Downgrade for ast::HasAttr { } impl Downgrade for ast::UnaryOp { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { UnOp { - rhs: self.expr().unwrap().downgrade(state)?.boxed(), + rhs: self.expr().unwrap().downgrade(ctx)?.boxed(), kind: self.operator().unwrap().into(), } .ir() @@ -523,12 +533,12 @@ impl Downgrade for ast::UnaryOp { } impl Downgrade for ast::Select { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { Select { - expr: self.expr().unwrap().downgrade(state)?.boxed(), - attrpath: downgrade_attrpath(self.attrpath().unwrap(), state)?, + expr: self.expr().unwrap().downgrade(ctx)?.boxed(), + attrpath: downgrade_attrpath(self.attrpath().unwrap(), ctx)?, default: match self.default_expr() { - Some(default) => Some(default.downgrade(state)?.boxed()), + Some(default) => Some(default.downgrade(ctx)?.boxed()), None => None, }, } @@ -538,8 +548,8 @@ impl Downgrade for ast::Select { } impl Downgrade for ast::LegacyLet { - fn downgrade(self, state: &mut DowngradeState) -> Result { - let attrs = downgrade_has_entry(self, true, state)?; + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + let attrs = downgrade_has_entry(self, true, ctx)?; Select { expr: attrs.ir().boxed(), attrpath: vec![Attr::Str("body".to_string().into())], @@ -551,60 +561,59 @@ impl Downgrade for ast::LegacyLet { } impl Downgrade for ast::LetIn { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let body = self.body().unwrap(); - let attrs = downgrade_has_entry(self, true, state)?; - let expr = body.downgrade(state)?.boxed(); + let attrs = downgrade_has_entry(self, true, ctx)?; + let expr = body.downgrade(ctx)?.boxed(); Let { attrs, expr }.ir().ok() } } impl Downgrade for ast::With { - fn downgrade(self, state: &mut DowngradeState) -> Result { - let namespace = self.namespace().unwrap().downgrade(state)?; + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + let namespace = self.namespace().unwrap().downgrade(ctx)?; if let Ir::Attrs(attrs) = namespace { - let expr = self.body().unwrap().downgrade(state)?.boxed(); + let expr = self.body().unwrap().downgrade(ctx)?.boxed(); Let { attrs, expr }.ir().ok() } else { let namespace = namespace.boxed(); - let expr = self.body().unwrap().downgrade(state)?.boxed(); + let expr = self.body().unwrap().downgrade(ctx)?.boxed(); With { namespace, expr }.ir().ok() } } } impl Downgrade for ast::Lambda { - fn downgrade(self, state: &mut DowngradeState) -> Result { + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { let body = self.body().unwrap(); - let param = downgrade_param(self.param().unwrap(), state)?; - let body = body.downgrade(state)?; - let body = state.new_thunk(body); - Func { param, body }.ir().ok() + let param = downgrade_param(self.param().unwrap(), ctx)?; + let body = body.downgrade(ctx)?.boxed(); + ctx.new_func(Func { param, body }).ir().ok() } } impl Downgrade for ast::Apply { - fn downgrade(self, state: &mut DowngradeState) -> Result { - let mut args = vec![self.argument().unwrap().downgrade(state)?]; + fn downgrade(self, ctx: &mut DowngradeContext) -> Result { + let mut args = vec![self.argument().unwrap().downgrade(ctx)?]; let mut func = self.lambda().unwrap(); while let ast::Expr::Apply(call) = func { func = call.lambda().unwrap(); - args.push(call.argument().unwrap().downgrade(state)?); + args.push(call.argument().unwrap().downgrade(ctx)?); } - let func = func.downgrade(state)?.boxed(); + let func = func.downgrade(ctx)?.boxed(); args.reverse(); Call { func, args }.ir().ok() } } -fn downgrade_param(param: ast::Param, state: &mut DowngradeState) -> Result { +fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result { match param { ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())), - ast::Param::Pattern(pattern) => downgrade_pattern(pattern, state), + ast::Param::Pattern(pattern) => downgrade_pattern(pattern, ctx), } } -fn downgrade_pattern(pattern: ast::Pattern, state: &mut DowngradeState) -> Result { +fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Result { let formals = pattern .pat_entries() .map(|entry| { @@ -615,8 +624,8 @@ fn downgrade_pattern(pattern: ast::Pattern, state: &mut DowngradeState) -> Resul entry .default() .unwrap() - .downgrade(state) - .map(|ok| (ident, Some(state.new_thunk(ok)))) + .downgrade(ctx) + .map(|ok| (ident, Some(ctx.new_thunk(ok)))) } }) .collect::>>()?; @@ -634,7 +643,7 @@ fn downgrade_pattern(pattern: ast::Pattern, state: &mut DowngradeState) -> Resul fn downgrade_has_entry( has_entry: impl ast::HasEntry, rec: bool, - state: &mut DowngradeState, + ctx: &mut DowngradeContext, ) -> Result { let entires = has_entry.entries(); let mut attrs = Attrs { @@ -645,8 +654,8 @@ fn downgrade_has_entry( for entry in entires { match entry { - ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, state)?, - ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, state)?, + ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, ctx)?, + ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, ctx)?, } } @@ -656,16 +665,16 @@ fn downgrade_has_entry( fn downgrade_inherit( inherit: ast::Inherit, stcs: &mut HashMap, - state: &mut DowngradeState, + ctx: &mut DowngradeContext, ) -> Result<()> { let from = if let Some(from) = inherit.from() { - let from = from.expr().unwrap().downgrade(state)?; - Some(state.new_thunk(from)) + let from = from.expr().unwrap().downgrade(ctx)?; + Some(ctx.new_thunk(from)) } else { None }; for attr in inherit.attrs() { - let ident: EcoString = match downgrade_attr(attr, state)? { + let ident: EcoString = match downgrade_attr(attr, ctx)? { Attr::Str(ident) => ident.to_string().into(), _ => { return Err(Error::DowngradeError( @@ -689,7 +698,7 @@ fn downgrade_inherit( Ok(()) } -fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result { +fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result { use ast::Attr::*; use ast::InterpolPart::*; match attr { @@ -700,7 +709,7 @@ fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result { match parts.into_iter().next().unwrap() { Literal(ident) => Ok(Attr::Str(ident.into())), Interpolation(interpol) => { - Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(state)?)) + Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?)) } } } else { @@ -708,29 +717,29 @@ fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result { .into_iter() .map(|part| match part { Literal(lit) => Const { value: lit.into() }.ir().ok(), - Interpolation(interpol) => interpol.expr().unwrap().downgrade(state), + Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx), }) .collect::>>()?; Ok(Attr::Strs(ConcatStrings { parts })) } } - Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(state)?)), + Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(ctx)?)), } } -fn downgrade_attrpath(attrpath: ast::Attrpath, state: &mut DowngradeState) -> Result> { +fn downgrade_attrpath(attrpath: ast::Attrpath, ctx: &mut DowngradeContext) -> Result> { attrpath .attrs() - .map(|attr| downgrade_attr(attr, state)) + .map(|attr| downgrade_attr(attr, ctx)) .collect::>>() } fn downgrade_attrpathvalue( value: ast::AttrpathValue, attrs: &mut Attrs, - state: &mut DowngradeState, + ctx: &mut DowngradeContext, ) -> Result<()> { - let path = downgrade_attrpath(value.attrpath().unwrap(), state)?; - let value = value.value().unwrap().downgrade(state)?; - attrs.insert(path, state.new_thunk(value).ir()) + let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?; + let value = value.value().unwrap().downgrade(ctx)?; + attrs.insert(path, ctx.new_thunk(value).ir()) } diff --git a/src/jit/codegen.rs b/src/jit/codegen.rs index 01b219d..d390e68 100644 --- a/src/jit/codegen.rs +++ b/src/jit/codegen.rs @@ -1,5 +1,111 @@ +#![allow(unused_variables)] + +use crate::ir::*; + use super::JITContext; pub trait CodeGen { - fn codegen(self, ctx: JITContext); + fn codegen(self, ctx: &JITContext); +} + +impl CodeGen for Attrs { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for List { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for HasAttr { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for BinOp { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for UnOp { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Select { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for If { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for LoadFunc { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Call { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Let { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for With { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Assert { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for ConcatStrings { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Const { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Var { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Thunk { + fn codegen(self, ctx: &JITContext) { + todo!() + } +} + +impl CodeGen for Path { + fn codegen(self, ctx: &JITContext) { + todo!() + } } diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index a2d8f6e..96bd2e2 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -2,43 +2,46 @@ use ecow::EcoString; use itertools::Itertools; use rpds::HashTrieMap; -use crate::bytecode::OpCodes; +use crate::bytecode::{OpCodes, ThunkIdx}; use crate::error::Result; -use crate::ty::internal::{Thunk, Value}; +use crate::ty::internal::Value; use crate::vm::{CapturedEnv, VM}; +use crate::ir; #[derive(Debug, Clone)] pub enum Param { Ident(EcoString), Formals { - formals: Vec<(EcoString, Option)>, + formals: Vec<(EcoString, Option)>, ellipsis: bool, alias: Option, }, } +impl From for Param { + fn from(value: ir::Param) -> Self { + match value { + ir::Param::Ident(ident) => Param::Ident(ident), + ir::Param::Formals { formals, ellipsis, alias } => + Param::Formals { formals: formals.into_iter().map(|(sym, default)| (sym, default.map(|default| default.idx))).collect(), ellipsis, alias } + } + } +} + #[derive(Debug, Clone)] pub struct Func { - pub env: CapturedEnv, - pub param: Option, - pub opcodes: OpCodes, + pub env: Option, + pub param: Param, + pub opcodes: OpCodes } impl Func { - pub fn new(env: CapturedEnv, opcodes: OpCodes) -> Func { - Func { - env, - opcodes, - param: None, - } - } - pub fn call(self, vm: &VM, arg: Value) -> Result { use Param::*; - let env = self.env.released(); + let env = self.env.unwrap().released(); - match self.param.unwrap() { + match self.param { Ident(ident) => env.enter(HashTrieMap::new_sync().insert(ident.into(), arg)), Formals { formals, @@ -60,7 +63,7 @@ impl Func { for (formal, default) in formals { let arg = arg .select(formal.clone().into()) - .or_else(|| default.map(Value::Thunk)) + .or_else(|| default.map(|idx| Value::Thunk(vm.get_thunk(idx)))) .unwrap(); new.insert_mut(formal.into(), arg); } @@ -73,50 +76,6 @@ impl Func { vm.eval(self.opcodes, env) } - - pub fn push_ident_param(&mut self, param: EcoString) { - self.param = Some(Param::Ident(param)) - } - - pub fn push_formal_param(&mut self, param: EcoString) { - let Param::Formals { formals, .. } = self.param.get_or_insert_with(|| Param::Formals { - formals: Vec::with_capacity(1), - ellipsis: false, - alias: None, - }) else { - panic!() - }; - formals.push((param, None)); - } - - pub fn push_default_param(&mut self, default: Thunk) { - let Param::Formals { formals, .. } = self.param.as_mut().unwrap() else { - panic!() - }; - formals.last_mut().unwrap().1 = Some(default) - } - - pub fn set_ellipsis(&mut self) { - let Param::Formals { ellipsis, .. } = self.param.get_or_insert_with(|| Param::Formals { - formals: Vec::new(), - ellipsis: false, - alias: None, - }) else { - panic!() - }; - *ellipsis = true; - } - - pub fn set_alias(&mut self, sym: EcoString) { - let Param::Formals { alias, .. } = self.param.get_or_insert_with(|| Param::Formals { - formals: Vec::new(), - ellipsis: false, - alias: None, - }) else { - panic!() - }; - *alias = Some(sym); - } } impl PartialEq for Func { diff --git a/src/ty/internal/mod.rs b/src/ty/internal/mod.rs index d68d700..14595e9 100644 --- a/src/ty/internal/mod.rs +++ b/src/ty/internal/mod.rs @@ -60,17 +60,15 @@ impl Thunk { } pub fn force(&self, vm: &VM) -> Result { - { - match &*self.thunk.borrow() { - _Thunk::Value(value) => return Ok(value.as_ref().clone()), - _Thunk::SuspendedFrom(from) => { - return Err(Error::EvalError(format!( - "thunk {:p} already suspended from {from:p} (infinite recursion encountered)", - self as *const Thunk - ))); - } - _Thunk::Code(_) => (), + match &*self.thunk.borrow() { + _Thunk::Value(value) => return Ok(value.as_ref().clone()), + _Thunk::SuspendedFrom(from) => { + return Err(Error::EvalError(format!( + "thunk {:p} already suspended from {from:p} (infinite recursion encountered)", + self as *const Thunk + ))); } + _Thunk::Code(_) => (), } let opcodes = std::mem::replace( &mut *self.thunk.borrow_mut(), @@ -366,14 +364,14 @@ impl Value { if let Value::AttrSet(attrs) = self { let val = attrs .select(sym.clone()) - .unwrap_or(Value::Catchable(c::Catchable::new(Some(format!( + .unwrap_or_else(|| Value::Catchable(c::Catchable::new(Some(format!( "{sym:?} not found" ))))); *self = val; } else if let Value::RecAttrSet(attrs) = self { let val = attrs .select(sym.clone()) - .unwrap_or(Value::Catchable(c::Catchable::new(Some(format!( + .unwrap_or_else(|| Value::Catchable(c::Catchable::new(Some(format!( "{sym:?} not found" ))))); *self = val; diff --git a/src/vm/stack.rs b/src/vm/stack.rs index 7517356..dd038fb 100644 --- a/src/vm/stack.rs +++ b/src/vm/stack.rs @@ -32,7 +32,7 @@ impl Stack { pub fn push(&mut self, item: Value) -> Result<()> { self.items .get_mut(self.top) - .map_or(Err(Error::EvalError("stack overflow".to_string())), |ok| { + .map_or_else(|| Err(Error::EvalError("stack overflow".to_string())), |ok| { Ok(ok) })? .write(item); @@ -47,14 +47,6 @@ impl Stack { unsafe { replace(item, MaybeUninit::uninit()).assume_init() } } - pub fn tos(&self) -> Result<&Value> { - if self.top == 0 { - panic!("stack empty") - } else { - Ok(into!(&self.items[self.top - 1])) - } - } - pub fn tos_mut(&mut self) -> Result<&mut Value> { if self.top == 0 { panic!("stack empty") diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 676cb1f..8e98d3c 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use crate::builtins::env; -use crate::bytecode::{self, BinOp, OpCode, OpCodes, Program, Thunks, UnOp}; +use crate::bytecode::{self, BinOp, Funcs, OpCode, OpCodes, Program, Thunks, UnOp}; use crate::error::*; use crate::ty::common::Symbol; use crate::ty::internal::*; @@ -11,27 +11,32 @@ use super::env::Env; use super::stack::{STACK_SIZE, Stack}; pub fn run(prog: Program) -> Result { - let vm = VM::new(prog.thunks); + let vm = VM::new(prog.thunks, prog.funcs); Ok(vm.eval(prog.top_level, env())?.to_public(&vm)) } pub struct VM { thunks: Box<[Thunk]>, + funcs: Funcs, } impl VM { - fn new(thunks: Thunks) -> Self { + fn new(thunks: Thunks, funcs: Funcs) -> Self { let thunks = thunks .into_iter() .map(|bytecode::Thunk { opcodes }| Thunk::new(opcodes)) .collect(); - VM { thunks } + VM { thunks, funcs } } pub fn get_thunk(&self, idx: usize) -> Thunk { self.thunks[idx].clone() } + pub fn get_func(&self, idx: usize) -> Func { + self.funcs[idx].clone() + } + pub fn eval(&self, opcodes: OpCodes, env: Arc) -> Result { let mut stack = Stack::::new(); let mut iter = opcodes.into_iter(); @@ -88,37 +93,9 @@ impl VM { stack.push(func.call(self, args)?)?; } OpCode::Func { idx } => { - stack.push(Value::Func(Func::new( - env.captured(), - self.thunks[idx].unwrap_code(), - )))?; - } - OpCode::PushIdentParam { sym } => { - stack - .tos_mut()? - .as_mut() - .unwrap_func() - .push_ident_param(sym); - } - OpCode::PushFormalParam { sym } => { - stack - .tos_mut()? - .as_mut() - .unwrap_func() - .push_formal_param(sym); - } - OpCode::PushDefaultParam { idx } => { - stack - .tos_mut()? - .as_mut() - .unwrap_func() - .push_default_param(self.get_thunk(idx)); - } - OpCode::SetEllipsis => { - stack.tos_mut()?.as_mut().unwrap_func().set_ellipsis(); - } - OpCode::SetAlias { sym } => { - stack.tos_mut()?.as_mut().unwrap_func().set_alias(sym); + let mut func = self.get_func(idx); + func.env = Some(env.captured()); + stack.push(Value::Func(func))?; } OpCode::UnOp { op } => { use UnOp::*; @@ -216,7 +193,7 @@ impl VM { OpCode::LookUp { sym } => { stack.push( env.lookup(Symbol::new(sym.clone())) - .ok_or(Error::EvalError(format!(r#""{sym}" not found"#)))?, + .ok_or_else(|| Error::EvalError(format!(r#""{sym}" not found"#)))?, )?; } OpCode::EnterEnv => match stack.pop() {