aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-php-shim/src/exception.rs
blob: c57a34513ea783def2bc23d55be40af17db59b36 (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
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
use crate::PharException;

#[derive(Debug)]
pub struct Exception {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for Exception {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for Exception {}

#[derive(Debug)]
pub struct RuntimeException {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for RuntimeException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for RuntimeException {}

#[derive(Debug)]
pub struct UnexpectedValueException {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for UnexpectedValueException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for UnexpectedValueException {}

#[derive(Debug)]
pub struct InvalidArgumentException {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for InvalidArgumentException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for InvalidArgumentException {}

#[derive(Debug)]
pub struct TypeError {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for TypeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for TypeError {}

#[derive(Debug)]
pub struct LogicException {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for LogicException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for LogicException {}

#[derive(Debug)]
pub struct BadMethodCallException {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for BadMethodCallException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for BadMethodCallException {}

#[derive(Debug)]
pub struct OutOfBoundsException {
    pub message: String,
    pub code: i64,
}

impl std::fmt::Display for OutOfBoundsException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for OutOfBoundsException {}

#[derive(Debug)]
pub struct ErrorException {
    pub message: String,
    pub code: i64,
    pub severity: i64,
    pub filename: String,
    pub lineno: i64,
}

impl std::fmt::Display for ErrorException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.message)
    }
}

impl std::error::Error for ErrorException {}

/// Models PHP's `exit`/`die` language construct propagated as a recoverable error so the actual
/// process termination happens at a single top-level site instead of deep in the call stack.
///
/// Like PHP's `exit`, this must NOT be caught by ported `try`/`catch` blocks: any broad catch on
/// the propagation path has to re-raise it untouched, and only the outermost handler converts it
/// into the process exit code.
#[derive(Debug)]
pub struct ExitException {
    pub code: i64,
}

impl std::fmt::Display for ExitException {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "exit({})", self.code)
    }
}

impl std::error::Error for ExitException {}

pub fn php_exception_get_code(_error: &anyhow::Error) -> i32 {
    // PHP's Throwable::getCode(). anyhow::Error carries the concrete exception type, so enumerate
    // the flat standard exception structs and read their `code` field; everything else defaults to
    // 0, matching PHP's default exception code.
    if let Some(e) = _error.downcast_ref::<Exception>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<RuntimeException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<UnexpectedValueException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<InvalidArgumentException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<TypeError>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<LogicException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<BadMethodCallException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<OutOfBoundsException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<ErrorException>() {
        return e.code as i32;
    }
    if let Some(e) = _error.downcast_ref::<PharException>() {
        return e.code as i32;
    }
    0
}