Skip to main content

seahorse_dev/core/compile/builtin/
python.rs

1//! Python builtin types.
2
3use crate::{
4    core::compile::{ast::*, build::*, builtin::*},
5    match1,
6};
7use prelude::{Namespace, NamespacedObject};
8use quote::quote;
9use std::collections::BTreeMap;
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum Python {
13    // Types
14    None,
15    List,
16    Tuple,
17    Int,
18    Bool,
19    Str,
20    // Meta types
21    Iter,
22    AsLen,
23    // Functions
24    Abs,
25    Print,
26    Min,
27    Max,
28    Round,
29    Range,
30    Len,
31    Enumerate,
32    Filter,
33    Map,
34    Zip,
35    Sorted,
36    Sum,
37    ListConstructor,
38}
39
40/// Create the Python builtins namespace.
41pub fn namespace() -> Namespace {
42    let data = [
43        ("None", Python::None),
44        ("List", Python::List),
45        ("Tuple", Python::Tuple),
46        ("int", Python::Int),
47        ("bool", Python::Bool),
48        ("str", Python::Str),
49        ("abs", Python::Abs),
50        ("print", Python::Print),
51        ("min", Python::Min),
52        ("max", Python::Max),
53        ("round", Python::Round),
54        ("range", Python::Range),
55        ("len", Python::Len),
56        ("enumerate", Python::Enumerate),
57        ("filter", Python::Filter),
58        ("map", Python::Map),
59        ("zip", Python::Zip),
60        ("sorted", Python::Sorted),
61        ("sum", Python::Sum),
62        ("list", Python::ListConstructor),
63    ];
64
65    let mut namespace = BTreeMap::new();
66    for (name, obj) in data.into_iter() {
67        namespace.insert(
68            name.to_string(),
69            NamespacedObject::Automatic(Builtin::Python(obj)),
70        );
71    }
72
73    return namespace;
74}
75
76impl BuiltinSource for Python {
77    fn name(&self) -> String {
78        match self {
79            Self::None => "None",
80            Self::List => "List",
81            Self::Tuple => "Tuple",
82            Self::Int => "int",
83            Self::Bool => "bool",
84            Self::Str => "str",
85            Self::Iter => "<Iter>",
86            Self::AsLen => "<Len>",
87            Self::Abs => "abs",
88            Self::Print => "print",
89            Self::Min => "min",
90            Self::Max => "max",
91            Self::Round => "round",
92            Self::Range => "range",
93            Self::Len => "len",
94            Self::Enumerate => "enumerate",
95            Self::Filter => "filter",
96            Self::Map => "map",
97            Self::Zip => "zip",
98            Self::Sorted => "sorted",
99            Self::Sum => "sum",
100            Self::ListConstructor => "list",
101        }
102        .to_string()
103    }
104
105    fn ty(&self) -> Ty {
106        match self {
107            Self::Str => Ty::Type(
108                TyName::Builtin(Builtin::Python(self.clone())),
109                Some(Ty::new_function(
110                    vec![("", Ty::Any, ParamType::Required)],
111                    Ty::Transformed(
112                        Ty::python(Self::Str, vec![]).into(),
113                        Transformation::new(|mut expr| {
114                            let s = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
115
116                            expr.obj = if expr.ty.is_display() {
117                                ExpressionObj::Rendered(quote! {
118                                    format!("{}", #s)
119                                })
120                            } else {
121                                ExpressionObj::Rendered(quote! {
122                                    format!("{:?}", #s)
123                                })
124                            };
125
126                            Ok(Transformed::Expression(expr))
127                        })
128                    )
129                ).into())
130            ),
131            // abs(T) -> T
132            Self::Abs => Ty::new_function(
133                vec![("x", Ty::Anonymous(0), ParamType::Required)],
134                Ty::Transformed(
135                    Ty::Anonymous(0).into(),
136                    Transformation::new(|mut expr| {
137                        let x = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
138
139                        match &expr.ty {
140                            Ty::Generic(TyName::Builtin(Builtin::Prelude(Prelude::RustInt(true, _) | Prelude::RustFloat)), _) => {},
141                            _ => {
142                                return Err(CoreError::make_raw(
143                                    "cannot take the absolute value of an unsigned integer",
144                                    ""
145                                ))
146                            }
147                        }
148
149                        expr.obj = ExpressionObj::Rendered(quote! {
150                            #x.abs()
151                        });
152
153                        Ok(Transformed::Expression(expr))
154                    })
155                )
156            ),
157            // print(...any) -> None
158            Self::Print => Ty::new_function(
159                vec![("", Ty::Any.into(), ParamType::Variadic)],
160                Ty::Transformed(
161                    Ty::python(Self::None, vec![]).into(),
162                    Transformation::new(|expr| {
163                        let args = match1!(expr.obj, ExpressionObj::Call { mut args, .. } => args.remove(0));
164                        let args = match1!(args.obj, ExpressionObj::Vec(args) => args);
165
166                        let mut format = String::new();
167                        for arg in args.iter() {
168                            if format.len() > 0 {
169                                format.push_str(" ");
170                            }
171
172                            format.push_str(if arg.ty.is_display() { "{}" } else { "{:?}" });
173                        }
174
175                        Ok(Transformed::Expression(
176                            ExpressionObj::Rendered(quote! {
177                                solana_program::msg!(#format, #(#args),*)
178                            })
179                            .into(),
180                        ))
181                    }),
182                ),
183            ),
184            // min(...T) -> T
185            Self::Min => Ty::new_function(
186                vec![("", Ty::Anonymous(0), ParamType::Variadic)],
187                Ty::Transformed(
188                    Ty::Anonymous(0).into(),
189                    Transformation::new(|expr| {
190                        let args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
191                        let mut parts =
192                            match1!(args.obj, ExpressionObj::Vec(parts) => parts.into_iter());
193                        if parts.len() < 2 {
194                            return Err(CoreError::make_raw(
195                                "min() requires at least 1 argument",
196                                "",
197                            ));
198                        }
199
200                        let mut accum = parts.next().unwrap();
201                        for part in parts {
202                            accum.obj = accum.obj.with_call("min", vec![part]);
203                        }
204
205                        Ok(Transformed::Expression(accum))
206                    }),
207                ),
208            ),
209            // max(...T) -> T
210            Self::Max => Ty::new_function(
211                vec![("", Ty::Anonymous(0), ParamType::Variadic)],
212                Ty::Transformed(
213                    Ty::Anonymous(0).into(),
214                    Transformation::new(|expr| {
215                        let args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
216                        let mut parts =
217                            match1!(args.obj, ExpressionObj::Vec(parts) => parts.into_iter());
218                        if parts.len() < 2 {
219                            return Err(CoreError::make_raw(
220                                "max() requires at least 1 argument",
221                                "",
222                            ));
223                        }
224
225                        let mut accum = parts.next().unwrap();
226                        for part in parts {
227                            accum.obj = accum.obj.with_call("max", vec![part]);
228                        }
229
230                        Ok(Transformed::Expression(accum))
231                    }),
232                ),
233            ),
234            // round(f64) -> i128
235            Self::Round => Ty::new_function(
236                vec![(
237                    "x",
238                    Ty::prelude(Prelude::RustFloat, vec![]),
239                    ParamType::Required,
240                )],
241                Ty::Transformed(
242                    Ty::prelude(Prelude::RustInt(true, 128), vec![]).into(),
243                    Transformation::new(|mut expr| {
244                        let args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args);
245                        let x = args.into_iter().next().unwrap();
246
247                        expr.obj = ExpressionObj::As {
248                            value: ExpressionObj::Rendered(quote! { #x.round() }).into(),
249                            ty: TyExpr::new_specific(vec!["i128"], Mutability::Immutable)
250                        };
251
252                        Ok(Transformed::Expression(expr))
253                    }),
254                ),
255            ),
256            // range(T, T?, T?) -> <Iter>[T]
257            Self::Range => Ty::new_function(
258                vec![
259                    ("start", Ty::Anonymous(0), ParamType::Required),
260                    ("stop", Ty::Anonymous(0), ParamType::Optional),
261                    ("step", Ty::Anonymous(0), ParamType::Optional)
262                ],
263                Ty::Transformed(
264                    Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into(),
265                    Transformation::new(|mut expr| {
266                        let mut args =
267                            match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
268                        let start = args.next().unwrap();
269                        let stop = args.next().unwrap();
270                        let step = args.next().unwrap();
271
272                        let range = match stop.obj {
273                            ExpressionObj::Placeholder => ExpressionObj::Rendered(quote! {
274                                0 .. #start
275                            }),
276                            stop => ExpressionObj::Rendered(quote! {
277                                #start .. #stop
278                            }),
279                        };
280
281                        let range = match step.obj {
282                            ExpressionObj::Placeholder => range,
283                            step => ExpressionObj::Rendered(quote! {
284                                (#range).step_by(#step.try_into().unwrap())
285                            })
286                        };
287
288                        expr.obj = range;
289
290                        Ok(Transformed::Expression(expr))
291                    }),
292                ),
293            ),
294            // len(Cast(<Len>)) -> u64
295            Self::Len => Ty::new_function(
296                vec![
297                    ("iterable", Ty::Cast(Ty::python(Self::AsLen, vec![]).into()), ParamType::Required)
298                ],
299                Ty::Transformed(
300                    Ty::prelude(Prelude::RustInt(false, 64), vec![]).into(),
301                    Transformation::new(|mut expr| {
302                        let len = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
303
304                        expr.obj = len.obj;
305
306                        Ok(Transformed::Expression(expr))
307                    })
308                )
309            ),
310            // enumerate(Cast(<Iter>[T])) -> <Iter>[(u64, T)]
311            Self::Enumerate => Ty::new_function(
312                vec![(
313                    "iterable",
314                    Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
315                    ParamType::Required,
316                )],
317                Ty::Transformed(
318                    Ty::python(
319                        Self::Iter,
320                        vec![Ty::python(
321                            Self::Tuple,
322                            vec![
323                                Ty::prelude(Prelude::RustInt(false, 64), vec![]),
324                                Ty::Anonymous(0),
325                            ],
326                        )],
327                    )
328                    .into(),
329                    Transformation::new(|mut expr| {
330                        let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
331
332                        expr.obj = ExpressionObj::Rendered(quote! {
333                            (#iterable).enumerate().map(|(i, x)| (i as u64, x))
334                        });
335
336                        Ok(Transformed::Expression(expr))
337                    }),
338                ),
339            ),
340            // filter((T) -> bool, Cast(<Iter>[T])) -> <Iter>[T]
341            Self::Filter => Ty::new_function(
342                vec![
343                    (
344                        "function",
345                        Ty::new_function(
346                            vec![
347                                ("x", Ty::Anonymous(0), ParamType::Required)
348                            ],
349                            Ty::python(Self::Bool, vec![])
350                        ),
351                        ParamType::Required
352                    ),
353                    (
354                        "iterable",
355                        Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
356                        ParamType::Required,
357                    )
358                ],
359                Ty::Transformed(
360                    Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into(),
361                    Transformation::new(|mut expr| {
362                        let mut args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
363                        let function = args.next().unwrap();
364                        let iterable = args.next().unwrap();
365
366                        let return_ty = match1!(&function.ty, Ty::Function(_, returns) => *returns.clone());
367
368                        let elem = ExpressionObj::Rendered(quote! { elem.clone() });
369                        let call = ExpressionObj::Call {
370                            function: function.into(),
371                            args: vec![elem.into()]
372                        }.into();
373
374                        let elem = match return_ty {
375                            Ty::Transformed(_, transformation) => match (transformation.function)(call, &vec![].into())? {
376                                Transformed::Expression(expression) => expression,
377                                _ => {
378                                    return Err(CoreError::make_raw(
379                                        "can not filter using a special function",
380                                        "Hint: this function causes an effect that needs compiler magic to work, and can't be called from a filter."
381                                    ));
382                                }
383                            }
384                            _ => call
385                        };
386
387                        expr.obj = ExpressionObj::Rendered(quote! {
388                            #iterable.filter(|elem| #elem)
389                        });
390
391                        Ok(Transformed::Expression(expr))
392                    })
393                )
394            ),
395            // map((T) -> U, Cast(<Iter>[T])) -> <Iter>[U]
396            Self::Map => Ty::new_function(
397                vec![
398                    (
399                        "function",
400                        Ty::new_function(
401                            vec![
402                                ("x", Ty::Anonymous(0), ParamType::Required)
403                            ],
404                            Ty::Anonymous(1)
405                        ),
406                        ParamType::Required
407                    ),
408                    (
409                        "iterable",
410                        Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
411                        ParamType::Required,
412                    )
413                ],
414                Ty::Transformed(
415                    Ty::python(Self::Iter, vec![Ty::Anonymous(1)]).into(),
416                    Transformation::new(|mut expr| {
417                        let mut args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
418                        let function = args.next().unwrap();
419                        let iterable = args.next().unwrap();
420
421                        let return_ty = match1!(&function.ty, Ty::Function(_, returns) => *returns.clone());
422
423                        let elem = ExpressionObj::Rendered(quote! { elem.clone() });
424                        let call = ExpressionObj::Call {
425                            function: function.into(),
426                            args: vec![elem.into()]
427                        }.into();
428
429                        let elem = match return_ty {
430                            Ty::Transformed(_, transformation) => match (transformation.function)(call, &vec![].into())? {
431                                Transformed::Expression(expression) => expression,
432                                _ => {
433                                    return Err(CoreError::make_raw(
434                                        "can not map using a special function",
435                                        "Hint: this function causes an effect that needs compiler magic to work, and can't be called from a map."
436                                    ));
437                                }
438                            }
439                            _ => call
440                        };
441
442                        expr.obj = ExpressionObj::Rendered(quote! {
443                            #iterable.map(|elem| #elem)
444                        });
445
446                        Ok(Transformed::Expression(expr))
447                    })
448                )
449            ),
450            // zip(Cast(<Iter>[T]), Cast(<Iter>[U])) -> <Iter>[(T, U)]
451            // Unfortunately the type system doesn't allow for `zip`ing with variadic iterators,
452            // like Python does
453            // TODO could either make specialized prelude functions (zip3, zip4, etc.) to solve this
454            // or do more compiler magic like in the array constructors
455            Self::Zip => Ty::new_function(
456                vec![
457                    (
458                        "iterable1",
459                        Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
460                        ParamType::Required,
461                    ),
462                    (
463                        "iterable2",
464                        Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(1)]).into()),
465                        ParamType::Required,
466                    )
467                ],
468                Ty::Transformed(
469                    Ty::python(Self::Iter, vec![
470                        Ty::python(Self::Tuple, vec![Ty::Anonymous(0), Ty::Anonymous(1)])
471                    ]).into(),
472                    Transformation::new(|mut expr| {
473                        let mut args = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter());
474                        let iterable1 = args.next().unwrap();
475                        let iterable2 = args.next().unwrap();
476
477                        expr.obj = ExpressionObj::Rendered(quote! {
478                            #iterable1.zip(#iterable2)
479                        });
480
481                        Ok(Transformed::Expression(expr))
482                    })
483                )
484            ),
485            // sorted(Cast(<Iter>[T])) -> List[T]
486            // TODO support key, reverse
487            Self::Sorted => Ty::new_function(
488                vec![(
489                    "iterable",
490                    Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
491                    ParamType::Required,
492                )],
493                Ty::Transformed(
494                    Ty::python(
495                        Self::List,
496                        vec![Ty::Anonymous(0)],
497                    ).into(),
498                    Transformation::new(|mut expr| {
499                        let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
500
501                        expr.obj = ExpressionObj::Rendered(quote! {
502                            Mutable::new({
503                                let mut temp = #iterable.collect::<Vec<_>>();
504                                temp.sort();
505                                temp
506                            })
507                        });
508
509                        Ok(Transformed::Expression(expr))
510                    }),
511                ),
512            ),
513            // sum(Cast(<Iter>[T])) -> T
514            Self::Sum => Ty::new_function(
515                vec![(
516                    "iterable",
517                    Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
518                    ParamType::Required,
519                )],
520                Ty::Transformed(
521                    Ty::Anonymous(0).into(),
522                    Transformation::new(|mut expr| {
523                        let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
524
525                        let init = match &expr.ty {
526                            Ty::Generic(TyName::Builtin(Builtin::Prelude(Prelude::RustInt(..))), _) => quote! { 0 },
527                            Ty::IntParam(..) => quote! { 0 },
528                            Ty::Generic(TyName::Builtin(Builtin::Prelude(Prelude::RustFloat)), _) => quote! { 0.0 },
529                            ty => {
530                                return Err(CoreError::make_raw(
531                                    format!("cannot perform sum of type {}", ty),
532                                    "Hint: sums can be performed on numeric types only."
533                                ))
534                            }
535                        };
536
537                        expr.obj = ExpressionObj::Rendered(quote! {
538                            // Rolling my own sum implementation here because Rust's `Iterator.sum`
539                            // requires type info which is annoying to obtain
540                            #iterable.fold(#init, |accum, elem| accum + elem)
541                        });
542
543                        Ok(Transformed::Expression(expr))
544                    })
545                )
546            ),
547            // list(Cast(<Iter>[T])) -> List[T]
548            Self::ListConstructor => Ty::new_function(
549                vec![(
550                    "iterable",
551                    Ty::Cast(Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into()),
552                    ParamType::Required,
553                )],
554                Ty::Transformed(
555                    Ty::python(
556                        Self::List,
557                        vec![Ty::Anonymous(0)],
558                    ).into(),
559                    Transformation::new(|mut expr| {
560                        let iterable = match1!(expr.obj, ExpressionObj::Call { args, .. } => args.into_iter().next().unwrap());
561
562                        expr.obj = ExpressionObj::Rendered(quote! {
563                            Mutable::new((#iterable).collect::<Vec<_>>())
564                        });
565
566                        Ok(Transformed::Expression(expr))
567                    }),
568                ),
569            ),
570            name => Ty::Type(TyName::Builtin(Builtin::Python(name.clone())), None),
571        }
572    }
573
574    fn as_instance(&self, params: &Vec<Ty>) -> CResult<()> {
575        match self {
576            Self::List if params.len() == 1 => Ok(()),
577            Self::Tuple => Ok(()),
578            Self::None | Self::Int if params.len() == 0 => Ok(()),
579            _ => Err(CoreError::make_raw("invalid type", "")),
580        }
581    }
582
583    fn attr(&self, attr: &String) -> Option<(Ty, Ty)> {
584        match (self, attr.as_str()) {
585            // List[T].append(T) -> None
586            (Self::List, "append") => Some((
587                Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
588                Ty::new_function(
589                    vec![("x", Ty::Anonymous(0), ParamType::Required)],
590                    Ty::Transformed(
591                        Ty::python(Self::Tuple, vec![]).into(),
592                        Transformation::new(|mut expr| {
593                            let (function, args) = match1!(expr.obj, ExpressionObj::Call { function, args } => (*function, args));
594                            let value = match1!(function.obj, ExpressionObj::Attribute { value, .. } => *value);
595
596                            expr.obj = ExpressionObj::Rendered(quote! {
597                                #value.borrow_mut().push(#(#args),*)
598                            });
599
600                            Ok(Transformed::Expression(expr))
601                        }),
602                    ),
603                ),
604            )),
605            // List[T].pop() -> T
606            (Self::List, "pop") => Some((
607                Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
608                Ty::new_function(
609                    vec![],
610                    Ty::Transformed(
611                        Ty::Anonymous(0).into(),
612                        Transformation::new(|mut expr| {
613                            let function = match1!(expr.obj, ExpressionObj::Call { function, .. } => *function);
614                            let value = match1!(function.obj, ExpressionObj::Attribute { value, .. } => *value);
615
616                            expr.obj = ExpressionObj::Rendered(quote! {
617                                #value.borrow_mut().pop().unwrap()
618                            });
619
620                            Ok(Transformed::Expression(expr))
621                        }),
622                    ),
623                ),
624            )),
625            _ => None,
626        }
627    }
628
629    fn index(&self) -> Option<(Ty, Ty)> {
630        match self {
631            // List[T].__index__(i128) -> T
632            Self::List => Some((
633                Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
634                Ty::new_function(
635                    vec![
636                        ("", Ty::Cast(Ty::prelude(Prelude::RustInt(true, 128), vec![]).into()), ParamType::Required)
637                    ],
638                    Ty::Transformed(
639                        Ty::Anonymous(0).into(),
640                        Transformation::new(|mut expr| {
641                            let (value, index) = match1!(expr.obj, ExpressionObj::Index { value, index } => (*value, *index));
642                            
643                            if let ExpressionObj::BorrowMut(..) = &value.obj {
644                                expr.obj = ExpressionObj::Rendered(quote! {
645                                    (*#value.index_wrapped_mut(#index.into()))
646                                });
647                            } else {
648                                expr.obj = ExpressionObj::Rendered(quote! {
649                                    (*#value.index_wrapped(#index.into()))
650                                });
651                            }
652
653                            Ok(Transformed::Expression(expr))
654                        })
655                    ).into()
656                )
657            )),
658            _ => None
659        }
660    }
661
662    fn static_attr(&self, attr: &String) -> Option<Ty> {
663        None
664    }
665
666    fn casted(&self, ty: &Ty) -> Option<(Ty, Ty)> {
667        let builtin = if let Ty::Generic(TyName::Builtin(builtin), _) = ty {
668            builtin
669        } else {
670            return None;
671        };
672
673        match self {
674            Self::List => match builtin {
675                Builtin::Python(Self::Iter) => Some((
676                    Ty::python(Self::List, vec![Ty::Anonymous(0)]),
677                    Ty::Transformed(
678                        Ty::python(Self::Iter, vec![Ty::Anonymous(0)]).into(),
679                        Transformation::new(|mut expr| {
680                            let list = expr.obj;
681
682                            expr.obj = ExpressionObj::Rendered(quote! {
683                                #list.borrow().iter().map(|elem| elem.clone())
684                            });
685
686                            Ok(Transformed::Expression(expr))
687                        }),
688                    ),
689                )),
690                Builtin::Python(Self::AsLen) => Some((
691                    Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
692                    Ty::Transformed(
693                        Ty::python(Self::AsLen, vec![]).into(),
694                        Transformation::new(|mut expr| {
695                            let list = expr.obj;
696
697                            expr.obj = ExpressionObj::Rendered(quote! {
698                                (#list.borrow().len() as u64)
699                            });
700
701                            Ok(Transformed::Expression(expr))
702                        }),
703                    ),
704                )),
705                Builtin::Prelude(Prelude::Seed) => Some((
706                    Ty::python(
707                        self.clone(),
708                        vec![Ty::prelude(Prelude::RustInt(false, 8), vec![])],
709                    ),
710                    Ty::Transformed(
711                        Ty::prelude(Prelude::Seed, vec![]).into(),
712                        Transformation::new(|mut expr| {
713                            let err = CoreError::make_raw(
714                                "to use a list of bytes as a seed, the list must be known at compile-time",
715                                ""
716                            );
717
718                            let list = match expr.obj {
719                                ExpressionObj::Mutable(obj) => match obj.obj {
720                                    ExpressionObj::Vec(list) => {
721                                        list.into_iter().map(|element| element.without_borrows())
722                                    }
723                                    _ => {
724                                        return Err(err);
725                                    }
726                                },
727                                _ => {
728                                    return Err(err);
729                                }
730                            };
731
732                            expr.obj = ExpressionObj::Rendered(quote! {
733                                [#(#list),*].as_ref()
734                            });
735
736                            Ok(Transformed::Expression(expr))
737                        }),
738                    ),
739                )),
740                _ => None,
741            },
742            Self::Str => match builtin {
743                Builtin::Prelude(Prelude::Seed) => Some((
744                    Ty::python(Python::Str, vec![]),
745                    Ty::Transformed(
746                        Ty::prelude(Prelude::Seed, vec![]).into(),
747                        Transformation::new(|mut expr| {
748                            // TODO maybe limit to only string literals?
749                            let obj = expr.obj.without_borrows();
750                            expr.obj = ExpressionObj::Rendered(quote! {
751                                #obj.as_bytes().as_ref()
752                            });
753
754                            Ok(Transformed::Expression(expr))
755                        }),
756                    ),
757                )),
758                Builtin::Python(Self::AsLen) => Some((
759                    Ty::python(self.clone(), vec![]),
760                    Ty::Transformed(
761                        Ty::python(Self::AsLen, vec![]).into(),
762                        Transformation::new(|mut expr| {
763                            let string = expr.obj;
764
765                            expr.obj = ExpressionObj::Rendered(quote! {
766                                (#string.chars().count() as u64)
767                            });
768
769                            Ok(Transformed::Expression(expr))
770                        }),
771                    ),
772                )),
773                _ => None,
774            },
775            Self::Iter => match builtin {
776                Builtin::Python(Self::Iter) => Some((
777                    Ty::python(Self::Iter, vec![Ty::Anonymous(0)]),
778                    Ty::python(Self::Iter, vec![Ty::Anonymous(0)]),
779                )),
780                Builtin::Python(Self::AsLen) => Some((
781                    Ty::python(self.clone(), vec![Ty::Anonymous(0)]),
782                    Ty::Transformed(
783                        Ty::python(Self::AsLen, vec![]).into(),
784                        Transformation::new(|mut expr| {
785                            let iterable = expr.obj;
786
787                            expr.obj = ExpressionObj::Rendered(quote! {
788                                (#iterable.count() as u64)
789                            });
790
791                            Ok(Transformed::Expression(expr))
792                        }),
793                    ),
794                )),
795                _ => None,
796            },
797            _ => None,
798        }
799    }
800}