1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use erg_common::log;
use erg_common::traits::Stream;

use crate::hir::{Accessor, Block, Expr, ReDef, HIR};

/// Desugares HIR to make it more like Python semantics.
pub struct HIRDesugarer {}

impl HIRDesugarer {
    pub fn desugar(hir: HIR) -> HIR {
        log!(info "HIR desugaring process has started.");
        let hir = Self::desugar_class_member(hir);
        log!(info "HIR desugaring process has completed.");
        hir
    }

    /// ```erg
    /// C = Class ...
    /// C.
    ///     _Self = C
    ///     a = C.x
    ///     x = 1
    ///     m(self) = ...
    /// ```
    /// ↓
    /// ```python
    /// class C:
    ///     def m(self): ...
    /// C._Self = C
    /// C.a = C.x
    /// C.x = 1
    /// ```
    fn desugar_class_member(mut hir: HIR) -> HIR {
        for chunk in hir.module.iter_mut() {
            Self::desugar_class_member_expr(chunk);
        }
        hir
    }

    fn desugar_class_member_expr(chunk: &mut Expr) {
        match chunk {
            Expr::ClassDef(class_def) => {
                let class = Expr::Accessor(Accessor::Ident(class_def.sig.ident().clone()));
                let mut static_members = vec![];
                for methods_ in class_def.methods_list.iter_mut() {
                    let block = std::mem::take(&mut methods_.defs);
                    let (methods, statics): (Vec<_>, Vec<_>) = block
                        .into_iter()
                        .partition(|attr| matches!(attr, Expr::Def(def) if def.sig.is_subr()));
                    methods_.defs.extend(methods);
                    static_members.extend(statics.into_iter().map(|expr| match expr {
                        Expr::Def(def) => {
                            let acc = class.clone().attr(def.sig.into_ident());
                            let redef = ReDef::new(acc, def.body.block);
                            Expr::ReDef(redef)
                        }
                        _ => expr,
                    }));
                }
                if !static_members.is_empty() {
                    *chunk = Expr::Compound(Block::new(
                        [vec![std::mem::take(chunk)], static_members].concat(),
                    ));
                }
            }
            Expr::Code(block) | Expr::Compound(block) => {
                for expr in block.iter_mut() {
                    Self::desugar_class_member_expr(expr);
                }
            }
            Expr::Def(def) => {
                for chunk in def.body.block.iter_mut() {
                    Self::desugar_class_member_expr(chunk);
                }
            }
            // `HIRLinker` binds the modules and embed as the argument for the `exec` function call
            Expr::Call(call) => {
                call.args.pos_args.iter_mut().for_each(|arg| {
                    Self::desugar_class_member_expr(&mut arg.expr);
                });
            }
            _ => {}
        };
    }
}