diff --git a/src/eval/function.rs b/src/eval/function.rs index d9f79adfe..cbbc0b366 100644 --- a/src/eval/function.rs +++ b/src/eval/function.rs @@ -77,25 +77,22 @@ pub struct Arg { } impl Args { - /// Find and consume the first castable positional argument. - pub fn eat(&mut self) -> Option + /// Consume and cast the first positional argument. + /// + /// Returns a `missing argument: {what}` error if no positional argument is + /// left. + pub fn expect(&mut self, what: &str) -> TypResult where T: Cast>, { - for (i, slot) in self.items.iter().enumerate() { - if slot.name.is_none() { - if T::is(&slot.value) { - let value = self.items.remove(i).value; - return T::cast(value).ok(); - } - } + match self.eat()? { + Some(v) => Ok(v), + None => bail!(self.span, "missing argument: {}", what), } - None } - /// Try to cast the first positional argument ir returning a `missing - /// argument: {what}` error if no positional argument is left. - pub fn expect(&mut self, what: &str) -> TypResult + /// Consume and cast the first positional argument if there is one. + pub fn eat(&mut self) -> TypResult> where T: Cast>, { @@ -103,11 +100,24 @@ impl Args { if slot.name.is_none() { let value = self.items.remove(i).value; let span = value.span; - return T::cast(value).at(span); + return T::cast(value).at(span).map(Some); } } + Ok(None) + } - bail!(self.span, "missing argument: {}", what); + /// Find and consume the first castable positional argument. + pub fn find(&mut self) -> Option + where + T: Cast>, + { + for (i, slot) in self.items.iter().enumerate() { + if slot.name.is_none() && T::is(&slot.value) { + let value = self.items.remove(i).value; + return T::cast(value).ok(); + } + } + None } /// Find and consume all castable positional arguments. @@ -115,7 +125,7 @@ impl Args { where T: Cast>, { - std::iter::from_fn(move || self.eat()) + std::iter::from_fn(move || self.find()) } /// Cast and remove the value for the given named argument, returning an diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 2adf785e1..691e3c494 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -317,7 +317,6 @@ impl Eval for BinaryExpr { BinOp::SubAssign => self.assign(ctx, ops::sub), BinOp::MulAssign => self.assign(ctx, ops::mul), BinOp::DivAssign => self.assign(ctx, ops::div), - BinOp::Range => self.apply(ctx, ops::range), } } } diff --git a/src/eval/ops.rs b/src/eval/ops.rs index 8756e8c64..732bfb143 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -244,14 +244,6 @@ comparison!(leq, "<=", Ordering::Less | Ordering::Equal); comparison!(gt, ">", Ordering::Greater); comparison!(geq, ">=", Ordering::Greater | Ordering::Equal); -/// Compute the range from `lhs` to `rhs`. -pub fn range(lhs: Value, rhs: Value) -> StrResult { - match (lhs, rhs) { - (Int(a), Int(b)) => Ok(Array((a .. b).map(Int).collect())), - (a, b) => mismatch!("cannot apply '..' to {} and {}", a, b), - } -} - /// Determine whether two values are equal. pub fn equal(lhs: &Value, rhs: &Value) -> bool { match (lhs, rhs) { diff --git a/src/library/elements.rs b/src/library/elements.rs index 5d87d65db..cd8a6f88a 100644 --- a/src/library/elements.rs +++ b/src/library/elements.rs @@ -30,7 +30,7 @@ pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult { let width = args.named("width")?; let height = args.named("height")?; let fill = args.named("fill")?; - let body = args.eat(); + let body = args.find(); Ok(shape_impl(ShapeKind::Rect, width, height, fill, body)) } @@ -46,7 +46,7 @@ pub fn square(_: &mut EvalContext, args: &mut Args) -> TypResult { size => size, }; let fill = args.named("fill")?; - let body = args.eat(); + let body = args.find(); Ok(shape_impl(ShapeKind::Square, width, height, fill, body)) } @@ -55,7 +55,7 @@ pub fn ellipse(_: &mut EvalContext, args: &mut Args) -> TypResult { let width = args.named("width")?; let height = args.named("height")?; let fill = args.named("fill")?; - let body = args.eat(); + let body = args.find(); Ok(shape_impl(ShapeKind::Ellipse, width, height, fill, body)) } @@ -71,7 +71,7 @@ pub fn circle(_: &mut EvalContext, args: &mut Args) -> TypResult { diameter => diameter, }; let fill = args.named("fill")?; - let body = args.eat(); + let body = args.find(); Ok(shape_impl(ShapeKind::Circle, width, height, fill, body)) } diff --git a/src/library/layout.rs b/src/library/layout.rs index d412af674..4b416156f 100644 --- a/src/library/layout.rs +++ b/src/library/layout.rs @@ -6,7 +6,7 @@ use crate::style::{Paper, PaperClass}; /// `page`: Configure pages. pub fn page(ctx: &mut EvalContext, args: &mut Args) -> TypResult { - let paper = match args.named::>("paper")?.or_else(|| args.eat()) { + let paper = match args.named::>("paper")?.or_else(|| args.find()) { Some(name) => match Paper::from_name(&name.v) { None => bail!(name.span, "invalid paper name"), paper => paper, @@ -80,9 +80,9 @@ pub fn pagebreak(_: &mut EvalContext, _: &mut Args) -> TypResult { /// `align`: Configure the alignment along the layouting axes. pub fn align(ctx: &mut EvalContext, args: &mut Args) -> TypResult { - let first = args.eat::(); - let second = args.eat::(); - let body = args.eat::