implement __functor
This commit is contained in:
@@ -244,6 +244,8 @@ pub enum PrimOpPhase {
|
|||||||
|
|
||||||
// TODO: split into separate enums
|
// TODO: split into separate enums
|
||||||
CallPattern,
|
CallPattern,
|
||||||
|
CallFunctor1,
|
||||||
|
CallFunctor2,
|
||||||
|
|
||||||
Illegal,
|
Illegal,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ table! {
|
|||||||
JumpIfTrue => op_jump_if_true,
|
JumpIfTrue => op_jump_if_true,
|
||||||
Jump => op_jump,
|
Jump => op_jump,
|
||||||
|
|
||||||
CoerceToString => op_coerce_to_string,
|
CoerceToString => op_coerce_to_string,
|
||||||
|
|
||||||
ConcatStrings => op_concat_strings,
|
ConcatStrings => op_concat_strings,
|
||||||
ResolvePath => op_resolve_path,
|
ResolvePath => op_resolve_path,
|
||||||
|
|||||||
@@ -85,8 +85,30 @@ impl<'gc> crate::Vm<'gc> {
|
|||||||
new_app.args[position] = arg;
|
new_app.args[position] = arg;
|
||||||
self.push(Value::new_gc(Gc::new(mc, new_app)))
|
self.push(Value::new_gc(Gc::new(mc, new_app)))
|
||||||
}
|
}
|
||||||
|
} else if let Some(attrs) = func.as_gc::<AttrSet>()
|
||||||
|
&& let Some(functor) = attrs.lookup(self.functor_sym)
|
||||||
|
{
|
||||||
|
// f arg => (f.__functor f) arg
|
||||||
|
//
|
||||||
|
// Stage the work for `CallFunctor1` so retries during force are
|
||||||
|
// safe: the stack invariant `[..., orig_arg, self, functor]`
|
||||||
|
// holds every time control re-enters phase 1.
|
||||||
|
self.call_depth -= 1;
|
||||||
|
self.call_stack.push(CallFrame {
|
||||||
|
pc: resume_pc,
|
||||||
|
thunk: None,
|
||||||
|
env: self.env,
|
||||||
|
});
|
||||||
|
self.push(arg);
|
||||||
|
self.push(func.relax());
|
||||||
|
self.push(functor);
|
||||||
|
reader.set_pc(PrimOpPhase::CallFunctor1.ip() as usize);
|
||||||
|
return Step::Continue(());
|
||||||
} else {
|
} else {
|
||||||
todo!("call other types: {func:?}")
|
return self.finish_err(Error::eval_error(format!(
|
||||||
|
"attempt to call something which is not a function but {}",
|
||||||
|
func.ty()
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
Step::Continue(())
|
Step::Continue(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,8 @@ pub struct Vm<'gc> {
|
|||||||
|
|
||||||
#[collect(require_static)]
|
#[collect(require_static)]
|
||||||
result: Option<Result<fix_common::Value>>,
|
result: Option<Result<fix_common::Value>>,
|
||||||
|
|
||||||
|
functor_sym: StringId,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OperandData {
|
enum OperandData {
|
||||||
@@ -340,6 +342,8 @@ impl<'gc> Vm<'gc> {
|
|||||||
force_mode,
|
force_mode,
|
||||||
|
|
||||||
result: None,
|
result: None,
|
||||||
|
|
||||||
|
functor_sym: ctx.intern_string("__functor"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ use gc_arena::{Gc, Mutation, RefLock};
|
|||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use crate::{BytecodeReader, Step, Vm, VmRuntimeCtx, VmRuntimeCtxExt};
|
use crate::{BytecodeReader, NixNum, Step, Vm, VmRuntimeCtx, VmRuntimeCtxExt};
|
||||||
|
|
||||||
impl<'gc> Vm<'gc> {
|
impl<'gc> Vm<'gc> {
|
||||||
pub(crate) fn primop_seq(
|
pub(crate) fn primop_seq(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ctx: &mut impl VmRuntimeCtx,
|
||||||
reader: &mut BytecodeReader<'_>,
|
reader: &mut BytecodeReader<'_>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Step {
|
) -> Step {
|
||||||
@@ -36,6 +37,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
|
|
||||||
pub(crate) fn primop_deep_seq_force_top(
|
pub(crate) fn primop_deep_seq_force_top(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ctx: &mut impl VmRuntimeCtx,
|
||||||
reader: &mut BytecodeReader<'_>,
|
reader: &mut BytecodeReader<'_>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Step {
|
) -> Step {
|
||||||
@@ -84,6 +86,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
|
|
||||||
pub(crate) fn primop_deep_seq_push(
|
pub(crate) fn primop_deep_seq_push(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ctx: &mut impl VmRuntimeCtx,
|
||||||
reader: &mut BytecodeReader<'_>,
|
reader: &mut BytecodeReader<'_>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Step {
|
) -> Step {
|
||||||
@@ -271,6 +274,43 @@ impl<'gc> Vm<'gc> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn primop_call_functor_1(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
// Stack invariant on every (re-)entry: [..., orig_arg, self, functor]
|
||||||
|
// where `functor` is TOS. Retries during force land back here safely.
|
||||||
|
let functor = self.force_and_retry::<StrictValue>(reader, mc)?;
|
||||||
|
// Stack now: [..., orig_arg, self]
|
||||||
|
let self_val = self.pop();
|
||||||
|
self.push(functor.relax());
|
||||||
|
// Stack: [..., orig_arg, functor]
|
||||||
|
// Call 1: functor(self). Resume into CallFunctor2 once it returns.
|
||||||
|
self.call(
|
||||||
|
reader,
|
||||||
|
mc,
|
||||||
|
self_val,
|
||||||
|
PrimOpPhase::CallFunctor2.ip() as usize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn primop_call_functor_2(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
// Stack on entry: [..., orig_arg, intermediate]
|
||||||
|
// call_stack top: synthetic frame with caller's resume_pc.
|
||||||
|
let intermediate = self.pop();
|
||||||
|
let orig_arg = self.pop();
|
||||||
|
let saved = self.call_stack.pop().expect("functor outer frame missing");
|
||||||
|
self.env = saved.env;
|
||||||
|
self.push(intermediate);
|
||||||
|
// Call 2: intermediate(orig_arg). Resume to caller.
|
||||||
|
self.call(reader, mc, orig_arg, saved.pc)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn primop_call_pattern(
|
pub(crate) fn primop_call_pattern(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut impl VmRuntimeCtx,
|
ctx: &mut impl VmRuntimeCtx,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use gc_arena::Mutation;
|
|||||||
|
|
||||||
use crate::bytecode_reader::BytecodeReader;
|
use crate::bytecode_reader::BytecodeReader;
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use crate::{Step, Vm};
|
use crate::{Step, Vm, VmRuntimeCtx};
|
||||||
|
|
||||||
impl<'gc> Vm<'gc> {
|
impl<'gc> Vm<'gc> {
|
||||||
pub(crate) fn primop_filter_force_list(
|
pub(crate) fn primop_filter_force_list(
|
||||||
@@ -44,6 +44,7 @@ impl<'gc> Vm<'gc> {
|
|||||||
|
|
||||||
pub(crate) fn primop_filter_check(
|
pub(crate) fn primop_filter_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ctx: &mut impl VmRuntimeCtx,
|
||||||
reader: &mut BytecodeReader<'_>,
|
reader: &mut BytecodeReader<'_>,
|
||||||
mc: &Mutation<'gc>,
|
mc: &Mutation<'gc>,
|
||||||
) -> Step {
|
) -> Step {
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ impl<'gc> Vm<'gc> {
|
|||||||
match phase {
|
match phase {
|
||||||
Abort => self.primop_abort(ctx, reader, mc),
|
Abort => self.primop_abort(ctx, reader, mc),
|
||||||
|
|
||||||
DeepSeq => self.primop_deep_seq_force_top(reader, mc),
|
DeepSeq => self.primop_deep_seq_force_top(ctx, reader, mc),
|
||||||
DeepSeqPush => self.primop_deep_seq_push(reader, mc),
|
DeepSeqPush => self.primop_deep_seq_push(ctx, reader, mc),
|
||||||
DeepSeqLoop => self.primop_deep_seq_loop(reader, mc),
|
DeepSeqLoop => self.primop_deep_seq_loop(reader, mc),
|
||||||
Seq => self.primop_seq(reader, mc),
|
Seq => self.primop_seq(ctx, reader, mc),
|
||||||
|
|
||||||
FilterForceList => self.primop_filter_force_list(reader, mc),
|
FilterForceList => self.primop_filter_force_list(reader, mc),
|
||||||
FilterCallPred => self.primop_filter_call_pred(reader, mc),
|
FilterCallPred => self.primop_filter_call_pred(reader, mc),
|
||||||
FilterCheck => self.primop_filter_check(reader, mc),
|
FilterCheck => self.primop_filter_check(ctx, reader, mc),
|
||||||
|
|
||||||
ForceResultShallow => self.primop_force_result_shallow(ctx, reader, mc),
|
ForceResultShallow => self.primop_force_result_shallow(ctx, reader, mc),
|
||||||
ForceResultShallowPush => self.primop_force_result_shallow_push(ctx, reader, mc),
|
ForceResultShallowPush => self.primop_force_result_shallow_push(ctx, reader, mc),
|
||||||
@@ -47,6 +47,8 @@ impl<'gc> Vm<'gc> {
|
|||||||
ForceResultDeepFinish => self.primop_force_result_deep_finish(ctx, reader, mc),
|
ForceResultDeepFinish => self.primop_force_result_deep_finish(ctx, reader, mc),
|
||||||
|
|
||||||
CallPattern => self.primop_call_pattern(ctx, reader, mc),
|
CallPattern => self.primop_call_pattern(ctx, reader, mc),
|
||||||
|
CallFunctor1 => self.primop_call_functor_1(reader, mc),
|
||||||
|
CallFunctor2 => self.primop_call_functor_2(reader, mc),
|
||||||
|
|
||||||
phase => todo!("primop phase {phase:?}"),
|
phase => todo!("primop phase {phase:?}"),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user