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}