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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use crate::*;
use py_ir::types::TypeDefine;

use std::collections::HashMap;
use terl::Span;

#[derive(Default)]
pub struct Defs {
    pub(crate) fn_signs: FnSigns,
}

impl Defs {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn new_fn(&mut self, unmangled: &str, mangled: &str, sign: defs::FnSign) -> Type {
        self.fn_signs.new_fn(unmangled, mangled, sign)
    }

    pub fn get_mangled(&self, name: &str) -> &Overload {
        self.fn_signs.get_mangled(name)
    }

    pub fn try_get_mangled(&self, name: &str) -> Option<&Overload> {
        self.fn_signs.try_get_mangled(name)
    }

    pub fn get_unmangled(&self, name: &str) -> Option<&[Overload]> {
        self.fn_signs.get_unmangled(name)
    }
}

#[derive(Default)]
pub struct FnSigns {
    fn_signs: Vec<Overload>,
    unmangled: HashMap<String, Vec<Overload>>,
    mangled: HashMap<String, Overload>,
}

impl FnSigns {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn new_fn(&mut self, unmangled: &str, mangled: &str, sign: defs::FnSign) -> Type {
        let value = defs::FnSignWithName {
            sign,
            name: mangled.to_owned(),
        };

        let overload: Overload = value.into();

        self.fn_signs.push(overload.clone());
        self.unmangled
            .entry(unmangled.to_owned())
            .or_default()
            .push(overload.clone());
        self.mangled.insert(mangled.to_owned(), overload.clone());
        Type::Overload(overload)
    }

    pub fn get_unmangled(&self, name: &str) -> Option<&[Overload]> {
        self.unmangled.get(name).map(|v| &**v)
    }

    pub fn get_mangled(&self, name: &str) -> &Overload {
        self.mangled.get(name).unwrap()
    }

    pub fn try_get_mangled(&self, name: &str) -> Option<&Overload> {
        self.mangled.get(name)
    }

    // pub fn search_fns
}

#[derive(Debug, Clone)]
pub struct FnSignWithName {
    pub sign: FnSign,
    pub name: String,
}

impl std::ops::Deref for FnSignWithName {
    type Target = FnSign;

    fn deref(&self) -> &Self::Target {
        &self.sign
    }
}

impl std::ops::DerefMut for FnSignWithName {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.sign
    }
}

#[derive(Debug, Clone)]
pub struct FnSign {
    /// return type of the function must be cleared (will change in future versions)
    pub ty: TypeDefine,
    pub params: Vec<Parameter>,
    pub retty_span: Span,
    pub sign_span: Span,
}

impl FnSign {
    pub fn new(ty: TypeDefine, params: Vec<Parameter>, retty_span: Span, sign_span: Span) -> Self {
        Self {
            ty,
            params,
            retty_span,
            sign_span,
        }
    }
}

impl std::fmt::Display for FnSignWithName {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // NOTO: this may only work with default Chinese Mangler
        let unmangled = self.name.split_ascii_whitespace().next().unwrap();
        f.write_str(unmangled)?;
        f.write_str("(")?;
        match self.params.len() {
            0 => f.write_str(")")?,
            1 => f.write_fmt(format_args!("{})", self.params[0].ty))?,
            _ => {
                f.write_fmt(format_args!("{}", self.params[0].ty))?;
                for param in &self.params[1..] {
                    f.write_fmt(format_args!(", {}", param.name))?;
                }
                f.write_str(")")?
            }
        }
        f.write_fmt(format_args!(" -> {}", self.ty))
    }
}

pub type Parameter = py_ir::Parameter<TypeDefine>;

#[derive(Debug, Clone)]
pub struct VarDef {
    pub ty: GroupIdx,
    pub mutable: bool,
}