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
57pub struct OnionLambdaDefinition {
58    parameter: Arc<OnionObject>,
59    body: LambdaBody,
60    capture: Arc<OnionObject>,
61    self_object: Arc<OnionObject>,
62    signature: String,
63}
64
65impl OnionLambdaDefinition {
66    pub fn new_static(
67        parameter: &OnionStaticObject,
68        body: LambdaBody,
69        capture: Option<&OnionStaticObject>,
70        self_object: Option<&OnionStaticObject>,
71        signature: String,
72    ) -> OnionStaticObject {
73        OnionObject::Lambda(
74            OnionLambdaDefinition {
75                parameter: parameter.weak().clone().into(),
76                body,
77                capture: (match capture {
78                    Some(capture) => capture.weak().clone(),
79                    None => OnionObject::Undefined(None),
80                })
81                .into(),
82                self_object: (match self_object {
83                    Some(self_object) => self_object.weak().clone(),
84                    None => OnionObject::Undefined(None),
85                })
86                .into(),
87                signature,
88            }
89            .into(),
90        )
91        .consume_and_stabilize()
92    }
93
94    pub fn create_runnable(
95        &self,
96        argument: OnionStaticObject,
97        this_lambda: &OnionStaticObject,
98        gc: &mut GC<OnionObjectCell>,
99    ) -> Result<Box<dyn Runnable>, RuntimeError> {
100        match &self.body {
101            LambdaBody::Instruction(instruction) => {
102                let runnable = OnionLambdaRunnable::new(
103                    argument,
104                    self.self_object.as_ref(),
105                    this_lambda,
106                    instruction.clone(),
107                    match instruction.get_table().get(&self.signature) {
108                        Some(ip) => *ip as isize,
109                        None => {
110                            return Err(RuntimeError::InvalidOperation(
111                                format!(
112                                    "Signature '{}' not found in instruction package",
113                                    self.signature
114                                )
115                                .into(),
116                            ));
117                        }
118                    },
119                )?;
120                Ok(Box::new(runnable))
121            }
122            LambdaBody::NativeFunction(native_function) => {
123                let mut runnable = native_function.copy();
124                runnable.receive(&StepResult::Return(argument.into()), gc)?;
125                runnable.receive(
126                    &StepResult::SetSelfObject(self.self_object.stabilize().into()),
127                    gc,
128                )?;
129                Ok(runnable)
130            }
131        }
132    }
133
134    pub fn get_signature(&self) -> &str {
135        &self.signature
136    }
137
138    pub fn get_parameter(&self) -> &OnionObject {
139        &self.parameter
140    }
141
142    pub fn get_capture(&self) -> &OnionObject {
143        &self.capture
144    }
145
146    pub fn get_self_object(&self) -> &OnionObject {
147        &self.self_object
148    }
149
150    pub fn get_body(&self) -> &LambdaBody {
151        &self.body
152    }
153
154    pub fn clone_and_replace_self_object(
155        &self,
156        new_self_object: &OnionStaticObject,
157    ) -> OnionStaticObject {
158        let new_definition = OnionLambdaDefinition {
159            parameter: self.parameter.clone(),
160            body: self.body.clone(),
161            capture: self.capture.clone(),
162            self_object: new_self_object.weak().clone().into(),
163            signature: self.signature.clone(),
164        };
165        OnionObject::Lambda(new_definition.into()).consume_and_stabilize()
166    }
167
168    pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
169        self.parameter.upgrade(collected);
170        self.capture.upgrade(collected);
171        self.self_object.upgrade(collected);
172    }
173
174    pub fn with_attribute<F, R>(&self, key: &OnionObject, f: &F) -> Result<R, RuntimeError>
175    where
176        F: Fn(&OnionObject) -> Result<R, RuntimeError>,
177    {
178        match key {
179            OnionObject::String(s) if s.as_str() == "parameter" => f(&self.parameter),
180            OnionObject::String(s) if s.as_str() == "capture" => f(&self.capture),
181            OnionObject::String(s) if s.as_str() == "self" => f(&self.self_object),
182            OnionObject::String(s) if s.as_str() == "signature" => {
183                f(&OnionObject::String(Arc::new(self.signature.clone())))
184            }
185            _ => Err(RuntimeError::InvalidOperation(
186                format!("Attribute '{:?}' not found in lambda definition", key).into(),
187            )),
188        }
189    }
190
191    pub fn with_parameter<F, R>(&self, f: F) -> Result<R, RuntimeError>
192    where
193        F: Fn(&OnionObject) -> Result<R, RuntimeError>,
194    {
195        f(&self.parameter)
196    }
197}
198
199impl GCTraceable<OnionObjectCell> for OnionLambdaDefinition {
200    fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
201        self.parameter.collect(queue);
202        self.capture.collect(queue);
203        self.self_object.collect(queue);
204    }
205}
206
207impl Debug for OnionLambdaDefinition {
208    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209        write!(
210            f,
211            "OnionLambdaDefinition {{ parameter: {:?}, body: {:?}, capture: {:?}, self_object: {:?} }}",
212            self.parameter, self.body, self.capture, self.self_object
213        )
214    }
215}
216
217impl OnionLambdaDefinition {
218    pub fn reconstruct_container(&self) -> Result<OnionObject, RuntimeError> {
219        let parameter = self.parameter.clone();
220        let body = self.body.clone();
221        let capture = self.capture.clone();
222        let self_object = self.self_object.clone();
223        let signature = self.signature.clone();
224        Ok(OnionObject::Lambda(
225            OnionLambdaDefinition {
226                parameter: parameter,
227                body,
228                capture,
229                self_object,
230                signature,
231            }
232            .into(),
233        ))
234    }
235}