diff options
| author | Martin Haug <mhaug@live.de> | 2022-02-28 14:36:02 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-02-28 15:41:38 +0100 |
| commit | 4f09233bdae8f79ebafed43e8135f1a0285bd370 (patch) | |
| tree | ae79152aba0a7b863be3574dd16d5d12e1e311df /src/eval/control.rs | |
| parent | 9fde38a6f82106e4c3a47f1bc34343650d8aad5b (diff) | |
Enable join collection for control flow constructs
Diffstat (limited to 'src/eval/control.rs')
| -rw-r--r-- | src/eval/control.rs | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/eval/control.rs b/src/eval/control.rs new file mode 100644 index 00000000..b310bfb8 --- /dev/null +++ b/src/eval/control.rs @@ -0,0 +1,63 @@ +use super::{ops, EvalResult, Value}; +use crate::diag::{At, Error, TypError}; +use crate::syntax::Span; + +/// A control flow event that occurred during evaluation. +#[derive(Clone, Debug, PartialEq)] +pub enum Control { + /// Stop iteration in a loop. + Break(Value, Span), + /// Skip the remainder of the current iteration in a loop. + Continue(Value, Span), + /// Stop execution of a function early, returning a value. The bool + /// indicates whether this was an explicit return with value. + Return(Value, bool, Span), + /// Stop the execution because an error occurred. + Err(TypError), +} + +impl From<TypError> for Control { + fn from(error: TypError) -> Self { + Self::Err(error) + } +} + +impl From<Control> for TypError { + fn from(control: Control) -> Self { + match control { + Control::Break(_, span) => Error::boxed(span, "cannot break outside of loop"), + Control::Continue(_, span) => { + Error::boxed(span, "cannot continue outside of loop") + } + Control::Return(_, _, span) => { + Error::boxed(span, "cannot return outside of function") + } + Control::Err(e) => e, + } + } +} + +/// Join a value with an evaluated result. +pub(super) fn join_result( + prev: Value, + result: EvalResult<Value>, + result_span: Span, +) -> EvalResult<Value> { + match result { + Ok(value) => Ok(ops::join(prev, value).at(result_span)?), + Err(Control::Break(value, span)) => Err(Control::Break( + ops::join(prev, value).at(result_span)?, + span, + )), + Err(Control::Continue(value, span)) => Err(Control::Continue( + ops::join(prev, value).at(result_span)?, + span, + )), + Err(Control::Return(value, false, span)) => Err(Control::Return( + ops::join(prev, value).at(result_span)?, + false, + span, + )), + other => other, + } +} |
