diff options
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/expr.rs | 55 | ||||
| -rw-r--r-- | src/syntax/func/keys.rs | 1 | ||||
| -rw-r--r-- | src/syntax/func/maps.rs | 67 | ||||
| -rw-r--r-- | src/syntax/func/mod.rs | 8 | ||||
| -rw-r--r-- | src/syntax/func/values.rs | 43 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 6 | ||||
| -rw-r--r-- | src/syntax/parsing.rs | 74 | ||||
| -rw-r--r-- | src/syntax/scope.rs | 22 | ||||
| -rw-r--r-- | src/syntax/span.rs | 94 | ||||
| -rw-r--r-- | src/syntax/test.rs | 6 | ||||
| -rw-r--r-- | src/syntax/tokens.rs | 52 |
11 files changed, 215 insertions, 213 deletions
diff --git a/src/syntax/expr.rs b/src/syntax/expr.rs index a1b3fd62..d849366c 100644 --- a/src/syntax/expr.rs +++ b/src/syntax/expr.rs @@ -6,13 +6,12 @@ use std::ops::Deref; use std::str::FromStr; use std::u8; -use crate::problem::Problems; -use crate::size::Size; +use crate::diagnostic::Diagnostics; +use crate::length::Length; use super::func::{Key, Value}; use super::span::{Span, Spanned}; use super::tokens::is_identifier; - /// An argument or return value. #[derive(Clone, PartialEq)] pub enum Expr { @@ -22,8 +21,8 @@ pub enum Expr { Str(String), /// A number: `1.2, 200%`. Number(f64), - /// A size: `2cm, 5.2in`. - Size(Size), + /// A length: `2cm, 5.2in`. + Length(Length), /// A bool: `true, false`. Bool(bool), /// A color value, including the alpha channel: `#f79143ff`. @@ -32,7 +31,7 @@ pub enum Expr { Tuple(Tuple), /// A named tuple: `cmyk(37.7, 0, 3.9, 1.1)`. NamedTuple(NamedTuple), - /// An object: `{ fit: false, size: 12pt }`. + /// An object: `{ fit: false, width: 12pt }`. Object(Object), /// An operator that negates the contained expression. Neg(Box<Spanned<Expr>>), @@ -54,7 +53,7 @@ impl Expr { Ident(_) => "identifier", Str(_) => "string", Number(_) => "number", - Size(_) => "size", + Length(_) => "length", Bool(_) => "bool", Color(_) => "color", Tuple(_) => "tuple", @@ -76,7 +75,7 @@ impl Debug for Expr { Ident(i) => i.fmt(f), Str(s) => s.fmt(f), Number(n) => n.fmt(f), - Size(s) => s.fmt(f), + Length(s) => s.fmt(f), Bool(b) => b.fmt(f), Color(c) => c.fmt(f), Tuple(t) => t.fmt(f), @@ -128,7 +127,7 @@ impl Debug for Ident { /// /// # Example /// ```typst -/// [box: background=#423abaff] +/// [page: background=#423abaff] /// ^^^^^^^^ /// ``` #[derive(Copy, Clone, Eq, PartialEq, Hash)] @@ -256,28 +255,28 @@ impl Tuple { } /// Extract (and remove) the first matching value and remove and generate - /// problems for all previous items that did not match. - pub fn get<V: Value>(&mut self, problems: &mut Problems) -> Option<V> { + /// diagnostics for all previous items that did not match. + pub fn get<V: Value>(&mut self, diagnostics: &mut Diagnostics) -> Option<V> { while !self.items.is_empty() { let expr = self.items.remove(0); let span = expr.span; match V::parse(expr) { Ok(output) => return Some(output), - Err(v) => problems.push(Spanned { v, span }), + Err(v) => diagnostics.push(Spanned { v, span }), } } None } /// Extract and return an iterator over all values that match and generate - /// problems for all items that do not match. - pub fn get_all<'a, V: Value>(&'a mut self, problems: &'a mut Problems) + /// diagnostics for all items that do not match. + pub fn get_all<'a, V: Value>(&'a mut self, diagnostics: &'a mut Diagnostics) -> impl Iterator<Item=V> + 'a { self.items.drain(..).filter_map(move |expr| { let span = expr.span; match V::parse(expr) { Ok(output) => Some(output), - Err(v) => { problems.push(Spanned { v, span }); None } + Err(v) => { diagnostics.push(Spanned { v, span }); None } } }) } @@ -351,13 +350,9 @@ impl Deref for NamedTuple { /// A key-value collection of identifiers and associated expressions. /// -/// The pairs themselves are not spanned, but the combined spans can easily be -/// retrieved by merging the spans of key and value as happening in -/// [`FuncArg::span`](super::func::FuncArg::span). -/// /// # Example /// ```typst -/// { fit: false, size: 12cm, items: (1, 2, 3) } +/// { fit: false, width: 12cm, items: (1, 2, 3) } /// ``` #[derive(Default, Clone, PartialEq)] pub struct Object { @@ -398,9 +393,9 @@ impl Object { /// /// Inserts an error if the value does not match. If the key is not /// contained, no error is inserted. - pub fn get<V: Value>(&mut self, problems: &mut Problems, key: &str) -> Option<V> { + pub fn get<V: Value>(&mut self, diagnostics: &mut Diagnostics, key: &str) -> Option<V> { let index = self.pairs.iter().position(|pair| pair.v.key.v.as_str() == key)?; - self.get_index::<V>(problems, index) + self.get_index::<V>(diagnostics, index) } /// Extract (and remove) a pair with a matching key and value. @@ -409,12 +404,12 @@ impl Object { /// found, no error is inserted. pub fn get_with_key<K: Key, V: Value>( &mut self, - problems: &mut Problems, + diagnostics: &mut Diagnostics, ) -> Option<(K, V)> { for (index, pair) in self.pairs.iter().enumerate() { let key = Spanned { v: pair.v.key.v.as_str(), span: pair.v.key.span }; if let Some(key) = K::parse(key) { - return self.get_index::<V>(problems, index).map(|value| (key, value)); + return self.get_index::<V>(diagnostics, index).map(|value| (key, value)); } } None @@ -425,7 +420,7 @@ impl Object { /// Inserts errors for values that do not match. pub fn get_all<'a, K: Key, V: Value>( &'a mut self, - problems: &'a mut Problems, + diagnostics: &'a mut Diagnostics, ) -> impl Iterator<Item=(K, V)> + 'a { let mut index = 0; std::iter::from_fn(move || { @@ -434,7 +429,7 @@ impl Object { let key = Spanned { v: key.v.as_str(), span: key.span }; Some(if let Some(key) = K::parse(key) { - self.get_index::<V>(problems, index).map(|v| (key, v)) + self.get_index::<V>(diagnostics, index).map(|v| (key, v)) } else { index += 1; None @@ -454,20 +449,20 @@ impl Object { /// ``` pub fn get_all_spanned<'a, K: Key + 'a, V: Value + 'a>( &'a mut self, - problems: &'a mut Problems, + diagnostics: &'a mut Diagnostics, ) -> impl Iterator<Item=Spanned<(K, V)>> + 'a { - self.get_all::<Spanned<K>, Spanned<V>>(problems) + self.get_all::<Spanned<K>, Spanned<V>>(diagnostics) .map(|(k, v)| Spanned::new((k.v, v.v), Span::merge(k.span, v.span))) } /// Extract the argument at the given index and insert an error if the value /// does not match. - fn get_index<V: Value>(&mut self, problems: &mut Problems, index: usize) -> Option<V> { + fn get_index<V: Value>(&mut self, diagnostics: &mut Diagnostics, index: usize) -> Option<V> { let expr = self.pairs.remove(index).v.value; let span = expr.span; match V::parse(expr) { Ok(output) => Some(output), - Err(v) => { problems.push(Spanned { v, span }); None } + Err(v) => { diagnostics.push(Spanned { v, span }); None } } } diff --git a/src/syntax/func/keys.rs b/src/syntax/func/keys.rs index b8f142ee..558667dd 100644 --- a/src/syntax/func/keys.rs +++ b/src/syntax/func/keys.rs @@ -7,7 +7,6 @@ use super::*; use self::AxisKey::*; use self::PaddingKey::*; - /// Key types are used to extract keyword arguments from /// [`Objects`](crate::syntax::expr::Object). They represent the key part of a /// keyword argument. diff --git a/src/syntax/func/maps.rs b/src/syntax/func/maps.rs index 44d8e1aa..2ac70223 100644 --- a/src/syntax/func/maps.rs +++ b/src/syntax/func/maps.rs @@ -1,18 +1,17 @@ //! Deduplicating maps and keys for argument parsing. -use crate::problem::Problems; +use crate::diagnostic::Diagnostics; use crate::layout::prelude::*; -use crate::size::{PSize, ValueBox}; +use crate::length::{ScaleLength, Value4}; use crate::syntax::span::Spanned; use super::keys::*; use super::values::*; use super::*; - /// A map which deduplicates redundant arguments. /// /// Whenever a duplicate argument is inserted into the map, through the -/// functions `from_iter`, `insert` or `extend` an problems is added to the error +/// functions `from_iter`, `insert` or `extend` an diagnostics is added to the error /// list that needs to be passed to those functions. /// /// All entries need to have span information to enable the error reporting. @@ -28,27 +27,27 @@ impl<K, V> DedupMap<K, V> where K: Eq { } /// Create a new map from an iterator of spanned keys and values. - pub fn from_iter<I>(problems: &mut Problems, iter: I) -> DedupMap<K, V> + pub fn from_iter<I>(diagnostics: &mut Diagnostics, iter: I) -> DedupMap<K, V> where I: IntoIterator<Item=Spanned<(K, V)>> { let mut map = DedupMap::new(); - map.extend(problems, iter); + map.extend(diagnostics, iter); map } /// Add a spanned key-value pair. - pub fn insert(&mut self, problems: &mut Problems, entry: Spanned<(K, V)>) { + pub fn insert(&mut self, diagnostics: &mut Diagnostics, entry: Spanned<(K, V)>) { if self.map.iter().any(|e| e.v.0 == entry.v.0) { - problems.push(error!(entry.span, "duplicate argument")); + diagnostics.push(error!(entry.span, "duplicate argument")); } else { self.map.push(entry); } } /// Add multiple spanned key-value pairs. - pub fn extend<I>(&mut self, problems: &mut Problems, items: I) + pub fn extend<I>(&mut self, diagnostics: &mut Diagnostics, items: I) where I: IntoIterator<Item=Spanned<(K, V)>> { for item in items.into_iter() { - self.insert(problems, item); + self.insert(diagnostics, item); } } @@ -71,15 +70,15 @@ impl<K, V> DedupMap<K, V> where K: Eq { } /// Create a new map where keys and values are mapped to new keys and - /// values. When the mapping introduces new duplicates, problems are + /// values. When the mapping introduces new duplicates, diagnostics are /// generated. - pub fn dedup<F, K2, V2>(&self, problems: &mut Problems, mut f: F) -> DedupMap<K2, V2> + pub fn dedup<F, K2, V2>(&self, diagnostics: &mut Diagnostics, mut f: F) -> DedupMap<K2, V2> where F: FnMut(&K, &V) -> (K2, V2), K2: Eq { let mut map = DedupMap::new(); for Spanned { v: (key, value), span } in self.map.iter() { let (key, value) = f(key, value); - map.insert(problems, Spanned { v: (key, value), span: *span }); + map.insert(diagnostics, Spanned { v: (key, value), span: *span }); } map @@ -98,21 +97,21 @@ pub struct AxisMap<V>(DedupMap<AxisKey, V>); impl<V: Value> AxisMap<V> { /// Parse an axis map from the object. pub fn parse<K>( - problems: &mut Problems, + diagnostics: &mut Diagnostics, object: &mut Object, ) -> AxisMap<V> where K: Key + Into<AxisKey> { let values: Vec<_> = object - .get_all_spanned::<K, V>(problems) + .get_all_spanned::<K, V>(diagnostics) .map(|s| s.map(|(k, v)| (k.into(), v))) .collect(); - AxisMap(DedupMap::from_iter(problems, values)) + AxisMap(DedupMap::from_iter(diagnostics, values)) } /// Deduplicate from specific or generic to just specific axes. - pub fn dedup(&self, problems: &mut Problems, axes: LayoutAxes) -> DedupMap<SpecificAxis, V> + pub fn dedup(&self, diagnostics: &mut Diagnostics, axes: LayoutAxes) -> DedupMap<SpecificAxis, V> where V: Clone { - self.0.dedup(problems, |key, val| (key.to_specific(axes), val.clone())) + self.0.dedup(diagnostics, |key, val| (key.to_specific(axes), val.clone())) } } @@ -124,23 +123,23 @@ pub struct PosAxisMap<V>(DedupMap<PosAxisKey, V>); impl<V: Value> PosAxisMap<V> { /// Parse a positional/axis map from the function arguments. pub fn parse<K>( - problems: &mut Problems, + diagnostics: &mut Diagnostics, args: &mut FuncArgs, ) -> PosAxisMap<V> where K: Key + Into<AxisKey> { let mut map = DedupMap::new(); for &key in &[PosAxisKey::First, PosAxisKey::Second] { - if let Some(Spanned { v, span }) = args.pos.get::<Spanned<V>>(problems) { - map.insert(problems, Spanned { v: (key, v), span }) + if let Some(Spanned { v, span }) = args.pos.get::<Spanned<V>>(diagnostics) { + map.insert(diagnostics, Spanned { v: (key, v), span }) } } let keywords: Vec<_> = args.key - .get_all_spanned::<K, V>(problems) + .get_all_spanned::<K, V>(diagnostics) .map(|s| s.map(|(k, v)| (PosAxisKey::Keyword(k.into()), v))) .collect(); - map.extend(problems, keywords); + map.extend(diagnostics, keywords); PosAxisMap(map) } @@ -149,7 +148,7 @@ impl<V: Value> PosAxisMap<V> { /// or specific axes to just generic axes. pub fn dedup<F>( &self, - problems: &mut Problems, + diagnostics: &mut Diagnostics, axes: LayoutAxes, mut f: F, ) -> DedupMap<GenericAxis, V> @@ -157,7 +156,7 @@ impl<V: Value> PosAxisMap<V> { F: FnMut(&V) -> Option<GenericAxis>, V: Clone, { - self.0.dedup(problems, |key, val| { + self.0.dedup(diagnostics, |key, val| { (match key { PosAxisKey::First => f(val).unwrap_or(GenericAxis::Primary), PosAxisKey::Second => f(val).unwrap_or(GenericAxis::Secondary), @@ -171,24 +170,24 @@ impl<V: Value> PosAxisMap<V> { /// A map for storing padding given for a combination of all sides, opposing /// sides or single sides. #[derive(Debug, Clone, PartialEq)] -pub struct PaddingMap(DedupMap<PaddingKey<AxisKey>, Option<PSize>>); +pub struct PaddingMap(DedupMap<PaddingKey<AxisKey>, Option<ScaleLength>>); impl PaddingMap { /// Parse a padding map from the function arguments. - pub fn parse(problems: &mut Problems, args: &mut FuncArgs) -> PaddingMap { + pub fn parse(diagnostics: &mut Diagnostics, args: &mut FuncArgs) -> PaddingMap { let mut map = DedupMap::new(); - let all = args.pos.get::<Spanned<Defaultable<PSize>>>(problems); + let all = args.pos.get::<Spanned<Defaultable<ScaleLength>>>(diagnostics); if let Some(Spanned { v, span }) = all { - map.insert(problems, Spanned { v: (PaddingKey::All, v.into()), span }); + map.insert(diagnostics, Spanned { v: (PaddingKey::All, v.into()), span }); } let paddings: Vec<_> = args.key - .get_all_spanned::<PaddingKey<AxisKey>, Defaultable<PSize>>(problems) + .get_all_spanned::<PaddingKey<AxisKey>, Defaultable<ScaleLength>>(diagnostics) .map(|s| s.map(|(k, v)| (k, v.into()))) .collect(); - map.extend(problems, paddings); + map.extend(diagnostics, paddings); PaddingMap(map) } @@ -196,13 +195,13 @@ impl PaddingMap { /// Apply the specified padding on a value box of optional, scalable sizes. pub fn apply( &self, - problems: &mut Problems, + diagnostics: &mut Diagnostics, axes: LayoutAxes, - padding: &mut ValueBox<Option<PSize>> + padding: &mut Value4<Option<ScaleLength>> ) { use PaddingKey::*; - let map = self.0.dedup(problems, |key, &val| { + let map = self.0.dedup(diagnostics, |key, &val| { (match key { All => All, Both(axis) => Both(axis.to_specific(axes)), diff --git a/src/syntax/func/mod.rs b/src/syntax/func/mod.rs index 4228488d..c2631727 100644 --- a/src/syntax/func/mod.rs +++ b/src/syntax/func/mod.rs @@ -1,7 +1,7 @@ //! Primitives for argument parsing in library functions. use std::iter::FromIterator; -use crate::problem::{Problem, Problems}; +use crate::diagnostic::{Diagnostic, Diagnostics}; use super::expr::{Expr, Ident, Tuple, Object, Pair}; use super::span::{Span, Spanned}; @@ -85,13 +85,13 @@ pub enum FuncArg { pub trait OptionExt: Sized { /// Add an error about a missing argument `arg` with the given span if the /// option is `None`. - fn or_missing(self, problems: &mut Problems, span: Span, arg: &str) -> Self; + fn or_missing(self, diagnostics: &mut Diagnostics, span: Span, arg: &str) -> Self; } impl<T> OptionExt for Option<T> { - fn or_missing(self, problems: &mut Problems, span: Span, arg: &str) -> Self { + fn or_missing(self, diagnostics: &mut Diagnostics, span: Span, arg: &str) -> Self { if self.is_none() { - problems.push(error!(span, "missing argument: {}", arg)); + diagnostics.push(error!(span, "missing argument: {}", arg)); } self } diff --git a/src/syntax/func/values.rs b/src/syntax/func/values.rs index 7a1aa912..3269f8e9 100644 --- a/src/syntax/func/values.rs +++ b/src/syntax/func/values.rs @@ -4,13 +4,12 @@ use std::fmt::{self, Display, Formatter}; use toddle::query::{FontStyle, FontWeight}; use crate::layout::prelude::*; -use crate::size::{Size, ScaleSize}; -use crate::style::Paper; +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 @@ -24,14 +23,14 @@ use self::AlignmentValue::*; /// An implementation for `bool` might look as follows: /// ``` /// # use typstc::error; -/// # use typstc::problem::Problem; +/// # 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, Problem> { +/// fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> { /// match expr.v { /// # /* /// Expr::Bool(b) => Ok(b), @@ -44,11 +43,11 @@ use self::AlignmentValue::*; 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, Problem>; + fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic>; } impl<V: Value> Value for Spanned<V> { - fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> { + fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> { let span = expr.span; V::parse(expr).map(|v| Spanned { v, span }) } @@ -58,7 +57,7 @@ impl<V: Value> Value for Spanned<V> { macro_rules! value { ($type:ty, $name:expr, $($p:pat => $r:expr),* $(,)?) => { impl Value for $type { - fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> { + fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> { #[allow(unreachable_patterns)] match expr.v { $($p => Ok($r)),*, @@ -77,13 +76,13 @@ 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!(Size, "size", Expr::Size(s) => s); +value!(Length, "length", Expr::Length(s) => s); value!(Tuple, "tuple", Expr::Tuple(t) => t); value!(Object, "object", Expr::Object(o) => o); -value!(ScaleSize, "number or size", - Expr::Size(size) => ScaleSize::Absolute(size), - Expr::Number(scale) => ScaleSize::Scaled(scale as f32), +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 @@ -108,20 +107,20 @@ impl From<StringLike> for String { /// # Example /// ``` /// # use typstc::syntax::func::{FuncArgs, Defaultable}; -/// # use typstc::size::Size; +/// # use typstc::length::Length; /// # let mut args = FuncArgs::new(); /// # let mut errors = vec![]; -/// args.key.get::<Defaultable<Size>>(&mut errors, "size"); +/// args.key.get::<Defaultable<Length>>(&mut errors, "length"); /// ``` /// This will yield. /// ```typst -/// [func: size=default] => None -/// [func: size=2cm] => Some(Size::cm(2.0)) +/// [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, Problem> { + 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)?) @@ -136,7 +135,7 @@ impl<V> From<Defaultable<V>> for Option<V> { } impl Value for FontStyle { - fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> { + fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> { FontStyle::from_name(Ident::parse(expr)?.as_str()) .ok_or_else(|| error!("invalid font style")) } @@ -145,7 +144,7 @@ impl Value for FontStyle { /// 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, bool) { - fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> { + fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> { match expr.v { Expr::Number(weight) => { let weight = weight.round(); @@ -170,14 +169,14 @@ impl Value for (FontWeight, bool) { } impl Value for Paper { - fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> { + 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, Problem> { + 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, @@ -250,7 +249,7 @@ impl AlignmentValue { } impl Value for AlignmentValue { - fn parse(expr: Spanned<Expr>) -> Result<Self, Problem> { + fn parse(expr: Spanned<Expr>) -> Result<Self, Diagnostic> { Ok(match Ident::parse(expr)?.as_str() { "origin" => Align(Origin), "center" => Align(Center), diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index f7321c77..b67d8cd7 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -20,7 +20,6 @@ pub_use_mod!(scope); pub_use_mod!(parsing); pub_use_mod!(tokens); - /// Represents a parsed piece of source that can be layouted and in the future /// also be queried for information used for refactorings, autocomplete, etc. #[async_trait(?Send)] @@ -94,6 +93,9 @@ impl PartialEq for Node { } } +/// A list of spanned decorations. +pub type Decorations = SpanVec<Decoration>; + /// Decorations for semantic syntax highlighting. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize)] #[serde(rename_all = "camelCase")] @@ -110,7 +112,6 @@ pub enum Decoration { /// ^^^^^^ /// ``` InvalidFuncName, - /// A key of a keyword argument: /// ```typst /// [box: width=5cm] @@ -123,7 +124,6 @@ pub enum Decoration { /// ^^^^ ^^^^^ /// ``` ObjectKey, - /// An italic word. Italic, /// A bold word. diff --git a/src/syntax/parsing.rs b/src/syntax/parsing.rs index a0d9c4e4..a8151125 100644 --- a/src/syntax/parsing.rs +++ b/src/syntax/parsing.rs @@ -4,9 +4,12 @@ use std::str::FromStr; use super::expr::*; use super::func::{FuncCall, FuncHeader, FuncArgs, FuncArg}; -use super::span::{Position, Span, Spanned}; +use super::span::{Pos, Span, Spanned}; use super::*; +/// A function which parses a function call into a model. +pub type CallParser = dyn Fn(FuncCall, &ParseState) -> Pass<Box<dyn Model>>; + /// The state which can influence how a string of source code is parsed. /// /// Parsing is pure - when passed in the same state and source code, the output @@ -22,7 +25,7 @@ pub struct ParseState { /// `offset` position. This is used to make spans of a function body relative to /// the start of the function as a whole as opposed to the start of the /// function's body. -pub fn parse(src: &str, offset: Position, state: &ParseState) -> Pass<SyntaxModel> { +pub fn parse(src: &str, offset: Pos, state: &ParseState) -> Pass<SyntaxModel> { let mut model = SyntaxModel::new(); let mut feedback = Feedback::new(); @@ -102,7 +105,7 @@ impl<'s> FuncParser<'s> { state, // Start at column 1 because the opening bracket is also part of // the function, but not part of the `header` string. - tokens: Tokens::new(header, Position::new(0, 1), TokenMode::Header), + tokens: Tokens::new(header, Pos::new(0, 1), TokenMode::Header), peeked: None, body, feedback: Feedback::new(), @@ -127,7 +130,7 @@ impl<'s> FuncParser<'s> { } }; - self.feedback.decos.push(Spanned::new(deco, header.name.span)); + self.feedback.decorations.push(Spanned::new(deco, header.name.span)); (parser, header) } else { // Parse the body with the fallback parser even when the header is @@ -186,7 +189,7 @@ impl<'s> FuncParser<'s> { self.skip_white(); let key = ident; - self.feedback.decos.push( + self.feedback.decorations.push( Spanned::new(Decoration::ArgumentKey, key.span) ); @@ -325,7 +328,7 @@ impl FuncParser<'_> { } Token::ExprNumber(n) => self.eat_span(Expr::Number(n)), - Token::ExprSize(s) => self.eat_span(Expr::Size(s)), + Token::ExprLength(s) => self.eat_span(Expr::Length(s)), Token::ExprBool(b) => self.eat_span(Expr::Bool(b)), Token::ExprHex(s) => { if let Ok(color) = RgbaColor::from_str(s) { @@ -423,7 +426,7 @@ impl FuncParser<'_> { continue; } - self.feedback.decos.push( + self.feedback.decorations.push( Spanned::new(Decoration::ObjectKey, key.span) ); @@ -464,7 +467,7 @@ impl FuncParser<'_> { } } - fn expect_at(&mut self, token: Token<'_>, pos: Position) -> bool { + fn expect_at(&mut self, token: Token<'_>, pos: Pos) -> bool { if self.check(token) { self.eat(); true @@ -485,11 +488,11 @@ impl FuncParser<'_> { } } - fn expected_at(&mut self, thing: &str, pos: Position) { + fn expected_at(&mut self, thing: &str, pos: Pos) { error!(@self.feedback, Span::at(pos), "expected {}", thing); } - fn expected_found_or_at(&mut self, thing: &str, pos: Position) { + fn expected_found_or_at(&mut self, thing: &str, pos: Pos) { if self.eof() { self.expected_at(thing, pos) } else { @@ -544,7 +547,7 @@ impl<'s> FuncParser<'s> { self.peek().is_none() } - fn pos(&self) -> Position { + fn pos(&self) -> Pos { self.peeked.flatten() .map(|s| s.span.start) .unwrap_or_else(|| self.tokens.pos()) @@ -604,13 +607,13 @@ fn unescape_raw(raw: &str) -> Vec<String> { #[cfg(test)] #[allow(non_snake_case)] mod tests { - use crate::size::Size; + use crate::length::Length; use super::super::test::{check, DebugFn}; use super::super::func::Value; use super::*; use Decoration::*; - use Expr::{Number as Num, Size as Sz, Bool}; + use Expr::{Number as Num, Length as Len, Bool}; use Node::{ Space as S, ToggleItalic as Italic, ToggleBolder as Bold, Parbreak, Linebreak, @@ -625,7 +628,7 @@ mod tests { p!($source => [$($model)*], []); }; - ($source:expr => [$($model:tt)*], [$($problems:tt)*] $(, [$($decos:tt)*])? $(,)?) => { + ($source:expr => [$($model:tt)*], [$($diagnostics:tt)*] $(, [$($decos:tt)*])? $(,)?) => { let mut scope = Scope::new::<DebugFn>(); scope.add::<DebugFn>("f"); scope.add::<DebugFn>("n"); @@ -633,25 +636,25 @@ mod tests { scope.add::<DebugFn>("val"); let state = ParseState { scope }; - let pass = parse($source, Position::ZERO, &state); + let pass = parse($source, Pos::ZERO, &state); // Test model. let (exp, cmp) = span_vec![$($model)*]; check($source, exp, pass.output.nodes, cmp); - // Test problems. - let (exp, cmp) = span_vec![$($problems)*]; + // Test diagnostics. + let (exp, cmp) = span_vec![$($diagnostics)*]; let exp = exp.into_iter() .map(|s: Spanned<&str>| s.map(|e| e.to_string())) .collect::<Vec<_>>(); - let found = pass.feedback.problems.into_iter() + let found = pass.feedback.diagnostics.into_iter() .map(|s| s.map(|e| e.message)) .collect::<Vec<_>>(); check($source, exp, found, cmp); // Test decos. $(let (exp, cmp) = span_vec![$($decos)*]; - check($source, exp, pass.feedback.decos, cmp);)? + check($source, exp, pass.feedback.decorations, cmp);)? }; } @@ -664,7 +667,6 @@ mod tests { fn Id(text: &str) -> Expr { Expr::Ident(Ident(text.to_string())) } fn Str(text: &str) -> Expr { Expr::Str(text.to_string()) } - fn Pt(points: f32) -> Expr { Expr::Size(Size::pt(points)) } fn Color(r: u8, g: u8, b: u8, a: u8) -> Expr { Expr::Color(RgbaColor::new(r, g, b, a)) } fn ColorStr(color: &str) -> Expr { Expr::Color(RgbaColor::from_str(color).expect("invalid test color")) } fn ColorHealed() -> Expr { Expr::Color(RgbaColor::new_healed(0, 0, 0, 255)) } @@ -878,8 +880,8 @@ mod tests { pval!("name" => (Id("name"))); pval!("\"hi\"" => (Str("hi"))); pval!("3.14" => (Num(3.14))); - pval!("4.5cm" => (Sz(Size::cm(4.5)))); - pval!("12e1pt" => (Pt(12e1))); + pval!("4.5cm" => (Len(Length::cm(4.5)))); + pval!("12e1pt" => (Len(Length::pt(12e1)))); pval!("#f7a20500" => (ColorStr("f7a20500"))); pval!("\"a\n[]\\\"string\"" => (Str("a\n[]\"string"))); @@ -890,10 +892,10 @@ mod tests { pval!("(hi)" => (Id("hi"))); // Math. - pval!("3.2in + 6pt" => (Add(Sz(Size::inches(3.2)), Sz(Size::pt(6.0))))); + pval!("3.2in + 6pt" => (Add(Len(Length::inches(3.2)), Len(Length::pt(6.0))))); pval!("5 - 0.01" => (Sub(Num(5.0), Num(0.01)))); - pval!("(3mm * 2)" => (Mul(Sz(Size::mm(3.0)), Num(2.0)))); - pval!("12e-3cm/1pt" => (Div(Sz(Size::cm(12e-3)), Sz(Size::pt(1.0))))); + pval!("(3mm * 2)" => (Mul(Len(Length::mm(3.0)), Num(2.0)))); + pval!("12e-3cm/1pt" => (Div(Len(Length::cm(12e-3)), Len(Length::pt(1.0))))); // Unclosed string. p!("[val: \"hello]" => [func!("val": (Str("hello]")), {})], [ @@ -912,26 +914,24 @@ mod tests { fn parse_complex_mathematical_expressions() { // Valid expressions. pval!("(3.2in + 6pt)*(5/2-1)" => (Mul( - Add(Sz(Size::inches(3.2)), Sz(Size::pt(6.0))), + Add(Len(Length::inches(3.2)), Len(Length::pt(6.0))), Sub(Div(Num(5.0), Num(2.0)), Num(1.0)) ))); pval!("(6.3E+2+4* - 3.2pt)/2" => (Div( - Add(Num(6.3e2),Mul(Num(4.0), Neg(Pt(3.2)))), + Add(Num(6.3e2), Mul(Num(4.0), Neg(Len(Length::pt(3.2))))), Num(2.0) ))); // Associativity of multiplication and division. - p!("[val: 3/4*5]" => - [func!("val": (Mul(Div(Num(3.0), Num(4.0)), Num(5.0))), {})] - ); + pval!("3/4*5" => (Mul(Div(Num(3.0), Num(4.0)), Num(5.0)))); // Invalid expressions. - p!("[val: 4pt--]" => [func!("val": (Pt(4.0)))], [ + p!("[val: 4pt--]" => [func!("val": (Len(Length::pt(4.0))))], [ (0:10, 0:11, "dangling minus"), (0:6, 0:10, "missing right summand") ]); p!("[val: 3mm+4pt*]" => - [func!("val": (Add(Sz(Size::mm(3.0)), Pt(4.0))))], + [func!("val": (Add(Len(Length::mm(3.0)), Len(Length::pt(4.0)))))], [(0:10, 0:14, "missing right factor")], ); } @@ -976,7 +976,7 @@ mod tests { // Nested tuples. pval!("css(1pt, rgb(90, 102, 254), \"solid\")" => (named_tuple!( "css", - Pt(1.0), + Len(Length::pt(1.0)), named_tuple!("rgb", Num(90.0), Num(102.0), Num(254.0)), Str("solid"), ))); @@ -1012,7 +1012,7 @@ mod tests { // Missing key. p!("[val: {,}]" => [val()], [(0:7, 0:8, "expected key, found comma")]); - p!("[val: { 12pt }]" => [val()], [(0:8, 0:12, "expected key, found size")]); + p!("[val: { 12pt }]" => [val()], [(0:8, 0:12, "expected key, found length")]); p!("[val: { : }]" => [val()], [(0:8, 0:9, "expected key, found colon")]); // Missing colon. @@ -1053,7 +1053,7 @@ mod tests { Num(1.0), object!( "ab" => tuple!(), - "d" => tuple!(Num(3.0), Pt(14.0)), + "d" => tuple!(Num(3.0), Len(Length::pt(14.0))), ), ), Bool(false), @@ -1085,7 +1085,7 @@ mod tests { #[test] fn parse_multiple_mixed_arguments() { p!("[val: 12pt, key=value]" => - [func!("val": (Pt(12.0)), { "key" => Id("value") })], [], + [func!("val": (Len(Length::pt(12.0))), { "key" => Id("value") })], [], [(0:12, 0:15, ArgumentKey), (0:1, 0:4, ValidFuncName)], ); pval!("a , x=\"b\" , c" => (Id("a"), Id("c")), { "x" => Str("b"), }); @@ -1144,7 +1144,7 @@ mod tests { fn parse_invalid_commas() { // Missing commas. p!("[val: 1pt 1]" => - [func!("val": (Pt(1.0), Num(1.0)), {})], + [func!("val": (Len(Length::pt(1.0)), Num(1.0)), {})], [(0:9, 0:9, "expected comma")], ); p!(r#"[val: _"s"]"# => diff --git a/src/syntax/scope.rs b/src/syntax/scope.rs index 74c64280..c6350836 100644 --- a/src/syntax/scope.rs +++ b/src/syntax/scope.rs @@ -3,16 +3,14 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; -use crate::Pass; use crate::func::ParseFunc; -use super::func::FuncCall; -use super::parsing::ParseState; +use super::parsing::CallParser; use super::Model; /// A map from identifiers to function parsers. pub struct Scope { - parsers: HashMap<String, Box<Parser>>, - fallback: Box<Parser>, + parsers: HashMap<String, Box<CallParser>>, + fallback: Box<CallParser>, } impl Scope { @@ -22,7 +20,7 @@ impl Scope { where F: ParseFunc<Meta=()> + Model + 'static { Scope { parsers: HashMap::new(), - fallback: parser::<F>(()), + fallback: make_parser::<F>(()), } } @@ -43,17 +41,17 @@ impl Scope { where F: ParseFunc + Model + 'static { self.parsers.insert( name.to_string(), - parser::<F>(metadata), + make_parser::<F>(metadata), ); } /// Return the parser with the given name if there is one. - pub fn get_parser(&self, name: &str) -> Option<&Parser> { + pub fn get_parser(&self, name: &str) -> Option<&CallParser> { self.parsers.get(name).map(AsRef::as_ref) } /// Return the fallback parser. - pub fn get_fallback_parser(&self) -> &Parser { + pub fn get_fallback_parser(&self) -> &CallParser { &*self.fallback } } @@ -66,11 +64,7 @@ impl Debug for Scope { } } -/// A function which parses the source of a function into a model type which -/// implements [`Model`]. -type Parser = dyn Fn(FuncCall, &ParseState) -> Pass<Box<dyn Model>>; - -fn parser<F>(metadata: <F as ParseFunc>::Meta) -> Box<Parser> +fn make_parser<F>(metadata: <F as ParseFunc>::Meta) -> Box<CallParser> where F: ParseFunc + Model + 'static { Box::new(move |f, s| { F::parse(f, s, metadata.clone()) diff --git a/src/syntax/span.rs b/src/syntax/span.rs index c8e2cddb..19562fb1 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -4,16 +4,22 @@ use std::fmt::{self, Debug, Formatter}; use std::ops::{Add, Sub}; use serde::Serialize; +/// Span offsetting. +pub trait Offset { + /// Offset all spans contained in `Self` by the given position. + fn offset(self, by: Pos) -> Self; +} + /// A vector of spanned values of type `T`. pub type SpanVec<T> = Vec<Spanned<T>>; -/// [Offset](Span::offset) all spans in a vector of spanned things by a start -/// position. -pub fn offset_spans<T>( - vec: SpanVec<T>, - start: Position, -) -> impl Iterator<Item=Spanned<T>> { - vec.into_iter().map(move |s| s.map_span(|span| span.offset(start))) +impl<T> Offset for SpanVec<T> { + fn offset(mut self, by: Pos) -> Self { + for spanned in &mut self { + spanned.span = spanned.span.offset(by); + } + self + } } /// A value with the span it corresponds to in the source code. @@ -53,6 +59,12 @@ impl<T> Spanned<T> { } } +impl<T> Offset for Spanned<T> { + fn offset(self, by: Pos) -> Self { + self.map_span(|span| span.offset(by)) + } +} + impl<T: Debug> Debug for Spanned<T> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { self.v.fmt(f)?; @@ -68,20 +80,25 @@ impl<T: Debug> Debug for Spanned<T> { #[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize)] pub struct Span { /// The inclusive start position. - pub start: Position, + pub start: Pos, /// The inclusive end position. - pub end: Position, + pub end: Pos, } impl Span { /// The zero span. - pub const ZERO: Span = Span { start: Position::ZERO, end: Position::ZERO }; + pub const ZERO: Span = Span { start: Pos::ZERO, end: Pos::ZERO }; /// Create a new span from start and end positions. - pub fn new(start: Position, end: Position) -> Span { + pub fn new(start: Pos, end: Pos) -> Span { Span { start, end } } + /// Create a span including just a single position. + pub fn at(pos: Pos) -> Span { + Span { start: pos, end: pos } + } + /// Create a new span with the earlier start and later end position. pub fn merge(a: Span, b: Span) -> Span { Span { @@ -90,24 +107,17 @@ impl Span { } } - /// Create a span including just a single position. - pub fn at(pos: Position) -> Span { - Span { start: pos, end: pos } - } - /// Expand a span by merging it with another span. pub fn expand(&mut self, other: Span) { *self = Span::merge(*self, other) } +} - /// Offset a span by a start position. - /// - /// This is, for example, used to translate error spans from function local - /// to global. - pub fn offset(self, start: Position) -> Span { +impl Offset for Span { + fn offset(self, by: Pos) -> Self { Span { - start: start + self.start, - end: start + self.end, + start: self.start.offset(by), + end: self.end.offset(by), } } } @@ -120,34 +130,40 @@ impl Debug for Span { /// Zero-indexed line-column position in source code. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize)] -pub struct Position { +pub struct Pos { /// The zero-indexed line. pub line: usize, /// The zero-indexed column. pub column: usize, } -impl Position { +impl Pos { /// The line 0, column 0 position. - pub const ZERO: Position = Position { line: 0, column: 0 }; + pub const ZERO: Pos = Pos { line: 0, column: 0 }; /// Create a new position from line and column. - pub fn new(line: usize, column: usize) -> Position { - Position { line, column } + pub fn new(line: usize, column: usize) -> Pos { + Pos { line, column } + } +} + +impl Offset for Pos { + fn offset(self, by: Pos) -> Self { + by + self } } -impl Add for Position { - type Output = Position; +impl Add for Pos { + type Output = Pos; - fn add(self, rhs: Position) -> Position { + fn add(self, rhs: Pos) -> Pos { if rhs.line == 0 { - Position { + Pos { line: self.line, column: self.column + rhs.column } } else { - Position { + Pos { line: self.line + rhs.line, column: rhs.column, } @@ -155,17 +171,17 @@ impl Add for Position { } } -impl Sub for Position { - type Output = Position; +impl Sub for Pos { + type Output = Pos; - fn sub(self, rhs: Position) -> Position { + fn sub(self, rhs: Pos) -> Pos { if self.line == rhs.line { - Position { + Pos { line: 0, column: self.column - rhs.column } } else { - Position { + Pos { line: self.line - rhs.line, column: self.column, } @@ -173,7 +189,7 @@ impl Sub for Position { } } -impl Debug for Position { +impl Debug for Pos { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}:{}", self.line, self.column) } diff --git a/src/syntax/test.rs b/src/syntax/test.rs index 7b1e0830..639fbb61 100644 --- a/src/syntax/test.rs +++ b/src/syntax/test.rs @@ -39,11 +39,11 @@ macro_rules! span_vec { macro_rules! span_item { (($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => ({ - use $crate::syntax::span::{Position, Span, Spanned}; + use $crate::syntax::span::{Pos, Span, Spanned}; Spanned { span: Span::new( - Position::new($sl, $sc), - Position::new($el, $ec) + Pos::new($sl, $sc), + Pos::new($el, $ec) ), v: $v } diff --git a/src/syntax/tokens.rs b/src/syntax/tokens.rs index 10200708..9bb95c97 100644 --- a/src/syntax/tokens.rs +++ b/src/syntax/tokens.rs @@ -2,8 +2,8 @@ use std::iter::Peekable; use std::str::Chars; use unicode_xid::UnicodeXID; -use crate::size::Size; -use super::span::{Position, Span, Spanned}; +use crate::length::Length; +use super::span::{Pos, Span, Spanned}; use Token::*; use TokenMode::*; @@ -73,8 +73,8 @@ pub enum Token<'s> { }, /// A number in a function header: `3.14`. ExprNumber(f64), - /// A size in a function header: `12pt`. - ExprSize(Size), + /// A length in a function header: `12pt`. + ExprLength(Length), /// A boolean in a function header: `true | false`. ExprBool(bool), /// A hex value in a function header: `#20d82a`. @@ -129,7 +129,7 @@ impl<'s> Token<'s> { ExprIdent(_) => "identifier", ExprStr { .. } => "string", ExprNumber(_) => "number", - ExprSize(_) => "size", + ExprLength(_) => "length", ExprBool(_) => "bool", ExprHex(_) => "hex value", Plus => "plus", @@ -153,7 +153,7 @@ pub struct Tokens<'s> { src: &'s str, mode: TokenMode, iter: Peekable<Chars<'s>>, - position: Position, + pos: Pos, index: usize, } @@ -172,12 +172,12 @@ impl<'s> Tokens<'s> { /// /// The first token's span starts an the given `offset` position instead of /// the zero position. - pub fn new(src: &'s str, offset: Position, mode: TokenMode) -> Tokens<'s> { + pub fn new(src: &'s str, offset: Pos, mode: TokenMode) -> Tokens<'s> { Tokens { src, mode, iter: src.chars().peekable(), - position: offset, + pos: offset, index: 0, } } @@ -190,8 +190,8 @@ impl<'s> Tokens<'s> { /// The line-colunn position in the source at which the last token ends and /// next token will start. - pub fn pos(&self) -> Position { - self.position + pub fn pos(&self) -> Pos { + self.pos } } @@ -315,14 +315,14 @@ impl<'s> Tokens<'s> { }, true, 0, -2).0) } - fn read_whitespace(&mut self, start: Position) -> Token<'s> { + fn read_whitespace(&mut self, start: Pos) -> Token<'s> { self.read_string_until(|n| !n.is_whitespace(), false, 0, 0); let end = self.pos(); Space(end.line - start.line) } - fn read_function(&mut self, start: Position) -> Token<'s> { + fn read_function(&mut self, start: Pos) -> Token<'s> { let (header, terminated) = self.read_function_part(Header); self.eat(); @@ -354,7 +354,7 @@ impl<'s> Tokens<'s> { self.eat(); match n { - '[' => { self.read_function(Position::ZERO); } + '[' => { self.read_function(Pos::ZERO); } '/' if self.peek() == Some('/') => { self.read_line_comment(); } '/' if self.peek() == Some('*') => { self.read_block_comment(); } '"' if mode == Header => { self.read_string(); } @@ -427,8 +427,8 @@ impl<'s> Tokens<'s> { ExprNumber(num) } else if let Some(num) = parse_percentage(text) { ExprNumber(num / 100.0) - } else if let Ok(size) = text.parse::<Size>() { - ExprSize(size) + } else if let Ok(length) = text.parse::<Length>() { + ExprLength(length) } else if is_identifier(text) { ExprIdent(text) } else { @@ -476,10 +476,10 @@ impl<'s> Tokens<'s> { self.index += c.len_utf8(); if is_newline_char(c) && !(c == '\r' && self.peek() == Some('\n')) { - self.position.line += 1; - self.position.column = 0; + self.pos.line += 1; + self.pos.column = 0; } else { - self.position.column += 1; + self.pos.column += 1; } Some(c) @@ -543,7 +543,7 @@ mod tests { LeftBrace as LB, RightBrace as RB, ExprIdent as Id, ExprNumber as Num, - ExprSize as Sz, + ExprLength as Len, ExprBool as Bool, ExprHex as Hex, Text as T, @@ -557,7 +557,7 @@ mod tests { macro_rules! t { ($mode:expr, $source:expr => [$($tokens:tt)*]) => { let (exp, spans) = span_vec![$($tokens)*]; - let found = Tokens::new($source, Position::ZERO, $mode).collect::<Vec<_>>(); + let found = Tokens::new($source, Pos::ZERO, $mode).collect::<Vec<_>>(); check($source, exp, found, spans); } } @@ -640,13 +640,13 @@ mod tests { t!(Header, "__main__" => [Id("__main__")]); t!(Header, ".func.box" => [Id(".func.box")]); t!(Header, "arg, _b, _1" => [Id("arg"), Comma, S(0), Id("_b"), Comma, S(0), Id("_1")]); - t!(Header, "12_pt, 12pt" => [Invalid("12_pt"), Comma, S(0), Sz(Size::pt(12.0))]); - t!(Header, "1e5in" => [Sz(Size::inches(100000.0))]); - t!(Header, "2.3cm" => [Sz(Size::cm(2.3))]); - t!(Header, "12e-3in" => [Sz(Size::inches(12e-3))]); - t!(Header, "6.1cm + 4pt,a=1*2" => [Sz(Size::cm(6.1)), S(0), Plus, S(0), Sz(Size::pt(4.0)), Comma, Id("a"), Equals, Num(1.0), Star, Num(2.0)]); + t!(Header, "12_pt, 12pt" => [Invalid("12_pt"), Comma, S(0), Len(Length::pt(12.0))]); + t!(Header, "1e5in" => [Len(Length::inches(100000.0))]); + t!(Header, "2.3cm" => [Len(Length::cm(2.3))]); + t!(Header, "12e-3in" => [Len(Length::inches(12e-3))]); + t!(Header, "6.1cm + 4pt,a=1*2" => [Len(Length::cm(6.1)), S(0), Plus, S(0), Len(Length::pt(4.0)), Comma, Id("a"), Equals, Num(1.0), Star, Num(2.0)]); t!(Header, "(5 - 1) / 2.1" => [LP, Num(5.0), S(0), Min, S(0), Num(1.0), RP, S(0), Slash, S(0), Num(2.1)]); - t!(Header, "02.4mm" => [Sz(Size::mm(2.4))]); + t!(Header, "02.4mm" => [Len(Length::mm(2.4))]); t!(Header, "2.4.cm" => [Invalid("2.4.cm")]); t!(Header, "(1,2)" => [LP, Num(1.0), Comma, Num(2.0), RP]); t!(Header, "{abc}" => [LB, Id("abc"), RB]); |
