pit_teavm/
lib.rs

1use std::{
2    collections::{BTreeMap, BTreeSet},
3    iter::once,
4};
5
6use itertools::Itertools;
7use pit_core::{Arg, Interface, ResTy, Sig};
8
9pub fn emit(i: &Interface, pkg: &str, binders: &Binders) -> String {
10    let generics: u32 = i
11        .ann
12        .iter()
13        .find_map(|a| {
14            if a.name == "generics" {
15                Some(a.value.clone())
16            } else {
17                None
18            }
19        })
20        .map(|a| a.parse().unwrap())
21        .unwrap_or_default();
22    let mut genericsStr = (0..generics)
23        .map(|a| format!("T{a}: Handler"))
24        .collect::<Vec<_>>()
25        .join(",");
26    let mut genericsRStr = (0..generics)
27        .map(|a| format!("T{a}"))
28        .collect::<Vec<_>>()
29        .join(",");
30    if genericsStr != "" {
31        genericsStr = format!("[{}]", genericsStr);
32    }
33    if genericsRStr != "" {
34        genericsRStr = format!("[{}]", genericsRStr);
35    }
36    let qs = if generics == 0 {
37        "".to_owned()
38    } else {
39        format!("[{}]", ",?".repeat(generics as usize).split_off(1))
40    };
41    let bs = binders
42        .iter()
43        .map(|((name, pkg, exp), (a, cfg))| {
44            let generics2: Option<u32> = a
45                .ann
46                .iter()
47                .find_map(|a| {
48                    if a.name == "generics" {
49                        Some(a.value.clone())
50                    } else {
51                        None
52                    }
53                })
54                .map(|a| a.parse().unwrap());
55            let generics2 = generics2.unwrap_or_default();
56            let mut generics2Str = (0..generics2)
57                .map(|a| a + generics)
58                .map(|a| format!("T{a}: Handler"))
59                .collect::<Vec<_>>()
60                .join(",");
61            let mut generics2RStr = (0..generics2)
62                .map(|a| a + generics)
63                .map(|a| format!("T{a}"))
64                .collect::<Vec<_>>()
65                .join(",");
66            if generics2Str != "" {
67                generics2Str = format!("[{}]", generics2Str);
68            }
69            if generics2RStr != "" {
70                generics2RStr = format!("[{}]", generics2RStr);
71            }
72            let mut n = cfg
73                .split(",")
74                .map(|i2| {
75                    let (is2, instance_renders) = do_instances(
76                        &i2.split(",").collect::<Vec<_>>(),
77                        i.rid_str().as_str(),
78                        generics,
79                    );
80                    is2[0].clone()
81                })
82                .chain(once(format!("{}{genericsRStr}", i.rid_str())))
83                .join(",");
84            n = format!("[{n}]");
85            let rns = a
86            .rets
87            .iter()
88            .enumerate()
89            .map(|(a, _)| format!("r{a}"))
90            .collect::<Vec<_>>()
91            .join(",");
92        let rvs = a
93            .rets
94            .iter()
95            .enumerate()
96            .map(|(a, b)| {
97                let mut c = format!("r{a}");
98                if let Arg::Resource {
99                    ty,
100                    nullable,
101                    take,
102                    ann,
103                } = b
104                {
105                    match ty {
106                        // ResTy::None  if !ann.iter().any(|a|a.name == "instance") => {}
107                        _ => {
108                            // let rid = match ty {
109                            //     ResTy::None => todo!(),
110                            //     ResTy::Of(a) => *a,
111                            //     ResTy::This => i.rid(),
112                            // };
113                            // let rid = hex::encode(rid);
114                            let d = emit_ty(
115                                b,
116                                i.rid_str().as_str(),
117                                &FFIStatus::HighLevel { generics },
118                            );
119                            c = format!("summon[Handler[{d}]].fromHandle({c})");
120                        }
121                    }
122                }
123                c
124            })
125            .collect::<Vec<_>>()
126            .join(",");
127        let s = format!(
128            r#"
129    given {name}{genericsStr}: {pkg}.{name}{n} = new {pkg}.{name}{n}{{
130        def {name}{} = {{
131            @Import(name=".{name}@{}",module="tpit") @native def go {};
132            return go(me.handle,{}) match{{
133                case ({rns}) => ({rvs})
134            }};
135        }};
136    }};
137    "#,
138            emit_sig(a, None, "me: Impl,", &FFIStatus::HighLevel { generics: 0 }),
139            a.to_string(),
140            emit_sig(a, None, "handle: Int,", &FFIStatus::FFI),
141            a.params
142                .iter()
143                .enumerate()
144                .map(|(a, b)| {
145                    let mut c = format!("_{a}");
146                    if let Arg::Resource {
147                        ty,
148                        nullable,
149                        take,
150                        ann,
151                    } = b
152                    {
153                        match ty {
154                            // ResTy::None if !ann.iter().any(|a|a.name == "instance")=> {}
155                            _ => {
156                                // let rid = match ty {
157                                //     ResTy::None => todo!(),
158                                //     ResTy::Of(a) => *a,
159                                //     ResTy::This => i.rid(),
160                                // };
161                                // let rid = hex::encode(rid);
162                                let d = emit_ty(
163                                    b,
164                                    i.rid_str().as_str(),
165                                    &FFIStatus::HighLevel { generics },
166                                );
167                                c = format!("summon[Handler[{d}]].handleOf({c})")
168                            }
169                        }
170                    }
171                    c
172                })
173                .collect::<Vec<_>>()
174                .join(",")
175        );
176            match exp {
177                Exposition::Import => {
178                    return s;
179                }
180                Exposition::Expose => {
181                    let rns = a
182                        .rets
183                        .iter()
184                        .enumerate()
185                        .map(|(a, _)| format!("r{a}"))
186                        .collect::<Vec<_>>()
187                        .join(",");
188                    let pvs = a
189                        .params
190                        .iter()
191                        .enumerate()
192                        .map(|(a, b)| {
193                            let mut c = format!("_{a}");
194                            if let Arg::Resource {
195                                ty,
196                                nullable,
197                                take,
198                                ann,
199                            } = b
200                            {
201                                match ty {
202                                    // ResTy::None  if !ann.iter().any(|a|a.name == "instance") => {}
203                                    _ => {
204                                        // let rid = match ty {
205                                        //     ResTy::None => todo!(),
206                                        //     ResTy::Of(a) => *a,
207                                        //     ResTy::This => i.rid(),
208                                        // };
209                                        // let rid = hex::encode(rid);
210                                        let d = emit_ty(
211                                            b,
212                                            i.rid_str().as_str(),
213                                            &FFIStatus::HighLevel { generics },
214                                        );
215                                        c = format!("summon[Handler[{d}]].fromHandle({c})");
216                                    }
217                                }
218                            }
219                            c
220                        })
221                        .collect::<Vec<_>>()
222                        .join(",");
223                    let rvs = a
224                        .rets
225                        .iter()
226                        .enumerate()
227                        .map(|(a, b)| {
228                            let mut c = format!("r{a}");
229                            if let Arg::Resource {
230                                ty,
231                                nullable,
232                                take,
233                                ann,
234                            } = b
235                            {
236                                match ty {
237                                    // ResTy::None  if !ann.iter().any(|a|a.name == "instance") => {}
238                                    _ => {
239                                        // let rid = match ty {
240                                        //     ResTy::None => todo!(),
241                                        //     ResTy::Of(a) => *a,
242                                        //     ResTy::This => i.rid(),
243                                        // };
244                                        // let rid = hex::encode(rid);
245                                        let d = emit_ty(
246                                            b,
247                                            i.rid_str().as_str(),
248                                            &FFIStatus::HighLevel { generics },
249                                        );
250                                        c = format!("summon[Handler[{d}]].handleOf({c}")
251                                    }
252                                }
253                            }
254                            c
255                        })
256                        .collect::<Vec<_>>()
257                        .join(",");
258                    format!(
259                        r#"
260                    @Export(name = "tpit/{}/.{name}@{}") def go{} = {{
261                        val z = all.get(handle);
262                        return summon[{pkg}.{name}Impl[{n}]].{name}({pvs}) match {{
263                            case ({rns}) => ({rvs})
264                        }};
265                    }};
266                    {s}
267                "#,
268                        i.rid_str(),
269                        a.to_string(),
270                        emit_sig(a, None, "handle: Int,", &FFIStatus::FFI),
271                    )
272                }
273            }
274        })
275        .join(";");
276    format!(
277        r#"
278        package {pkg};
279        import scala.collection.mutable.{{Map,HashMap}};
280        import org.teavm.interop.{{Import,Export}};
281        import pc.portal.pit.guest.{{Handler,drop}};
282        trait R{}{genericsStr}{{
283            {}
284            def finalize: Unit
285        }}
286        object R{}{{
287            given handler{genericsStr} = new Handler[R{}{genericsRStr}]{{
288                type Impl = Impl{genericsRStr}
289                def createImpl(a: R{}{genericsRStr}): Impl{genericsRStr} = new Impl(a);
290                def handleOf(a: Impl{genericsRStr}): Int = a.handle;
291                def fromHandle(a: Int): Impl{genericsRStr} = new Impl(a);
292                def finalize(a: R{}{genericsRStr}): Unit = a.finalize;
293            }};
294            {bs}
295            object Impl{{
296                val all: Map[Int,R{}{qs}] = HashMap.empty;
297                def create(r: R{}{qs}): Int = {{
298                    var x = 0
299                    while all.contains(x){{
300                        x = x + 1   
301                    }}
302                    all.addOne((x,r))
303                    return x
304                }}
305                {}
306            }}
307            class Impl{genericsStr}(val handle: Int) extends R{}{genericsRStr}{{
308                import Impl.{{all,create}};
309                def finalize: Unit = {{
310                    drop(handle);
311                }}
312                {}
313                def this(res: R{}{genericsRStr}) = {{
314                    @Import(name="~{pkg}",module="tpit/{}") @native def go(a: Int): Int
315                    this(go(create(res)))
316                }}
317            }};
318        }}"#,
319        i.rid_str(),
320        i.methods
321            .iter()
322            .map(|(a, b)| format!(
323                "def {a}{}",
324                emit_sig(
325                    b,
326                    i.rid_str().as_str(),
327                    "",
328                    &FFIStatus::HighLevel { generics }
329                )
330            ))
331            .collect::<Vec<_>>()
332            .join("\n"),
333        i.rid_str(),
334        i.rid_str(),
335        i.rid_str(),
336        i.rid_str(),
337        i.rid_str(),
338        i.rid_str(),
339        i.methods
340            .iter()
341            .map(|(a, b)| {
342                let rns = b
343                    .rets
344                    .iter()
345                    .enumerate()
346                    .map(|(a, _)| format!("r{a}"))
347                    .collect::<Vec<_>>()
348                    .join(",");
349                let pvs = b
350                    .params
351                    .iter()
352                    .enumerate()
353                    .map(|(a, b)| {
354                        let mut c = format!("_{a}");
355                        if let Arg::Resource {
356                            ty,
357                            nullable,
358                            take,
359                            ann,
360                        } = b
361                        {
362                            match ty {
363                                // ResTy::None  if !ann.iter().any(|a|a.name == "instance") => {}
364                                _ => {
365                                    // let rid = match ty {
366                                    //     ResTy::None => todo!(),
367                                    //     ResTy::Of(a) => *a,
368                                    //     ResTy::This => i.rid(),
369                                    // };
370                                    // let rid = hex::encode(rid);
371                                    let d = emit_ty(
372                                        b,
373                                        i.rid_str().as_str(),
374                                        &FFIStatus::HighLevel { generics },
375                                    );
376                                    c = format!("summon[Handler[{d}]].fromHandle({c})");
377                                }
378                            }
379                        }
380                        c
381                    })
382                    .collect::<Vec<_>>()
383                    .join(",");
384                let rvs = b
385                    .rets
386                    .iter()
387                    .enumerate()
388                    .map(|(a, b)| {
389                        let mut c = format!("r{a}");
390                        if let Arg::Resource {
391                            ty,
392                            nullable,
393                            take,
394                            ann,
395                        } = b
396                        {
397                            match ty {
398                                // ResTy::None  if !ann.iter().any(|a|a.name == "instance") => {}
399                                _ => {
400                                    // let rid = match ty {
401                                    //     ResTy::None => todo!(),
402                                    //     ResTy::Of(a) => *a,
403                                    //     ResTy::This => i.rid(),
404                                    // };
405                                    // let rid = hex::encode(rid);
406                                    let d = emit_ty(
407                                        b,
408                                        i.rid_str().as_str(),
409                                        &FFIStatus::HighLevel { generics },
410                                    );
411                                    c = format!("summon[Handler[{d}]].handleOf({c}")
412                                }
413                            }
414                        }
415                        c
416                    })
417                    .collect::<Vec<_>>()
418                    .join(",");
419                format!(
420                    r#"@Export(name="tpit/{}/~{pkg}/{a}") def {a}{} = {{
421                        var z = all(handle);
422                        return z.{a}({pvs}) match {{
423                            case ({rns}) => ({rvs})
424                        }};
425                    }}"#,
426                    i.rid_str(),
427                    emit_sig(b, i.rid_str().as_str(), "handle:Int,", &FFIStatus::FFI)
428                )
429            })
430            .chain(once(format!(
431                r#"
432            @Export(name="tpit/{}/~{pkg}.drop") def finalize(z: Int) = {{
433                val a = all.get(z);
434                all.subtractOne(z);
435                a match{{
436                    None=>(),
437                    Some(a) => finalize(a)
438                }}
439            }}"#,
440                i.rid_str()
441            )))
442            .collect::<Vec<_>>()
443            .join("\n"),
444        i.rid_str(),
445        i.methods
446            .iter()
447            .map(|(a, b)| {
448                let rns = b
449                    .rets
450                    .iter()
451                    .enumerate()
452                    .map(|(a, _)| format!("r{a}"))
453                    .collect::<Vec<_>>()
454                    .join(",");
455                let rvs = b
456                    .rets
457                    .iter()
458                    .enumerate()
459                    .map(|(a, b)| {
460                        let mut c = format!("r{a}");
461                        if let Arg::Resource {
462                            ty,
463                            nullable,
464                            take,
465                            ann,
466                        } = b
467                        {
468                            match ty {
469                                // ResTy::None  if !ann.iter().any(|a|a.name == "instance") => {}
470                                _ => {
471                                    // let rid = match ty {
472                                    //     ResTy::None => todo!(),
473                                    //     ResTy::Of(a) => *a,
474                                    //     ResTy::This => i.rid(),
475                                    // };
476                                    // let rid = hex::encode(rid);
477                                    let d = emit_ty(
478                                        b,
479                                        i.rid_str().as_str(),
480                                        &FFIStatus::HighLevel { generics },
481                                    );
482                                    c = format!("summon[Handler[{d}]].fromHandle({c})");
483                                }
484                            }
485                        }
486                        c
487                    })
488                    .collect::<Vec<_>>()
489                    .join(",");
490                format!(
491                    r#"def {a}{} = {{
492                        @Import(name = "{}",module="{}") @native def go{};
493                        return go(handle,{}) match{{
494                            case ({rns}) => ({rvs})
495                        }};
496                    }}"#,
497                    emit_sig(
498                        b,
499                        i.rid_str().as_str(),
500                        "",
501                        &FFIStatus::HighLevel { generics }
502                    ),
503                    a,
504                    format!("tpit/{}", i.rid_str()),
505                    emit_sig(b, i.rid_str().as_str(), "handle: Int,", &FFIStatus::FFI),
506                    b.params
507                        .iter()
508                        .enumerate()
509                        .map(|(a, b)| {
510                            let mut c = format!("_{a}");
511                            if let Arg::Resource {
512                                ty,
513                                nullable,
514                                take,
515                                ann,
516                            } = b
517                            {
518                                match ty {
519                                    // ResTy::None if !ann.iter().any(|a|a.name == "instance")=> {}
520                                    _ => {
521                                        // let rid = match ty {
522                                        //     ResTy::None => todo!(),
523                                        //     ResTy::Of(a) => *a,
524                                        //     ResTy::This => i.rid(),
525                                        // };
526                                        // let rid = hex::encode(rid);
527                                        let d = emit_ty(
528                                            b,
529                                            i.rid_str().as_str(),
530                                            &FFIStatus::HighLevel { generics },
531                                        );
532                                        c = format!("summon[Handler[{d}]].handleOf({c})")
533                                    }
534                                }
535                            }
536                            c
537                        })
538                        .collect::<Vec<_>>()
539                        .join(",")
540                )
541            })
542            .collect::<Vec<_>>()
543            .join("\n"),
544        i.rid_str(),
545        i.rid_str(),
546    )
547}
548pub enum FFIStatus {
549    FFI,
550    HighLevel { generics: u32 },
551}
552pub fn do_instances<'a>(
553    instances: &[&str],
554    rid: impl Into<Option<&'a str>>,
555    generics: u32,
556) -> (Vec<String>, String) {
557    let rid = rid.into();
558    let is2 = instances
559        .iter()
560        .filter_map(|a| {
561            let mut stack = vec![];
562            for s in a.split(";") {
563                if let Ok(g) = s.parse::<u32>() {
564                    stack.push(format!("T{a}"));
565                }
566                if s.starts_with("R") {
567                    let (rid, n) = s.split_once("N")?;
568                    let n: u32 = n.parse().ok()?;
569                    let mut n = (0..n).filter_map(|a| stack.pop()).join(",");
570                    if n != "" {
571                        n = format!("[{n}]");
572                    };
573                    stack.push(format!("R{rid}{n}"));
574                }
575                if s == "any" {
576                    stack.push(format!("Int"));
577                }
578                if s == "this" {
579                    let mut n = (0..generics).filter_map(|a| stack.pop()).join(",");
580                    if n != "" {
581                        n = format!("[{n}]");
582                    };
583                    let rid = rid.unwrap();
584                    stack.push(format!("R{rid}{n}"));
585                }
586            }
587            stack.pop()
588        })
589        .collect::<Vec<_>>();
590    let mut instance_renders = is2.join(",");
591    if instance_renders != "" {
592        instance_renders = format!("[{}]", instance_renders);
593    };
594    return (is2, instance_renders);
595}
596pub fn emit_ty<'a>(a: &Arg, rid: impl Into<Option<&'a str>>, ffi: &FFIStatus) -> String {
597    let rid = rid.into();
598    match a {
599        Arg::I32 => "Int".to_owned(),
600        Arg::I64 => "Long".to_owned(),
601        Arg::F32 => "Float".to_owned(),
602        Arg::F64 => "Double".to_owned(),
603        Arg::Resource {
604            ty,
605            nullable,
606            take,
607            ann,
608        } => match ffi {
609            FFIStatus::FFI => format!("Int"),
610            FFIStatus::HighLevel { generics } => {
611                let instances: Vec<_> = ann
612                    .iter()
613                    .find_map(|a| {
614                        if a.name == "instance" {
615                            Some(a.value.as_str())
616                        } else {
617                            None
618                        }
619                    })
620                    .into_iter()
621                    .flat_map(|a| a.split(","))
622                    .collect();
623                let (is2, instance_renders) = do_instances(&instances, rid, *generics);
624                match ty {
625                    ResTy::Of(x) => {
626                        let x = hex::encode(x);
627                        format!("Option[R{x}.Impl{instance_renders}]")
628                    }
629                    ResTy::This => {
630                        let rid = rid.unwrap();
631                        format!("Option[R{rid}.Impl{instance_renders}]")
632                    }
633                    ResTy::None => {
634                        if is2.len() == 1 {
635                            format!("Option[summon[Handler[{}]].Impl]", is2[0])
636                        } else {
637                            format!("Int")
638                        }
639                    },
640                    _ => todo!()
641                }
642            }
643        },
644        _ => todo!()
645    }
646}
647pub fn emit_sig<'a>(
648    a: &Sig,
649    rid: impl Into<Option<&'a str>>,
650    prepend: &str,
651    ffi: &FFIStatus,
652) -> String {
653    let rid = rid.into();
654    let generics2: Option<u32> = a
655        .ann
656        .iter()
657        .find_map(|a| {
658            if a.name == "generics" {
659                Some(a.value.clone())
660            } else {
661                None
662            }
663        })
664        .map(|a| a.parse().unwrap());
665    let gstr = match ffi {
666        FFIStatus::FFI => format!(""),
667        FFIStatus::HighLevel { generics } => match generics2 {
668            None => format!(""),
669            Some(generics2) => {
670                let mut generics2Str = (0..generics2)
671                    .map(|a| a + generics)
672                    .map(|a| format!("T{a}: Handler"))
673                    .collect::<Vec<_>>()
674                    .join(",");
675                let mut generics2RStr = (0..generics2)
676                    .map(|a| a + generics)
677                    .map(|a| format!("T{a}"))
678                    .collect::<Vec<_>>()
679                    .join(",");
680                if generics2Str != "" {
681                    generics2Str = format!("[{}]", generics2Str);
682                }
683                if generics2RStr != "" {
684                    generics2RStr = format!("[{}]", generics2RStr);
685                }
686                generics2Str
687            }
688        },
689    };
690    format!(
691        "{gstr}({prepend}{}): ({})",
692        a.params
693            .iter()
694            .enumerate()
695            .map(|(i, x)| format!("_{i}: {}", emit_ty(x, rid, ffi)))
696            .collect::<Vec<_>>()
697            .join(","),
698        a.rets
699            .iter()
700            .map(|x| emit_ty(x, rid, ffi))
701            .collect::<Vec<_>>()
702            .join(",")
703    )
704}
705pub type Binders = BTreeMap<(String, String, Exposition), (Sig, String)>;
706#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
707pub enum Exposition {
708    Expose,
709    Import,
710}
711pub fn emit_binder_sig(s: &Sig, name: &str, pkg: &str) -> String {
712    let rname = format!(".{name}@{s}");
713    let generics2: u32 = s
714        .ann
715        .iter()
716        .find_map(|a| {
717            if a.name == "generics" {
718                Some(a.value.clone())
719            } else {
720                None
721            }
722        })
723        .map(|a| a.parse::<u32>().unwrap())
724        .unwrap_or(0u32);
725    let mut generics2Str = (0..generics2)
726        // .map(|a| a + generics)
727        .map(|a| format!("T{a}: Handler"))
728        .chain(once(format!("Item")))
729        .collect::<Vec<_>>()
730        .join(",");
731    let mut generics2RStr = (0..generics2)
732        // .map(|a| a + generics)
733        .map(|a| format!("T{a}"))
734        .chain(once(format!("Item")))
735        .collect::<Vec<_>>()
736        .join(",");
737    if generics2Str != "" {
738        generics2Str = format!("[{}]", generics2Str);
739    }
740    if generics2RStr != "" {
741        generics2RStr = format!("[{}]", generics2RStr);
742    }
743    return format!(
744        r"
745        package {pkg};
746        import scala.collection.mutable.{{Map,HashMap}};
747        import org.teavm.interop.{{Import,Export}};
748        import pc.portal.pit.guest.{{Handler,drop}};
749        trait {name}{generics2Str}: Handler[Item]{{
750            def {name}{}
751        }};
752        trait {name}Impl{generics2Str}: Handler[Item] with {name}{generics2RStr}{{
753            def impl_{name}{}
754        }};
755    ",
756        emit_sig(s, None, "me: Impl,", &FFIStatus::HighLevel { generics: 0 }),
757        emit_sig(s, None, "me: Item,", &FFIStatus::HighLevel { generics: 0 })
758    );
759}