Skip to content

Commit 302dd33

Browse files
committed
🔄 Add FunctionBody::Opaque to round-trip VM functions through the interpreter
1 parent 2b270da commit 302dd33

2 files changed

Lines changed: 50 additions & 4 deletions

File tree

‎ndc_interpreter/src/function.rs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ pub enum FunctionBody {
176176
cache: RefCell<HashMap<u64, Value>>,
177177
function: Box<FunctionBody>,
178178
},
179+
/// Opaque foreign function that cannot be called by the interpreter.
180+
/// Used to round-trip VM functions through interpreter values.
181+
Opaque {
182+
data: Rc<dyn std::any::Any>,
183+
static_type: StaticType,
184+
},
179185
}
180186

181187
impl FunctionBody {
@@ -186,6 +192,7 @@ impl FunctionBody {
186192
Self::NumericBinaryOp { .. } => Some(2),
187193
Self::GenericFunction { type_signature, .. } => type_signature.arity(),
188194
Self::Memoized { function, .. } => function.arity(),
195+
Self::Opaque { .. } => None,
189196
}
190197
}
191198

@@ -213,6 +220,7 @@ impl FunctionBody {
213220
Parameter::new("right", StaticType::Number),
214221
]),
215222
Self::GenericFunction { type_signature, .. } => type_signature.clone(),
223+
Self::Opaque { .. } => TypeSignature::Variadic,
216224
}
217225
}
218226

@@ -223,6 +231,7 @@ impl FunctionBody {
223231
}
224232
Self::NumericUnaryOp { .. } | Self::NumericBinaryOp { .. } => &StaticType::Number,
225233
Self::Memoized { function, .. } => function.return_type(),
234+
Self::Opaque { static_type, .. } => static_type,
226235
}
227236
}
228237
pub fn call(&self, args: &mut [Value], env: &Rc<RefCell<Environment>>) -> EvaluationResult {
@@ -277,6 +286,13 @@ impl FunctionBody {
277286
.into()),
278287
},
279288
Self::GenericFunction { function, .. } => function(args, env),
289+
Self::Opaque { .. } => {
290+
Err(FunctionCallError::ArgumentCountError {
291+
expected: 0,
292+
actual: args.len(),
293+
}
294+
.into())
295+
}
280296
Self::Memoized { cache, function } => {
281297
let mut hasher = DefaultHasher::default();
282298
for arg in &*args {

‎ndc_interpreter/src/vm_bridge.rs‎

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use ndc_core::num::Number;
66
use ndc_vm::value::{Function as VmFunction, NativeFunction, Object as VmObject, Value as VmValue};
77

88
use crate::environment::Environment;
9-
use crate::function::Function as InterpFunction;
9+
use crate::function::{Function as InterpFunction, FunctionBody, FunctionBuilder};
1010
use crate::sequence::Sequence;
1111
use crate::value::Value as InterpValue;
1212

@@ -60,8 +60,31 @@ pub fn vm_to_interp(value: &VmValue) -> InterpValue {
6060
VmObject::Tuple(vs) => InterpValue::Sequence(Sequence::Tuple(Rc::new(
6161
vs.iter().map(vm_to_interp).collect(),
6262
))),
63-
VmObject::Function(_) => panic!("cannot convert vm function to interpreter value"),
64-
VmObject::OverloadSet(_) => panic!("cannot convert overload set to interpreter value"),
63+
VmObject::Function(f) => {
64+
let static_type = f.static_type();
65+
InterpValue::function(
66+
FunctionBuilder::default()
67+
.body(FunctionBody::Opaque {
68+
data: Rc::new(VmValue::Object(Box::new(VmObject::Function(f.clone())))),
69+
static_type,
70+
})
71+
.build()
72+
.expect("must succeed"),
73+
)
74+
}
75+
VmObject::OverloadSet(slots) => {
76+
InterpValue::function(
77+
FunctionBuilder::default()
78+
.body(FunctionBody::Opaque {
79+
data: Rc::new(VmValue::Object(Box::new(VmObject::OverloadSet(
80+
slots.clone(),
81+
)))),
82+
static_type: ndc_parser::StaticType::Any,
83+
})
84+
.build()
85+
.expect("must succeed"),
86+
)
87+
}
6588
},
6689
}
6790
}
@@ -97,7 +120,14 @@ pub fn interp_to_vm(value: InterpValue) -> VmValue {
97120
InterpValue::Sequence(seq) => {
98121
panic!("cannot convert {} to vm value", seq.static_type())
99122
}
100-
InterpValue::Function(_) => panic!("cannot convert interpreter function to vm value"),
123+
InterpValue::Function(f) => {
124+
if let FunctionBody::Opaque { data, .. } = f.body() {
125+
if let Some(vm_val) = data.downcast_ref::<VmValue>() {
126+
return vm_val.clone();
127+
}
128+
}
129+
panic!("cannot convert interpreter function to vm value")
130+
}
101131
}
102132
}
103133

0 commit comments

Comments
 (0)