texlang/parse/
glue.rs

1use core::{Glue, Scaled};
2
3use super::keyword::parse_keyword;
4use crate::prelude as txl;
5use crate::token::Value;
6use crate::traits::*;
7use crate::*;
8
9impl Parsable for Glue {
10    // TeX.2021.461
11    fn parse_impl<S: TexlangState>(input: &mut vm::ExpandedStream<S>) -> txl::Result<Self> {
12        let negative = match super::integer::parse_optional_signs(input)? {
13            None => 1,
14            Some(_) => -1,
15        };
16        let first_token = input.next_or_err(GlueEndOfInputError {})?;
17        let width = match first_token.value() {
18            Value::CommandRef(command_ref) => {
19                use super::integer::InternalNumber;
20                match super::integer::parse_internal_number(input, first_token, command_ref)? {
21                    InternalNumber::Integer(i) => {
22                        super::dimen::scan_and_apply_units(
23                            input,
24                            first_token,
25                            i.abs(),
26                            Scaled::ZERO,
27                            None,
28                        )? * negative
29                            * i.signum()
30                    }
31                    InternalNumber::Dimen(d) => d * negative,
32                    InternalNumber::Glue(g) => {
33                        return Ok(g * negative);
34                    }
35                }
36            }
37            _ => {
38                input.back(first_token);
39                core::Scaled::parse(input)? * negative
40            }
41        };
42
43        let mut g = Glue {
44            width,
45            ..Default::default()
46        };
47        if parse_keyword(input, "plus")? {
48            g.stretch = super::dimen::scan_dimen(input, Some(&mut g.stretch_order))?
49        }
50        if parse_keyword(input, "minus")? {
51            g.shrink = super::dimen::scan_dimen(input, Some(&mut g.shrink_order))?
52        };
53        Ok(g)
54    }
55}
56
57#[derive(Debug)]
58struct GlueEndOfInputError;
59
60impl error::EndOfInputError for GlueEndOfInputError {
61    fn doing(&self) -> String {
62        "parsing a glue".into()
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use crate::parse::testing::*;
70    use core::GlueOrder;
71
72    #[derive(Default)]
73    struct State;
74
75    impl TexlangState for State {}
76
77    parse_success_tests![
78        (
79            width_1,
80            "0pt",
81            Glue {
82                ..Default::default()
83            }
84        ),
85        (
86            width_2,
87            "1pt",
88            Glue {
89                width: Scaled::ONE,
90                ..Default::default()
91            }
92        ),
93        (
94            width_3,
95            "-1pt",
96            Glue {
97                width: -Scaled::ONE,
98                ..Default::default()
99            }
100        ),
101        (
102            stretch_1,
103            "1pt plus 1pt",
104            Glue {
105                width: Scaled::ONE,
106                stretch: Scaled::ONE,
107                ..Default::default()
108            }
109        ),
110        (
111            stretch_fil,
112            "1pt plus 1fil",
113            Glue {
114                width: Scaled::ONE,
115                stretch: Scaled::ONE,
116                stretch_order: GlueOrder::Fil,
117                ..Default::default()
118            }
119        ),
120        (
121            stretch_fill,
122            "1pt plus 1fill",
123            Glue {
124                width: Scaled::ONE,
125                stretch: Scaled::ONE,
126                stretch_order: GlueOrder::Fill,
127                ..Default::default()
128            }
129        ),
130        (
131            stretch_filll,
132            "1pt plus 1filll",
133            Glue {
134                width: Scaled::ONE,
135                stretch: Scaled::ONE,
136                stretch_order: GlueOrder::Filll,
137                ..Default::default()
138            }
139        ),
140    ];
141
142    parse_failure_tests!(
143        Glue,
144        State,
145        (
146            stretch_overflow_1,
147            "1pt plus 30000000fil",
148            Glue {
149                width: Scaled::ONE,
150                stretch: Scaled::MAX_DIMEN,
151                stretch_order: GlueOrder::Fil,
152                ..Default::default()
153            }
154        ),
155        (
156            stretch_overflow_2,
157            "1pt plus -30000000fil",
158            Glue {
159                width: Scaled::ONE,
160                stretch: -Scaled::MAX_DIMEN,
161                stretch_order: GlueOrder::Fil,
162                ..Default::default()
163            }
164        ),
165        (
166            stretch_fillll,
167            "1pt plus 2fillll",
168            Glue {
169                width: Scaled::ONE,
170                stretch: Scaled::ONE * 2,
171                stretch_order: GlueOrder::Filll,
172                ..Default::default()
173            }
174        ),
175    );
176}