//! Value types for extracting function arguments. use std::fmt::{self, Display, Formatter}; use fontdock::{FontStyle, FontWeight, FontWidth}; use crate::layout::prelude::*; use crate::length::{Length, ScaleLength}; use crate::paper::Paper; use super::*; use self::AlignmentValue::*; /// Value types are used to extract the values of positional and keyword /// arguments from [`Tuples`](crate::syntax::expr::Tuple) and /// [`Objects`](crate::syntax::expr::Object). They represent the value part of /// an argument. /// ```typst /// [func: value, key=value] /// ^^^^^ ^^^^^ /// ``` /// /// # Example implementation /// An implementation for `bool` might look as follows: /// ``` /// # use typstc::error; /// # use typstc::diagnostic::Diagnostic; /// # use typstc::syntax::expr::Expr; /// # use typstc::syntax::func::Value; /// # use typstc::syntax::span::Spanned; /// # struct Bool; /* /// impl Value for bool { /// # */ impl Value for Bool { /// fn parse(expr: Spanned) -> Result { /// match expr.v { /// # /* /// Expr::Bool(b) => Ok(b), /// # */ Expr::Bool(_) => Ok(Bool), /// other => Err(error!("expected bool, found {}", other.name())), /// } /// } /// } /// ``` pub trait Value: Sized { /// Parse an expression into this value or return an error if the expression /// is valid for this value type. fn parse(expr: Spanned) -> Result; } impl Value for Spanned { fn parse(expr: Spanned) -> Result { let span = expr.span; V::parse(expr).map(|v| Spanned { v, span }) } } /// Implements [`Value`] for types that just need to match on expressions. macro_rules! value { ($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => { impl Value for $type { fn parse(expr: Spanned) -> Result { #[allow(unreachable_patterns)] match expr.v { $($p => Ok($r)),*, other => Err( error!("expected {}, found {}", $name, other.name()) ), } } } }; } value!(Expr, "expression", e => e); value!(Ident, "identifier", Expr::Ident(i) => i); value!(String, "string", Expr::Str(s) => s); value!(f64, "number", Expr::Number(n) => n); value!(bool, "bool", Expr::Bool(b) => b); value!(Length, "length", Expr::Length(s) => s); value!(Tuple, "tuple", Expr::Tuple(t) => t); value!(Object, "object", Expr::Object(o) => o); value!(ScaleLength, "number or length", Expr::Length(length) => ScaleLength::Absolute(length), Expr::Number(scale) => ScaleLength::Scaled(scale as f64), ); /// A value type that matches [`Expr::Ident`] and [`Expr::Str`] and implements /// `Into`. pub struct StringLike(pub String); value!(StringLike, "identifier or string", Expr::Ident(Ident(s)) => StringLike(s), Expr::Str(s) => StringLike(s), ); impl From for String { fn from(like: StringLike) -> String { like.0 } } /// A value type that matches the identifier `default` or a value type `V` and /// implements `Into