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 std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::ops::Deref;

use crate::check::context::clss;
use crate::check::context::field::generic::GenericField;
use crate::check::name::Name;
use crate::check::name::string_name::StringName;
use crate::check::result::{TypeErr, TypeResult};
use crate::common::position::Position;
use crate::parse::ast::{AST, Node};

pub const SELF: &str = "self";

#[derive(Debug, Clone)]
pub struct ClassArgument {
    pub field: Option<GenericField>,
    pub fun_arg: GenericFunctionArg,
}

#[derive(Debug, Clone, Eq)]
pub struct GenericFunctionArg {
    pub is_py_type: bool,
    pub name: String,
    pub pos: Position,
    pub has_default: bool,
    pub vararg: bool,
    pub mutable: bool,
    pub ty: Option<Name>,
}

impl PartialEq for GenericFunctionArg {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name && self.ty == other.ty && self.vararg == other.vararg
    }
}

impl Hash for GenericFunctionArg {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.name.hash(state);
        self.ty.hash(state);
        self.vararg.hash(state);
    }
}

impl GenericFunctionArg {
    pub fn in_class(self, class: Option<&StringName>) -> TypeResult<GenericFunctionArg> {
        if self.name.as_str() == SELF {
            if class.is_none() {
                let msg = "Cannot have self argument outside class";
                return Err(vec![TypeErr::new(self.pos, msg)]);
            }

            if self.ty.is_none() {
                return if let Some(class) = class {
                    Ok(GenericFunctionArg { ty: Some(Name::from(class)), ..self })
                } else {
                    Ok(self)
                };
            }
        }

        Ok(self)
    }
}

impl TryFrom<&AST> for ClassArgument {
    type Error = Vec<TypeErr>;

    fn try_from(ast: &AST) -> TypeResult<ClassArgument> {
        match &ast.node {
            Node::VariableDef { mutable, var, expr: expression, ty, .. } => {
                let fun_arg = GenericFunctionArg {
                    is_py_type: false,
                    name: argument_name(var)?,
                    pos: ast.pos,
                    has_default: expression.is_some(),
                    vararg: false,
                    mutable: *mutable,
                    ty: if let Some(ty) = ty {
                        Some(Name::try_from(ty)?)
                    } else {
                        None
                    },
                };

                Ok(ClassArgument { field: Some(GenericField::try_from(ast)?), fun_arg })
            }
            Node::FunArg { .. } =>
                Ok(ClassArgument { field: None, fun_arg: GenericFunctionArg::try_from(ast)? }),
            _ => Err(vec![TypeErr::new(ast.pos, "Expected definition or function argument")])
        }
    }
}

impl TryFrom<&AST> for GenericFunctionArg {
    type Error = Vec<TypeErr>;

    /// Construct FunctionArg from AST.
    fn try_from(ast: &AST) -> TypeResult<GenericFunctionArg> {
        match &ast.node {
            Node::FunArg { vararg, var, mutable, ty, default, .. } => {
                let name = argument_name(var.deref())?;
                Ok(GenericFunctionArg {
                    is_py_type: false,
                    name: name.clone(),
                    has_default: default.is_some(),
                    vararg: *vararg,
                    mutable: *mutable,
                    pos: ast.pos,
                    ty: match ty {
                        Some(ty) => Some(Name::try_from(ty.deref())?),
                        None if name.as_str() == SELF => None,
                        None => if let Some(default) = default {
                            Some(match &default.deref().node {
                                Node::Str { .. } => Name::from(clss::python::STRING_PRIMITIVE),
                                Node::Bool { .. } => Name::from(clss::python::BOOL_PRIMITIVE),
                                Node::Int { .. } => Name::from(clss::python::INT_PRIMITIVE),
                                Node::Real { .. } => Name::from(clss::python::FLOAT_PRIMITIVE),
                                Node::ENum { .. } => Name::from(clss::python::INT_PRIMITIVE),
                                _ => return Err(vec![TypeErr::new(
                                    default.pos,
                                    "Can only infer type of literals",
                                )]),
                            })
                        } else {
                            return Err(vec![TypeErr::new(
                                var.pos,
                                "Non-self argument must have type if no default present",
                            )]);
                        },
                    },
                })
            }
            _ => Err(vec![TypeErr::new(ast.pos, "Expected function argument")])
        }
    }
}

pub fn argument_name(ast: &AST) -> TypeResult<String> {
    match &ast.node {
        Node::Id { lit } => Ok(lit.clone()),
        _ => Err(vec![TypeErr::new(ast.pos, "Expected identifier in argument")])
    }
}