aboutsummaryrefslogtreecommitdiff
path: root/src/type/display.rs
blob: fe54941e9c05ae14c26e27264f4a52d64d026f87 (plain)
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

use std::fmt;
use crate::r#type::{Type, TypeError, Type::*, TypeError::*};


impl fmt::Display for Type {
    /// Formats the type for display to the programmer
    /// using this programming language.
    ///
    /// Examples:
    /// ```rust
    /// use myslip::r#type::{Type::*, util::*};
    /// assert_eq!(Integer.to_string(), "Int".to_string());
    /// assert_eq!(Boolean.to_string(), "Bool".to_string());
    /// assert_eq!(arr(Integer, Boolean).to_string(), "(Int -> Bool)".to_string());
    /// assert_eq!(List(vec![Integer, Boolean, Integer]).to_string(), "(Int Bool Int)".to_string());
    /// ```
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Integer     => write!(f, "{}", "Int"),
            Boolean     => write!(f, "{}", "Bool"),
            QuoteTy     => write!(f, "{}", "Quote"),
            VecType     => write!(f, "{}", "Vector"),
            LetType     => write!(f, "{}", "Let"),
            VecOf(ty)   => write!(f, "({} ... {})", *ty, *ty),
            Arrow(a, b) => write!(f, "({} -> {})", a, b),
            List(types) => write!(
                               f,
                               "({})",
                               types.into_iter()
                                    .map(|t| t.to_string())
                                    .collect::<Vec<String>>()
                                    .join(" ")
                           ),
            VarType(name) => write!(f, "{}", name),
        }
    }
}


impl fmt::Display for TypeError {
    /// Formats this type error for display to humans.
    ///
    /// Examples:
    /// ```rust
    /// use myslip::r#type::{TypeError::*, Type::*, util::*};
    /// use myslip::sexp::{SExp, SExp::*, SLeaf::*, util::*};
    ///
    /// assert_eq!(
    ///     UndefinedVariable(String::from("x")).to_string(),
    ///     "undefined variable: 'x'".to_string()
    /// );
    /// assert_eq!(
    ///     InvalidOperator {
    ///         operator: Atom(Int(1)),
    ///         expected: arr(VarType("?".to_string()), VarType("?".to_string())),
    ///         found:    Integer
    ///     }.to_string(),
    ///     "invalid operator: '1'\nexpected: '(? -> ?)'\nfound: 'Int'".to_string()
    /// );
    /// assert_eq!(
    ///     InvalidArgList {
    ///         arglist:  scons(1, scons(2, scons(3, Nil))),
    ///         expected: List(vec![Integer, Integer]),
    ///         found:    List(vec![Integer, Integer, Integer]),
    ///     }.to_string(),
    ///     "invalid argument list: '(1 2 3)'\nexpected: '(Int Int)'\nfound: '(Int Int Int)'".to_string()
    /// );
    /// assert_eq!(
    ///     UnboundGeneric(String::from("?")).to_string(),
    ///     "unbound generic type: '?'".to_string()
    /// );
    /// assert_eq!(
    ///     ArgumentsDontMatchGeneric {
    ///         argtype: Integer,
    ///         generictype: arr(VarType("T".to_string()), Integer)
    ///     }.to_string(),
    ///     "incompatible argument type 'Int' and generic operator type '(T -> Int)'".to_string()
    /// );
    /// ```
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UndefinedVariable(name) => write!(f, "undefined variable: '{}'", name),
            UnboundGeneric(name)    => write!(f, "unbound generic type: '{}'", name),
            InvalidOperator { operator, expected, found } => {
                write!(
                    f,
                    "invalid operator: '{}'\nexpected: '{}'\nfound: '{}'",
                    operator, expected, found
                )
            },
            InvalidArgList { arglist, expected, found } => {
                write!(
                    f,
                    "invalid argument list: '{}'\nexpected: '{}'\nfound: '{}'",
                    arglist, expected, found
                )
            },
            ArgumentsDontMatchGeneric { argtype, generictype } => {
                write!(
                    f,
                    "incompatible argument type '{}' and generic operator type '{}'",
                    argtype, generictype
                )
            },
            OtherError => write!(f, "uncategorized error"),
        }
    }
}