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}