summaryrefslogtreecommitdiff
path: root/src/syntax/func/values.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntax/func/values.rs')
-rw-r--r--src/syntax/func/values.rs301
1 files changed, 0 insertions, 301 deletions
diff --git a/src/syntax/func/values.rs b/src/syntax/func/values.rs
deleted file mode 100644
index d5e9c6e8..00000000
--- a/src/syntax/func/values.rs
+++ /dev/null
@@ -1,301 +0,0 @@
-//! 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<Expr>) -> Result<Self, Diagnostic> {
-/// 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<Expr>) -> Result<Self, Diagnostic>;
-}
-
-impl<V: Value> Value for Spanned<V> {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- 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<Expr>) -> Result<Self, Diagnostic> {
- #[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(l) => l);
-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),
-);
-
-/// A value type that matches [`Expr::Ident`] and [`Expr::Str`] and implements
-/// `Into<String>`.
-pub struct StringLike(pub String);
-
-value!(StringLike, "identifier or string",
- Expr::Ident(Ident(s)) => StringLike(s),
- Expr::Str(s) => StringLike(s),
-);
-
-impl From<StringLike> 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<Option>` yielding `Option::Some(V)` for a value and
-/// `Option::None` for `default`.
-///
-/// # Example
-/// ```
-/// # use typstc::syntax::func::{FuncArgs, Defaultable};
-/// # use typstc::length::Length;
-/// # let mut args = FuncArgs::new();
-/// # let mut errors = vec![];
-/// args.key.get::<Defaultable<Length>>(&mut errors, "length");
-/// ```
-/// This will yield.
-/// ```typst
-/// [func: length=default] => None
-/// [func: length=2cm] => Some(Length::cm(2.0))
-/// ```
-pub struct Defaultable<V>(pub Option<V>);
-
-impl<V: Value> Value for Defaultable<V> {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- Ok(Defaultable(match expr.v {
- Expr::Ident(ident) if ident.as_str() == "default" => None,
- _ => Some(V::parse(expr)?)
- }))
- }
-}
-
-impl<V> From<Defaultable<V>> for Option<V> {
- fn from(defaultable: Defaultable<V>) -> Option<V> {
- defaultable.0
- }
-}
-
-impl Value for FontStyle {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- FontStyle::from_name(Ident::parse(expr)?.as_str())
- .ok_or_else(|| error!("invalid font style"))
- }
-}
-
-/// The additional boolean specifies whether a number was clamped into the range
-/// 100 - 900 to make it a valid font weight.
-impl Value for FontWeight {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- match expr.v {
- Expr::Number(weight) => {
- let weight = weight.round();
- if weight >= 100.0 && weight <= 900.0 {
- Ok(FontWeight(weight as u16))
- } else {
- let clamped = weight.min(900.0).max(100.0);
- Ok(FontWeight(clamped as u16))
- }
- }
- Expr::Ident(id) => {
- FontWeight::from_name(id.as_str())
- .ok_or_else(|| error!("invalid font weight"))
- }
- other => Err(
- error!("expected identifier or number, found {}", other.name())
- ),
- }
- }
-}
-
-/// The additional boolean specifies whether a number was clamped into the range
-/// 1 - 9 to make it a valid font width.
-impl Value for FontWidth {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- match expr.v {
- Expr::Number(width) => {
- let width = width.round();
- if width >= 1.0 && width <= 9.0 {
- Ok(FontWidth::new(width as u16).unwrap())
- } else {
- let clamped = width.min(9.0).max(1.0);
- Ok(FontWidth::new(clamped as u16).unwrap())
- }
- }
- Expr::Ident(id) => {
- FontWidth::from_name(id.as_str())
- .ok_or_else(|| error!("invalid font width"))
- }
- other => Err(
- error!("expected identifier or number, found {}", other.name())
- ),
- }
- }
-}
-
-impl Value for Paper {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- Paper::from_name(Ident::parse(expr)?.as_str())
- .ok_or_else(|| error!("invalid paper type"))
- }
-}
-
-impl Value for Direction {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- Ok(match Ident::parse(expr)?.as_str() {
- "left-to-right" | "ltr" | "LTR" => LeftToRight,
- "right-to-left" | "rtl" | "RTL" => RightToLeft,
- "top-to-bottom" | "ttb" | "TTB" => TopToBottom,
- "bottom-to-top" | "btt" | "BTT" => BottomToTop,
- _ => return Err(error!("invalid direction"))
- })
- }
-}
-
-/// A value type that matches identifiers that are valid alignments like
-/// `origin` or `right`.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-#[allow(missing_docs)]
-pub enum AlignmentValue {
- /// A generic alignment.
- Align(Alignment),
- Left,
- Top,
- Right,
- Bottom,
-}
-
-impl AlignmentValue {
- /// The specific axis this alignment corresponds to. `None` if the alignment
- /// is generic.
- pub fn axis(self) -> Option<SpecificAxis> {
- match self {
- Left | Right => Some(Horizontal),
- Top | Bottom => Some(Vertical),
- Align(_) => None,
- }
- }
-
- /// The generic version of this alignment on the given axis in the given
- /// system of layouting axes.
- ///
- /// Returns `None` if the alignment is invalid for the given axis.
- pub fn to_generic(self, axes: LayoutAxes, axis: GenericAxis) -> Option<Alignment> {
- let specific = axis.to_specific(axes);
- let positive = axes.get(axis).is_positive();
-
- // The alignment matching the origin of the positive coordinate direction.
- let start = if positive { Origin } else { End };
-
- match (self, specific) {
- (Align(alignment), _) => Some(alignment),
- (Left, Horizontal) | (Top, Vertical) => Some(start),
- (Right, Horizontal) | (Bottom, Vertical) => Some(start.inv()),
- _ => None
- }
- }
-
- /// The specific version of this alignment on the given axis in the given
- /// system of layouting axes.
- pub fn to_specific(self, axes: LayoutAxes, axis: GenericAxis) -> AlignmentValue {
- let direction = axes.get(axis);
- if let Align(alignment) = self {
- match (direction, alignment) {
- (LeftToRight, Origin) | (RightToLeft, End) => Left,
- (LeftToRight, End) | (RightToLeft, Origin) => Right,
- (TopToBottom, Origin) | (BottomToTop, End) => Top,
- (TopToBottom, End) | (BottomToTop, Origin) => Bottom,
- (_, Center) => self,
- }
- } else {
- self
- }
- }
-}
-
-impl Value for AlignmentValue {
- fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> {
- Ok(match Ident::parse(expr)?.as_str() {
- "origin" => Align(Origin),
- "center" => Align(Center),
- "end" => Align(End),
- "left" => Left,
- "top" => Top,
- "right" => Right,
- "bottom" => Bottom,
- _ => return Err(error!("invalid alignment"))
- })
- }
-}
-
-impl Display for AlignmentValue {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- match self {
- Align(Origin) => write!(f, "origin"),
- Align(Center) => write!(f, "center"),
- Align(End) => write!(f, "end"),
- Left => write!(f, "left"),
- Top => write!(f, "top"),
- Right => write!(f, "right"),
- Bottom => write!(f, "bottom"),
- }
- }
-}