portal_jsc_simpl_js/
lib.rs

1use std::borrow::Cow;
2use std::collections::BTreeMap;
3use std::collections::HashMap;
4use std::convert::Infallible;
5use std::env::Args;
6use std::fmt::Debug;
7use std::fmt::Display;
8use std::hash::Hash;
9
10use portal_jsc_swc_batch::ImportMapping;
11use portal_jsc_swc_util::BreakKind;
12use portal_jsc_swc_util::ModuleMapper;
13use portal_jsc_swc_util::{Extract, ImportMapper, ImportOr, MakeSpanned};
14use swc_atoms::Atom;
15use swc_common::{Span, Spanned};
16use swc_ecma_ast::BreakStmt;
17use swc_ecma_ast::ContinueStmt;
18use swc_ecma_ast::Function;
19use swc_ecma_ast::Id;
20use swc_ecma_ast::KeyValueProp;
21use swc_ecma_ast::MethodProp;
22use swc_ecma_ast::ObjectLit;
23use swc_ecma_ast::Param;
24use swc_ecma_ast::Prop;
25use swc_ecma_ast::SwitchCase;
26use swc_ecma_ast::SwitchStmt;
27use swc_ecma_ast::{
28    ArrowExpr, AssignExpr, AssignOp, BinExpr, BinaryOp, BindingIdent, BlockStmt, CallExpr, Expr,
29    ExprOrSpread, ExprStmt, Ident, IdentName, IfStmt, LabeledStmt, Lit, MemberExpr, MemberProp,
30    ReturnStmt, SimpleAssignTarget, Stmt, WhileStmt,
31};
32use typenum::Same;
33
34pub trait Dialect {
35    type Mark<T>: Extract<T>;
36    type MarkSpanned<T: Spanned + Clone + Debug + Hash + Eq>: Same<Output = Self::Mark<T>>
37        + Extract<T>
38        + Spanned
39        + Clone
40        + Debug
41        + Hash
42        + Eq;
43    type Tag: Spanned + Clone + Debug + Hash + Eq;
44    fn span<T: Spanned + Clone + Debug + Hash + Eq>(
45        a: Self::Mark<()>,
46        b: T,
47    ) -> Self::MarkSpanned<T>;
48    fn despan<T: Spanned + Clone + Debug + Hash + Eq>(
49        a: Self::MarkSpanned<T>,
50    ) -> (Self::Mark<()>, T);
51}
52
53#[non_exhaustive]
54#[derive(Clone, Hash, Debug, PartialEq, Eq, Spanned)]
55pub enum SimplExpr<D: Dialect> {
56    Lit(Lit),
57    Ident(D::MarkSpanned<SimplPath>),
58    Assign(MakeSpanned<SimplAssignment<D>>),
59    Bin(MakeSpanned<SimplBinOp<D>>),
60    Call(MakeSpanned<Box<SimplCallExpr<D>>>),
61    Select(MakeSpanned<SimplSelectExpr<D>>),
62}
63#[non_exhaustive]
64#[derive(Clone, Hash, Debug, PartialEq, Eq, Spanned)]
65pub enum SimplStmt<D: Dialect> {
66    Expr(MakeSpanned<Box<SimplExpr<D>>>),
67    Block(MakeSpanned<Vec<SimplStmt<D>>>),
68    If(MakeSpanned<SimplIf<D>>),
69    Return(MakeSpanned<Box<SimplExpr<D>>>),
70    Break(Ident),
71    Continue(Ident),
72    Switch(MakeSpanned<SimplSwitchStmt<D>>),
73}
74#[derive(Clone, Hash, Debug, PartialEq, Eq, Spanned)]
75pub struct SimplPath {
76    #[span]
77    pub root: Ident,
78    pub keys: Vec<Atom>,
79}
80#[derive(Clone, Hash, Debug, PartialEq, Eq)]
81pub struct SimplPathId {
82    pub root: Id,
83    pub keys: Vec<Atom>,
84}
85impl SimplPath {
86    pub fn to_id(&self) -> SimplPathId {
87        SimplPathId {
88            root: self.root.to_id(),
89            keys: self.keys.clone(),
90        }
91    }
92}
93impl SimplPathId {
94    pub fn span(self, span: Span) -> SimplPath {
95        SimplPath {
96            root: Ident {
97                span: span,
98                ctxt: self.root.1,
99                sym: self.root.0,
100                optional: false,
101            },
102            keys: self.keys,
103        }
104    }
105}
106#[derive(Clone, Hash, Debug, PartialEq, Eq)]
107pub struct FuncId<E, P> {
108    // #[span]
109    pub path: P,
110    pub template_args: BTreeMap<Atom, E>,
111}
112impl<E, P: Spanned> Spanned for FuncId<E, P> {
113    fn span(&self) -> Span {
114        self.path.span()
115    }
116}
117impl<E, P> FuncId<E, P> {
118    pub fn map<F, Q, Error>(
119        self,
120        mut path: impl FnMut(P) -> Result<Q, Error>,
121        mut arg: impl FnMut(E) -> Result<F, Error>,
122    ) -> Result<FuncId<F, Q>, Error> {
123        Ok(FuncId {
124            path: path(self.path)?,
125            template_args: self
126                .template_args
127                .into_iter()
128                .map(|(k, v)| Ok((k, arg(v)?)))
129                .collect::<Result<_, Error>>()?,
130        })
131    }
132}
133#[derive(Clone, Hash, Debug, PartialEq, Eq, Spanned)]
134pub enum SimplCallExpr<D: Dialect> {
135    Path {
136        #[span]
137        path: FuncId<Expr, D::MarkSpanned<SimplPath>>,
138        args: Vec<SimplExpr<D>>,
139    },
140    Tag {
141        #[span]
142        tag: FuncId<Expr, D::Tag>,
143        args: Vec<SimplExpr<D>>,
144    },
145    Block(Box<SimplStmt<D>>),
146}
147#[derive(Clone, Hash, Debug, PartialEq, Eq)]
148pub struct SimplSelectExpr<D: Dialect> {
149    pub scrutinee: Box<SimplExpr<D>>,
150    pub cases: BTreeMap<Id, (Vec<SimplStmt<D>>, Vec<Ident>)>,
151}
152#[derive(Clone, Hash, Debug, PartialEq, Eq)]
153pub struct SimplSwitchStmt<D: Dialect> {
154    pub scrutinee: Box<SimplExpr<D>>,
155    pub label: Ident,
156    pub cases: Vec<(Box<SimplExpr<D>>, Vec<SimplStmt<D>>, BreakKind)>,
157}
158#[derive(Clone, Hash, Debug, PartialEq, Eq)]
159pub struct SimplAssignment<D: Dialect> {
160    pub target: D::MarkSpanned<SimplPath>,
161    pub assign: AssignOp,
162    pub body: Box<SimplExpr<D>>,
163}
164#[derive(Clone, Hash, Debug, PartialEq, Eq)]
165pub struct SimplBinOp<D: Dialect> {
166    pub lhs: Box<SimplExpr<D>>,
167    pub op: BinaryOp,
168    pub rhs: Box<SimplExpr<D>>,
169}
170#[derive(Clone, Hash, Debug, PartialEq, Eq)]
171pub struct SimplIf<D: Dialect> {
172    pub kind: SimplIfKind<D>,
173    pub cond: Box<SimplExpr<D>>,
174    pub body: Vec<SimplStmt<D>>,
175}
176
177#[derive(Clone, Hash, Debug, PartialEq, Eq)]
178pub enum SimplIfKind<D: Dialect> {
179    If { r#else: Vec<SimplStmt<D>> },
180    While { label: Ident },
181}
182
183impl<D: Dialect> SimplStmt<D> {
184    pub fn apply_label(&mut self, label: &Ident) {
185        match self {
186            SimplStmt::Expr(make_spanned) | SimplStmt::Return(make_spanned) => {}
187            SimplStmt::Block(make_spanned) => {
188                for a in make_spanned.value.iter_mut() {
189                    a.apply_label(label);
190                }
191            }
192            SimplStmt::If(make_spanned) => match &mut make_spanned.value.kind {
193                SimplIfKind::If { r#else } => {
194                    for a in make_spanned.value.body.iter_mut().chain(r#else.iter_mut()) {
195                        a.apply_label(label);
196                    }
197                }
198                SimplIfKind::While { label: l } => {
199                    *l = label.clone();
200                }
201            },
202            SimplStmt::Break(l) | SimplStmt::Continue(l) => {
203                *l = label.clone();
204            }
205            SimplStmt::Switch(make_spanned) => {
206                make_spanned.value.label = label.clone();
207            }
208        }
209    }
210}
211
212impl<D: Dialect<Tag = Infallible>> From<SimplExpr<D>> for Expr {
213    fn from(value: SimplExpr<D>) -> Self {
214        match value {
215            SimplExpr::Ident(i) => match i.extract_own() {
216                p => p.keys.into_iter().fold(Expr::Ident(p.root), |a, b| {
217                    let asp = a.span();
218                    Expr::Member(MemberExpr {
219                        span: a.span(),
220                        obj: Box::new(a),
221                        prop: swc_ecma_ast::MemberProp::Ident(IdentName { span: asp, sym: b }),
222                    })
223                }),
224            },
225            SimplExpr::Assign(a) => match a.value.target.extract_own() {
226                mut p => {
227                    let h = match p.keys.pop() {
228                        None => SimpleAssignTarget::Ident(BindingIdent {
229                            id: p.root,
230                            type_ann: None,
231                        }),
232                        Some(pa) => SimpleAssignTarget::Member(MemberExpr {
233                            span: a.span,
234                            obj: Box::new(p.keys.into_iter().fold(Expr::Ident(p.root), |a, b| {
235                                let asp = a.span();
236                                Expr::Member(MemberExpr {
237                                    span: a.span(),
238                                    obj: Box::new(a),
239                                    prop: swc_ecma_ast::MemberProp::Ident(IdentName {
240                                        span: asp,
241                                        sym: b,
242                                    }),
243                                })
244                            })),
245                            prop: MemberProp::Ident(IdentName {
246                                span: a.span,
247                                sym: pa,
248                            }),
249                        }),
250                    };
251                    Expr::Assign(AssignExpr {
252                        span: a.span,
253                        op: a.value.assign,
254                        left: swc_ecma_ast::AssignTarget::Simple(h),
255                        right: Box::new((*a.value.body).into()),
256                    })
257                }
258            },
259            SimplExpr::Bin(b) => Expr::Bin(BinExpr {
260                span: b.span,
261                op: b.value.op,
262                left: Box::new((*b.value.lhs).into()),
263                right: Box::new((*b.value.rhs).into()),
264            }),
265            SimplExpr::Lit(l) => Expr::Lit(l),
266            SimplExpr::Call(c) => match *c.value {
267                SimplCallExpr::Path { path, args } => {
268                    let pid = match path.path.extract_own() {
269                        p => p.keys.into_iter().fold(Expr::Ident(p.root), |a, b| {
270                            let asp = a.span();
271                            Expr::Member(MemberExpr {
272                                span: a.span(),
273                                obj: Box::new(a),
274                                prop: swc_ecma_ast::MemberProp::Ident(IdentName {
275                                    span: asp,
276                                    sym: b,
277                                }),
278                            })
279                        }),
280                    };
281                    Expr::Call(CallExpr {
282                        span: c.span,
283                        ctxt: Default::default(),
284                        callee: swc_ecma_ast::Callee::Expr(Box::new(pid)),
285                        args: if path.template_args.len() == 0 {
286                            None
287                        } else {
288                            Some(Expr::Object(ObjectLit {
289                                span: c.span,
290                                props: path
291                                    .template_args
292                                    .into_iter()
293                                    .map(|(a, b)| {
294                                        swc_ecma_ast::PropOrSpread::Prop(Box::new(Prop::KeyValue(
295                                            KeyValueProp {
296                                                key: swc_ecma_ast::PropName::Ident(IdentName {
297                                                    span: c.span,
298                                                    sym: a,
299                                                }),
300                                                value: Box::new(b),
301                                            },
302                                        )))
303                                    })
304                                    .collect(),
305                            }))
306                        }
307                        .into_iter()
308                        .chain(args.into_iter().map(|a| a.into()))
309                        .map(|a| ExprOrSpread {
310                            spread: None,
311                            expr: Box::new(a),
312                        })
313                        .collect(),
314                        type_args: None,
315                    })
316                }
317                SimplCallExpr::Block(simpl_stmt) => {
318                    let pid = Expr::Arrow(ArrowExpr {
319                        span: c.span,
320                        ctxt: Default::default(),
321                        params: vec![],
322                        body: Box::new(swc_ecma_ast::BlockStmtOrExpr::BlockStmt(BlockStmt {
323                            span: c.span,
324                            ctxt: Default::default(),
325                            stmts: vec![(*simpl_stmt).into()],
326                        })),
327                        is_async: false,
328                        is_generator: false,
329                        type_params: None,
330                        return_type: None,
331                    });
332                    Expr::Call(CallExpr {
333                        span: c.span,
334                        ctxt: Default::default(),
335                        callee: swc_ecma_ast::Callee::Expr(Box::new(pid)),
336                        args: vec![],
337                        type_args: None,
338                    })
339                }
340                SimplCallExpr::Tag { tag, args } => match tag {},
341            },
342            SimplExpr::Select(s) => Expr::Call(CallExpr {
343                span: s.span,
344                ctxt: Default::default(),
345                callee: swc_ecma_ast::Callee::Expr(Box::new(Expr::Member(MemberExpr {
346                    span: s.span,
347                    obj: Box::new((*s.value.scrutinee).into()),
348                    prop: MemberProp::Ident(IdentName {
349                        span: s.span,
350                        sym: Atom::new("$match"),
351                    }),
352                }))),
353                args: vec![ExprOrSpread {
354                    spread: None,
355                    expr: Box::new(Expr::Object(ObjectLit {
356                        span: s.span,
357                        props: s
358                            .value
359                            .cases
360                            .into_iter()
361                            .map(|p| {
362                                swc_ecma_ast::PropOrSpread::Prop(Box::new(Prop::Method(
363                                    MethodProp {
364                                        key: swc_ecma_ast::PropName::Ident(IdentName {
365                                            span: s.span,
366                                            sym: p.0 .0,
367                                        }),
368                                        function: Box::new(Function {
369                                            params: p
370                                                .1
371                                                 .1
372                                                .into_iter()
373                                                .map(|x| Param {
374                                                    span: s.span,
375                                                    decorators: vec![],
376                                                    pat: swc_ecma_ast::Pat::Ident(x.into()),
377                                                })
378                                                .collect(),
379                                            decorators: vec![],
380                                            span: s.span,
381                                            ctxt: Default::default(),
382                                            body: Some(BlockStmt {
383                                                span: s.span,
384                                                ctxt: Default::default(),
385                                                stmts: p
386                                                    .1
387                                                     .0
388                                                    .into_iter()
389                                                    .map(|a| a.into())
390                                                    .collect(),
391                                            }),
392                                            is_generator: false,
393                                            is_async: false,
394                                            type_params: None,
395                                            return_type: None,
396                                        }),
397                                    },
398                                )))
399                            })
400                            .collect(),
401                    })),
402                }],
403                type_args: None,
404            }),
405            _ => todo!(),
406        }
407    }
408}
409impl<D: Dialect> SimplStmt<D> {
410    pub fn flat(self) -> Vec<SimplStmt<D>> {
411        match self {
412            SimplStmt::Block(b) => b.value.into_iter().flat_map(|a| a.flat()).collect(),
413            SimplStmt::If(i) => vec![SimplStmt::If(MakeSpanned {
414                value: SimplIf {
415                    kind: match i.value.kind {
416                        SimplIfKind::If { r#else } => SimplIfKind::If {
417                            r#else: r#else.into_iter().flat_map(|a| a.flat()).collect(),
418                        },
419                        a => a,
420                    },
421                    cond: i.value.cond,
422                    body: i.value.body.into_iter().flat_map(|a| a.flat()).collect(),
423                },
424                span: i.span,
425            })],
426            a => vec![a],
427        }
428    }
429}
430impl<D: Dialect<Tag = Infallible>> From<SimplStmt<D>> for Stmt {
431    fn from(value: SimplStmt<D>) -> Self {
432        match value {
433            SimplStmt::Expr(e) => Stmt::Expr(ExprStmt {
434                expr: Box::new((*e.value).into()),
435                span: e.span,
436            }),
437            SimplStmt::Block(b) => Stmt::Block(BlockStmt {
438                span: b.span,
439                ctxt: Default::default(),
440                stmts: b.value.into_iter().map(|a| a.into()).collect(),
441            }),
442            SimplStmt::Return(e) => Stmt::Return(ReturnStmt {
443                span: e.span,
444                arg: Some(Box::new((*e.value).into())),
445            }),
446            SimplStmt::If(i) => match i.value.kind {
447                SimplIfKind::If { r#else } => Stmt::If(IfStmt {
448                    span: i.span,
449                    test: Box::new((*i.value.cond).into()),
450                    cons: Box::new(Stmt::Block(BlockStmt {
451                        span: i.span,
452                        ctxt: Default::default(),
453                        stmts: i.value.body.into_iter().map(|a| a.into()).collect(),
454                    })),
455                    alt: if r#else.len() != 0 {
456                        Some(Box::new(Stmt::Block(BlockStmt {
457                            span: i.span,
458                            ctxt: Default::default(),
459                            stmts: r#else.into_iter().map(|a| a.into()).collect(),
460                        })))
461                    } else {
462                        None
463                    },
464                }),
465                SimplIfKind::While { label } => Stmt::Labeled(LabeledStmt {
466                    span: i.span,
467                    label,
468                    body: Box::new(Stmt::While(WhileStmt {
469                        span: i.span,
470                        test: Box::new((*i.value.cond).into()),
471                        body: Box::new(Stmt::Block(BlockStmt {
472                            span: i.span,
473                            ctxt: Default::default(),
474                            stmts: i.value.body.into_iter().map(|a| a.into()).collect(),
475                        })),
476                    })),
477                }),
478            },
479            SimplStmt::Break(b) => Stmt::Break(BreakStmt {
480                span: b.span(),
481                label: Some(b),
482            }),
483            SimplStmt::Continue(b) => Stmt::Continue(ContinueStmt {
484                span: b.span(),
485                label: Some(b),
486            }),
487            SimplStmt::Switch(s) => Stmt::Labeled(LabeledStmt {
488                span: s.span,
489                label: s.value.label,
490                body: Box::new(Stmt::Switch(SwitchStmt {
491                    span: s.span,
492                    discriminant: Box::new((*s.value.scrutinee).into()),
493                    cases: s
494                        .value
495                        .cases
496                        .into_iter()
497                        .map(|(a, b, c)| SwitchCase {
498                            span: s.span,
499                            test: Some(Box::new((*a).into())),
500                            cons: b
501                                .into_iter()
502                                .map(|c| c.into())
503                                .chain(match c {
504                                    BreakKind::BreakAfter => Some(Stmt::Break(BreakStmt {
505                                        span: s.span,
506                                        label: None,
507                                    })),
508                                    BreakKind::DoNotBreakAfter => None,
509                                })
510                                .collect(),
511                        })
512                        .collect(),
513                })),
514            }),
515            _ => todo!(),
516        }
517    }
518}
519#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
520pub enum Error {
521    Unsupported,
522}
523impl Display for Error {
524    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
525        match self {
526            Error::Unsupported => write!(f, "unsupported syntax construct"),
527        }
528    }
529}
530impl std::error::Error for Error {
531    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
532        match self {
533            _ => None,
534        }
535    }
536}
537pub trait ConvTagLookup<D: Dialect> {
538    fn lookup_tag<'a, 'b>(
539        &self,
540        a: &'a Expr,
541        args: &'b [ExprOrSpread],
542    ) -> Result<(D::Tag, Cow<'b, [ExprOrSpread]>), &'a Expr>;
543}
544pub trait ConvCtx<D: ConvDialect>: ImportMapper + ModuleMapper + ConvTagLookup<D> {}
545impl<D: ConvDialect, T: ImportMapper + ModuleMapper + ConvTagLookup<D> + ?Sized> ConvCtx<D> for T {}
546pub trait Conv {
547    type Target<D: Dialect>;
548    fn conv<D: ConvDialect>(&self, imports: &impl ConvCtx<D>) -> Result<Self::Target<D>, Error>;
549}
550pub trait ConvDialect: Dialect {
551    type IMark<T>: Extract<T> + From<T>;
552    type IMarkSpanned<T: Spanned + Clone + Debug + Hash + Eq>: Same<Output = Self::IMark<T>>
553        + Extract<T>
554        + From<T>
555        + Spanned
556        + Clone
557        + Debug
558        + Hash
559        + Eq;
560    fn new_import<T: Eq + Hash + Clone + Spanned + Debug>(
561        a: ImportOr<Self::IMarkSpanned<T>>,
562    ) -> Self::MarkSpanned<T>;
563    fn get_import<T: Eq + Hash + Clone + Spanned + Debug>(
564        a: Self::MarkSpanned<T>,
565    ) -> ImportOr<Self::IMarkSpanned<T>>;
566}
567impl Conv for Expr {
568    type Target<D: Dialect> = SimplExpr<D>;
569
570    fn conv<D: ConvDialect>(&self, imports: &impl ConvCtx<D>) -> Result<Self::Target<D>, Error> {
571        Ok(match self {
572            Expr::Lit(l) => SimplExpr::Lit(l.clone()),
573            Expr::Ident(i) => SimplExpr::Ident(match i.clone() {
574                i => D::new_import(match imports.import_of(&i.to_id()) {
575                    None => ImportOr::NotImport(
576                        SimplPath {
577                            root: i,
578                            keys: vec![],
579                        }
580                        .into(),
581                    ),
582                    Some((a, b)) => ImportOr::Import {
583                        value: SimplPath {
584                            root: i,
585                            keys: vec![],
586                        }
587                        .into(),
588                        module: a,
589                        name: b,
590                    },
591                }),
592            }),
593            Expr::Member(m) => {
594                let a: SimplExpr<D> = m.obj.conv(imports)?;
595                let mut path: ImportOr<_> = D::get_import(match a {
596                    SimplExpr::Ident(path) => path,
597                    SimplExpr::Assign(a) => a.value.target,
598                    _ => return Err(Error::Unsupported),
599                });
600                let MemberProp::Ident(i) = &m.prop else {
601                    return Err(Error::Unsupported);
602                };
603                match &mut path {
604                    ImportOr::NotImport(value) => {
605                        value.as_mut().keys.push(i.sym.clone());
606                    }
607                    ImportOr::Import {
608                        value,
609                        module,
610                        name,
611                    } => {
612                        value.as_mut().keys.push(i.sym.clone());
613                    }
614                };
615                SimplExpr::Ident(D::new_import(path))
616            }
617            Expr::Assign(a) => {
618                let e: SimplExpr<D> = match &a.left {
619                    swc_ecma_ast::AssignTarget::Simple(simple_assign_target) => {
620                        match simple_assign_target {
621                            swc_ecma_ast::SimpleAssignTarget::Ident(binding_ident) => {
622                                Expr::Ident(binding_ident.id.clone()).conv(imports)?
623                            }
624                            swc_ecma_ast::SimpleAssignTarget::Member(m) => {
625                                let a: SimplExpr<D> = m.obj.conv(imports)?;
626                                let mut path: ImportOr<_> = D::get_import(match a {
627                                    SimplExpr::Ident(path) => path,
628                                    SimplExpr::Assign(a) => a.value.target,
629                                    _ => return Err(Error::Unsupported),
630                                });
631                                let MemberProp::Ident(i) = &m.prop else {
632                                    return Err(Error::Unsupported);
633                                };
634                                match &mut path {
635                                    ImportOr::NotImport(value) => {
636                                        value.as_mut().keys.push(i.sym.clone());
637                                    }
638                                    ImportOr::Import {
639                                        value,
640                                        module,
641                                        name,
642                                    } => {
643                                        value.as_mut().keys.push(i.sym.clone());
644                                    }
645                                };
646                                SimplExpr::Ident(D::new_import(path))
647                            }
648                            swc_ecma_ast::SimpleAssignTarget::SuperProp(super_prop_expr) => todo!(),
649                            swc_ecma_ast::SimpleAssignTarget::Paren(paren_expr) => todo!(),
650                            swc_ecma_ast::SimpleAssignTarget::OptChain(opt_chain_expr) => todo!(),
651                            swc_ecma_ast::SimpleAssignTarget::TsAs(ts_as_expr) => todo!(),
652                            swc_ecma_ast::SimpleAssignTarget::TsSatisfies(ts_satisfies_expr) => {
653                                todo!()
654                            }
655                            swc_ecma_ast::SimpleAssignTarget::TsNonNull(ts_non_null_expr) => {
656                                todo!()
657                            }
658                            swc_ecma_ast::SimpleAssignTarget::TsTypeAssertion(
659                                ts_type_assertion,
660                            ) => todo!(),
661                            swc_ecma_ast::SimpleAssignTarget::TsInstantiation(ts_instantiation) => {
662                                todo!()
663                            }
664                            swc_ecma_ast::SimpleAssignTarget::Invalid(invalid) => todo!(),
665                        }
666                    }
667                    swc_ecma_ast::AssignTarget::Pat(assign_target_pat) => todo!(),
668                };
669                let mut path = match e {
670                    SimplExpr::Ident(path) => path,
671                    SimplExpr::Assign(a) => a.value.target,
672                    _ => return Err(Error::Unsupported),
673                };
674                SimplExpr::Assign(MakeSpanned {
675                    value: SimplAssignment {
676                        target: path,
677                        assign: a.op,
678                        body: Box::new(a.right.conv(imports)?),
679                    },
680                    span: a.span,
681                })
682            }
683            Expr::Bin(b) => SimplExpr::Bin(MakeSpanned {
684                value: SimplBinOp {
685                    lhs: Box::new(b.left.conv(imports)?),
686                    op: b.op,
687                    rhs: Box::new(b.right.conv(imports)?),
688                },
689                span: b.span,
690            }),
691            Expr::Call(c) => {
692                match &c.callee {
693                    swc_ecma_ast::Callee::Super(_) => todo!(),
694                    swc_ecma_ast::Callee::Import(import) => todo!(),
695                    swc_ecma_ast::Callee::Expr(expr) => {
696                        match &**expr {
697                            Expr::Fn(f) if f.function.params.len() == 0 => {
698                                SimplExpr::Call(MakeSpanned {
699                                    value: Box::new(SimplCallExpr::Block(Box::new(
700                                        SimplStmt::Block(MakeSpanned {
701                                            value: f
702                                                .function
703                                                .body
704                                                .iter()
705                                                .flat_map(|a| a.stmts.iter())
706                                                .map(|s| s.conv(imports))
707                                                .collect::<Result<Vec<_>, _>>()?,
708                                            span: f.span(),
709                                        }),
710                                    ))),
711                                    span: f.span(),
712                                })
713                            }
714                            Expr::Arrow(f) if f.params.len() == 0 => SimplExpr::Call(MakeSpanned {
715                                value: Box::new(SimplCallExpr::Block(Box::new(SimplStmt::Block(
716                                    MakeSpanned {
717                                        value: match &*f.body {
718                                            swc_ecma_ast::BlockStmtOrExpr::BlockStmt(
719                                                block_stmt,
720                                            ) => block_stmt
721                                                .stmts
722                                                .iter()
723                                                .map(|s| s.conv(imports))
724                                                .collect::<Result<Vec<_>, _>>()?,
725                                            swc_ecma_ast::BlockStmtOrExpr::Expr(expr) => {
726                                                vec![SimplStmt::Return(MakeSpanned {
727                                                    value: Box::new(expr.conv(imports)?),
728                                                    span: f.span(),
729                                                })]
730                                            }
731                                        },
732                                        span: f.span(),
733                                    },
734                                )))),
735                                span: f.span(),
736                            }),
737                            e => {
738                                match imports.lookup_tag(e, &c.args) {
739                                    Err(e) => {
740                                        let a: SimplExpr<D> = e.conv(imports)?;
741                                        let mut path = match &a {
742                                            SimplExpr::Ident(path) => path,
743                                            SimplExpr::Assign(a) => &a.value.target,
744                                            _ => return Err(Error::Unsupported),
745                                        }
746                                        .clone();
747                                        match (
748                                            &c.args[..],
749                                            path.as_ref().keys.last().map(|a| a as &str),
750                                        ) {
751                                            (
752                                                &[ExprOrSpread {
753                                                    ref spread,
754                                                    ref expr,
755                                                }],
756                                                Some("$match"),
757                                            ) if expr.as_object().is_some() => {
758                                                let obj = expr.as_object().unwrap();
759                                                SimplExpr::Select(MakeSpanned {
760                                        value: SimplSelectExpr {
761                                            scrutinee: Box::new(a),
762                                            cases: obj
763                                                .props
764                                                .iter()
765                                                .filter_map(|a| a.as_prop())
766                                                .filter_map(|p| {
767                                                    let (id, body, args) = match &**p {
768                                                        Prop::Method(m) => (
769                                                            m.key.as_ident()?.clone(),
770                                                            m.function.body.as_ref(),
771                                                            m.function
772                                                                .params
773                                                                .iter()
774                                                                .map(|a| a.pat.clone())
775                                                                .collect(),
776                                                        ),
777                                                        Prop::KeyValue(a) => match &*a.value {
778                                                            Expr::Fn(f) => (
779                                                                IdentName {
780                                                                    span: a.key.as_ident().unwrap().span,
781                                                                    sym: a.key.as_ident().unwrap().sym.clone(),
782                                                                },
783                                                                f.function.body.as_ref(),
784                                                                f.function
785                                                                    .params
786                                                                    .iter()
787                                                                    .map(|a| a.pat.clone())
788                                                                    .collect(),
789                                                            ),
790                                                            Expr::Arrow(f) => (
791                                                                IdentName {
792                                                                    span: a.key.as_ident().unwrap().span,
793                                                                    sym: a.key.as_ident().unwrap().sym.clone(),
794                                                                },
795                                                                f.body.as_block_stmt(),
796                                                                f.params.clone(),
797                                                            ),
798                                                            _ => return None,
799                                                        },
800                                                        _ => return None,
801                                                    };
802                                                    Some((id, body, args))
803                                                })
804                                                .map(|(id, body, arg)| {
805                                                    Ok((
806                                                        Ident::new(
807                                                            id.sym,
808                                                            id.span,
809                                                            Default::default(),
810                                                        )
811                                                        .to_id(),
812                                                        (
813                                                            body.iter()
814                                                                .flat_map(|c| c.stmts.iter())
815                                                                .map(|a| a.conv(imports))
816                                                                .collect::<Result<Vec<_>, _>>()?,
817                                                            arg.iter()
818                                                                .filter_map(|a| a.as_ident())
819                                                                .map(|a| a.id.clone())
820                                                                .collect(),
821                                                        ),
822                                                    ))
823                                                })
824                                                .collect::<Result<BTreeMap<_, _>, Error>>()?,
825                                        },
826                                        span: c.span,
827                                    })
828                                            }
829                                            _ => {
830                                                let mut args = c.args.as_slice();
831                                                let mut template = BTreeMap::new();
832                                                while let Some(([a], b)) = args.split_first_chunk()
833                                                {
834                                                    if let Some(a) = a.expr.as_object() {
835                                                        args = b;
836                                                        for k in a
837                                                            .props
838                                                            .iter()
839                                                            .filter_map(|p| p.as_prop())
840                                                            .filter_map(|p| p.as_key_value())
841                                                        {
842                                                            template.insert(
843                                                                match k.key.as_ident() {
844                                                                    Some(a) => a.sym.clone(),
845                                                                    None => {
846                                                                        return Err(
847                                                                            Error::Unsupported,
848                                                                        )
849                                                                    }
850                                                                },
851                                                                (&*k.value).clone(),
852                                                            );
853                                                        }
854                                                    } else {
855                                                        break;
856                                                    }
857                                                }
858                                                SimplExpr::Call(MakeSpanned {
859                                                    value: Box::new(SimplCallExpr::Path {
860                                                        path: FuncId {
861                                                            path: path,
862                                                            template_args: template,
863                                                        },
864                                                        args: args
865                                                            .iter()
866                                                            .map(|a| a.expr.conv(imports))
867                                                            .collect::<Result<Vec<_>, _>>()?,
868                                                    }),
869                                                    span: c.span,
870                                                })
871                                            }
872                                        }
873                                    }
874                                    Ok((t, args)) => {
875                                        let mut args = args.as_ref();
876                                        let mut template = BTreeMap::new();
877                                        while let Some(([a], b)) = args.split_first_chunk() {
878                                            if let Some(a) = a.expr.as_object() {
879                                                args = b;
880                                                for k in a
881                                                    .props
882                                                    .iter()
883                                                    .filter_map(|p| p.as_prop())
884                                                    .filter_map(|p| p.as_key_value())
885                                                {
886                                                    template.insert(
887                                                        match k.key.as_ident() {
888                                                            Some(a) => a.sym.clone(),
889                                                            None => return Err(Error::Unsupported),
890                                                        },
891                                                        (&*k.value).clone(),
892                                                    );
893                                                }
894                                            } else {
895                                                break;
896                                            }
897                                        }
898                                        SimplExpr::Call(MakeSpanned {
899                                            value: Box::new(SimplCallExpr::Tag {
900                                                tag: FuncId {
901                                                    path: t,
902                                                    template_args: template,
903                                                },
904                                                args: args
905                                                    .iter()
906                                                    .map(|a| a.expr.conv(imports))
907                                                    .collect::<Result<Vec<_>, _>>()?,
908                                            }),
909                                            span: c.span,
910                                        })
911                                    }
912                                }
913                            }
914                        }
915                    }
916                }
917            }
918            _ => return Err(Error::Unsupported),
919        })
920    }
921}
922impl Conv for Stmt {
923    type Target<D: Dialect> = SimplStmt<D>;
924
925    fn conv<D: ConvDialect>(&self, imports: &impl ConvCtx<D>) -> Result<Self::Target<D>, Error> {
926        Ok(match self {
927            Stmt::Break(b) => SimplStmt::Break(match b.label.as_ref().cloned() {
928                Some(l) => l,
929                None => return Err(Error::Unsupported),
930            }),
931            Stmt::Continue(b) => SimplStmt::Continue(match b.label.as_ref().cloned() {
932                Some(l) => l,
933                None => return Err(Error::Unsupported),
934            }),
935            Stmt::Expr(e) => SimplStmt::Expr(MakeSpanned {
936                value: Box::new(e.expr.conv(imports)?),
937                span: e.span,
938            }),
939            Stmt::Block(b) => SimplStmt::Block(MakeSpanned {
940                value: b
941                    .stmts
942                    .iter()
943                    .map(|a| a.conv(imports))
944                    .collect::<Result<Vec<_>, _>>()?,
945                span: b.span,
946            }),
947            Stmt::If(i) => SimplStmt::If(MakeSpanned {
948                value: SimplIf {
949                    kind: SimplIfKind::If {
950                        r#else: i
951                            .alt
952                            .iter()
953                            .map(|a| a.conv(imports))
954                            .collect::<Result<Vec<_>, _>>()?,
955                    },
956                    cond: Box::new(i.test.conv(imports)?),
957                    body: vec![i.cons.conv(imports)?],
958                },
959                span: i.span,
960            }),
961            Stmt::While(w) => SimplStmt::If(MakeSpanned {
962                value: SimplIf {
963                    kind: SimplIfKind::While {
964                        label: Ident::new_private(Atom::new("$"), w.span),
965                    },
966                    cond: Box::new(w.test.conv(imports)?),
967                    body: vec![w.body.conv(imports)?],
968                },
969                span: w.span,
970            }),
971            Stmt::Labeled(l) => {
972                let mut w = l.body.conv(imports)?;
973                w.apply_label(&l.label);
974                w
975            }
976            Stmt::Return(r) => SimplStmt::Return(MakeSpanned {
977                value: Box::new(match r.arg.as_ref() {
978                    None => return Err(Error::Unsupported),
979                    Some(a) => a.conv(imports)?,
980                }),
981                span: r.span,
982            }),
983            Stmt::Switch(s) => SimplStmt::Switch(MakeSpanned {
984                value: SimplSwitchStmt {
985                    scrutinee: Box::new(s.discriminant.conv(imports)?),
986                    label: Ident::new_private(Atom::new("$"), s.span),
987                    cases: s
988                        .cases
989                        .iter()
990                        .map(|c| {
991                            let Some(a) = c.test.as_ref() else {
992                                return Err(Error::Unsupported);
993                            };
994                            let a = a.conv(imports)?;
995                            let (b, d) = match c.cons.last() {
996                                Some(Stmt::Break(BreakStmt { span, label: None })) => (
997                                    c.cons[..(c.cons.len() - 1)]
998                                        .iter()
999                                        .map(|a| a.conv(imports))
1000                                        .collect::<Result<Vec<_>, Error>>()?,
1001                                    BreakKind::BreakAfter,
1002                                ),
1003                                _ => (
1004                                    c.cons
1005                                        .iter()
1006                                        .map(|a| a.conv(imports))
1007                                        .collect::<Result<Vec<_>, Error>>()?,
1008                                    BreakKind::DoNotBreakAfter,
1009                                ),
1010                            };
1011                            Ok((Box::new(a), b, d))
1012                        })
1013                        .collect::<Result<_, Error>>()?,
1014                },
1015                span: s.span(),
1016            }),
1017            _ => return Err(Error::Unsupported),
1018        })
1019    }
1020}