onion_vm/types/lambda/
definition.rs

1use std::{
2    collections::VecDeque,
3    fmt::{Debug, Display},
4    sync::Arc,
5};
6
7use arc_gc::{
8    arc::{GCArc, GCArcWeak},
9    gc::GC,
10    traceable::GCTraceable,
11};
12
13use crate::{
14    lambda::runnable::{Runnable, RuntimeError, StepResult},
15    types::{
16        lambda::vm_instructions::instruction_set::VMInstructionPackage,
17        object::{OnionObject, OnionObjectCell, OnionStaticObject},
18    },
19};
20
21use super::runnable::OnionLambdaRunnable;
22
23pub enum LambdaBody {
24    Instruction(Arc<VMInstructionPackage>),
25    NativeFunction(Box<dyn Runnable>),
26}
27
28impl Clone for LambdaBody {
29    fn clone(&self) -> Self {
30        match self {
31            LambdaBody::Instruction(instruction) => LambdaBody::Instruction(instruction.clone()),
32            LambdaBody::NativeFunction(native_function) => {
33                LambdaBody::NativeFunction(native_function.copy())
34            }
35        }
36    }
37}
38
39impl Debug for LambdaBody {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        match self {
42            LambdaBody::Instruction(_) => write!(f, "Instruction(...)"),
43            LambdaBody::NativeFunction(_) => write!(f, "NativeFunction"),
44        }
45    }
46}
47
48impl Display for LambdaBody {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        match self {
51            LambdaBody::Instruction(_) => write!(f, "Instruction(...)"),
52            LambdaBody::NativeFunction(_) => write!(f, "NativeFunction"),
53        }
54    }
55}
56
57#[derive(Clone)]
58pub struct OnionLambdaDefinition {
59    parameter: Arc<OnionObject>,
60    body: LambdaBody,
61    capture: Arc<OnionObject>,
62    self_object: Arc<OnionObject>,
63    signature: String,
64}
65
66impl OnionLambdaDefinition {
67    pub fn new_static(
68        parameter: &OnionStaticObject,
69        body: LambdaBody,
70        capture: Option<&OnionStaticObject>,
71        self_object: Option<&OnionStaticObject>,
72        signature: String,
73    ) -> OnionStaticObject {
74        OnionObject::Lambda(
75            OnionLambdaDefinition {
76                parameter: parameter.weak().clone().into(),
77                body,
78                capture: (match capture {
79                    Some(capture) => capture.weak().clone(),
80                    None => OnionObject::Undefined(None),
81                })
82                .into(),
83                self_object: (match self_object {
84                    Some(self_object) => self_object.weak().clone(),
85                    None => OnionObject::Undefined(None),
86                })
87                .into(),
88                signature,
89            }
90            .into(),
91        )
92        .consume_and_stabilize()
93    }
94
95    pub fn create_runnable(
96        &self,
97        argument: OnionStaticObject,
98        this_lambda: &OnionStaticObject,
99        gc: &mut GC<OnionObjectCell>,
100    ) -> Result<Box<dyn Runnable>, RuntimeError> {
101        match &self.body {
102            LambdaBody::Instruction(instruction) => {
103                let runnable = OnionLambdaRunnable::new(
104                    argument,
105                    self.self_object.as_ref(),
106                    this_lambda,
107                    instruction.clone(),
108                    match instruction.get_table().get(&self.signature) {
109                        Some(ip) => *ip as isize,
110                        None => {
111                            return Err(RuntimeError::InvalidOperation(
112                                format!(
113                                    "Signature '{}' not found in instruction package",
114                                    self.signature
115                                )
116                                .into(),
117                            ));
118                        }
119                    },
120                )?;
121                Ok(Box::new(runnable))
122            }
123            LambdaBody::NativeFunction(native_function) => {
124                let mut runnable = native_function.copy();
125                runnable.receive(&StepResult::Return(argument.into()), gc)?;
126                runnable.receive(
127                    &StepResult::SetSelfObject(self.self_object.stabilize().into()),
128                    gc,
129                )?;
130                Ok(runnable)
131            }
132        }
133    }
134
135    pub fn get_signature(&self) -> &str {
136        &self.signature
137    }
138
139    pub fn get_parameter(&self) -> &OnionObject {
140        &self.parameter
141    }
142
143    pub fn get_capture(&self) -> &OnionObject {
144        &self.capture
145    }
146
147    pub fn get_self_object(&self) -> &OnionObject {
148        &self.self_object
149    }
150
151    pub fn get_body(&self) -> &LambdaBody {
152        &self.body
153    }
154
155    pub fn clone_and_replace_self_object(
156        &self,
157        new_self_object: &OnionStaticObject,
158    ) -> OnionStaticObject {
159        let new_definition = OnionLambdaDefinition {
160            parameter: self.parameter.clone(),
161            body: self.body.clone(),
162            capture: self.capture.clone(),
163            self_object: new_self_object.weak().clone().into(),
164            signature: self.signature.clone(),
165        };
166        OnionObject::Lambda(new_definition.into()).consume_and_stabilize()
167    }
168
169    pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
170        self.parameter.upgrade(collected);
171        self.capture.upgrade(collected);
172        self.self_object.upgrade(collected);
173    }
174
175    pub fn with_attribute<F, R>(&self, key: &OnionObject, f: &F) -> Result<R, RuntimeError>
176    where
177        F: Fn(&OnionObject) -> Result<R, RuntimeError>,
178    {
179        match key {
180            OnionObject::String(s) if s.as_str() == "parameter" => f(&self.parameter),
181            OnionObject::String(s) if s.as_str() == "capture" => f(&self.capture),
182            OnionObject::String(s) if s.as_str() == "self" => f(&self.self_object),
183            OnionObject::String(s) if s.as_str() == "signature" => {
184                f(&OnionObject::String(Arc::new(self.signature.clone())))
185            }
186            _ => Err(RuntimeError::InvalidOperation(
187                format!("Attribute '{:?}' not found in lambda definition", key).into(),
188            )),
189        }
190    }
191
192    pub fn with_parameter<F, R>(&self, f: F) -> Result<R, RuntimeError>
193    where
194        F: Fn(&OnionObject) -> Result<R, RuntimeError>,
195    {
196        f(&self.parameter)
197    }
198}
199
200impl GCTraceable<OnionObjectCell> for OnionLambdaDefinition {
201    fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
202        self.parameter.collect(queue);
203        self.capture.collect(queue);
204        self.self_object.collect(queue);
205    }
206}
207
208impl Debug for OnionLambdaDefinition {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        write!(
211            f,
212            "OnionLambdaDefinition {{ parameter: {:?}, body: {:?}, capture: {:?}, self_object: {:?} }}",
213            self.parameter, self.body, self.capture, self.self_object
214        )
215    }
216}
217
218impl OnionLambdaDefinition {
219    pub fn reconstruct_container(&self) -> Result<OnionObject, RuntimeError> {
220        let parameter = self.parameter.clone();
221        let body = self.body.clone();
222        let capture = self.capture.clone();
223        let self_object = self.self_object.clone();
224        let signature = self.signature.clone();
225        Ok(OnionObject::Lambda(
226            OnionLambdaDefinition {
227                parameter: parameter,
228                body,
229                capture,
230                self_object,
231                signature,
232            }
233            .into(),
234        ))
235    }
236}