refactor: function
This commit is contained in:
@@ -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]>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
243
src/ir.rs
@@ -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())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -60,17 +60,15 @@ 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) => {
|
return Err(Error::EvalError(format!(
|
||||||
return Err(Error::EvalError(format!(
|
"thunk {:p} already suspended from {from:p} (infinite recursion encountered)",
|
||||||
"thunk {:p} already suspended from {from:p} (infinite recursion encountered)",
|
self as *const Thunk
|
||||||
self as *const 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(),
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
49
src/vm/vm.rs
49
src/vm/vm.rs
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user