|
1 | 1 | use std::cell::RefCell;
|
2 | 2 |
|
3 |
| -use crate::{fixed_point::FixedPointStack, Set}; |
| 3 | +use crate::{fixed_point::FixedPointStack, Fallible, Set}; |
4 | 4 |
|
5 | 5 | mod proven_set;
|
6 | 6 | pub use proven_set::{FailedJudgment, FailedRule, ProvenSet, RuleFailureCause, TryIntoIter};
|
7 | 7 |
|
| 8 | +mod test_fallible; |
8 | 9 | mod test_filtered;
|
9 | 10 | mod test_reachable;
|
10 | 11 |
|
@@ -290,14 +291,21 @@ macro_rules! push_rules {
|
290 | 291 | // output of this rule, once all the conditions are evaluated.
|
291 | 292 |
|
292 | 293 | (@body $args:tt; $inputs:tt; $step_index:expr; (if let $p:pat = $e:expr) $($m:tt)*) => {
|
293 |
| - let value = &$e; |
294 |
| - if let $p = Clone::clone(value) { |
295 |
| - $crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*); |
296 |
| - } else { |
297 |
| - $crate::push_rules!(@record_failure $inputs; $step_index, $e; $crate::judgment::RuleFailureCause::IfLetDidNotMatch { |
298 |
| - pattern: stringify!($p).to_string(), |
299 |
| - value: format!("{:?}", value), |
300 |
| - }); |
| 294 | + match $crate::judgment::try_catch(|| Ok($e)) { |
| 295 | + Ok(value) => { |
| 296 | + if let $p = Clone::clone(&value) { |
| 297 | + $crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*); |
| 298 | + } else { |
| 299 | + $crate::push_rules!(@record_failure $inputs; $step_index, $e; $crate::judgment::RuleFailureCause::IfLetDidNotMatch { |
| 300 | + pattern: stringify!($p).to_string(), |
| 301 | + value: format!("{:?}", value), |
| 302 | + }); |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + Err(e) => { |
| 307 | + $crate::push_rules!(@record_failure $inputs; $step_index, $e; e); |
| 308 | + } |
301 | 309 | }
|
302 | 310 | };
|
303 | 311 |
|
@@ -405,16 +413,28 @@ macro_rules! push_rules {
|
405 | 413 | (@body $args:tt; $inputs:tt; $step_index:expr; (let $p:ident /*[1]*/: $t:ty = $i:expr) $($m:tt)*) => {
|
406 | 414 | // [1] I'd prefer to have `$p:pat` but the follow-set rules don't allow for it.
|
407 | 415 | // That's dumb.
|
408 |
| - { |
409 |
| - let $p : $t = $i; |
410 |
| - $crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*); |
| 416 | + match $crate::judgment::try_catch::<$t>(|| Ok($i)) { |
| 417 | + Ok(p) => { |
| 418 | + let $p = p; |
| 419 | + $crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*); |
| 420 | + } |
| 421 | + |
| 422 | + Err(e) => { |
| 423 | + $crate::push_rules!(@record_failure $inputs; $step_index, $i; e); |
| 424 | + } |
411 | 425 | }
|
412 | 426 | };
|
413 | 427 |
|
414 | 428 | (@body $args:tt; $inputs:tt; $step_index:expr; (let $p:pat = $i:expr) $($m:tt)*) => {
|
415 |
| - { |
416 |
| - let $p = $i; |
417 |
| - $crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*); |
| 429 | + match $crate::judgment::try_catch(|| Ok($i)) { |
| 430 | + Ok(p) => { |
| 431 | + let $p = p; // this enforces that `$p` is infalliblr |
| 432 | + $crate::push_rules!(@body $args; $inputs; $step_index + 1; $($m)*); |
| 433 | + } |
| 434 | + |
| 435 | + Err(e) => { |
| 436 | + $crate::push_rules!(@record_failure $inputs; $step_index, $i; e); |
| 437 | + } |
418 | 438 | }
|
419 | 439 | };
|
420 | 440 |
|
@@ -464,3 +484,17 @@ macro_rules! push_rules {
|
464 | 484 | }
|
465 | 485 | }
|
466 | 486 | }
|
| 487 | + |
| 488 | +/// Helper function that just calls `f` and returns the value. |
| 489 | +/// Used for implementing `judgement_fn` macro to allow expressions to include `?`. |
| 490 | +pub fn try_catch<R>(f: impl FnOnce() -> Fallible<R>) -> Result<R, RuleFailureCause> { |
| 491 | + match f() { |
| 492 | + Ok(v) => Ok(v), |
| 493 | + |
| 494 | + // Kind of dumb that `Inapplicable` only includes a `String` and not an `anyhow::Error` |
| 495 | + // but it's super annoying to package one of those up in the way we want. |
| 496 | + Err(e) => Err(RuleFailureCause::Inapplicable { |
| 497 | + reason: e.to_string(), |
| 498 | + }), |
| 499 | + } |
| 500 | +} |
0 commit comments