summaryrefslogtreecommitdiff
path: root/src/eval/control.rs
diff options
context:
space:
mode:
authorMartin Haug <mhaug@live.de>2022-02-28 14:36:02 +0100
committerMartin Haug <mhaug@live.de>2022-02-28 15:41:38 +0100
commit4f09233bdae8f79ebafed43e8135f1a0285bd370 (patch)
treeae79152aba0a7b863be3574dd16d5d12e1e311df /src/eval/control.rs
parent9fde38a6f82106e4c3a47f1bc34343650d8aad5b (diff)
Enable join collection for control flow constructs
Diffstat (limited to 'src/eval/control.rs')
-rw-r--r--src/eval/control.rs63
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,
+ }
+}