Leaner argument parsing
This commit is contained in:
parent
7025590405
commit
118fc1014b
6
src/env/fs.rs
vendored
6
src/env/fs.rs
vendored
@ -130,11 +130,7 @@ impl FsLoader {
|
||||
fn parse_face(&mut self, path: &Path, face: &Face<'_>, index: u32) -> io::Result<()> {
|
||||
fn find_name(face: &Face, name_id: u16) -> Option<String> {
|
||||
face.names().find_map(|entry| {
|
||||
if entry.name_id() == name_id {
|
||||
entry.to_string()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
(entry.name_id() == name_id).then(|| entry.to_string()).flatten()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ impl Eval for ClosureExpr {
|
||||
for param in params.iter() {
|
||||
// Set the parameter to `none` if the argument is missing.
|
||||
let value =
|
||||
args.require::<Value>(ctx, param.as_str()).unwrap_or_default();
|
||||
args.eat_expect::<Value>(ctx, param.as_str()).unwrap_or_default();
|
||||
ctx.scopes.def_mut(param.as_str(), value);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ use std::rc::Rc;
|
||||
|
||||
use super::{EvalContext, NodeMap};
|
||||
use crate::color::Color;
|
||||
use crate::diag::DiagSet;
|
||||
use crate::exec::ExecContext;
|
||||
use crate::geom::{Angle, Length, Linear, Relative};
|
||||
use crate::syntax::{Span, Spanned, Tree};
|
||||
@ -261,51 +260,67 @@ pub struct FuncArgs {
|
||||
}
|
||||
|
||||
impl FuncArgs {
|
||||
/// Find and remove the first convertible positional argument.
|
||||
pub fn find<T>(&mut self, ctx: &mut EvalContext) -> Option<T>
|
||||
/// Find and consume the first castable positional argument.
|
||||
pub fn eat<T>(&mut self, ctx: &mut EvalContext) -> Option<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
(0 .. self.items.len()).find_map(move |i| self.try_take(&mut ctx.diags, i))
|
||||
(0 .. self.items.len()).find_map(|index| {
|
||||
let slot = &mut self.items[index];
|
||||
if slot.name.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = std::mem::replace(&mut slot.value, Spanned::zero(Value::None));
|
||||
let span = value.span;
|
||||
|
||||
match T::cast(value) {
|
||||
CastResult::Ok(t) => {
|
||||
self.items.remove(index);
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Warn(t, m) => {
|
||||
self.items.remove(index);
|
||||
ctx.diag(warning!(span, "{}", m));
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Err(value) => {
|
||||
slot.value = value;
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Find and remove the first convertible positional argument, producing an
|
||||
/// error if no match was found.
|
||||
pub fn require<T>(&mut self, ctx: &mut EvalContext, what: &str) -> Option<T>
|
||||
/// Find and consume the first castable positional argument, producing a
|
||||
/// `missing argument: {what}` error if no match was found.
|
||||
pub fn eat_expect<T>(&mut self, ctx: &mut EvalContext, what: &str) -> Option<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
let found = self.find(ctx);
|
||||
let found = self.eat(ctx);
|
||||
if found.is_none() {
|
||||
ctx.diag(error!(self.span, "missing argument: {}", what));
|
||||
}
|
||||
found
|
||||
}
|
||||
|
||||
/// Filter out and remove all convertible positional arguments.
|
||||
pub fn filter<'a, T>(
|
||||
&'a mut self,
|
||||
ctx: &'a mut EvalContext,
|
||||
) -> impl Iterator<Item = T> + 'a
|
||||
/// Find, consume and collect all castable positional arguments.
|
||||
///
|
||||
/// This function returns a vector instead of an iterator because the
|
||||
/// iterator would require unique access to the context, rendering it rather
|
||||
/// unusable. If you need to process arguments one-by-one, you probably want
|
||||
/// to use a while-let loop together with [`eat()`](Self::eat).
|
||||
pub fn eat_all<T>(&mut self, ctx: &mut EvalContext) -> Vec<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
let diags = &mut ctx.diags;
|
||||
let mut i = 0;
|
||||
std::iter::from_fn(move || {
|
||||
while i < self.items.len() {
|
||||
if let Some(val) = self.try_take(diags, i) {
|
||||
return Some(val);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
None
|
||||
})
|
||||
std::iter::from_fn(|| self.eat(ctx)).collect()
|
||||
}
|
||||
|
||||
/// Convert and remove the value for the given named argument, producing an
|
||||
/// Cast and remove the value for the given named argument, producing an
|
||||
/// error if the conversion fails.
|
||||
pub fn get<T>(&mut self, ctx: &mut EvalContext, name: &str) -> Option<T>
|
||||
pub fn eat_named<T>(&mut self, ctx: &mut EvalContext, name: &str) -> Option<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
@ -315,24 +330,8 @@ impl FuncArgs {
|
||||
.position(|arg| arg.name.as_ref().map(|s| s.v.as_str()) == Some(name))?;
|
||||
|
||||
let value = self.items.remove(index).value;
|
||||
self.cast(ctx, value)
|
||||
}
|
||||
|
||||
/// Produce "unexpected argument" errors for all remaining arguments.
|
||||
pub fn finish(self, ctx: &mut EvalContext) {
|
||||
for arg in &self.items {
|
||||
if arg.value.v != Value::Error {
|
||||
ctx.diag(error!(arg.span(), "unexpected argument"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast the value into `T`, generating an error if the conversion fails.
|
||||
fn cast<T>(&self, ctx: &mut EvalContext, value: Spanned<Value>) -> Option<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
let span = value.span;
|
||||
|
||||
match T::cast(value) {
|
||||
CastResult::Ok(t) => Some(t),
|
||||
CastResult::Warn(t, m) => {
|
||||
@ -344,39 +343,18 @@ impl FuncArgs {
|
||||
span,
|
||||
"expected {}, found {}",
|
||||
T::TYPE_NAME,
|
||||
value.v.type_name()
|
||||
value.v.type_name(),
|
||||
));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to take and cast a positional argument in the i'th slot into `T`,
|
||||
/// putting it back if the conversion fails.
|
||||
fn try_take<T>(&mut self, diags: &mut DiagSet, i: usize) -> Option<T>
|
||||
where
|
||||
T: Cast<Spanned<Value>>,
|
||||
{
|
||||
let slot = &mut self.items[i];
|
||||
if slot.name.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value = std::mem::replace(&mut slot.value, Spanned::zero(Value::None));
|
||||
let span = value.span;
|
||||
match T::cast(value) {
|
||||
CastResult::Ok(t) => {
|
||||
self.items.remove(i);
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Warn(t, m) => {
|
||||
self.items.remove(i);
|
||||
diags.insert(warning!(span, "{}", m));
|
||||
Some(t)
|
||||
}
|
||||
CastResult::Err(value) => {
|
||||
slot.value = value;
|
||||
None
|
||||
/// Produce "unexpected argument" errors for all remaining arguments.
|
||||
pub fn finish(self, ctx: &mut EvalContext) {
|
||||
for arg in &self.items {
|
||||
if arg.value.v != Value::Error {
|
||||
ctx.diag(error!(arg.span(), "unexpected argument"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,11 +24,11 @@ use super::*;
|
||||
/// - `top`
|
||||
/// - `bottom`
|
||||
pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let first = args.find::<AlignValue>(ctx);
|
||||
let second = args.find::<AlignValue>(ctx);
|
||||
let mut horizontal = args.get::<AlignValue>(ctx, "horizontal");
|
||||
let mut vertical = args.get::<AlignValue>(ctx, "vertical");
|
||||
let body = args.find::<TemplateValue>(ctx);
|
||||
let first = args.eat::<AlignValue>(ctx);
|
||||
let second = args.eat::<AlignValue>(ctx);
|
||||
let mut horizontal = args.eat_named::<AlignValue>(ctx, "horizontal");
|
||||
let mut vertical = args.eat_named::<AlignValue>(ctx, "vertical");
|
||||
let body = args.eat::<TemplateValue>(ctx);
|
||||
|
||||
for value in first.into_iter().chain(second) {
|
||||
match value.axis() {
|
||||
|
@ -11,7 +11,7 @@ use super::*;
|
||||
/// # Return value
|
||||
/// The name of the value's type as a string.
|
||||
pub fn type_(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
match args.require::<Value>(ctx, "value") {
|
||||
match args.eat_expect::<Value>(ctx, "value") {
|
||||
Some(value) => value.type_name().into(),
|
||||
None => Value::Error,
|
||||
}
|
||||
@ -25,7 +25,7 @@ pub fn type_(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// # Return value
|
||||
/// The string representation of the value.
|
||||
pub fn repr(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
match args.require::<Value>(ctx, "value") {
|
||||
match args.eat_expect::<Value>(ctx, "value") {
|
||||
Some(value) => pretty(&value).into(),
|
||||
None => Value::Error,
|
||||
}
|
||||
@ -42,10 +42,10 @@ pub fn repr(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// # Return value
|
||||
/// The color with the given components.
|
||||
pub fn rgb(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let r = args.require(ctx, "red component");
|
||||
let g = args.require(ctx, "green component");
|
||||
let b = args.require(ctx, "blue component");
|
||||
let a = args.find(ctx);
|
||||
let r = args.eat_expect(ctx, "red component");
|
||||
let g = args.eat_expect(ctx, "green component");
|
||||
let b = args.eat_expect(ctx, "blue component");
|
||||
let a = args.eat(ctx);
|
||||
|
||||
let mut clamp = |component: Option<Spanned<f64>>, default| {
|
||||
component.map_or(default, |c| {
|
||||
|
@ -56,18 +56,18 @@ use super::*;
|
||||
/// - `baseline`
|
||||
/// - `descender`
|
||||
pub fn font(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let size = args.find::<Linear>(ctx);
|
||||
let list: Vec<_> = args.filter::<FontFamily>(ctx).collect();
|
||||
let style = args.get(ctx, "style");
|
||||
let weight = args.get(ctx, "weight");
|
||||
let stretch = args.get(ctx, "stretch");
|
||||
let top_edge = args.get(ctx, "top-edge");
|
||||
let bottom_edge = args.get(ctx, "bottom-edge");
|
||||
let color = args.get(ctx, "color");
|
||||
let serif = args.get(ctx, "serif");
|
||||
let sans_serif = args.get(ctx, "sans-serif");
|
||||
let monospace = args.get(ctx, "monospace");
|
||||
let body = args.find::<TemplateValue>(ctx);
|
||||
let size = args.eat::<Linear>(ctx);
|
||||
let list = args.eat_all::<FontFamily>(ctx);
|
||||
let style = args.eat_named(ctx, "style");
|
||||
let weight = args.eat_named(ctx, "weight");
|
||||
let stretch = args.eat_named(ctx, "stretch");
|
||||
let top_edge = args.eat_named(ctx, "top-edge");
|
||||
let bottom_edge = args.eat_named(ctx, "bottom-edge");
|
||||
let color = args.eat_named(ctx, "color");
|
||||
let serif = args.eat_named(ctx, "serif");
|
||||
let sans_serif = args.eat_named(ctx, "sans-serif");
|
||||
let monospace = args.eat_named(ctx, "monospace");
|
||||
let body = args.eat::<TemplateValue>(ctx);
|
||||
|
||||
Value::template("font", move |ctx| {
|
||||
let snapshot = ctx.state.clone();
|
||||
|
@ -14,9 +14,9 @@ use crate::layout::{AnyNode, Areas, Element, Frame, Layout, LayoutContext};
|
||||
/// # Return value
|
||||
/// A template that inserts an image.
|
||||
pub fn image(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let path = args.require::<Spanned<String>>(ctx, "path to image file");
|
||||
let width = args.get(ctx, "width");
|
||||
let height = args.get(ctx, "height");
|
||||
let path = args.eat_expect::<Spanned<String>>(ctx, "path to image file");
|
||||
let width = args.eat_named(ctx, "width");
|
||||
let height = args.eat_named(ctx, "height");
|
||||
|
||||
Value::template("image", move |ctx| {
|
||||
if let Some(path) = &path {
|
||||
|
@ -16,8 +16,8 @@ use super::*;
|
||||
/// - `ltr`
|
||||
/// - `rtl`
|
||||
pub fn lang(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let iso = args.find::<String>(ctx).map(|s| s.to_ascii_lowercase());
|
||||
let dir = args.get::<Spanned<Dir>>(ctx, "dir");
|
||||
let iso = args.eat::<String>(ctx).map(|s| s.to_ascii_lowercase());
|
||||
let dir = args.eat_named::<Spanned<Dir>>(ctx, "dir");
|
||||
|
||||
Value::template("lang", move |ctx| {
|
||||
if let Some(iso) = &iso {
|
||||
|
@ -43,7 +43,7 @@ pub fn parbreak(_: &mut EvalContext, _: &mut FuncArgs) -> Value {
|
||||
/// A template that flips the boldness of text. The effect is scoped to the
|
||||
/// body if present.
|
||||
pub fn strong(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let body = args.find::<TemplateValue>(ctx);
|
||||
let body = args.eat::<TemplateValue>(ctx);
|
||||
Value::template(Node::STRONG, move |ctx| {
|
||||
let snapshot = ctx.state.clone();
|
||||
ctx.state.font.strong ^= true;
|
||||
@ -70,7 +70,7 @@ pub fn strong(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// A template that flips whether text is set in italics. The effect is scoped
|
||||
/// to the body if present.
|
||||
pub fn emph(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let body = args.find::<TemplateValue>(ctx);
|
||||
let body = args.eat::<TemplateValue>(ctx);
|
||||
Value::template(Node::EMPH, move |ctx| {
|
||||
let snapshot = ctx.state.clone();
|
||||
ctx.state.font.emph ^= true;
|
||||
@ -104,9 +104,9 @@ pub fn emph(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// A template that sets the body as a section heading, that is, large and in
|
||||
/// bold.
|
||||
pub fn heading(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let level = args.get(ctx, HeadingNode::LEVEL).unwrap_or(1);
|
||||
let level = args.eat_named(ctx, HeadingNode::LEVEL).unwrap_or(1);
|
||||
let body = args
|
||||
.require::<TemplateValue>(ctx, HeadingNode::BODY)
|
||||
.eat_expect::<TemplateValue>(ctx, HeadingNode::BODY)
|
||||
.unwrap_or_default();
|
||||
|
||||
Value::template(Node::HEADING, move |ctx| {
|
||||
@ -149,9 +149,9 @@ pub fn heading(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// A template that sets the text raw, that is, in monospace and optionally with
|
||||
/// syntax highlighting.
|
||||
pub fn raw(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let text = args.require::<String>(ctx, RawNode::TEXT).unwrap_or_default();
|
||||
let _lang = args.get::<String>(ctx, RawNode::LANG);
|
||||
let block = args.get(ctx, RawNode::BLOCK).unwrap_or(false);
|
||||
let text = args.eat_expect::<String>(ctx, RawNode::TEXT).unwrap_or_default();
|
||||
let _lang = args.eat_named::<String>(ctx, RawNode::LANG);
|
||||
let block = args.eat_named(ctx, RawNode::BLOCK).unwrap_or(false);
|
||||
|
||||
Value::template(Node::RAW, move |ctx| {
|
||||
if block {
|
||||
|
@ -27,17 +27,15 @@ pub fn max(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
}
|
||||
|
||||
/// Find the minimum or maximum of a sequence of values.
|
||||
fn minmax(ctx: &mut EvalContext, args: &mut FuncArgs, which: Ordering) -> Value {
|
||||
let mut values = args.filter::<Value>(ctx);
|
||||
fn minmax(ctx: &mut EvalContext, args: &mut FuncArgs, goal: Ordering) -> Value {
|
||||
let mut extremum = None;
|
||||
|
||||
for value in &mut values {
|
||||
while let Some(value) = args.eat::<Value>(ctx) {
|
||||
if let Some(prev) = &extremum {
|
||||
match value.cmp(&prev) {
|
||||
Some(ord) if ord == which => extremum = Some(value),
|
||||
Some(ordering) if ordering == goal => extremum = Some(value),
|
||||
Some(_) => {}
|
||||
None => {
|
||||
drop(values);
|
||||
ctx.diag(error!(
|
||||
args.span,
|
||||
"cannot compare {} with {}",
|
||||
@ -52,9 +50,8 @@ fn minmax(ctx: &mut EvalContext, args: &mut FuncArgs, which: Ordering) -> Value
|
||||
}
|
||||
}
|
||||
|
||||
drop(values);
|
||||
extremum.unwrap_or_else(|| {
|
||||
args.require::<Value>(ctx, "value");
|
||||
args.eat_expect::<Value>(ctx, "value");
|
||||
Value::Error
|
||||
})
|
||||
}
|
||||
|
@ -16,12 +16,12 @@ use crate::layout::PadNode;
|
||||
/// # Return value
|
||||
/// A template that sets the body into a padded area.
|
||||
pub fn pad(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let all = args.find(ctx);
|
||||
let left = args.get(ctx, "left");
|
||||
let top = args.get(ctx, "top");
|
||||
let right = args.get(ctx, "right");
|
||||
let bottom = args.get(ctx, "bottom");
|
||||
let body = args.require::<TemplateValue>(ctx, "body").unwrap_or_default();
|
||||
let all = args.eat(ctx);
|
||||
let left = args.eat_named(ctx, "left");
|
||||
let top = args.eat_named(ctx, "top");
|
||||
let right = args.eat_named(ctx, "right");
|
||||
let bottom = args.eat_named(ctx, "bottom");
|
||||
let body = args.eat_expect::<TemplateValue>(ctx, "body").unwrap_or_default();
|
||||
|
||||
let padding = Sides::new(
|
||||
left.or(all).unwrap_or_default(),
|
||||
|
@ -22,22 +22,22 @@ use crate::paper::{Paper, PaperClass};
|
||||
/// A template that configures page properties. The effect is scoped to the body
|
||||
/// if present.
|
||||
pub fn page(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let paper = args.find::<Spanned<String>>(ctx).and_then(|name| {
|
||||
let paper = args.eat::<Spanned<String>>(ctx).and_then(|name| {
|
||||
Paper::from_name(&name.v).or_else(|| {
|
||||
ctx.diag(error!(name.span, "invalid paper name"));
|
||||
None
|
||||
})
|
||||
});
|
||||
|
||||
let width = args.get(ctx, "width");
|
||||
let height = args.get(ctx, "height");
|
||||
let margins = args.get(ctx, "margins");
|
||||
let left = args.get(ctx, "left");
|
||||
let top = args.get(ctx, "top");
|
||||
let right = args.get(ctx, "right");
|
||||
let bottom = args.get(ctx, "bottom");
|
||||
let flip = args.get(ctx, "flip");
|
||||
let body = args.find::<TemplateValue>(ctx);
|
||||
let width = args.eat_named(ctx, "width");
|
||||
let height = args.eat_named(ctx, "height");
|
||||
let margins = args.eat_named(ctx, "margins");
|
||||
let left = args.eat_named(ctx, "left");
|
||||
let top = args.eat_named(ctx, "top");
|
||||
let right = args.eat_named(ctx, "right");
|
||||
let bottom = args.eat_named(ctx, "bottom");
|
||||
let flip = args.eat_named(ctx, "flip");
|
||||
let body = args.eat::<TemplateValue>(ctx);
|
||||
let span = args.span;
|
||||
|
||||
Value::template("page", move |ctx| {
|
||||
|
@ -10,9 +10,9 @@ use super::*;
|
||||
/// # Return value
|
||||
/// A template that configures paragraph properties.
|
||||
pub fn par(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let spacing = args.get(ctx, "spacing");
|
||||
let leading = args.get(ctx, "leading");
|
||||
let word_spacing = args.get(ctx, "word-spacing");
|
||||
let spacing = args.eat_named(ctx, "spacing");
|
||||
let leading = args.eat_named(ctx, "leading");
|
||||
let word_spacing = args.eat_named(ctx, "word-spacing");
|
||||
|
||||
Value::template("par", move |ctx| {
|
||||
if let Some(spacing) = spacing {
|
||||
|
@ -17,10 +17,10 @@ use crate::layout::{BackgroundNode, BackgroundShape, Fill, FixedNode, PadNode};
|
||||
/// # Return value
|
||||
/// A template that inserts a rectangle and sets the body into it.
|
||||
pub fn rect(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = args.get(ctx, "width");
|
||||
let height = args.get(ctx, "height");
|
||||
let fill = args.get(ctx, "fill");
|
||||
let body = args.find::<TemplateValue>(ctx).unwrap_or_default();
|
||||
let width = args.eat_named(ctx, "width");
|
||||
let height = args.eat_named(ctx, "height");
|
||||
let fill = args.eat_named(ctx, "fill");
|
||||
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
|
||||
rect_impl("rect", width, height, None, fill, body)
|
||||
}
|
||||
|
||||
@ -42,11 +42,11 @@ pub fn rect(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// # Return value
|
||||
/// A template that inserts a square and sets the body into it.
|
||||
pub fn square(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let length = args.get::<Length>(ctx, "length").map(Linear::from);
|
||||
let width = length.or_else(|| args.get(ctx, "width"));
|
||||
let height = if width.is_none() { args.get(ctx, "height") } else { None };
|
||||
let fill = args.get(ctx, "fill");
|
||||
let body = args.find::<TemplateValue>(ctx).unwrap_or_default();
|
||||
let length = args.eat_named::<Length>(ctx, "length").map(Linear::from);
|
||||
let width = length.or_else(|| args.eat_named(ctx, "width"));
|
||||
let height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten();
|
||||
let fill = args.eat_named(ctx, "fill");
|
||||
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
|
||||
rect_impl("square", width, height, Some(1.0), fill, body)
|
||||
}
|
||||
|
||||
@ -89,10 +89,10 @@ fn rect_impl(
|
||||
/// # Return value
|
||||
/// A template that inserts an ellipse and sets the body into it.
|
||||
pub fn ellipse(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let width = args.get(ctx, "width");
|
||||
let height = args.get(ctx, "height");
|
||||
let fill = args.get(ctx, "fill");
|
||||
let body = args.find::<TemplateValue>(ctx).unwrap_or_default();
|
||||
let width = args.eat_named(ctx, "width");
|
||||
let height = args.eat_named(ctx, "height");
|
||||
let fill = args.eat_named(ctx, "fill");
|
||||
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
|
||||
ellipse_impl("ellipse", width, height, None, fill, body)
|
||||
}
|
||||
|
||||
@ -114,11 +114,11 @@ pub fn ellipse(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
/// # Return value
|
||||
/// A template that inserts a circle and sets the body into it.
|
||||
pub fn circle(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
|
||||
let radius = args.get::<Length>(ctx, "radius").map(|r| 2.0 * Linear::from(r));
|
||||
let width = radius.or_else(|| args.get(ctx, "width"));
|
||||
let height = if width.is_none() { args.get(ctx, "height") } else { None };
|
||||
let fill = args.get(ctx, "fill");
|
||||
let body = args.find::<TemplateValue>(ctx).unwrap_or_default();
|
||||
let radius = args.eat_named::<Length>(ctx, "radius").map(|r| 2.0 * Linear::from(r));
|
||||
let width = radius.or_else(|| args.eat_named(ctx, "width"));
|
||||
let height = width.is_none().then(|| args.eat_named(ctx, "height")).flatten();
|
||||
let fill = args.eat_named(ctx, "fill");
|
||||
let body = args.eat::<TemplateValue>(ctx).unwrap_or_default();
|
||||
ellipse_impl("circle", width, height, Some(1.0), fill, body)
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ fn spacing_impl(
|
||||
args: &mut FuncArgs,
|
||||
axis: GenAxis,
|
||||
) -> Value {
|
||||
let spacing: Option<Linear> = args.require(ctx, "spacing");
|
||||
let spacing: Option<Linear> = args.eat_expect(ctx, "spacing");
|
||||
Value::template(name, move |ctx| {
|
||||
if let Some(linear) = spacing {
|
||||
let amount = linear.resolve(ctx.state.font.resolve_size());
|
||||
|
@ -321,8 +321,8 @@ fn register_helpers(scope: &mut Scope, panics: Rc<RefCell<Vec<Panic>>>) {
|
||||
}
|
||||
|
||||
let test = move |ctx: &mut EvalContext, args: &mut FuncArgs| -> Value {
|
||||
let lhs = args.require::<Value>(ctx, "left-hand side");
|
||||
let rhs = args.require::<Value>(ctx, "right-hand side");
|
||||
let lhs = args.eat_expect::<Value>(ctx, "left-hand side");
|
||||
let rhs = args.eat_expect::<Value>(ctx, "right-hand side");
|
||||
if lhs != rhs {
|
||||
panics.borrow_mut().push(Panic { pos: args.span.start, lhs, rhs });
|
||||
Value::Str(format!("(panic)"))
|
||||
|
Loading…
x
Reference in New Issue
Block a user