Mercurial > hg > Others > Rakudo
comparison src/core.c/Failure.pm6 @ 0:c341f82e7ad7 default tip
Rakudo branch in cr.ie.u-ryukyu.ac.jp
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Thu, 26 Dec 2019 16:50:27 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c341f82e7ad7 |
---|---|
1 my class Failure is Nil { | |
2 has $.exception; | |
3 has $.backtrace; | |
4 #?if !jvm | |
5 has int $!handled; | |
6 #?endif | |
7 #?if jvm | |
8 has Int $!handled; # alas, native int breaks on the JVM | |
9 #?endif | |
10 | |
11 method !SET-SELF($!exception) { | |
12 $!backtrace = $!exception.backtrace || Backtrace.new(3); | |
13 $!exception.reset-backtrace; | |
14 self | |
15 } | |
16 | |
17 multi method new(Failure:D:) { self!throw } | |
18 multi method new(Failure:U:) { | |
19 my $stash := CALLER::LEXICAL::; | |
20 my $payload = ($stash<$!>:exists && $stash<$!>.DEFINITE) ?? $stash<$!> !! "Failed"; | |
21 nqp::create(self)!SET-SELF( | |
22 $payload ~~ Exception ?? $payload !! X::AdHoc.new(:$payload) | |
23 ) | |
24 } | |
25 multi method new(Failure:U: Exception:D \exception) { | |
26 nqp::create(self)!SET-SELF(exception) | |
27 } | |
28 multi method new(Failure:U: $payload) { | |
29 nqp::create(self)!SET-SELF(X::AdHoc.new(:$payload)) | |
30 } | |
31 multi method new(Failure:U: |cap (*@msg)) { | |
32 nqp::create(self)!SET-SELF(X::AdHoc.from-slurpy(|cap)) | |
33 } | |
34 | |
35 submethod DESTROY () { | |
36 note "WARNING: unhandled Failure detected in DESTROY. If you meant " | |
37 ~ "to ignore it, you can mark it as handled by calling .Bool, " | |
38 ~ ".so, .not, or .defined methods. The Failure was:\n" ~ self.mess | |
39 unless $!handled; | |
40 } | |
41 | |
42 # allow Failures to throw when they replace an Iterable | |
43 multi method iterator(Failure:D:) { self!throw } | |
44 multi method list(Failure:D:) { self!throw } | |
45 | |
46 # Marks the Failure has handled (since we're now fatalizing it) and throws. | |
47 method !throw(Failure:D:) { | |
48 $!handled = 1; | |
49 $!exception.throw($!backtrace); | |
50 } | |
51 | |
52 # Turns out multidimensional lookups are one way to leak unhandled failures, so | |
53 # we'll just propagate the initial failure much as we propagate Nil on methods. | |
54 method AT-POS(|) { self } | |
55 method AT-KEY(|) { self } | |
56 | |
57 multi method defined(Failure:D: --> False) { $!handled = 1 } | |
58 | |
59 multi method Bool(Failure:D: --> False) { $!handled = 1 } | |
60 method handled() is rw { | |
61 Proxy.new( | |
62 FETCH => { | |
63 #?if !jvm | |
64 nqp::hllbool($!handled) | |
65 #?endif | |
66 #?if jvm | |
67 $!handled.Bool | |
68 #?endif | |
69 }, | |
70 STORE => -> $, $value { $!handled = $value.Bool.Numeric } | |
71 ) | |
72 } | |
73 | |
74 method Capture() { | |
75 self.DEFINITE.not || $!handled | |
76 ?? X::Cannot::Capture.new(what => self).throw | |
77 !! self!throw | |
78 } | |
79 method Int(Failure:D:) { $!handled ?? Int !! self!throw(); } | |
80 method Num(Failure:D:) { $!handled ?? NaN !! self!throw(); } | |
81 method Numeric(Failure:D:) { $!handled ?? NaN !! self!throw(); } | |
82 | |
83 method Set(Failure:D:) { $!handled ?? Set.new(self) !! self!throw } | |
84 method SetHash(Failure:D:) { $!handled ?? SetHash.new(self) !! self!throw } | |
85 method Bag(Failure:D:) { $!handled ?? Bag.new(self) !! self!throw } | |
86 method BagHash(Failure:D:) { $!handled ?? BagHash.new(self) !! self!throw } | |
87 method Mix(Failure:D:) { $!handled ?? Mix.new(self) !! self!throw } | |
88 method MixHash(Failure:D:) { $!handled ?? MixHash.new(self) !! self!throw } | |
89 | |
90 multi method Str(Failure:D:) { $!handled ?? $.mess !! self!throw(); } | |
91 multi method gist(Failure:D:) { $!handled ?? $.mess !! self!throw(); } | |
92 multi method gist(Failure:U:) { '(' ~ self.^name ~ ')' } | |
93 multi method perl(Failure:D:) { | |
94 $!handled ?? '&CORE::infix:<orelse>(' ~ self.Mu::perl ~ ', *.self)' | |
95 !! self.Mu::perl | |
96 } | |
97 multi method perl(Failure:U:) { self.^name } | |
98 method mess (Failure:D:) { | |
99 my $message = (try self.exception.message) // self.exception.^name ~ ' with no message'; | |
100 "(HANDLED) " x $!handled ~ "$message\n" ~ self.backtrace; | |
101 } | |
102 | |
103 method sink(Failure:D:) { | |
104 self!throw() unless $!handled | |
105 } | |
106 method self(Failure:D:) { | |
107 self!throw() unless $!handled; | |
108 self | |
109 } | |
110 method CALL-ME(Failure:D: |) { | |
111 self!throw() | |
112 } | |
113 method FALLBACK(Failure:D: *@) { | |
114 self!throw() | |
115 } | |
116 method STORE(Failure:D: *@) { | |
117 self!throw() | |
118 } | |
119 } | |
120 | |
121 proto sub fail(|) {*}; | |
122 multi sub fail(--> Nil) { | |
123 my $stash := CALLER::LEXICAL::; | |
124 my $payload = ($stash<$!>:exists && $stash<$!>.DEFINITE) ?? $stash<$!> !! "Failed"; | |
125 | |
126 my $fail := Failure.new( $payload ~~ Exception | |
127 ?? $payload !! X::AdHoc.new(:$payload)); | |
128 | |
129 nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail); | |
130 CATCH { $fail.exception.throw } | |
131 } | |
132 multi sub fail(Exception:U $e --> Nil) { | |
133 my $fail := Failure.new( | |
134 X::AdHoc.new(:payload("Failed with undefined " ~ $e.^name)) | |
135 ); | |
136 nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail); | |
137 CATCH { $fail.exception.throw } | |
138 } | |
139 multi sub fail($payload --> Nil) { | |
140 my $fail := Failure.new( $payload ~~ Exception | |
141 ?? $payload | |
142 !! X::AdHoc.new(:$payload) | |
143 ); | |
144 nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail); | |
145 CATCH { $fail.exception.throw } | |
146 } | |
147 multi sub fail(|cap (*@msg) --> Nil) { | |
148 my $fail := Failure.new(X::AdHoc.from-slurpy(|cap)); | |
149 nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail); | |
150 CATCH { $fail.exception.throw } | |
151 } | |
152 multi sub fail(Failure:U $f --> Nil) { | |
153 my $fail := Failure.new( | |
154 X::AdHoc.new(:payload("Failed with undefined " ~ $f.^name)) | |
155 ); | |
156 nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail); | |
157 CATCH { $fail.exception.throw } | |
158 } | |
159 multi sub fail(Failure:D $fail --> Nil) { | |
160 $fail.handled = 0; | |
161 nqp::throwpayloadlexcaller(nqp::const::CONTROL_RETURN, $fail); | |
162 CATCH { $fail.exception.throw } | |
163 } | |
164 | |
165 multi sub die(Failure:D $f --> Nil) { | |
166 $f.exception.throw | |
167 } | |
168 multi sub die(Failure:U $f --> Nil) { | |
169 X::AdHoc.new(:payload("Died with undefined " ~ $f.^name)).throw; | |
170 } | |
171 | |
172 # vim: ft=perl6 expandtab sw=4 |