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
146
147
148
149
150
151
152
153
154
155
use std::fmt;

use erg_common::Str;
use erg_common::ty::{Type};
use erg_common::traits::HasType;

use erg_parser::ast::DefId;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Mutability {
    Immutable,
    Const,
}

impl From<&str> for Mutability {
    fn from(item: &str) -> Self {
        if item.chars().next().unwrap().is_uppercase() {
            Self::Const
        } else { Self::Immutable }
    }
}

impl Mutability {
    pub const fn is_const(&self) -> bool { matches!(self, Self::Const) }
}

use Mutability::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Visibility {
    Private,
    Public,
}

impl Visibility {
    pub const fn is_public(&self) -> bool { matches!(self, Self::Public) }
    pub const fn is_private(&self) -> bool { matches!(self, Self::Private) }
}

use Visibility::*;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ParamId {
    /// 変数でないパターン
    /// e.g. `[x, y]` of `f [x, y], z = ...`
    PatNonDefault(usize),
    /// e.g. `[x, y]` of `f [x, y] |= [0, 1] = ...`
    PatWithDefault(usize),
    /// 変数パターン
    /// e.g. `z` of `f [x, y], z = ...`
    VarNonDefault{ keyword: Str, pos: usize },
    /// e.g. `z` of `f [x, y], z |= 0 = ...`
    VarWithDefault{ keyword: Str, pos: usize },
    /// パターンに埋め込まれた変数パターン
    /// この場合デフォルト値はない
    /// e.g. `x` or `y` of `f [x, y], z = ...`
    Embedded(Str),
}

impl ParamId {
    pub const fn var_default(keyword: Str, pos: usize) -> Self { Self::VarWithDefault{ keyword, pos } }
    pub const fn var_non_default(keyword: Str, pos: usize) -> Self { Self::VarNonDefault{ keyword, pos } }

    pub const fn pos(&self) -> Option<usize> {
        match self {
            Self::PatNonDefault(pos)
            | Self::PatWithDefault(pos)
            | Self::VarNonDefault{ pos, .. }
            | Self::VarWithDefault{ pos, .. } => Some(*pos),
            _ => None,
        }
    }

    pub const fn has_default(&self) -> bool {
        matches!(self, Self::PatWithDefault(_) | Self::VarWithDefault{ .. })
    }

    pub const fn is_embedded(&self) -> bool { matches!(self, Self::Embedded(_)) }
}

#[derive(Debug, Clone,  PartialEq, Eq, Hash)]
pub enum VarKind {
    Defined(DefId),
    Declared,
    Parameter{ def_id: DefId, param_id: ParamId },
    Generated,
    DoesNotExist,
    Builtin,
}

impl VarKind {
    pub const fn parameter(def_id: DefId, param_id: ParamId) -> Self {
        Self::Parameter{ def_id, param_id }
    }

    pub const fn pos_as_param(&self) -> Option<usize> {
        match self {
            Self::Parameter{ param_id, .. } => param_id.pos(),
            _ => None,
        }
    }

    pub const fn has_default(&self) -> bool {
        match self {
            Self::Parameter{ param_id, .. } => param_id.has_default(),
            _ => false,
        }
    }

    pub const fn is_parameter(&self) -> bool {
        matches!(self, Self::Parameter{ .. })
    }

    pub const fn is_embedded_param(&self) -> bool {
        matches!(self, Self::Parameter{ param_id, .. } if param_id.is_embedded())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarInfo {
    pub t: Type,
    pub muty: Mutability,
    pub vis: Visibility,
    pub kind: VarKind,
}

impl fmt::Display for VarInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "VarInfo{{t: {}, muty: {:?}, vis: {:?} kind: {:?}}}", self.t, self.muty, self.vis, self.kind)
    }
}

impl HasType for VarInfo {
    #[inline]
    fn ref_t(&self) -> &Type { &self.t }
    #[inline]
    fn signature_t(&self) -> Option<&Type> { None }
}

impl VarInfo {
    pub const ILLEGAL: &'static Self = &VarInfo::new(Type::Failure, Immutable, Private, VarKind::DoesNotExist);

    pub const fn new(t: Type, muty: Mutability, vis: Visibility, kind: VarKind) -> Self {
        Self { t, muty, vis, kind }
    }

    pub fn same_id_as(&self, id: DefId) -> bool {
        match self.kind {
            VarKind::Defined(i) | VarKind::Parameter{ def_id: i, .. } => id == i,
            _ => false,
        }
    }
}