mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Style nits 🎈
This commit is contained in:
parent
0f7c70fd93
commit
f4460f8abd
@ -351,7 +351,7 @@ impl<V> SpannedEntry<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create an entry with the same span for key and value.
|
/// Create an entry with the same span for key and value.
|
||||||
pub fn val(val: Spanned<V>) -> Self {
|
pub fn value(val: Spanned<V>) -> Self {
|
||||||
Self { key_span: val.span, value: val }
|
Self { key_span: val.span, value: val }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
use super::value::FuncValue;
|
use super::value::ValueFunc;
|
||||||
|
|
||||||
/// A map from identifiers to functions.
|
/// A map from identifiers to functions.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
functions: HashMap<String, FuncValue>,
|
functions: HashMap<String, ValueFunc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scope {
|
impl Scope {
|
||||||
@ -19,12 +19,12 @@ impl Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Associate the given name with the function.
|
/// Associate the given name with the function.
|
||||||
pub fn insert(&mut self, name: impl Into<String>, function: FuncValue) {
|
pub fn insert(&mut self, name: impl Into<String>, function: ValueFunc) {
|
||||||
self.functions.insert(name.into(), function);
|
self.functions.insert(name.into(), function);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the function with the given name if there is one.
|
/// Return the function with the given name if there is one.
|
||||||
pub fn func(&self, name: &str) -> Option<&FuncValue> {
|
pub fn func(&self, name: &str) -> Option<&ValueFunc> {
|
||||||
self.functions.get(name)
|
self.functions.get(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@ use crate::{DynFuture, Feedback};
|
|||||||
/// A computational value.
|
/// A computational value.
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
/// The result of invalid operations.
|
|
||||||
Error,
|
|
||||||
/// An identifier: `ident`.
|
/// An identifier: `ident`.
|
||||||
Ident(Ident),
|
Ident(Ident),
|
||||||
/// A boolean: `true, false`.
|
/// A boolean: `true, false`.
|
||||||
@ -36,27 +34,29 @@ pub enum Value {
|
|||||||
///
|
///
|
||||||
/// [literal]: ../syntax/ast/enum.Lit.html#variant.Percent
|
/// [literal]: ../syntax/ast/enum.Lit.html#variant.Percent
|
||||||
Relative(f64),
|
Relative(f64),
|
||||||
/// A combination of an absolute length and a relative value.
|
/// A combination of an absolute length and a relative value: `20% + 5cm`.
|
||||||
Linear(Linear),
|
Linear(Linear),
|
||||||
/// A color value with alpha channel: `#f79143ff`.
|
/// A color value with alpha channel: `#f79143ff`.
|
||||||
Color(RgbaColor),
|
Color(RgbaColor),
|
||||||
/// A string: `"string"`.
|
/// A string: `"string"`.
|
||||||
Str(String),
|
Str(String),
|
||||||
/// A dictionary value: `(false, 12cm, greeting="hi")`.
|
/// A dictionary value: `(false, 12cm, greeting="hi")`.
|
||||||
Dict(DictValue),
|
Dict(ValueDict),
|
||||||
/// A syntax tree containing typesetting content.
|
/// A content value: `{*Hi* there}`.
|
||||||
Tree(SynTree),
|
Content(SynTree),
|
||||||
/// An executable function.
|
/// An executable function.
|
||||||
Func(FuncValue),
|
Func(ValueFunc),
|
||||||
/// Layouting commands.
|
/// Layouting commands.
|
||||||
Commands(Commands),
|
Commands(Commands),
|
||||||
|
/// The result of invalid operations.
|
||||||
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
/// The natural-language name of this value for use in error messages.
|
/// The natural-language name of this value's type for use in error
|
||||||
pub fn name(&self) -> &'static str {
|
/// messages.
|
||||||
|
pub fn ty(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Error => "error",
|
|
||||||
Self::Ident(_) => "identifier",
|
Self::Ident(_) => "identifier",
|
||||||
Self::Bool(_) => "bool",
|
Self::Bool(_) => "bool",
|
||||||
Self::Int(_) => "integer",
|
Self::Int(_) => "integer",
|
||||||
@ -67,9 +67,10 @@ impl Value {
|
|||||||
Self::Color(_) => "color",
|
Self::Color(_) => "color",
|
||||||
Self::Str(_) => "string",
|
Self::Str(_) => "string",
|
||||||
Self::Dict(_) => "dict",
|
Self::Dict(_) => "dict",
|
||||||
Self::Tree(_) => "syntax tree",
|
Self::Content(_) => "content",
|
||||||
Self::Func(_) => "function",
|
Self::Func(_) => "function",
|
||||||
Self::Commands(_) => "commands",
|
Self::Commands(_) => "commands",
|
||||||
|
Self::Error => "error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +99,7 @@ impl Spanned<Value> {
|
|||||||
commands
|
commands
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Tree(tree) => vec![Command::LayoutSyntaxTree(tree)],
|
Value::Content(tree) => vec![Command::LayoutSyntaxTree(tree)],
|
||||||
Value::Commands(commands) => commands,
|
Value::Commands(commands) => commands,
|
||||||
|
|
||||||
// Format with debug.
|
// Format with debug.
|
||||||
@ -115,69 +116,67 @@ impl Debug for Value {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Error => f.pad("<error>"),
|
Self::Error => f.pad("<error>"),
|
||||||
Self::Ident(i) => i.fmt(f),
|
Self::Ident(v) => v.fmt(f),
|
||||||
Self::Bool(b) => b.fmt(f),
|
Self::Bool(v) => v.fmt(f),
|
||||||
Self::Int(i) => i.fmt(f),
|
Self::Int(v) => v.fmt(f),
|
||||||
Self::Float(n) => n.fmt(f),
|
Self::Float(v) => v.fmt(f),
|
||||||
Self::Length(l) => l.fmt(f),
|
Self::Length(v) => v.fmt(f),
|
||||||
Self::Relative(r) => r.fmt(f),
|
Self::Relative(v) => v.fmt(f),
|
||||||
Self::Linear(l) => l.fmt(f),
|
Self::Linear(v) => v.fmt(f),
|
||||||
Self::Color(c) => c.fmt(f),
|
Self::Color(v) => v.fmt(f),
|
||||||
Self::Str(s) => s.fmt(f),
|
Self::Str(v) => v.fmt(f),
|
||||||
Self::Dict(d) => d.fmt(f),
|
Self::Dict(v) => v.fmt(f),
|
||||||
Self::Tree(t) => t.fmt(f),
|
Self::Content(v) => v.fmt(f),
|
||||||
Self::Func(c) => c.fmt(f),
|
Self::Func(v) => v.fmt(f),
|
||||||
Self::Commands(c) => c.fmt(f),
|
Self::Commands(v) => v.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An executable function value.
|
/// An wrapper around a reference-counted executable function value.
|
||||||
///
|
|
||||||
/// The first argument is a dictionary containing the arguments passed to the
|
|
||||||
/// function. The function may be asynchronous (as such it returns a dynamic
|
|
||||||
/// future) and it may emit diagnostics, which are contained in the returned
|
|
||||||
/// `Pass`. In the end, the function must evaluate to [`Value`]. A typical
|
|
||||||
/// typesetting function will return a `Commands` value which will instruct the
|
|
||||||
/// layouting engine to do what the function pleases.
|
|
||||||
///
|
///
|
||||||
/// The dynamic function object is wrapped in an `Rc` to keep [`Value`]
|
/// The dynamic function object is wrapped in an `Rc` to keep [`Value`]
|
||||||
/// clonable.
|
/// clonable.
|
||||||
///
|
///
|
||||||
|
/// _Note_: This is needed because the compiler can't `derive(PartialEq)`
|
||||||
|
/// for `Value` when directly putting the boxed function in there,
|
||||||
|
/// see the [Rust Issue].
|
||||||
|
///
|
||||||
/// [`Value`]: enum.Value.html
|
/// [`Value`]: enum.Value.html
|
||||||
|
/// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FuncValue(pub Rc<FuncType>);
|
pub struct ValueFunc(pub Rc<Func>);
|
||||||
|
|
||||||
/// The signature of executable functions.
|
/// The signature of executable functions.
|
||||||
type FuncType = dyn Fn(DictValue, &mut LayoutContext) -> DynFuture<Value>;
|
pub type Func = dyn Fn(ValueDict, &mut LayoutContext) -> DynFuture<Value>;
|
||||||
|
|
||||||
impl FuncValue {
|
impl ValueFunc {
|
||||||
/// Create a new function value from a rust function or closure.
|
/// Create a new function value from a rust function or closure.
|
||||||
pub fn new<F: 'static>(f: F) -> Self
|
pub fn new<F: 'static>(f: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(DictValue, &mut LayoutContext) -> DynFuture<Value>,
|
F: Fn(ValueDict, &mut LayoutContext) -> DynFuture<Value>,
|
||||||
{
|
{
|
||||||
Self(Rc::new(f))
|
Self(Rc::new(f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for FuncValue {}
|
impl Eq for ValueFunc {}
|
||||||
|
|
||||||
impl PartialEq for FuncValue {
|
impl PartialEq for ValueFunc {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
Rc::ptr_eq(&self.0, &other.0)
|
Rc::ptr_eq(&self.0, &other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for FuncValue {
|
impl Deref for ValueFunc {
|
||||||
type Target = FuncType;
|
type Target = Func;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.0.as_ref()
|
self.0.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for FuncValue {
|
impl Debug for ValueFunc {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
f.pad("<function>")
|
f.pad("<function>")
|
||||||
}
|
}
|
||||||
@ -189,9 +188,9 @@ impl Debug for FuncValue {
|
|||||||
/// ```typst
|
/// ```typst
|
||||||
/// (false, 12cm, greeting="hi")
|
/// (false, 12cm, greeting="hi")
|
||||||
/// ```
|
/// ```
|
||||||
pub type DictValue = Dict<SpannedEntry<Value>>;
|
pub type ValueDict = Dict<SpannedEntry<Value>>;
|
||||||
|
|
||||||
impl DictValue {
|
impl ValueDict {
|
||||||
/// Retrieve and remove the matching value with the lowest number key,
|
/// Retrieve and remove the matching value with the lowest number key,
|
||||||
/// skipping and ignoring all non-matching entries with lower keys.
|
/// skipping and ignoring all non-matching entries with lower keys.
|
||||||
pub fn take<T: TryFromValue>(&mut self) -> Option<T> {
|
pub fn take<T: TryFromValue>(&mut self) -> Option<T> {
|
||||||
@ -331,7 +330,7 @@ macro_rules! impl_match {
|
|||||||
other => {
|
other => {
|
||||||
error!(
|
error!(
|
||||||
@f, value.span,
|
@f, value.span,
|
||||||
"expected {}, found {}", $name, other.name()
|
"expected {}, found {}", $name, other.ty()
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -354,7 +353,7 @@ macro_rules! impl_ident {
|
|||||||
} else {
|
} else {
|
||||||
error!(
|
error!(
|
||||||
@f, value.span,
|
@f, value.span,
|
||||||
"expected {}, found {}", $name, value.v.name()
|
"expected {}, found {}", $name, value.v.ty()
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -370,33 +369,13 @@ impl<T: TryFromValue> TryFromValue for Spanned<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_match!(Value, "value", v => v.clone());
|
|
||||||
impl_match!(Ident, "identifier", Value::Ident(i) => i.clone());
|
|
||||||
impl_match!(bool, "bool", &Value::Bool(b) => b);
|
|
||||||
impl_match!(i64, "integer", &Value::Int(i) => i);
|
|
||||||
impl_match!(f64, "float",
|
|
||||||
&Value::Int(i) => i as f64,
|
|
||||||
&Value::Float(f) => f,
|
|
||||||
);
|
|
||||||
impl_match!(Abs, "length", &Value::Length(l) => Abs(l));
|
|
||||||
impl_match!(Rel, "relative", &Value::Relative(r) => Rel(r));
|
|
||||||
impl_match!(Linear, "linear",
|
|
||||||
&Value::Linear(l) => l,
|
|
||||||
&Value::Length(l) => Linear::abs(l),
|
|
||||||
&Value::Relative(r) => Linear::rel(r),
|
|
||||||
);
|
|
||||||
impl_match!(String, "string", Value::Str(s) => s.clone());
|
|
||||||
impl_match!(SynTree, "tree", Value::Tree(t) => t.clone());
|
|
||||||
impl_match!(DictValue, "dict", Value::Dict(t) => t.clone());
|
|
||||||
impl_match!(FuncValue, "function", Value::Func(f) => f.clone());
|
|
||||||
|
|
||||||
/// A value type that matches [length] values.
|
/// A value type that matches [length] values.
|
||||||
///
|
///
|
||||||
/// [length]: enum.Value.html#variant.Length
|
/// [length]: enum.Value.html#variant.Length
|
||||||
pub struct Abs(pub f64);
|
pub struct Absolute(pub f64);
|
||||||
|
|
||||||
impl From<Abs> for f64 {
|
impl From<Absolute> for f64 {
|
||||||
fn from(abs: Abs) -> f64 {
|
fn from(abs: Absolute) -> f64 {
|
||||||
abs.0
|
abs.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,10 +383,10 @@ impl From<Abs> for f64 {
|
|||||||
/// A value type that matches [relative] values.
|
/// A value type that matches [relative] values.
|
||||||
///
|
///
|
||||||
/// [relative]: enum.Value.html#variant.Relative
|
/// [relative]: enum.Value.html#variant.Relative
|
||||||
pub struct Rel(pub f64);
|
pub struct Relative(pub f64);
|
||||||
|
|
||||||
impl From<Rel> for f64 {
|
impl From<Relative> for f64 {
|
||||||
fn from(rel: Rel) -> f64 {
|
fn from(rel: Relative) -> f64 {
|
||||||
rel.0
|
rel.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,12 +411,31 @@ impl Deref for StringLike {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_match!(Value, "value", v => v.clone());
|
||||||
|
impl_match!(Ident, "identifier", Value::Ident(v) => v.clone());
|
||||||
|
impl_match!(bool, "bool", &Value::Bool(v) => v);
|
||||||
|
impl_match!(i64, "integer", &Value::Int(v) => v);
|
||||||
|
impl_match!(f64, "float",
|
||||||
|
&Value::Int(v) => v as f64,
|
||||||
|
&Value::Float(v) => v,
|
||||||
|
);
|
||||||
|
impl_match!(Absolute, "length", &Value::Length(v) => Absolute(v));
|
||||||
|
impl_match!(Relative, "relative", &Value::Relative(v) => Relative(v));
|
||||||
|
impl_match!(Linear, "linear",
|
||||||
|
&Value::Linear(v) => v,
|
||||||
|
&Value::Length(v) => Linear::abs(v),
|
||||||
|
&Value::Relative(v) => Linear::rel(v),
|
||||||
|
);
|
||||||
|
impl_match!(String, "string", Value::Str(v) => v.clone());
|
||||||
|
impl_match!(SynTree, "tree", Value::Content(v) => v.clone());
|
||||||
|
impl_match!(ValueDict, "dict", Value::Dict(v) => v.clone());
|
||||||
|
impl_match!(ValueFunc, "function", Value::Func(v) => v.clone());
|
||||||
impl_match!(StringLike, "identifier or string",
|
impl_match!(StringLike, "identifier or string",
|
||||||
Value::Ident(Ident(s)) => StringLike(s.clone()),
|
Value::Ident(Ident(v)) => StringLike(v.clone()),
|
||||||
Value::Str(s) => StringLike(s.clone()),
|
Value::Str(v) => StringLike(v.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
impl_ident!(Dir, "direction", |s| match s {
|
impl_ident!(Dir, "direction", |v| match v {
|
||||||
"ltr" => Some(Self::LTR),
|
"ltr" => Some(Self::LTR),
|
||||||
"rtl" => Some(Self::RTL),
|
"rtl" => Some(Self::RTL),
|
||||||
"ttb" => Some(Self::TTB),
|
"ttb" => Some(Self::TTB),
|
||||||
@ -445,7 +443,7 @@ impl_ident!(Dir, "direction", |s| match s {
|
|||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
|
|
||||||
impl_ident!(SpecAlign, "alignment", |s| match s {
|
impl_ident!(SpecAlign, "alignment", |v| match v {
|
||||||
"left" => Some(Self::Left),
|
"left" => Some(Self::Left),
|
||||||
"right" => Some(Self::Right),
|
"right" => Some(Self::Right),
|
||||||
"top" => Some(Self::Top),
|
"top" => Some(Self::Top),
|
||||||
@ -486,7 +484,7 @@ impl TryFromValue for FontWeight {
|
|||||||
error!(
|
error!(
|
||||||
@f, value.span,
|
@f, value.span,
|
||||||
"expected font weight (name or integer), found {}",
|
"expected font weight (name or integer), found {}",
|
||||||
other.name(),
|
other.ty(),
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -499,7 +497,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn entry(value: Value) -> SpannedEntry<Value> {
|
fn entry(value: Value) -> SpannedEntry<Value> {
|
||||||
SpannedEntry::val(Spanned::zero(value))
|
SpannedEntry::value(Spanned::zero(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -14,7 +14,7 @@ use super::*;
|
|||||||
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
/// - `vertical`: Any of `top`, `bottom` or `center`.
|
||||||
///
|
///
|
||||||
/// There may not be two alignment specifications for the same axis.
|
/// There may not be two alignment specifications for the same axis.
|
||||||
pub async fn align(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn align(mut args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
let content = args.take::<SynTree>();
|
let content = args.take::<SynTree>();
|
||||||
let h = args.take_key::<Spanned<SpecAlign>>("horizontal", &mut ctx.f);
|
let h = args.take_key::<Spanned<SpecAlign>>("horizontal", &mut ctx.f);
|
||||||
let v = args.take_key::<Spanned<SpecAlign>>("vertical", &mut ctx.f);
|
let v = args.take_key::<Spanned<SpecAlign>>("vertical", &mut ctx.f);
|
||||||
|
@ -6,7 +6,7 @@ use crate::geom::Linear;
|
|||||||
/// # Keyword arguments
|
/// # Keyword arguments
|
||||||
/// - `width`: The width of the box (length or relative to parent's width).
|
/// - `width`: The width of the box (length or relative to parent's width).
|
||||||
/// - `height`: The height of the box (length or relative to parent's height).
|
/// - `height`: The height of the box (length or relative to parent's height).
|
||||||
pub async fn boxed(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn boxed(mut args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
let content = args.take::<SynTree>().unwrap_or_default();
|
let content = args.take::<SynTree>().unwrap_or_default();
|
||||||
|
|
||||||
let constraints = &mut ctx.constraints;
|
let constraints = &mut ctx.constraints;
|
||||||
|
@ -2,7 +2,7 @@ use super::*;
|
|||||||
use crate::color::RgbaColor;
|
use crate::color::RgbaColor;
|
||||||
|
|
||||||
/// `rgb`: Create an RGB(A) color.
|
/// `rgb`: Create an RGB(A) color.
|
||||||
pub async fn rgb(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn rgb(mut args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
let mut f = Feedback::new();
|
let mut f = Feedback::new();
|
||||||
|
|
||||||
let r = args.expect::<Spanned<i64>>("red value", Span::ZERO, &mut f);
|
let r = args.expect::<Spanned<i64>>("red value", Span::ZERO, &mut f);
|
||||||
|
@ -49,7 +49,7 @@ use crate::geom::Linear;
|
|||||||
/// ```typst
|
/// ```typst
|
||||||
/// [font: "My Serif", serif]
|
/// [font: "My Serif", serif]
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn font(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn font(mut args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
let mut text = ctx.state.text.clone();
|
let mut text = ctx.state.text.clone();
|
||||||
let mut updated_fallback = false;
|
let mut updated_fallback = false;
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ pub async fn font(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
|||||||
text.variant.stretch = stretch;
|
text.variant.stretch = stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (class, mut dict) in args.take_all_str::<DictValue>() {
|
for (class, mut dict) in args.take_all_str::<ValueDict>() {
|
||||||
let fallback = dict
|
let fallback = dict
|
||||||
.take_all_num_vals::<StringLike>()
|
.take_all_num_vals::<StringLike>()
|
||||||
.map(|s| s.to_lowercase())
|
.map(|s| s.to_lowercase())
|
||||||
|
@ -14,7 +14,7 @@ pub use font::*;
|
|||||||
pub use page::*;
|
pub use page::*;
|
||||||
pub use spacing::*;
|
pub use spacing::*;
|
||||||
|
|
||||||
use crate::eval::{FuncValue, Scope};
|
use crate::eval::{Scope, ValueFunc};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
macro_rules! std {
|
macro_rules! std {
|
||||||
@ -30,7 +30,7 @@ macro_rules! std {
|
|||||||
|
|
||||||
macro_rules! wrap {
|
macro_rules! wrap {
|
||||||
($func:expr) => {
|
($func:expr) => {
|
||||||
FuncValue::new(|args, ctx| Box::pin($func(args, ctx)))
|
ValueFunc::new(|args, ctx| Box::pin($func(args, ctx)))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::eval::Abs;
|
use crate::eval::Absolute;
|
||||||
use crate::geom::{Linear, Sides};
|
use crate::geom::{Linear, Sides};
|
||||||
use crate::paper::{Paper, PaperClass};
|
use crate::paper::{Paper, PaperClass};
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ use crate::paper::{Paper, PaperClass};
|
|||||||
/// - `top`: The top margin (length or relative to height).
|
/// - `top`: The top margin (length or relative to height).
|
||||||
/// - `bottom`: The bottom margin (length or relative to height).
|
/// - `bottom`: The bottom margin (length or relative to height).
|
||||||
/// - `flip`: Flips custom or paper-defined width and height (boolean).
|
/// - `flip`: Flips custom or paper-defined width and height (boolean).
|
||||||
pub async fn page(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn page(mut args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
let mut page = ctx.state.page.clone();
|
let mut page = ctx.state.page.clone();
|
||||||
|
|
||||||
if let Some(paper) = args.take::<Paper>() {
|
if let Some(paper) = args.take::<Paper>() {
|
||||||
@ -27,12 +27,12 @@ pub async fn page(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
|||||||
page.size = paper.size();
|
page.size = paper.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Abs(width)) = args.take_key::<Abs>("width", &mut ctx.f) {
|
if let Some(Absolute(width)) = args.take_key::<Absolute>("width", &mut ctx.f) {
|
||||||
page.class = PaperClass::Custom;
|
page.class = PaperClass::Custom;
|
||||||
page.size.width = width;
|
page.size.width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Abs(height)) = args.take_key::<Abs>("height", &mut ctx.f) {
|
if let Some(Absolute(height)) = args.take_key::<Absolute>("height", &mut ctx.f) {
|
||||||
page.class = PaperClass::Custom;
|
page.class = PaperClass::Custom;
|
||||||
page.size.height = height;
|
page.size.height = height;
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ pub async fn page(mut args: DictValue, ctx: &mut LayoutContext) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `pagebreak`: Ends the current page.
|
/// `pagebreak`: Ends the current page.
|
||||||
pub async fn pagebreak(args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn pagebreak(args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
args.unexpected(&mut ctx.f);
|
args.unexpected(&mut ctx.f);
|
||||||
Value::Commands(vec![BreakPage])
|
Value::Commands(vec![BreakPage])
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::layout::SpacingKind;
|
|||||||
///
|
///
|
||||||
/// # Positional arguments
|
/// # Positional arguments
|
||||||
/// - The spacing (length or relative to font size).
|
/// - The spacing (length or relative to font size).
|
||||||
pub async fn h(args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn h(args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
spacing(args, ctx, SpecAxis::Horizontal)
|
spacing(args, ctx, SpecAxis::Horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,11 +14,11 @@ pub async fn h(args: DictValue, ctx: &mut LayoutContext) -> Value {
|
|||||||
///
|
///
|
||||||
/// # Positional arguments
|
/// # Positional arguments
|
||||||
/// - The spacing (length or relative to font size).
|
/// - The spacing (length or relative to font size).
|
||||||
pub async fn v(args: DictValue, ctx: &mut LayoutContext) -> Value {
|
pub async fn v(args: ValueDict, ctx: &mut LayoutContext) -> Value {
|
||||||
spacing(args, ctx, SpecAxis::Vertical)
|
spacing(args, ctx, SpecAxis::Vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spacing(mut args: DictValue, ctx: &mut LayoutContext, axis: SpecAxis) -> Value {
|
fn spacing(mut args: ValueDict, ctx: &mut LayoutContext, axis: SpecAxis) -> Value {
|
||||||
let spacing = args.expect::<Linear>("spacing", Span::ZERO, &mut ctx.f);
|
let spacing = args.expect::<Linear>("spacing", Span::ZERO, &mut ctx.f);
|
||||||
args.unexpected(&mut ctx.f);
|
args.unexpected(&mut ctx.f);
|
||||||
Value::Commands(if let Some(spacing) = spacing {
|
Value::Commands(if let Some(spacing) = spacing {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! A prelude for building custom functions.
|
//! A prelude for building custom functions.
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::eval::{Dict, DictValue, Value};
|
pub use crate::eval::{Dict, Value, ValueDict};
|
||||||
pub use crate::layout::primitive::*;
|
pub use crate::layout::primitive::*;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::layout::{layout_tree, Command, Commands, LayoutContext};
|
pub use crate::layout::{layout_tree, Command, Commands, LayoutContext};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Expressions.
|
//! Expressions.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::eval::Value;
|
use crate::eval::Value;
|
||||||
use crate::layout::LayoutContext;
|
use crate::layout::LayoutContext;
|
||||||
use crate::syntax::{Decoration, Ident, Lit, LitDict, SpanWith, Spanned};
|
|
||||||
use crate::DynFuture;
|
use crate::DynFuture;
|
||||||
|
|
||||||
/// An expression.
|
/// An expression.
|
||||||
@ -10,12 +10,12 @@ use crate::DynFuture;
|
|||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// A literal: `true`, `1cm`, `"hi"`, `{_Hey!_}`.
|
/// A literal: `true`, `1cm`, `"hi"`, `{_Hey!_}`.
|
||||||
Lit(Lit),
|
Lit(Lit),
|
||||||
|
/// An invocation of a function: `[foo: ...]`, `foo(...)`.
|
||||||
|
Call(ExprCall),
|
||||||
/// A unary operation: `-x`.
|
/// A unary operation: `-x`.
|
||||||
Unary(ExprUnary),
|
Unary(ExprUnary),
|
||||||
/// A binary operation: `a + b`, `a / b`.
|
/// A binary operation: `a + b`, `a / b`.
|
||||||
Binary(ExprBinary),
|
Binary(ExprBinary),
|
||||||
/// An invocation of a function: `[foo: ...]`, `foo(...)`.
|
|
||||||
Call(ExprCall),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
@ -24,14 +24,43 @@ impl Expr {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
match self {
|
match self {
|
||||||
Self::Lit(lit) => lit.eval(ctx).await,
|
Self::Lit(lit) => lit.eval(ctx).await,
|
||||||
|
Self::Call(call) => call.eval(ctx).await,
|
||||||
Self::Unary(unary) => unary.eval(ctx).await,
|
Self::Unary(unary) => unary.eval(ctx).await,
|
||||||
Self::Binary(binary) => binary.eval(ctx).await,
|
Self::Binary(binary) => binary.eval(ctx).await,
|
||||||
Self::Call(call) => call.eval(ctx).await,
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An invocation of a function: `[foo: ...]`, `foo(...)`.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ExprCall {
|
||||||
|
/// The name of the function.
|
||||||
|
pub name: Spanned<Ident>,
|
||||||
|
/// The arguments to the function.
|
||||||
|
pub args: LitDict,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExprCall {
|
||||||
|
/// Evaluate the call expression to a value.
|
||||||
|
pub async fn eval(&self, ctx: &mut LayoutContext) -> Value {
|
||||||
|
let name = &self.name.v;
|
||||||
|
let span = self.name.span;
|
||||||
|
let args = self.args.eval(ctx).await;
|
||||||
|
|
||||||
|
if let Some(func) = ctx.state.scope.func(name) {
|
||||||
|
ctx.f.decorations.push(Decoration::Resolved.span_with(span));
|
||||||
|
(func.clone())(args, ctx).await
|
||||||
|
} else {
|
||||||
|
if !name.is_empty() {
|
||||||
|
error!(@ctx.f, span, "unknown function");
|
||||||
|
ctx.f.decorations.push(Decoration::Unresolved.span_with(span));
|
||||||
|
}
|
||||||
|
Value::Dict(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A unary operation: `-x`.
|
/// A unary operation: `-x`.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ExprUnary {
|
pub struct ExprUnary {
|
||||||
@ -54,13 +83,13 @@ impl ExprUnary {
|
|||||||
let span = self.op.span.join(self.expr.span);
|
let span = self.op.span.join(self.expr.span);
|
||||||
match self.op.v {
|
match self.op.v {
|
||||||
UnOp::Neg => match value {
|
UnOp::Neg => match value {
|
||||||
Int(x) => Int(-x),
|
Int(v) => Int(-v),
|
||||||
Float(x) => Float(-x),
|
Float(v) => Float(-v),
|
||||||
Length(x) => Length(-x),
|
Length(v) => Length(-v),
|
||||||
Relative(x) => Relative(-x),
|
Relative(v) => Relative(-v),
|
||||||
Linear(x) => Linear(-x),
|
Linear(v) => Linear(-v),
|
||||||
v => {
|
v => {
|
||||||
error!(@ctx.f, span, "cannot negate {}", v.name());
|
error!(@ctx.f, span, "cannot negate {}", v.ty());
|
||||||
Value::Error
|
Value::Error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -104,7 +133,8 @@ impl ExprBinary {
|
|||||||
BinOp::Add => match (lhs, rhs) {
|
BinOp::Add => match (lhs, rhs) {
|
||||||
// Numbers to themselves.
|
// Numbers to themselves.
|
||||||
(Int(a), Int(b)) => Int(a + b),
|
(Int(a), Int(b)) => Int(a + b),
|
||||||
(Int(i), Float(f)) | (Float(f), Int(i)) => Float(i as f64 + f),
|
(Int(a), Float(b)) => Float(a as f64 + b),
|
||||||
|
(Float(a), Int(b)) => Float(a + b as f64),
|
||||||
(Float(a), Float(b)) => Float(a + b),
|
(Float(a), Float(b)) => Float(a + b),
|
||||||
|
|
||||||
// Lengths, relatives and linears to themselves.
|
// Lengths, relatives and linears to themselves.
|
||||||
@ -123,11 +153,11 @@ impl ExprBinary {
|
|||||||
// Complex data types to themselves.
|
// Complex data types to themselves.
|
||||||
(Str(a), Str(b)) => Str(a + &b),
|
(Str(a), Str(b)) => Str(a + &b),
|
||||||
(Dict(a), Dict(b)) => Dict(concat(a, b)),
|
(Dict(a), Dict(b)) => Dict(concat(a, b)),
|
||||||
(Tree(a), Tree(b)) => Tree(concat(a, b)),
|
(Content(a), Content(b)) => Content(concat(a, b)),
|
||||||
(Commands(a), Commands(b)) => Commands(concat(a, b)),
|
(Commands(a), Commands(b)) => Commands(concat(a, b)),
|
||||||
|
|
||||||
(a, b) => {
|
(a, b) => {
|
||||||
error!(@ctx.f, span, "cannot add {} and {}", a.name(), b.name());
|
error!(@ctx.f, span, "cannot add {} and {}", a.ty(), b.ty());
|
||||||
Value::Error
|
Value::Error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -151,7 +181,7 @@ impl ExprBinary {
|
|||||||
(Linear(a), Linear(b)) => Linear(a - b),
|
(Linear(a), Linear(b)) => Linear(a - b),
|
||||||
|
|
||||||
(a, b) => {
|
(a, b) => {
|
||||||
error!(@ctx.f, span, "cannot subtract {1} from {0}", a.name(), b.name());
|
error!(@ctx.f, span, "cannot subtract {1} from {0}", a.ty(), b.ty());
|
||||||
Value::Error
|
Value::Error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -182,7 +212,7 @@ impl ExprBinary {
|
|||||||
(Str(a), Int(b)) => Str(a.repeat(b.max(0) as usize)),
|
(Str(a), Int(b)) => Str(a.repeat(b.max(0) as usize)),
|
||||||
|
|
||||||
(a, b) => {
|
(a, b) => {
|
||||||
error!(@ctx.f, span, "cannot multiply {} with {}", a.name(), b.name());
|
error!(@ctx.f, span, "cannot multiply {} with {}", a.ty(), b.ty());
|
||||||
Value::Error
|
Value::Error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -203,7 +233,7 @@ impl ExprBinary {
|
|||||||
(Linear(a), Float(b)) => Linear(a / b),
|
(Linear(a), Float(b)) => Linear(a / b),
|
||||||
|
|
||||||
(a, b) => {
|
(a, b) => {
|
||||||
error!(@ctx.f, span, "cannot divide {} by {}", a.name(), b.name());
|
error!(@ctx.f, span, "cannot divide {} by {}", a.ty(), b.ty());
|
||||||
Value::Error
|
Value::Error
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -232,32 +262,3 @@ pub enum BinOp {
|
|||||||
/// The division operator: `/`.
|
/// The division operator: `/`.
|
||||||
Div,
|
Div,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An invocation of a function: `[foo: ...]`, `foo(...)`.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct ExprCall {
|
|
||||||
/// The name of the function.
|
|
||||||
pub name: Spanned<Ident>,
|
|
||||||
/// The arguments to the function.
|
|
||||||
pub args: LitDict,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprCall {
|
|
||||||
/// Evaluate the call expression to a value.
|
|
||||||
pub async fn eval(&self, ctx: &mut LayoutContext) -> Value {
|
|
||||||
let name = &self.name.v;
|
|
||||||
let span = self.name.span;
|
|
||||||
let args = self.args.eval(ctx).await;
|
|
||||||
|
|
||||||
if let Some(func) = ctx.state.scope.func(name) {
|
|
||||||
ctx.f.decorations.push(Decoration::Resolved.span_with(span));
|
|
||||||
(func.clone())(args, ctx).await
|
|
||||||
} else {
|
|
||||||
if !name.is_empty() {
|
|
||||||
error!(@ctx.f, span, "unknown function");
|
|
||||||
ctx.f.decorations.push(Decoration::Unresolved.span_with(span));
|
|
||||||
}
|
|
||||||
Value::Dict(args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
//! Literals.
|
//! Literals.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::color::RgbaColor;
|
use crate::color::RgbaColor;
|
||||||
use crate::eval::{DictKey, DictValue, SpannedEntry, Value};
|
use crate::eval::{DictKey, SpannedEntry, Value, ValueDict};
|
||||||
use crate::layout::LayoutContext;
|
use crate::layout::LayoutContext;
|
||||||
use crate::length::Length;
|
use crate::length::Length;
|
||||||
use crate::syntax::{Expr, Ident, SpanWith, Spanned, SynTree};
|
|
||||||
use crate::DynFuture;
|
use crate::DynFuture;
|
||||||
|
|
||||||
/// A literal.
|
/// A literal.
|
||||||
@ -41,16 +41,16 @@ impl Lit {
|
|||||||
/// Evaluate the dictionary literal to a dictionary value.
|
/// Evaluate the dictionary literal to a dictionary value.
|
||||||
pub async fn eval(&self, ctx: &mut LayoutContext) -> Value {
|
pub async fn eval(&self, ctx: &mut LayoutContext) -> Value {
|
||||||
match *self {
|
match *self {
|
||||||
Lit::Ident(ref i) => Value::Ident(i.clone()),
|
Lit::Ident(ref v) => Value::Ident(v.clone()),
|
||||||
Lit::Bool(b) => Value::Bool(b),
|
Lit::Bool(v) => Value::Bool(v),
|
||||||
Lit::Int(i) => Value::Int(i),
|
Lit::Int(v) => Value::Int(v),
|
||||||
Lit::Float(f) => Value::Float(f),
|
Lit::Float(v) => Value::Float(v),
|
||||||
Lit::Length(l) => Value::Length(l.as_raw()),
|
Lit::Length(v) => Value::Length(v.as_raw()),
|
||||||
Lit::Percent(p) => Value::Relative(p / 100.0),
|
Lit::Percent(v) => Value::Relative(v / 100.0),
|
||||||
Lit::Color(c) => Value::Color(c),
|
Lit::Color(v) => Value::Color(v),
|
||||||
Lit::Str(ref s) => Value::Str(s.clone()),
|
Lit::Str(ref v) => Value::Str(v.clone()),
|
||||||
Lit::Dict(ref d) => Value::Dict(d.eval(ctx).await),
|
Lit::Dict(ref v) => Value::Dict(v.eval(ctx).await),
|
||||||
Lit::Content(ref c) => Value::Tree(c.clone()),
|
Lit::Content(ref v) => Value::Content(v.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,9 +66,9 @@ impl LitDict {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the dictionary literal to a dictionary value.
|
/// Evaluate the dictionary literal to a dictionary value.
|
||||||
pub fn eval<'a>(&'a self, ctx: &'a mut LayoutContext) -> DynFuture<'a, DictValue> {
|
pub fn eval<'a>(&'a self, ctx: &'a mut LayoutContext) -> DynFuture<'a, ValueDict> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut dict = DictValue::new();
|
let mut dict = ValueDict::new();
|
||||||
|
|
||||||
for entry in &self.0 {
|
for entry in &self.0 {
|
||||||
let val = entry.expr.v.eval(ctx).await;
|
let val = entry.expr.v.eval(ctx).await;
|
||||||
@ -76,7 +76,7 @@ impl LitDict {
|
|||||||
if let Some(key) = &entry.key {
|
if let Some(key) = &entry.key {
|
||||||
dict.insert(&key.v, SpannedEntry::new(key.span, spanned));
|
dict.insert(&key.v, SpannedEntry::new(key.span, spanned));
|
||||||
} else {
|
} else {
|
||||||
dict.push(SpannedEntry::val(spanned));
|
dict.push(SpannedEntry::value(spanned));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,3 +7,5 @@ mod tree;
|
|||||||
pub use expr::*;
|
pub use expr::*;
|
||||||
pub use lit::*;
|
pub use lit::*;
|
||||||
pub use tree::*;
|
pub use tree::*;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! The syntax tree.
|
//! The syntax tree.
|
||||||
|
|
||||||
use crate::syntax::{Expr, Ident, SpanVec, Spanned};
|
use super::*;
|
||||||
|
|
||||||
/// A collection of nodes which form a tree together with the nodes' children.
|
/// A collection of nodes which form a tree together with the nodes' children.
|
||||||
pub type SynTree = SpanVec<SynNode>;
|
pub type SynTree = SpanVec<SynNode>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user