refactor: function

This commit is contained in:
2025-05-10 20:01:56 +08:00
parent fa3193ea50
commit 046b03c60e
8 changed files with 293 additions and 277 deletions

View File

@@ -1,15 +1,15 @@
use ecow::EcoString; use ecow::EcoString;
use crate::ty::internal::Const; use crate::ty::internal::{Const, Func};
type Slice<T> = Box<[T]>; type Slice<T> = Box<[T]>;
pub type ThunkIdx = usize; pub type ThunkIdx = usize;
pub type ConstIdx = usize; pub type FuncIdx = usize;
pub type SymIdx = usize;
pub type OpCodes = Slice<OpCode>; pub type OpCodes = Slice<OpCode>;
pub type Consts = Slice<Const>; pub type Consts = Slice<Const>;
pub type Thunks = Slice<Thunk>; pub type Thunks = Slice<Thunk>;
pub type Funcs = Slice<Func>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Thunk { pub struct Thunk {
@@ -34,16 +34,6 @@ pub enum OpCode {
Call { arity: usize }, Call { arity: usize },
/// make a function /// make a function
Func { idx: ThunkIdx }, 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 /// consume 1 element, assert TOS is true
Assert, Assert,
@@ -118,4 +108,5 @@ pub enum UnOp {
pub struct Program { pub struct Program {
pub top_level: OpCodes, pub top_level: OpCodes,
pub thunks: Thunks, pub thunks: Thunks,
pub funcs: Box<[Func]>
} }

View File

@@ -1,6 +1,7 @@
use crate::bytecode::*; use crate::bytecode::*;
use crate::ir; use crate::ir;
use crate::ty::internal::Const; use crate::ty::internal::Const;
use crate::ty::internal::Func;
pub struct Compiler { pub struct Compiler {
opcodes: Vec<OpCode>, opcodes: Vec<OpCode>,
@@ -16,6 +17,15 @@ pub fn compile(downgraded: ir::Downgraded) -> Program {
opcodes: Compiler::new().compile(thunk), opcodes: Compiler::new().compile(thunk),
}) })
.collect(), .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; self.opcodes[idx] = code;
} }
fn last(&self) -> Option<OpCode> {
self.opcodes.last().cloned()
}
fn pop(&mut self) -> Option<OpCode> { fn pop(&mut self) -> Option<OpCode> {
self.opcodes.pop() 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) { fn compile(self, comp: &mut Compiler) {
comp.push(OpCode::Func { idx: self.body.idx }); comp.push(OpCode::Func { idx: self.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 });
}
}
}
} }
} }

243
src/ir.rs
View File

@@ -3,18 +3,21 @@ use std::collections::HashMap;
use ecow::EcoString; use ecow::EcoString;
use rnix::ast::{self, Expr}; use rnix::ast::{self, Expr};
use crate::bytecode::{ConstIdx, Consts, ThunkIdx}; use crate::bytecode::{Consts, ThunkIdx, FuncIdx};
use crate::compile::*; use crate::compile::*;
#[cfg(feature = "jit")]
use crate::jit::*;
use crate::error::*; use crate::error::*;
use crate::ty::internal as i; use crate::ty::internal as i;
pub fn downgrade(expr: Expr) -> Result<Downgraded> { pub fn downgrade(expr: Expr) -> Result<Downgraded> {
let mut state = DowngradeState::new(); let mut ctx = DowngradeContext::new();
let ir = expr.downgrade(&mut state)?; let ir = expr.downgrade(&mut ctx)?;
Ok(Downgraded { Ok(Downgraded {
top_level: ir, top_level: ir,
consts: state.consts.into(), consts: ctx.consts.into(),
thunks: state.thunks.into(), thunks: ctx.thunks.into(),
funcs: ctx.funcs.into()
}) })
} }
@@ -24,7 +27,6 @@ where
{ {
fn downcast_ref(&self) -> Option<&T>; fn downcast_ref(&self) -> Option<&T>;
fn downcast_mut(&mut self) -> Option<&mut T>; fn downcast_mut(&mut self) -> Option<&mut T>;
fn downcast(self) -> core::result::Result<T, Self>;
} }
macro_rules! ir { macro_rules! ir {
@@ -54,9 +56,18 @@ macro_rules! ir {
} }
impl Compile for Ir { impl Compile for Ir {
fn compile(self, state: &mut Compiler) { fn compile(self, ctx: &mut Compiler) {
match self { 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, _ => 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<Ir>, kind: UnOpKind }, UnOp => { rhs: Box<Ir>, kind: UnOpKind },
Select => { expr: Box<Ir>, attrpath: Vec<Attr>, default: Option<Box<Ir>> }, Select => { expr: Box<Ir>, attrpath: Vec<Attr>, default: Option<Box<Ir>> },
If => { cond: Box<Ir>, consq: Box<Ir>, alter: Box<Ir> }, If => { cond: Box<Ir>, consq: Box<Ir>, alter: Box<Ir> },
Func => { param: Param, body: Thunk }, LoadFunc => { idx: FuncIdx },
Call => { func: Box<Ir>, args: Vec<Ir> }, Call => { func: Box<Ir>, args: Vec<Ir> },
Let => { attrs: Attrs, expr: Box<Ir> }, Let => { attrs: Attrs, expr: Box<Ir> },
@@ -127,25 +132,23 @@ ir! {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DynamicAttrPair(pub Ir, pub Ir); pub struct DynamicAttrPair(pub Ir, pub Ir);
pub struct DowngradeState { #[derive(Default)]
pub struct DowngradeContext {
thunks: Vec<Ir>, thunks: Vec<Ir>,
funcs: Vec<Func>,
consts: Vec<i::Const>, consts: Vec<i::Const>,
consts_table: HashMap<i::Const, ConstIdx>,
} }
pub struct Downgraded { pub struct Downgraded {
pub top_level: Ir, pub top_level: Ir,
pub consts: Consts, pub consts: Consts,
pub thunks: Box<[Ir]>, pub thunks: Box<[Ir]>,
pub funcs: Box<[Func]>
} }
impl DowngradeState { impl DowngradeContext {
fn new() -> DowngradeState { fn new() -> DowngradeContext {
DowngradeState { DowngradeContext::default()
thunks: Vec::new(),
consts: Vec::new(),
consts_table: HashMap::new(),
}
} }
fn new_thunk(&mut self, thunk: Ir) -> Thunk { fn new_thunk(&mut self, thunk: Ir) -> Thunk {
@@ -154,8 +157,10 @@ impl DowngradeState {
Thunk { idx } Thunk { idx }
} }
fn lookup_thunk(&self, idx: ThunkIdx) -> &Ir { fn new_func(&mut self, func: Func) -> LoadFunc {
self.thunks.get(idx).unwrap() let idx = self.funcs.len();
self.funcs.push(func);
LoadFunc { idx }
} }
} }
@@ -169,7 +174,7 @@ impl Attrs {
.get_mut(&ident) .get_mut(&ident)
.unwrap() .unwrap()
.downcast_mut() .downcast_mut()
.ok_or(Error::DowngradeError(format!( .ok_or_else(|| Error::DowngradeError(format!(
r#""{ident}" already exsists in this set"# r#""{ident}" already exsists in this set"#
))) )))
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value)) .and_then(|attrs: &mut Attrs| attrs._insert(path, name, value))
@@ -320,6 +325,11 @@ impl From<ast::UnaryOpKind> for UnOpKind {
} }
} }
pub struct Func {
pub param: Param,
pub body: Box<Ir>,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Param { pub enum Param {
Ident(EcoString), Ident(EcoString),
@@ -334,41 +344,41 @@ trait Downgrade
where where
Self: Sized, Self: Sized,
{ {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir>; fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir>;
} }
impl Downgrade for Expr { impl Downgrade for Expr {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
match self { match self {
Expr::Apply(apply) => apply.downgrade(state), Expr::Apply(apply) => apply.downgrade(ctx),
Expr::Assert(assert) => assert.downgrade(state), Expr::Assert(assert) => assert.downgrade(ctx),
Expr::Error(error) => Err(Error::DowngradeError(error.to_string())), Expr::Error(error) => Err(Error::DowngradeError(error.to_string())),
Expr::IfElse(ifelse) => ifelse.downgrade(state), Expr::IfElse(ifelse) => ifelse.downgrade(ctx),
Expr::Select(select) => select.downgrade(state), Expr::Select(select) => select.downgrade(ctx),
Expr::Str(str) => str.downgrade(state), Expr::Str(str) => str.downgrade(ctx),
Expr::Path(path) => path.downgrade(state), Expr::Path(path) => path.downgrade(ctx),
Expr::Literal(lit) => lit.downgrade(state), Expr::Literal(lit) => lit.downgrade(ctx),
Expr::Lambda(lambda) => lambda.downgrade(state), Expr::Lambda(lambda) => lambda.downgrade(ctx),
Expr::LegacyLet(let_) => let_.downgrade(state), Expr::LegacyLet(let_) => let_.downgrade(ctx),
Expr::LetIn(letin) => letin.downgrade(state), Expr::LetIn(letin) => letin.downgrade(ctx),
Expr::List(list) => list.downgrade(state), Expr::List(list) => list.downgrade(ctx),
Expr::BinOp(op) => op.downgrade(state), Expr::BinOp(op) => op.downgrade(ctx),
Expr::Paren(paren) => paren.expr().unwrap().downgrade(state), Expr::Paren(paren) => paren.expr().unwrap().downgrade(ctx),
Expr::Root(root) => root.expr().unwrap().downgrade(state), Expr::Root(root) => root.expr().unwrap().downgrade(ctx),
Expr::AttrSet(attrs) => attrs.downgrade(state), Expr::AttrSet(attrs) => attrs.downgrade(ctx),
Expr::UnaryOp(op) => op.downgrade(state), Expr::UnaryOp(op) => op.downgrade(ctx),
Expr::Ident(ident) => ident.downgrade(state), Expr::Ident(ident) => ident.downgrade(ctx),
Expr::With(with) => with.downgrade(state), Expr::With(with) => with.downgrade(ctx),
Expr::HasAttr(has) => has.downgrade(state), Expr::HasAttr(has) => has.downgrade(ctx),
} }
} }
} }
impl Downgrade for ast::Assert { impl Downgrade for ast::Assert {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
Assert { Assert {
assertion: self.condition().unwrap().downgrade(state)?.boxed(), assertion: self.condition().unwrap().downgrade(ctx)?.boxed(),
expr: self.body().unwrap().downgrade(state)?.boxed(), expr: self.body().unwrap().downgrade(ctx)?.boxed(),
} }
.ir() .ir()
.ok() .ok()
@@ -376,11 +386,11 @@ impl Downgrade for ast::Assert {
} }
impl Downgrade for ast::IfElse { impl Downgrade for ast::IfElse {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
If { If {
cond: self.condition().unwrap().downgrade(state)?.boxed(), cond: self.condition().unwrap().downgrade(ctx)?.boxed(),
consq: self.body().unwrap().downgrade(state)?.boxed(), consq: self.body().unwrap().downgrade(ctx)?.boxed(),
alter: self.else_body().unwrap().downgrade(state)?.boxed(), alter: self.else_body().unwrap().downgrade(ctx)?.boxed(),
} }
.ir() .ir()
.ok() .ok()
@@ -388,7 +398,7 @@ impl Downgrade for ast::IfElse {
} }
impl Downgrade for ast::Path { impl Downgrade for ast::Path {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let parts = self let parts = self
.parts() .parts()
.map(|part| match part { .map(|part| match part {
@@ -398,7 +408,7 @@ impl Downgrade for ast::Path {
.ir() .ir()
.ok(), .ok(),
ast::InterpolPart::Interpolation(interpol) => { ast::InterpolPart::Interpolation(interpol) => {
interpol.expr().unwrap().downgrade(state) interpol.expr().unwrap().downgrade(ctx)
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
@@ -417,14 +427,14 @@ impl Downgrade for ast::Path {
} }
impl Downgrade for ast::Str { impl Downgrade for ast::Str {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let parts = self let parts = self
.normalized_parts() .normalized_parts()
.into_iter() .into_iter()
.map(|part| match part { .map(|part| match part {
ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(), ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(),
ast::InterpolPart::Interpolation(interpol) => { ast::InterpolPart::Interpolation(interpol) => {
interpol.expr().unwrap().downgrade(state) interpol.expr().unwrap().downgrade(ctx)
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
@@ -437,7 +447,7 @@ impl Downgrade for ast::Str {
} }
impl Downgrade for ast::Literal { impl Downgrade for ast::Literal {
fn downgrade(self, _state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, _ctx: &mut DowngradeContext) -> Result<Ir> {
match self.kind() { match self.kind() {
ast::LiteralKind::Integer(int) => Const { ast::LiteralKind::Integer(int) => Const {
value: int.value().unwrap().into(), value: int.value().unwrap().into(),
@@ -455,7 +465,7 @@ impl Downgrade for ast::Literal {
} }
impl Downgrade for ast::Ident { impl Downgrade for ast::Ident {
fn downgrade(self, _state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, _ctx: &mut DowngradeContext) -> Result<Ir> {
Var { Var {
sym: self.to_string().into(), sym: self.to_string().into(),
} }
@@ -465,27 +475,27 @@ impl Downgrade for ast::Ident {
} }
impl Downgrade for ast::AttrSet { impl Downgrade for ast::AttrSet {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let rec = self.rec_token().is_some(); 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 { impl Downgrade for ast::List {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let mut items = Vec::with_capacity(self.items().size_hint().0); let mut items = Vec::with_capacity(self.items().size_hint().0);
for item in self.items() { for item in self.items() {
items.push(item.downgrade(state)?) items.push(item.downgrade(ctx)?)
} }
List { items }.ir().ok() List { items }.ir().ok()
} }
} }
impl Downgrade for ast::BinOp { impl Downgrade for ast::BinOp {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
BinOp { BinOp {
lhs: self.lhs().unwrap().downgrade(state)?.boxed(), lhs: self.lhs().unwrap().downgrade(ctx)?.boxed(),
rhs: self.rhs().unwrap().downgrade(state)?.boxed(), rhs: self.rhs().unwrap().downgrade(ctx)?.boxed(),
kind: self.operator().unwrap().into(), kind: self.operator().unwrap().into(),
} }
.ir() .ir()
@@ -494,9 +504,9 @@ impl Downgrade for ast::BinOp {
} }
impl Downgrade for ast::HasAttr { impl Downgrade for ast::HasAttr {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let attrs = self.expr().unwrap().downgrade(state)?; let attrs = self.expr().unwrap().downgrade(ctx)?;
let path = downgrade_attrpath(self.attrpath().unwrap(), state)?; let path = downgrade_attrpath(self.attrpath().unwrap(), ctx)?;
if let Some(attrs) = Downcast::<Attrs>::downcast_ref(&attrs) { if let Some(attrs) = Downcast::<Attrs>::downcast_ref(&attrs) {
if let Some(res) = attrs.has_attr(&path) { if let Some(res) = attrs.has_attr(&path) {
return Const { value: res.into() }.ir().ok(); return Const { value: res.into() }.ir().ok();
@@ -512,9 +522,9 @@ impl Downgrade for ast::HasAttr {
} }
impl Downgrade for ast::UnaryOp { impl Downgrade for ast::UnaryOp {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
UnOp { UnOp {
rhs: self.expr().unwrap().downgrade(state)?.boxed(), rhs: self.expr().unwrap().downgrade(ctx)?.boxed(),
kind: self.operator().unwrap().into(), kind: self.operator().unwrap().into(),
} }
.ir() .ir()
@@ -523,12 +533,12 @@ impl Downgrade for ast::UnaryOp {
} }
impl Downgrade for ast::Select { impl Downgrade for ast::Select {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
Select { Select {
expr: self.expr().unwrap().downgrade(state)?.boxed(), expr: self.expr().unwrap().downgrade(ctx)?.boxed(),
attrpath: downgrade_attrpath(self.attrpath().unwrap(), state)?, attrpath: downgrade_attrpath(self.attrpath().unwrap(), ctx)?,
default: match self.default_expr() { default: match self.default_expr() {
Some(default) => Some(default.downgrade(state)?.boxed()), Some(default) => Some(default.downgrade(ctx)?.boxed()),
None => None, None => None,
}, },
} }
@@ -538,8 +548,8 @@ impl Downgrade for ast::Select {
} }
impl Downgrade for ast::LegacyLet { impl Downgrade for ast::LegacyLet {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let attrs = downgrade_has_entry(self, true, state)?; let attrs = downgrade_has_entry(self, true, ctx)?;
Select { Select {
expr: attrs.ir().boxed(), expr: attrs.ir().boxed(),
attrpath: vec![Attr::Str("body".to_string().into())], attrpath: vec![Attr::Str("body".to_string().into())],
@@ -551,60 +561,59 @@ impl Downgrade for ast::LegacyLet {
} }
impl Downgrade for ast::LetIn { impl Downgrade for ast::LetIn {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let body = self.body().unwrap(); let body = self.body().unwrap();
let attrs = downgrade_has_entry(self, true, state)?; let attrs = downgrade_has_entry(self, true, ctx)?;
let expr = body.downgrade(state)?.boxed(); let expr = body.downgrade(ctx)?.boxed();
Let { attrs, expr }.ir().ok() Let { attrs, expr }.ir().ok()
} }
} }
impl Downgrade for ast::With { impl Downgrade for ast::With {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let namespace = self.namespace().unwrap().downgrade(state)?; let namespace = self.namespace().unwrap().downgrade(ctx)?;
if let Ir::Attrs(attrs) = namespace { 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() Let { attrs, expr }.ir().ok()
} else { } else {
let namespace = namespace.boxed(); 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() With { namespace, expr }.ir().ok()
} }
} }
} }
impl Downgrade for ast::Lambda { impl Downgrade for ast::Lambda {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let body = self.body().unwrap(); let body = self.body().unwrap();
let param = downgrade_param(self.param().unwrap(), state)?; let param = downgrade_param(self.param().unwrap(), ctx)?;
let body = body.downgrade(state)?; let body = body.downgrade(ctx)?.boxed();
let body = state.new_thunk(body); ctx.new_func(Func { param, body }).ir().ok()
Func { param, body }.ir().ok()
} }
} }
impl Downgrade for ast::Apply { impl Downgrade for ast::Apply {
fn downgrade(self, state: &mut DowngradeState) -> Result<Ir> { fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
let mut args = vec![self.argument().unwrap().downgrade(state)?]; let mut args = vec![self.argument().unwrap().downgrade(ctx)?];
let mut func = self.lambda().unwrap(); let mut func = self.lambda().unwrap();
while let ast::Expr::Apply(call) = func { while let ast::Expr::Apply(call) = func {
func = call.lambda().unwrap(); 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(); args.reverse();
Call { func, args }.ir().ok() Call { func, args }.ir().ok()
} }
} }
fn downgrade_param(param: ast::Param, state: &mut DowngradeState) -> Result<Param> { fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result<Param> {
match param { match param {
ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())), 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<Param> { fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Result<Param> {
let formals = pattern let formals = pattern
.pat_entries() .pat_entries()
.map(|entry| { .map(|entry| {
@@ -615,8 +624,8 @@ fn downgrade_pattern(pattern: ast::Pattern, state: &mut DowngradeState) -> Resul
entry entry
.default() .default()
.unwrap() .unwrap()
.downgrade(state) .downgrade(ctx)
.map(|ok| (ident, Some(state.new_thunk(ok)))) .map(|ok| (ident, Some(ctx.new_thunk(ok))))
} }
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
@@ -634,7 +643,7 @@ fn downgrade_pattern(pattern: ast::Pattern, state: &mut DowngradeState) -> Resul
fn downgrade_has_entry( fn downgrade_has_entry(
has_entry: impl ast::HasEntry, has_entry: impl ast::HasEntry,
rec: bool, rec: bool,
state: &mut DowngradeState, ctx: &mut DowngradeContext,
) -> Result<Attrs> { ) -> Result<Attrs> {
let entires = has_entry.entries(); let entires = has_entry.entries();
let mut attrs = Attrs { let mut attrs = Attrs {
@@ -645,8 +654,8 @@ fn downgrade_has_entry(
for entry in entires { for entry in entires {
match entry { match entry {
ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, state)?, ast::Entry::Inherit(inherit) => downgrade_inherit(inherit, &mut attrs.stcs, ctx)?,
ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, state)?, ast::Entry::AttrpathValue(value) => downgrade_attrpathvalue(value, &mut attrs, ctx)?,
} }
} }
@@ -656,16 +665,16 @@ fn downgrade_has_entry(
fn downgrade_inherit( fn downgrade_inherit(
inherit: ast::Inherit, inherit: ast::Inherit,
stcs: &mut HashMap<EcoString, Ir>, stcs: &mut HashMap<EcoString, Ir>,
state: &mut DowngradeState, ctx: &mut DowngradeContext,
) -> Result<()> { ) -> Result<()> {
let from = if let Some(from) = inherit.from() { let from = if let Some(from) = inherit.from() {
let from = from.expr().unwrap().downgrade(state)?; let from = from.expr().unwrap().downgrade(ctx)?;
Some(state.new_thunk(from)) Some(ctx.new_thunk(from))
} else { } else {
None None
}; };
for attr in inherit.attrs() { 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(), Attr::Str(ident) => ident.to_string().into(),
_ => { _ => {
return Err(Error::DowngradeError( return Err(Error::DowngradeError(
@@ -689,7 +698,7 @@ fn downgrade_inherit(
Ok(()) Ok(())
} }
fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result<Attr> { fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result<Attr> {
use ast::Attr::*; use ast::Attr::*;
use ast::InterpolPart::*; use ast::InterpolPart::*;
match attr { match attr {
@@ -700,7 +709,7 @@ fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result<Attr> {
match parts.into_iter().next().unwrap() { match parts.into_iter().next().unwrap() {
Literal(ident) => Ok(Attr::Str(ident.into())), Literal(ident) => Ok(Attr::Str(ident.into())),
Interpolation(interpol) => { Interpolation(interpol) => {
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(state)?)) Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?))
} }
} }
} else { } else {
@@ -708,29 +717,29 @@ fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result<Attr> {
.into_iter() .into_iter()
.map(|part| match part { .map(|part| match part {
Literal(lit) => Const { value: lit.into() }.ir().ok(), Literal(lit) => Const { value: lit.into() }.ir().ok(),
Interpolation(interpol) => interpol.expr().unwrap().downgrade(state), Interpolation(interpol) => interpol.expr().unwrap().downgrade(ctx),
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
Ok(Attr::Strs(ConcatStrings { parts })) 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<Vec<Attr>> { fn downgrade_attrpath(attrpath: ast::Attrpath, ctx: &mut DowngradeContext) -> Result<Vec<Attr>> {
attrpath attrpath
.attrs() .attrs()
.map(|attr| downgrade_attr(attr, state)) .map(|attr| downgrade_attr(attr, ctx))
.collect::<Result<Vec<_>>>() .collect::<Result<Vec<_>>>()
} }
fn downgrade_attrpathvalue( fn downgrade_attrpathvalue(
value: ast::AttrpathValue, value: ast::AttrpathValue,
attrs: &mut Attrs, attrs: &mut Attrs,
state: &mut DowngradeState, ctx: &mut DowngradeContext,
) -> Result<()> { ) -> Result<()> {
let path = downgrade_attrpath(value.attrpath().unwrap(), state)?; let path = downgrade_attrpath(value.attrpath().unwrap(), ctx)?;
let value = value.value().unwrap().downgrade(state)?; let value = value.value().unwrap().downgrade(ctx)?;
attrs.insert(path, state.new_thunk(value).ir()) attrs.insert(path, ctx.new_thunk(value).ir())
} }

View File

@@ -1,5 +1,111 @@
#![allow(unused_variables)]
use crate::ir::*;
use super::JITContext; use super::JITContext;
pub trait CodeGen { 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!()
}
} }

View File

@@ -2,43 +2,46 @@ use ecow::EcoString;
use itertools::Itertools; use itertools::Itertools;
use rpds::HashTrieMap; use rpds::HashTrieMap;
use crate::bytecode::OpCodes; use crate::bytecode::{OpCodes, ThunkIdx};
use crate::error::Result; use crate::error::Result;
use crate::ty::internal::{Thunk, Value}; use crate::ty::internal::Value;
use crate::vm::{CapturedEnv, VM}; use crate::vm::{CapturedEnv, VM};
use crate::ir;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Param { pub enum Param {
Ident(EcoString), Ident(EcoString),
Formals { Formals {
formals: Vec<(EcoString, Option<Thunk>)>, formals: Vec<(EcoString, Option<ThunkIdx>)>,
ellipsis: bool, ellipsis: bool,
alias: Option<EcoString>, alias: Option<EcoString>,
}, },
} }
impl From<ir::Param> 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)] #[derive(Debug, Clone)]
pub struct Func { pub struct Func {
pub env: CapturedEnv, pub env: Option<CapturedEnv>,
pub param: Option<Param>, pub param: Param,
pub opcodes: OpCodes, pub opcodes: OpCodes
} }
impl Func { impl Func {
pub fn new(env: CapturedEnv, opcodes: OpCodes) -> Func {
Func {
env,
opcodes,
param: None,
}
}
pub fn call(self, vm: &VM, arg: Value) -> Result<Value> { pub fn call(self, vm: &VM, arg: Value) -> Result<Value> {
use Param::*; 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)), Ident(ident) => env.enter(HashTrieMap::new_sync().insert(ident.into(), arg)),
Formals { Formals {
formals, formals,
@@ -60,7 +63,7 @@ impl Func {
for (formal, default) in formals { for (formal, default) in formals {
let arg = arg let arg = arg
.select(formal.clone().into()) .select(formal.clone().into())
.or_else(|| default.map(Value::Thunk)) .or_else(|| default.map(|idx| Value::Thunk(vm.get_thunk(idx))))
.unwrap(); .unwrap();
new.insert_mut(formal.into(), arg); new.insert_mut(formal.into(), arg);
} }
@@ -73,50 +76,6 @@ impl Func {
vm.eval(self.opcodes, env) 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 { impl PartialEq for Func {

View File

@@ -60,7 +60,6 @@ impl Thunk {
} }
pub fn force(&self, vm: &VM) -> Result<Value> { pub fn force(&self, vm: &VM) -> Result<Value> {
{
match &*self.thunk.borrow() { match &*self.thunk.borrow() {
_Thunk::Value(value) => return Ok(value.as_ref().clone()), _Thunk::Value(value) => return Ok(value.as_ref().clone()),
_Thunk::SuspendedFrom(from) => { _Thunk::SuspendedFrom(from) => {
@@ -71,7 +70,6 @@ impl Thunk {
} }
_Thunk::Code(_) => (), _Thunk::Code(_) => (),
} }
}
let opcodes = std::mem::replace( let opcodes = std::mem::replace(
&mut *self.thunk.borrow_mut(), &mut *self.thunk.borrow_mut(),
_Thunk::SuspendedFrom(self as *const Thunk), _Thunk::SuspendedFrom(self as *const Thunk),
@@ -366,14 +364,14 @@ impl Value {
if let Value::AttrSet(attrs) = self { if let Value::AttrSet(attrs) = self {
let val = attrs let val = attrs
.select(sym.clone()) .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" "{sym:?} not found"
))))); )))));
*self = val; *self = val;
} else if let Value::RecAttrSet(attrs) = self { } else if let Value::RecAttrSet(attrs) = self {
let val = attrs let val = attrs
.select(sym.clone()) .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" "{sym:?} not found"
))))); )))));
*self = val; *self = val;

View File

@@ -32,7 +32,7 @@ impl<const CAP: usize> Stack<CAP> {
pub fn push(&mut self, item: Value) -> Result<()> { pub fn push(&mut self, item: Value) -> Result<()> {
self.items self.items
.get_mut(self.top) .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) Ok(ok)
})? })?
.write(item); .write(item);
@@ -47,14 +47,6 @@ impl<const CAP: usize> Stack<CAP> {
unsafe { replace(item, MaybeUninit::uninit()).assume_init() } 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> { pub fn tos_mut(&mut self) -> Result<&mut Value> {
if self.top == 0 { if self.top == 0 {
panic!("stack empty") panic!("stack empty")

View File

@@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use crate::builtins::env; 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::error::*;
use crate::ty::common::Symbol; use crate::ty::common::Symbol;
use crate::ty::internal::*; use crate::ty::internal::*;
@@ -11,27 +11,32 @@ use super::env::Env;
use super::stack::{STACK_SIZE, Stack}; use super::stack::{STACK_SIZE, Stack};
pub fn run(prog: Program) -> Result<p::Value> { pub fn run(prog: Program) -> Result<p::Value> {
let vm = VM::new(prog.thunks); let vm = VM::new(prog.thunks, prog.funcs);
Ok(vm.eval(prog.top_level, env())?.to_public(&vm)) Ok(vm.eval(prog.top_level, env())?.to_public(&vm))
} }
pub struct VM { pub struct VM {
thunks: Box<[Thunk]>, thunks: Box<[Thunk]>,
funcs: Funcs,
} }
impl VM { impl VM {
fn new(thunks: Thunks) -> Self { fn new(thunks: Thunks, funcs: Funcs) -> Self {
let thunks = thunks let thunks = thunks
.into_iter() .into_iter()
.map(|bytecode::Thunk { opcodes }| Thunk::new(opcodes)) .map(|bytecode::Thunk { opcodes }| Thunk::new(opcodes))
.collect(); .collect();
VM { thunks } VM { thunks, funcs }
} }
pub fn get_thunk(&self, idx: usize) -> Thunk { pub fn get_thunk(&self, idx: usize) -> Thunk {
self.thunks[idx].clone() self.thunks[idx].clone()
} }
pub fn get_func(&self, idx: usize) -> Func {
self.funcs[idx].clone()
}
pub fn eval(&self, opcodes: OpCodes, env: Arc<Env>) -> Result<Value> { pub fn eval(&self, opcodes: OpCodes, env: Arc<Env>) -> Result<Value> {
let mut stack = Stack::<STACK_SIZE>::new(); let mut stack = Stack::<STACK_SIZE>::new();
let mut iter = opcodes.into_iter(); let mut iter = opcodes.into_iter();
@@ -88,37 +93,9 @@ impl VM {
stack.push(func.call(self, args)?)?; stack.push(func.call(self, args)?)?;
} }
OpCode::Func { idx } => { OpCode::Func { idx } => {
stack.push(Value::Func(Func::new( let mut func = self.get_func(idx);
env.captured(), func.env = Some(env.captured());
self.thunks[idx].unwrap_code(), stack.push(Value::Func(func))?;
)))?;
}
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);
} }
OpCode::UnOp { op } => { OpCode::UnOp { op } => {
use UnOp::*; use UnOp::*;
@@ -216,7 +193,7 @@ impl VM {
OpCode::LookUp { sym } => { OpCode::LookUp { sym } => {
stack.push( stack.push(
env.lookup(Symbol::new(sym.clone())) 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() { OpCode::EnterEnv => match stack.pop() {