diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-02-28 15:47:46 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-02-28 15:47:46 +0100 |
| commit | b63c21c91d99a1554a019dc275f955d3e6a34271 (patch) | |
| tree | ae79152aba0a7b863be3574dd16d5d12e1e311df /src/eval/control.rs | |
| parent | 4f85fc3acd840ff8802035abcdcf2191689bb628 (diff) | |
| parent | 4f09233bdae8f79ebafed43e8135f1a0285bd370 (diff) | |
Merge pull request #65 from typst/control-flow
Add break, continue, and return
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, + } +} |
