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}