diff options
| author | Martin Haug <mhaug@live.de> | 2022-02-28 13:18:29 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2022-02-28 13:18:29 +0100 |
| commit | d007788db8bfc53089125456510216ea94667ff5 (patch) | |
| tree | fc388daad674da4ba127a752aa741f854d4418a7 /src | |
| parent | 4f85fc3acd840ff8802035abcdcf2191689bb628 (diff) | |
Introduce `EvalResult` for control flow
Diffstat (limited to 'src')
| -rw-r--r-- | src/diag.rs | 7 | ||||
| -rw-r--r-- | src/eval/mod.rs | 131 |
2 files changed, 89 insertions, 49 deletions
diff --git a/src/diag.rs b/src/diag.rs index 329e9a8a..9d1ec160 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -7,7 +7,7 @@ use crate::syntax::{Span, Spanned}; /// Early-return with a vec-boxed [`Error`]. macro_rules! bail { ($span:expr, $message:expr $(,)?) => { - return Err($crate::diag::Error::boxed($span, $message)) + return Err($crate::diag::Error::boxed($span, $message).into()) }; ($span:expr, $fmt:expr, $($arg:expr),+ $(,)?) => { @@ -16,7 +16,10 @@ macro_rules! bail { } /// The result type for typesetting and all its subpasses. -pub type TypResult<T> = Result<T, Box<Vec<Error>>>; +pub type TypResult<T> = Result<T, TypError>; + +/// The error type for typesetting and all its subpasses. +pub type TypError = Box<Vec<Error>>; /// A result type with a string error message. pub type StrResult<T> = Result<T, String>; diff --git a/src/eval/mod.rs b/src/eval/mod.rs index bc6c8fc8..be168d63 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -35,7 +35,7 @@ pub use value::*; use unicode_segmentation::UnicodeSegmentation; -use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypResult}; +use crate::diag::{At, Error, StrResult, Trace, Tracepoint, TypError, TypResult}; use crate::geom::{Angle, Fractional, Length, Relative}; use crate::library; use crate::syntax::ast::*; @@ -49,13 +49,46 @@ pub trait Eval { type Output; /// Evaluate the expression to the output value. - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output>; + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output>; +} + +/// The result type for evaluating a syntactic construct. +pub type EvalResult<T> = Result<T, Control>; + +/// A control flow event that occurred during evaluation. +#[derive(Clone, Debug, PartialEq)] +pub enum Control { + Break(Span), + Continue(Span), + Return(Option<Value>, Span), + 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, + } + } } impl Eval for Markup { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { eval_markup(ctx, scp, &mut self.nodes()) } } @@ -65,7 +98,7 @@ fn eval_markup( ctx: &mut Context, scp: &mut Scopes, nodes: &mut impl Iterator<Item = MarkupNode>, -) -> TypResult<Template> { +) -> EvalResult<Template> { let mut seq = Vec::with_capacity(nodes.size_hint().1.unwrap_or_default()); while let Some(node) = nodes.next() { @@ -93,7 +126,7 @@ fn eval_markup( impl Eval for MarkupNode { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { Ok(match self { Self::Space => Template::Space, Self::Linebreak => Template::Linebreak, @@ -114,7 +147,7 @@ impl Eval for MarkupNode { impl Eval for StrongNode { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { Ok(Template::show(library::StrongNode( self.body().eval(ctx, scp)?, ))) @@ -124,7 +157,7 @@ impl Eval for StrongNode { impl Eval for EmphNode { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { Ok(Template::show(library::EmphNode( self.body().eval(ctx, scp)?, ))) @@ -134,7 +167,7 @@ impl Eval for EmphNode { impl Eval for RawNode { type Output = Template; - fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, _: &mut Context, _: &mut Scopes) -> EvalResult<Self::Output> { let template = Template::show(library::RawNode { text: self.text.clone(), block: self.block, @@ -149,7 +182,7 @@ impl Eval for RawNode { impl Eval for MathNode { type Output = Template; - fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, _: &mut Context, _: &mut Scopes) -> EvalResult<Self::Output> { Ok(Template::show(library::MathNode { formula: self.formula.clone(), display: self.display, @@ -160,7 +193,7 @@ impl Eval for MathNode { impl Eval for HeadingNode { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { Ok(Template::show(library::HeadingNode { body: self.body().eval(ctx, scp)?, level: self.level(), @@ -171,7 +204,7 @@ impl Eval for HeadingNode { impl Eval for ListNode { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { Ok(Template::List(library::ListItem { number: None, body: Box::new(self.body().eval(ctx, scp)?), @@ -182,7 +215,7 @@ impl Eval for ListNode { impl Eval for EnumNode { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { Ok(Template::Enum(library::ListItem { number: self.number(), body: Box::new(self.body().eval(ctx, scp)?), @@ -193,7 +226,7 @@ impl Eval for EnumNode { impl Eval for Expr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { match self { Self::Lit(v) => v.eval(ctx, scp), Self::Ident(v) => v.eval(ctx, scp), @@ -211,6 +244,7 @@ impl Eval for Expr { Self::Set(_) | Self::Show(_) | Self::Wrap(_) => { Err("set, show and wrap are only allowed directly in markup") .at(self.span()) + .map_err(Into::into) } Self::If(v) => v.eval(ctx, scp), Self::While(v) => v.eval(ctx, scp), @@ -227,7 +261,7 @@ impl Eval for Expr { impl Eval for Lit { type Output = Value; - fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, _: &mut Context, _: &mut Scopes) -> EvalResult<Self::Output> { Ok(match self.kind() { LitKind::None => Value::None, LitKind::Auto => Value::Auto, @@ -246,7 +280,7 @@ impl Eval for Lit { impl Eval for Ident { type Output = Value; - fn eval(&self, _: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, _: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { match scp.get(self) { Some(slot) => Ok(slot.read().unwrap().clone()), None => bail!(self.span(), "unknown variable"), @@ -257,7 +291,7 @@ impl Eval for Ident { impl Eval for ArrayExpr { type Output = Array; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { self.items().map(|expr| expr.eval(ctx, scp)).collect() } } @@ -265,7 +299,7 @@ impl Eval for ArrayExpr { impl Eval for DictExpr { type Output = Dict; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { self.items() .map(|x| Ok((x.name().take(), x.expr().eval(ctx, scp)?))) .collect() @@ -275,7 +309,7 @@ impl Eval for DictExpr { impl Eval for TemplateExpr { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { scp.enter(); let template = self.body().eval(ctx, scp)?; scp.exit(); @@ -286,7 +320,7 @@ impl Eval for TemplateExpr { impl Eval for GroupExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { self.expr().eval(ctx, scp) } } @@ -294,7 +328,7 @@ impl Eval for GroupExpr { impl Eval for BlockExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { scp.enter(); let mut output = Value::None; @@ -312,21 +346,21 @@ impl Eval for BlockExpr { impl Eval for UnaryExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let value = self.expr().eval(ctx, scp)?; let result = match self.op() { UnOp::Pos => ops::pos(value), UnOp::Neg => ops::neg(value), UnOp::Not => ops::not(value), }; - result.at(self.span()) + Ok(result.at(self.span())?) } } impl Eval for BinaryExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { match self.op() { BinOp::Add => self.apply(ctx, scp, ops::add), BinOp::Sub => self.apply(ctx, scp, ops::sub), @@ -356,7 +390,7 @@ impl BinaryExpr { ctx: &mut Context, scp: &mut Scopes, op: fn(Value, Value) -> StrResult<Value>, - ) -> TypResult<Value> { + ) -> EvalResult<Value> { let lhs = self.lhs().eval(ctx, scp)?; // Short-circuit boolean operations. @@ -367,7 +401,7 @@ impl BinaryExpr { } let rhs = self.rhs().eval(ctx, scp)?; - op(lhs, rhs).at(self.span()) + Ok(op(lhs, rhs).at(self.span())?) } /// Apply an assignment operation. @@ -376,7 +410,7 @@ impl BinaryExpr { ctx: &mut Context, scp: &mut Scopes, op: fn(Value, Value) -> StrResult<Value>, - ) -> TypResult<Value> { + ) -> EvalResult<Value> { let rhs = self.rhs().eval(ctx, scp)?; self.lhs().access( ctx, @@ -394,12 +428,12 @@ impl BinaryExpr { impl Eval for CallExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let span = self.callee().span(); let callee = self.callee().eval(ctx, scp)?; let args = self.args().eval(ctx, scp)?; - match callee { + Ok(match callee { Value::Array(array) => { array.get(args.into_index()?).map(Value::clone).at(self.span()) } @@ -423,14 +457,14 @@ impl Eval for CallExpr { "expected callable or collection, found {}", v.type_name(), ), - } + }?) } } impl Eval for CallArgs { type Output = Args; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let mut items = Vec::new(); for arg in self.items() { @@ -482,7 +516,7 @@ impl Eval for CallArgs { impl Eval for ClosureExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { // The closure's name is defined by its let binding if there's one. let name = self.name().map(Ident::take); @@ -529,7 +563,7 @@ impl Eval for ClosureExpr { impl Eval for WithExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let callee = self.callee(); let func = callee.eval(ctx, scp)?.cast::<Func>().at(callee.span())?; let args = self.args().eval(ctx, scp)?; @@ -540,7 +574,7 @@ impl Eval for WithExpr { impl Eval for LetExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let value = match self.init() { Some(expr) => expr.eval(ctx, scp)?, None => Value::None, @@ -553,18 +587,18 @@ impl Eval for LetExpr { impl Eval for SetExpr { type Output = StyleMap; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let class = self.class(); let class = class.eval(ctx, scp)?.cast::<Class>().at(class.span())?; let args = self.args().eval(ctx, scp)?; - class.set(args) + Ok(class.set(args)?) } } impl Eval for ShowExpr { type Output = StyleMap; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let class = self.class(); let class = class.eval(ctx, scp)?.cast::<Class>().at(class.span())?; let closure = self.closure(); @@ -578,7 +612,7 @@ impl Eval for ShowExpr { impl Eval for IfExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let condition = self.condition(); if condition.eval(ctx, scp)?.cast::<bool>().at(condition.span())? { self.if_body().eval(ctx, scp) @@ -593,7 +627,7 @@ impl Eval for IfExpr { impl Eval for WhileExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let mut output = Value::None; let condition = self.condition(); @@ -610,7 +644,7 @@ impl Eval for WhileExpr { impl Eval for ForExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { macro_rules! iter { (for ($($binding:ident => $value:ident),*) in $iter:expr) => {{ let mut output = Value::None; @@ -673,7 +707,7 @@ impl Eval for ForExpr { impl Eval for ImportExpr { type Output = Value; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let span = self.path().span(); let path = self.path().eval(ctx, scp)?.cast::<EcoString>().at(span)?; let module = import(ctx, &path, span)?; @@ -702,7 +736,7 @@ impl Eval for ImportExpr { impl Eval for IncludeExpr { type Output = Template; - fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> TypResult<Self::Output> { + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { let span = self.path().span(); let path = self.path().eval(ctx, scp)?.cast::<EcoString>().at(span)?; let module = import(ctx, &path, span)?; @@ -735,24 +769,27 @@ fn import(ctx: &mut Context, path: &str, span: Span) -> TypResult<Module> { impl Eval for BreakExpr { type Output = Value; - fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> { - Err("break is not yet implemented").at(self.span()) + fn eval(&self, _: &mut Context, _: &mut Scopes) -> EvalResult<Self::Output> { + Err(Control::Break(self.span())) } } impl Eval for ContinueExpr { type Output = Value; - fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> { - Err("continue is not yet implemented").at(self.span()) + fn eval(&self, _: &mut Context, _: &mut Scopes) -> EvalResult<Self::Output> { + Err(Control::Continue(self.span())) } } impl Eval for ReturnExpr { type Output = Value; - fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult<Self::Output> { - Err("return is not yet implemented").at(self.span()) + fn eval(&self, ctx: &mut Context, scp: &mut Scopes) -> EvalResult<Self::Output> { + Err(Control::Return( + self.body().map(|body| body.eval(ctx, scp)).transpose()?, + self.span(), + )) } } |
