sphinx/runtime/
function.rs1use core::fmt;
2use core::cell::Cell;
3use crate::codegen::{FunctionID, FunctionProto};
4use crate::runtime::Variant;
5use crate::runtime::module::{Module, NamespaceEnv};
6use crate::runtime::vm::VirtualMachine;
7use crate::runtime::gc::{Gc, GcTrace};
8use crate::runtime::errors::ExecResult;
9
10mod signature;
11
12pub use signature::{Signature, Parameter};
13pub use crate::codegen::opcodes::UpvalueIndex;
14
15
16pub enum Call {
19 Chunk {
20 module: Gc<Module>,
21 chunk_id: FunctionID,
22 },
23 Native {
24 func: Gc<NativeFunction>,
25 nargs: usize,
26 },
27}
28
29pub trait Callable {
30 fn signature(&self) -> &Signature;
31 fn raw_call(&self, args: &[Variant]) -> Call;
32
33 fn checked_call(&self, args: &[Variant]) -> ExecResult<Call> {
34 self.signature().check_args(args)?;
35 Ok(self.raw_call(args))
36 }
37
38}
39
40#[derive(Debug)]
43pub struct Function {
44 fun_id: FunctionID,
45 module: Gc<Module>,
46 upvalues: Box<[Upvalue]>,
47}
48
49impl Function {
50 pub fn new(fun_id: FunctionID, module: Gc<Module>, upvalues: Box<[Upvalue]>) -> Self {
51 Self { fun_id, module, upvalues }
52 }
53
54 pub fn upvalues(&self) -> &[Upvalue] { &self.upvalues }
55
56 pub fn proto(&self) -> &FunctionProto {
57 self.module.data().get_function(self.fun_id)
58 }
59
60 pub fn signature(&self) -> &Signature {
61 self.proto().signature()
62 }
63}
64
65impl Callable for Function {
66 fn signature(&self) -> &Signature { self.proto().signature() }
67
68 fn raw_call(&self, _args: &[Variant]) -> Call {
69 Call::Chunk {
70 module: self.module,
71 chunk_id: self.fun_id,
72 }
73 }
74}
75
76impl Callable for Gc<Function> {
77 fn signature(&self) -> &Signature {
78 <Function as Callable>::signature(self)
79 }
80
81 fn raw_call(&self, args: &[Variant]) -> Call {
82 <Function as Callable>::raw_call(self, args)
83 }
84}
85
86unsafe impl GcTrace for Function {
87 fn trace(&self) {
88 self.module.mark_trace();
89 for upval in self.upvalues.iter() {
90 if let Closure::Closed(gc_cell) = upval.closure() {
91 gc_cell.mark_trace();
92 }
93 }
94 }
95
96 fn size_hint(&self) -> usize {
97 core::mem::size_of::<Upvalue>() * self.upvalues.len()
98 }
99}
100
101
102#[derive(Debug, Clone, Copy)]
105pub enum Closure {
106 Open(usize),
107 Closed(Gc<Cell<Variant>>),
108}
109
110impl Closure {
111 pub fn is_open(&self) -> bool { matches!(self, Self::Open(..)) }
112 pub fn is_closed(&self) -> bool { matches!(self, Self::Closed(..)) }
113}
114
115
116#[derive(Debug, Clone)]
117pub struct Upvalue {
118 value: Cell<Closure>,
119}
120
121impl Upvalue {
122 pub fn new(index: usize) -> Self {
123 Self {
124 value: Cell::new(Closure::Open(index)),
125 }
126 }
127
128 #[inline]
129 pub fn closure(&self) -> Closure { self.value.get() }
130
131 #[inline]
132 pub fn close(&self, gc_cell: Gc<Cell<Variant>>) {
133 self.value.set(Closure::Closed(gc_cell))
134 }
135}
136
137
138
139pub type NativeFn = fn(self_fun: &NativeFunction, vm: &mut VirtualMachine<'_>, args: &[Variant]) -> ExecResult<Variant>;
142
143pub struct NativeFunction {
144 signature: Signature,
145 defaults: Option<Box<[Variant]>>,
146 env: Gc<NamespaceEnv>,
147 func: NativeFn,
148}
149
150impl NativeFunction {
151 pub fn new(signature: Signature, defaults: Option<Box<[Variant]>>, env: Gc<NamespaceEnv>, func: NativeFn) -> Self {
152 Self { signature, defaults, env, func }
153 }
154
155 pub fn signature(&self) -> &Signature { &self.signature }
156
157 pub fn env(&self) -> Gc<NamespaceEnv> { self.env }
158
159 pub fn defaults(&self) -> &[Variant] {
160 match self.defaults.as_ref() {
161 Some(defaults) => &*defaults,
162 None => &[],
163 }
164 }
165
166 pub fn exec_fun(&self, vm: &mut VirtualMachine<'_>, args: &[Variant]) -> ExecResult<Variant> {
168 self.signature().check_args(args)?;
169 (self.func)(self, vm, args)
170 }
171}
172
173impl Callable for Gc<NativeFunction> {
174 fn signature(&self) -> &Signature { &self.signature }
175
176 fn raw_call(&self, args: &[Variant]) -> Call {
177 Call::Native {
178 func: *self,
179 nargs: args.len(),
180 }
181 }
182}
183
184unsafe impl GcTrace for NativeFunction {
185 fn trace(&self) {
186 self.env.mark_trace();
187
188 if let Some(defaults) = self.defaults.as_ref() {
189 defaults.trace()
190 }
191 }
192
193 fn size_hint(&self) -> usize {
194 self.defaults.as_ref()
195 .map_or(0, |defaults| {
196 core::mem::size_of::<Variant>() * defaults.len()
197 })
198 }
199}
200
201impl fmt::Debug for NativeFunction {
202 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
203 fmt.debug_struct("NativeFunction")
204 .field("signature", &self.signature)
205 .field("defaults", &self.defaults)
206 .field("env", &self.env)
207 .field("func", &core::ptr::addr_of!(self.func))
208 .finish()
209 }
210}