summaryrefslogtreecommitdiff
path: root/src/eval
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval')
-rw-r--r--src/eval/convert.rs152
-rw-r--r--src/eval/mod.rs47
-rw-r--r--src/eval/state.rs40
-rw-r--r--src/eval/value.rs11
4 files changed, 110 insertions, 140 deletions
diff --git a/src/eval/convert.rs b/src/eval/convert.rs
index 4c177c5b..69ef2506 100644
--- a/src/eval/convert.rs
+++ b/src/eval/convert.rs
@@ -6,8 +6,7 @@ use fontdock::{FontStretch, FontStyle, FontWeight};
use super::{Value, ValueDict, ValueFunc};
use crate::diag::Diag;
-use crate::geom::Linear;
-use crate::layout::{Dir, SpecAlign};
+use crate::geom::{Dir, Length, Linear, Relative};
use crate::paper::Paper;
use crate::syntax::{Ident, SpanWith, Spanned, SynTree};
@@ -37,26 +36,53 @@ impl<T: Convert> Convert for Spanned<T> {
}
}
-/// A value type that matches [length] values.
-///
-/// [length]: enum.Value.html#variant.Length
-pub struct Absolute(pub f64);
-
-impl From<Absolute> for f64 {
- fn from(abs: Absolute) -> f64 {
- abs.0
- }
+macro_rules! convert_match {
+ ($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => {
+ impl $crate::eval::Convert for $type {
+ fn convert(
+ value: $crate::syntax::Spanned<$crate::eval::Value>
+ ) -> (Result<Self, $crate::eval::Value>, Option<$crate::diag::Diag>) {
+ #[allow(unreachable_patterns)]
+ match value.v {
+ $($p => (Ok($r), None)),*,
+ v => {
+ let err = $crate::error!("expected {}, found {}", $name, v.ty());
+ (Err(v), Some(err))
+ },
+ }
+ }
+ }
+ };
}
-/// A value type that matches [relative] values.
-///
-/// [relative]: enum.Value.html#variant.Relative
-pub struct Relative(pub f64);
-
-impl From<Relative> for f64 {
- fn from(rel: Relative) -> f64 {
- rel.0
- }
+macro_rules! convert_ident {
+ ($type:ty, $name:expr, $parse:expr) => {
+ impl $crate::eval::Convert for $type {
+ fn convert(
+ value: $crate::syntax::Spanned<$crate::eval::Value>,
+ ) -> (
+ Result<Self, $crate::eval::Value>,
+ Option<$crate::diag::Diag>,
+ ) {
+ match value.v {
+ Value::Ident(id) => {
+ if let Some(thing) = $parse(&id) {
+ (Ok(thing), None)
+ } else {
+ (
+ Err($crate::eval::Value::Ident(id)),
+ Some($crate::error!("invalid {}", $name)),
+ )
+ }
+ }
+ v => {
+ let err = $crate::error!("expected {}, found {}", $name, v.ty());
+ (Err(v), Some(err))
+ }
+ }
+ }
+ }
+ };
}
/// A value type that matches [identifier] and [string] values.
@@ -79,70 +105,31 @@ impl Deref for StringLike {
}
}
-macro_rules! impl_match {
- ($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => {
- impl Convert for $type {
- fn convert(value: Spanned<Value>) -> (Result<Self, Value>, Option<Diag>) {
- #[allow(unreachable_patterns)]
- match value.v {
- $($p => (Ok($r), None)),*,
- v => {
- let err = error!("expected {}, found {}", $name, v.ty());
- (Err(v), Some(err))
- },
- }
- }
- }
- };
-}
-
-impl_match!(Value, "value", v => v);
-impl_match!(Ident, "identifier", Value::Ident(v) => v);
-impl_match!(bool, "bool", Value::Bool(v) => v);
-impl_match!(i64, "integer", Value::Int(v) => v);
-impl_match!(f64, "float",
+convert_match!(Value, "value", v => v);
+convert_match!(Ident, "identifier", Value::Ident(v) => v);
+convert_match!(bool, "bool", Value::Bool(v) => v);
+convert_match!(i64, "integer", Value::Int(v) => v);
+convert_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",
+convert_match!(Length, "length", Value::Length(v) => v);
+convert_match!(Relative, "relative", Value::Relative(v) => v);
+convert_match!(Linear, "linear",
Value::Linear(v) => v,
- Value::Length(v) => Linear::abs(v),
- Value::Relative(v) => Linear::rel(v),
+ Value::Length(v) => v.into(),
+ Value::Relative(v) => v.into(),
);
-impl_match!(String, "string", Value::Str(v) => v);
-impl_match!(SynTree, "tree", Value::Content(v) => v);
-impl_match!(ValueDict, "dictionary", Value::Dict(v) => v);
-impl_match!(ValueFunc, "function", Value::Func(v) => v);
-impl_match!(StringLike, "identifier or string",
+convert_match!(String, "string", Value::Str(v) => v);
+convert_match!(SynTree, "tree", Value::Content(v) => v);
+convert_match!(ValueDict, "dictionary", Value::Dict(v) => v);
+convert_match!(ValueFunc, "function", Value::Func(v) => v);
+convert_match!(StringLike, "identifier or string",
Value::Ident(Ident(v)) => StringLike(v),
Value::Str(v) => StringLike(v),
);
-macro_rules! impl_ident {
- ($type:ty, $name:expr, $parse:expr) => {
- impl Convert for $type {
- fn convert(value: Spanned<Value>) -> (Result<Self, Value>, Option<Diag>) {
- match value.v {
- Value::Ident(id) => {
- if let Some(thing) = $parse(&id) {
- (Ok(thing), None)
- } else {
- (Err(Value::Ident(id)), Some(error!("invalid {}", $name)))
- }
- }
- v => {
- let err = error!("expected {}, found {}", $name, v.ty());
- (Err(v), Some(err))
- }
- }
- }
- }
- };
-}
-
-impl_ident!(Dir, "direction", |v| match v {
+convert_ident!(Dir, "direction", |v| match v {
"ltr" => Some(Self::LTR),
"rtl" => Some(Self::RTL),
"ttb" => Some(Self::TTB),
@@ -150,18 +137,9 @@ impl_ident!(Dir, "direction", |v| match v {
_ => None,
});
-impl_ident!(SpecAlign, "alignment", |v| match v {
- "left" => Some(Self::Left),
- "right" => Some(Self::Right),
- "top" => Some(Self::Top),
- "bottom" => Some(Self::Bottom),
- "center" => Some(Self::Center),
- _ => None,
-});
-
-impl_ident!(FontStyle, "font style", Self::from_str);
-impl_ident!(FontStretch, "font stretch", Self::from_str);
-impl_ident!(Paper, "paper", Self::from_name);
+convert_ident!(FontStyle, "font style", Self::from_str);
+convert_ident!(FontStretch, "font stretch", Self::from_str);
+convert_ident!(Paper, "paper", Self::from_name);
impl Convert for FontWeight {
fn convert(value: Spanned<Value>) -> (Result<Self, Value>, Option<Diag>) {
diff --git a/src/eval/mod.rs b/src/eval/mod.rs
index 2c6f4d7c..fc8bbbd6 100644
--- a/src/eval/mod.rs
+++ b/src/eval/mod.rs
@@ -1,7 +1,8 @@
//! Evaluation of syntax trees.
-mod args;
+#[macro_use]
mod convert;
+mod args;
mod dict;
mod scope;
mod state;
@@ -22,10 +23,10 @@ use fontdock::FontStyle;
use crate::diag::Diag;
use crate::diag::{Deco, Feedback, Pass};
-use crate::layout::nodes::{
+use crate::geom::{Gen, Length, Relative, Spec, Switch};
+use crate::layout::{
Document, LayoutNode, Pad, Pages, Par, Softness, Spacing, Stack, Text,
};
-use crate::layout::{Gen2, Spec2, Switch};
use crate::syntax::*;
/// Evaluate a syntax tree into a document.
@@ -168,7 +169,7 @@ impl EvalContext {
dirs,
children,
aligns,
- expand: Spec2::new(true, true),
+ expand: Spec::new(true, true),
}),
}),
})
@@ -195,7 +196,7 @@ impl EvalContext {
line_spacing,
children,
aligns,
- expand: Gen2::new(false, expand_cross).switch(dirs),
+ expand: Gen::new(false, expand_cross).switch(dirs),
});
}
}
@@ -337,7 +338,7 @@ impl Eval for NodeRaw {
dirs: ctx.state.dirs,
children,
aligns: ctx.state.aligns,
- expand: Spec2::new(false, false),
+ expand: Spec::new(false, false),
});
ctx.state.text.fallback = prev;
@@ -366,8 +367,8 @@ impl Eval for Lit {
Lit::Bool(v) => Value::Bool(v),
Lit::Int(v) => Value::Int(v),
Lit::Float(v) => Value::Float(v),
- Lit::Length(v) => Value::Length(v.as_raw()),
- Lit::Percent(v) => Value::Relative(v / 100.0),
+ Lit::Length(v, unit) => Value::Length(Length::with_unit(v, unit)),
+ Lit::Percent(v) => Value::Relative(Relative::new(v / 100.0)),
Lit::Color(v) => Value::Color(v),
Lit::Str(ref v) => Value::Str(v.clone()),
Lit::Dict(ref v) => Value::Dict(v.eval(ctx)),
@@ -473,7 +474,6 @@ fn neg(ctx: &mut EvalContext, span: Span, value: Value) -> Value {
/// Compute the sum of two values.
fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
- use crate::geom::Linear as Lin;
use Value::*;
match (lhs, rhs) {
// Numbers to themselves.
@@ -484,15 +484,15 @@ fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
// Lengths, relatives and linears to themselves.
(Length(a), Length(b)) => Length(a + b),
- (Length(a), Relative(b)) => Linear(Lin::abs(a) + Lin::rel(b)),
- (Length(a), Linear(b)) => Linear(Lin::abs(a) + b),
+ (Length(a), Relative(b)) => Linear(a + b),
+ (Length(a), Linear(b)) => Linear(a + b),
- (Relative(a), Length(b)) => Linear(Lin::rel(a) + Lin::abs(b)),
+ (Relative(a), Length(b)) => Linear(a + b),
(Relative(a), Relative(b)) => Relative(a + b),
- (Relative(a), Linear(b)) => Linear(Lin::rel(a) + b),
+ (Relative(a), Linear(b)) => Linear(a + b),
- (Linear(a), Length(b)) => Linear(a + Lin::abs(b)),
- (Linear(a), Relative(b)) => Linear(a + Lin::rel(b)),
+ (Linear(a), Length(b)) => Linear(a + b),
+ (Linear(a), Relative(b)) => Linear(a + b),
(Linear(a), Linear(b)) => Linear(a + b),
// Complex data types to themselves.
@@ -509,7 +509,6 @@ fn add(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
/// Compute the difference of two values.
fn sub(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
- use crate::geom::Linear as Lin;
use Value::*;
match (lhs, rhs) {
// Numbers from themselves.
@@ -520,13 +519,13 @@ fn sub(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
// Lengths, relatives and linears from themselves.
(Length(a), Length(b)) => Length(a - b),
- (Length(a), Relative(b)) => Linear(Lin::abs(a) - Lin::rel(b)),
- (Length(a), Linear(b)) => Linear(Lin::abs(a) - b),
- (Relative(a), Length(b)) => Linear(Lin::rel(a) - Lin::abs(b)),
+ (Length(a), Relative(b)) => Linear(a - b),
+ (Length(a), Linear(b)) => Linear(a - b),
+ (Relative(a), Length(b)) => Linear(a - b),
(Relative(a), Relative(b)) => Relative(a - b),
- (Relative(a), Linear(b)) => Linear(Lin::rel(a) - b),
- (Linear(a), Length(b)) => Linear(a - Lin::abs(b)),
- (Linear(a), Relative(b)) => Linear(a - Lin::rel(b)),
+ (Relative(a), Linear(b)) => Linear(a - b),
+ (Linear(a), Length(b)) => Linear(a - b),
+ (Linear(a), Relative(b)) => Linear(a - b),
(Linear(a), Linear(b)) => Linear(a - b),
(a, b) => {
@@ -561,8 +560,8 @@ fn mul(ctx: &mut EvalContext, span: Span, lhs: Value, rhs: Value) -> Value {
(Float(a), Linear(b)) => Linear(a * b),
// Integers with strings.
- (Int(a), Str(b)) => Str(b.repeat(a.max(0) as usize)),
- (Str(a), Int(b)) => Str(a.repeat(b.max(0) as usize)),
+ (Int(a), Str(b)) => Str(b.repeat(0.max(a) as usize)),
+ (Str(a), Int(b)) => Str(a.repeat(0.max(b) as usize)),
(a, b) => {
ctx.diag(error!(span, "cannot multiply {} with {}", a.ty(), b.ty()));
diff --git a/src/eval/state.rs b/src/eval/state.rs
index 7372b851..3ae6b414 100644
--- a/src/eval/state.rs
+++ b/src/eval/state.rs
@@ -5,9 +5,7 @@ use std::rc::Rc;
use fontdock::{fallback, FallbackTree, FontStretch, FontStyle, FontVariant, FontWeight};
use super::Scope;
-use crate::geom::{Linear, Size};
-use crate::layout::{Dir, Gen2, GenAlign, Sides};
-use crate::length::Length;
+use crate::geom::{Align, Dir, Gen, Length, Linear, Relative, Sides, Size};
use crate::paper::{Paper, PaperClass, PAPER_A4};
/// The active evaluation state.
@@ -20,9 +18,9 @@ pub struct State {
/// The page state.
pub page: PageState,
/// The active layouting directions.
- pub dirs: Gen2<Dir>,
+ pub dirs: Gen<Dir>,
/// The active alignments.
- pub aligns: Gen2<GenAlign>,
+ pub aligns: Gen<Align>,
}
impl Default for State {
@@ -31,8 +29,8 @@ impl Default for State {
scope: crate::library::_std(),
text: TextState::default(),
page: PageState::default(),
- dirs: Gen2::new(Dir::TTB, Dir::LTR),
- aligns: Gen2::new(GenAlign::Start, GenAlign::Start),
+ dirs: Gen::new(Dir::TTB, Dir::LTR),
+ aligns: Gen::new(Align::Start, Align::Start),
}
}
}
@@ -62,22 +60,22 @@ pub struct TextState {
impl TextState {
/// The absolute font size.
- pub fn font_size(&self) -> f64 {
+ pub fn font_size(&self) -> Length {
self.font_size.eval()
}
/// The absolute word spacing.
- pub fn word_spacing(&self) -> f64 {
+ pub fn word_spacing(&self) -> Length {
self.word_spacing.eval(self.font_size())
}
/// The absolute line spacing.
- pub fn line_spacing(&self) -> f64 {
+ pub fn line_spacing(&self) -> Length {
self.line_spacing.eval(self.font_size())
}
/// The absolute paragraph spacing.
- pub fn par_spacing(&self) -> f64 {
+ pub fn par_spacing(&self) -> Length {
self.par_spacing.eval(self.font_size())
}
}
@@ -105,10 +103,10 @@ impl Default for TextState {
},
strong: false,
emph: false,
- font_size: FontSize::abs(Length::pt(11.0).as_raw()),
- word_spacing: Linear::rel(0.25),
- line_spacing: Linear::rel(0.2),
- par_spacing: Linear::rel(0.5),
+ font_size: FontSize::abs(Length::pt(11.0)),
+ word_spacing: Relative::new(0.25).into(),
+ line_spacing: Relative::new(0.2).into(),
+ par_spacing: Relative::new(0.5).into(),
}
}
}
@@ -117,7 +115,7 @@ impl Default for TextState {
#[derive(Debug, Clone, PartialEq)]
pub struct FontSize {
/// The base font size, updated whenever the font size is set absolutely.
- pub base: f64,
+ pub base: Length,
/// The scale to apply on the base font size, updated when the font size
/// is set relatively.
pub scale: Linear,
@@ -125,17 +123,17 @@ pub struct FontSize {
impl FontSize {
/// Create a new font size.
- pub fn new(base: f64, scale: Linear) -> Self {
- Self { base, scale }
+ pub fn new(base: Length, scale: impl Into<Linear>) -> Self {
+ Self { base, scale: scale.into() }
}
/// Create a new font size with the given `base` and a scale of `1.0`.
- pub fn abs(base: f64) -> Self {
- Self::new(base, Linear::rel(1.0))
+ pub fn abs(base: Length) -> Self {
+ Self::new(base, Relative::ONE)
}
/// Compute the absolute font size.
- pub fn eval(&self) -> f64 {
+ pub fn eval(&self) -> Length {
self.scale.eval(self.base)
}
}
diff --git a/src/eval/value.rs b/src/eval/value.rs
index c4b11ebe..56dadfc3 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -6,7 +6,7 @@ use std::rc::Rc;
use super::{Args, Dict, Eval, EvalContext, SpannedEntry};
use crate::color::RgbaColor;
-use crate::geom::Linear;
+use crate::geom::{Length, Linear, Relative};
use crate::syntax::{Ident, SynTree};
/// A computational value.
@@ -23,14 +23,9 @@ pub enum Value {
/// A floating-point number: `1.2, 200%`.
Float(f64),
/// A length: `2cm, 5.2in`.
- Length(f64),
+ Length(Length),
/// A relative value: `50%`.
- ///
- /// _Note_: `50%` is represented as `0.5` here, but as `50.0` in the
- /// corresponding [literal].
- ///
- /// [literal]: ../syntax/ast/enum.Lit.html#variant.Percent
- Relative(f64),
+ Relative(Relative),
/// A combination of an absolute length and a relative value: `20% + 5cm`.
Linear(Linear),
/// A color value with alpha channel: `#f79143ff`.