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},
15 types::{
16 lambda::{
17 parameter::LambdaParameter, vm_instructions::instruction_set::VMInstructionPackage,
18 },
19 object::{OnionObject, OnionObjectCell, OnionStaticObject},
20 },
21 utils::fastmap::{OnionFastMap, OnionKeyPool},
22};
23
24use super::runnable::OnionLambdaRunnable;
25
26pub enum LambdaBody {
27 Instruction(Arc<VMInstructionPackage>),
28 NativeFunction(
29 (
30 Arc<
31 dyn Fn(
32 &OnionObject, &OnionFastMap<Box<str>, OnionStaticObject>, &OnionFastMap<Box<str>, OnionObject>, &mut GC<OnionObjectCell>, ) -> Box<dyn Runnable>
37 + Send
38 + Sync,
39 >,
40 OnionKeyPool<Box<str>>,
41 ),
42 ),
43}
44
45impl Clone for LambdaBody {
46 fn clone(&self) -> Self {
47 match self {
48 LambdaBody::Instruction(instruction) => LambdaBody::Instruction(instruction.clone()),
49 LambdaBody::NativeFunction(native_function) => {
50 LambdaBody::NativeFunction(native_function.clone())
51 }
52 }
53 }
54}
55
56impl LambdaBody {
57 fn create_string_pool(&self) -> OnionKeyPool<Box<str>> {
58 match self {
59 LambdaBody::Instruction(instruction) => instruction.create_key_pool(),
60 LambdaBody::NativeFunction((_, key_pool)) => key_pool.clone(),
61 }
62 }
63}
64
65impl Debug for LambdaBody {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 match self {
68 LambdaBody::Instruction(_) => write!(f, "Instruction(...)"),
69 LambdaBody::NativeFunction(_) => write!(f, "NativeFunction"),
70 }
71 }
72}
73
74impl Display for LambdaBody {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 match self {
77 LambdaBody::Instruction(_) => write!(f, "Instruction(...)"),
78 LambdaBody::NativeFunction(_) => write!(f, "NativeFunction"),
79 }
80 }
81}
82
83pub enum LambdaType {
84 Normal,
85 AsyncLauncher,
86 SyncLauncher,
87}
88
89pub struct OnionLambdaDefinition {
90 parameter: LambdaParameter,
91 flatten_param_keys: Box<[Box<str>]>,
92 flatten_param_constraints: Box<[OnionObject]>,
93 body: LambdaBody,
94 capture: OnionFastMap<Box<str>, OnionObject>,
95 signature: Box<str>,
96 lambda_type: LambdaType,
97}
98
99impl OnionLambdaDefinition {
100 pub fn new_static(
101 parameter: LambdaParameter,
102 body: LambdaBody,
103 capture: OnionFastMap<Box<str>, OnionObject>,
104 signature: Box<str>,
105 lambda_type: LambdaType,
106 ) -> OnionStaticObject {
107 let flatten_param_keys = parameter.flatten_keys();
108 let flatten_param_constraints = parameter.flatten_constraints();
109 OnionObject::Lambda((
110 OnionLambdaDefinition {
111 parameter,
112 flatten_param_keys,
113 flatten_param_constraints,
114 body,
115 capture,
116 signature,
117 lambda_type,
118 }
119 .into(),
120 OnionObject::Undefined(None).into(),
121 ))
122 .consume_and_stabilize()
123 }
124
125 pub fn new_static_with_self(
126 parameter: LambdaParameter,
127 body: LambdaBody,
128 capture: OnionFastMap<Box<str>, OnionObject>,
129 self_object: &OnionObject,
130 signature: Box<str>,
131 lambda_type: LambdaType,
132 ) -> OnionStaticObject {
133 let flatten_param_keys = parameter.flatten_keys();
134 let flatten_param_constraints = parameter.flatten_constraints();
135 OnionObject::Lambda((
136 OnionLambdaDefinition {
137 parameter,
138 flatten_param_keys,
139 flatten_param_constraints,
140 body,
141 capture,
142 signature,
143 lambda_type,
144 }
145 .into(),
146 self_object.clone().into(),
147 ))
148 .consume_and_stabilize()
149 }
150
151 pub fn create_key_pool(&self) -> OnionKeyPool<Box<str>> {
153 self.body.create_string_pool()
154 }
155
156 pub fn with_lambda_type(&self, lambda_type: LambdaType) -> Self {
157 OnionLambdaDefinition {
158 parameter: self.parameter.clone(),
159 flatten_param_keys: self.flatten_param_keys.clone(),
160 flatten_param_constraints: self.flatten_param_constraints.clone(),
161 body: self.body.clone(),
162 capture: self.capture.clone(),
163 signature: self.signature.clone(),
164 lambda_type,
165 }
166 }
167
168 pub fn lambda_type(&self) -> &LambdaType {
169 &self.lambda_type
170 }
171
172 pub fn create_runnable(
174 &self,
175 argument: &OnionFastMap<Box<str>, OnionStaticObject>,
176 this_lambda: &OnionStaticObject,
177 self_object: &OnionObject,
178 gc: &mut GC<OnionObjectCell>,
179 ) -> Result<Box<dyn Runnable>, RuntimeError> {
180 match &self.body {
181 LambdaBody::Instruction(instruction) => {
182 let runnable = OnionLambdaRunnable::new(
183 argument,
184 &self.capture,
185 self_object,
186 this_lambda,
187 instruction.clone(),
188 match instruction.get_table().get(self.signature.as_ref()) {
189 Some(ip) => *ip as isize,
190 None => {
191 return Err(RuntimeError::InvalidOperation(
192 format!(
193 "Signature '{}' not found in instruction package",
194 self.signature
195 )
196 .into(),
197 ));
198 }
199 },
200 )?;
201 Ok(Box::new(runnable))
202 }
203 LambdaBody::NativeFunction((native_function, _)) => {
204 Ok(native_function(self_object, argument, &self.capture, gc))
205 }
206 }
207 }
208
209 pub fn get_signature(&self) -> &str {
210 &self.signature
211 }
212
213 pub fn get_parameter(&self) -> &LambdaParameter {
214 &self.parameter
215 }
216
217 pub fn get_flatten_param_keys(&self) -> &[Box<str>] {
218 &self.flatten_param_keys
219 }
220
221 pub fn get_flatten_param_constraints(&self) -> &[OnionObject] {
222 &self.flatten_param_constraints
223 }
224
225 pub fn get_capture(&self) -> &OnionFastMap<Box<str>, OnionObject> {
226 &self.capture
227 }
228
229 pub fn get_body(&self) -> &LambdaBody {
230 &self.body
231 }
232
233 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
234 self.parameter.upgrade(collected);
235 for (_, obj) in self.capture.pairs() {
236 obj.upgrade(collected);
237 }
238 }
239
240 pub fn with_attribute<F, R>(&self, key: &OnionObject, f: &F) -> Result<R, RuntimeError>
241 where
242 F: Fn(&OnionObject) -> Result<R, RuntimeError>,
243 {
244 match key {
245 OnionObject::String(s) if s.as_ref() == "$parameter" => {
246 let parameter = self.parameter.to_onion();
247 f(parameter.weak())
248 }
249 OnionObject::String(s) if s.as_ref() == "$signature" => {
250 f(&OnionObject::String(Arc::from(self.signature.clone())))
251 }
252 OnionObject::String(s) => {
253 if let Some(value) = self.capture.get(s.as_ref()) {
254 f(value)
255 } else {
256 Err(RuntimeError::InvalidOperation(
257 format!("Attribute '{:?}' not found in lambda definition", key).into(),
258 ))
259 }
260 }
261 _ => Err(RuntimeError::InvalidOperation(
262 format!("Attribute '{:?}' not found in lambda definition", key).into(),
263 )),
264 }
265 }
266}
267
268impl GCTraceable<OnionObjectCell> for OnionLambdaDefinition {
269 fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
270 self.parameter.collect(queue);
271 for (_, obj) in self.capture.pairs() {
272 obj.collect(queue);
273 }
274 }
275}
276
277impl Debug for OnionLambdaDefinition {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 write!(
280 f,
281 "OnionLambdaDefinition {{ parameter: {:?}, body: {:?}, capture: {:?} }}",
282 self.parameter, self.body, self.capture
283 )
284 }
285}