1 | // Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved. |
2 | // Use of this source code is governed by an MIT license |
3 | // that can be found in the LICENSE file. |
4 | module builtin |
5 | |
6 | // IError holds information about an error instance |
7 | pub interface IError { |
8 | // >> Hack to allow old style custom error implementations |
9 | // TODO: remove once deprecation period for `IError` methods has ended |
10 | msg string |
11 | code int // << |
12 | msg() string |
13 | code() int |
14 | } |
15 | |
16 | // str returns the message of IError |
17 | pub fn (err IError) str() string { |
18 | return match err { |
19 | None__ { |
20 | 'none' |
21 | } |
22 | Error { |
23 | err.msg() |
24 | } |
25 | MessageError { |
26 | err.msg() |
27 | } |
28 | else { |
29 | // >> Hack to allow old style custom error implementations |
30 | // TODO: remove once deprecation period for `IError` methods has ended |
31 | // old_error_style := unsafe { voidptr(&err.msg) != voidptr(&err.code) } // if fields are not defined (new style) they don't have an offset between |
32 | // << |
33 | '${err.type_name()}: ${err.msg()}' |
34 | } |
35 | } |
36 | } |
37 | |
38 | // Error is the empty default implementation of `IError`. |
39 | pub struct Error {} |
40 | |
41 | pub fn (err Error) msg() string { |
42 | return '' |
43 | } |
44 | |
45 | pub fn (err Error) code() int { |
46 | return 0 |
47 | } |
48 | |
49 | // MessageError is the default implementation of the `IError` interface that is returned by the `error()` function |
50 | struct MessageError { |
51 | pub: |
52 | msg string |
53 | code int |
54 | } |
55 | |
56 | // msg returns the message of MessageError |
57 | pub fn (err MessageError) msg() string { |
58 | if err.code > 0 { |
59 | return '${err.msg}; code: ${err.code}' |
60 | } |
61 | return err.msg |
62 | } |
63 | |
64 | // code returns the code of MessageError |
65 | pub fn (err MessageError) code() int { |
66 | return err.code |
67 | } |
68 | |
69 | [unsafe] |
70 | pub fn (err &MessageError) free() { |
71 | unsafe { err.msg.free() } |
72 | } |
73 | |
74 | const none__ = IError(&None__{}) |
75 | |
76 | struct None__ { |
77 | Error |
78 | } |
79 | |
80 | fn (_ None__) str() string { |
81 | return 'none' |
82 | } |
83 | |
84 | [if trace_error ?] |
85 | fn trace_error(x string) { |
86 | eprintln('> ${@FN} | ${x}') |
87 | } |
88 | |
89 | // error returns a default error instance containing the error given in `message`. |
90 | // Example: if ouch { return error('an error occurred') } |
91 | [inline] |
92 | pub fn error(message string) IError { |
93 | trace_error(message) |
94 | return &MessageError{ |
95 | msg: message |
96 | } |
97 | } |
98 | |
99 | // error_with_code returns a default error instance containing the given `message` and error `code`. |
100 | // Example: if ouch { return error_with_code('an error occurred', 1) } |
101 | [inline] |
102 | pub fn error_with_code(message string, code int) IError { |
103 | trace_error('${message} | code: ${code}') |
104 | return &MessageError{ |
105 | msg: message |
106 | code: code |
107 | } |
108 | } |
109 | |
110 | // Option is the base of V's internal option return system. |
111 | struct Option { |
112 | state u8 |
113 | err IError = none__ |
114 | // Data is trailing after err |
115 | // and is not included in here but in the |
116 | // derived Option_xxx types |
117 | } |
118 | |
119 | // option is the base of V's internal option return system. |
120 | struct _option { |
121 | state u8 |
122 | err IError = none__ |
123 | // Data is trailing after err |
124 | // and is not included in here but in the |
125 | // derived _option_xxx types |
126 | } |
127 | |
128 | fn _option_none(data voidptr, mut option _option, size int) { |
129 | unsafe { |
130 | *option = _option{ |
131 | state: 2 |
132 | } |
133 | // use err to get the end of OptionBase and then memcpy into it |
134 | vmemcpy(&u8(&option.err) + sizeof(IError), data, size) |
135 | } |
136 | } |
137 | |
138 | fn _option_ok(data voidptr, mut option _option, size int) { |
139 | unsafe { |
140 | *option = _option{} |
141 | // use err to get the end of OptionBase and then memcpy into it |
142 | vmemcpy(&u8(&option.err) + sizeof(IError), data, size) |
143 | } |
144 | } |
145 | |
146 | struct _result { |
147 | is_error bool |
148 | err IError = none__ |
149 | // Data is trailing after err |
150 | // and is not included in here but in the |
151 | // derived Result_xxx types |
152 | } |
153 | |
154 | fn _result_ok(data voidptr, mut res _result, size int) { |
155 | unsafe { |
156 | *res = _result{} |
157 | // use err to get the end of ResultBase and then memcpy into it |
158 | vmemcpy(&u8(&res.err) + sizeof(IError), data, size) |
159 | } |
160 | } |
161 | |
162 | pub fn (_ none) str() string { |
163 | return 'none' |
164 | } |