raffia/parser/
convert.rs

1use crate::{
2    ast::{
3        Dimension, DimensionKind, Ident, InterpolableIdentStaticPart, InterpolableStrStaticPart,
4        InterpolableUrlStaticPart, Number, Str,
5    },
6    error::{Error, ErrorKind, PResult},
7    tokenizer::token,
8    util, Span,
9};
10use std::borrow::Cow;
11
12impl<'s> TryFrom<(token::Dimension<'s>, Span)> for Dimension<'s> {
13    type Error = Error;
14
15    fn try_from((token, span): (token::Dimension<'s>, Span)) -> PResult<Self> {
16        let value_span = Span {
17            start: span.start,
18            end: span.start + token.value.raw.len(),
19        };
20        let unit_span = Span {
21            start: span.start + token.value.raw.len(),
22            end: span.end,
23        };
24
25        let value = (token.value, value_span).try_into()?;
26        let unit = Ident::from((token.unit, unit_span));
27        let unit_name = &unit.name;
28        let kind = if unit_name.eq_ignore_ascii_case("px")
29            || unit_name.eq_ignore_ascii_case("em")
30            || unit_name.eq_ignore_ascii_case("rem")
31            || unit_name.eq_ignore_ascii_case("ex")
32            || unit_name.eq_ignore_ascii_case("rex")
33            || unit_name.eq_ignore_ascii_case("cap")
34            || unit_name.eq_ignore_ascii_case("rcap")
35            || unit_name.eq_ignore_ascii_case("ch")
36            || unit_name.eq_ignore_ascii_case("rch")
37            || unit_name.eq_ignore_ascii_case("ic")
38            || unit_name.eq_ignore_ascii_case("ric")
39            || unit_name.eq_ignore_ascii_case("lh")
40            || unit_name.eq_ignore_ascii_case("rlh")
41            || unit_name.eq_ignore_ascii_case("vw")
42            || unit_name.eq_ignore_ascii_case("vh")
43            || unit_name.eq_ignore_ascii_case("vi")
44            || unit_name.eq_ignore_ascii_case("vb")
45            || unit_name.eq_ignore_ascii_case("vmin")
46            || unit_name.eq_ignore_ascii_case("vmax")
47            || unit_name.eq_ignore_ascii_case("lvw")
48            || unit_name.eq_ignore_ascii_case("lvh")
49            || unit_name.eq_ignore_ascii_case("lvi")
50            || unit_name.eq_ignore_ascii_case("lvb")
51            || unit_name.eq_ignore_ascii_case("lvmin")
52            || unit_name.eq_ignore_ascii_case("lvmax")
53            || unit_name.eq_ignore_ascii_case("svw")
54            || unit_name.eq_ignore_ascii_case("svh")
55            || unit_name.eq_ignore_ascii_case("svi")
56            || unit_name.eq_ignore_ascii_case("svb")
57            || unit_name.eq_ignore_ascii_case("vmin")
58            || unit_name.eq_ignore_ascii_case("vmax")
59            || unit_name.eq_ignore_ascii_case("dvw")
60            || unit_name.eq_ignore_ascii_case("dvh")
61            || unit_name.eq_ignore_ascii_case("dvi")
62            || unit_name.eq_ignore_ascii_case("dvb")
63            || unit_name.eq_ignore_ascii_case("dvmin")
64            || unit_name.eq_ignore_ascii_case("dvmax")
65            || unit_name.eq_ignore_ascii_case("cm")
66            || unit_name.eq_ignore_ascii_case("mm")
67            || unit_name.eq_ignore_ascii_case("Q")
68            || unit_name.eq_ignore_ascii_case("in")
69            || unit_name.eq_ignore_ascii_case("pc")
70            || unit_name.eq_ignore_ascii_case("pt")
71        {
72            DimensionKind::Length
73        } else if unit_name.eq_ignore_ascii_case("deg")
74            || unit_name.eq_ignore_ascii_case("grad")
75            || unit_name.eq_ignore_ascii_case("rad")
76            || unit_name.eq_ignore_ascii_case("turn")
77        {
78            DimensionKind::Angle
79        } else if unit_name.eq_ignore_ascii_case("s") || unit_name.eq_ignore_ascii_case("ms") {
80            DimensionKind::Duration
81        } else if unit_name.eq_ignore_ascii_case("Hz") || unit_name.eq_ignore_ascii_case("kHz") {
82            DimensionKind::Frequency
83        } else if unit_name.eq_ignore_ascii_case("dpi")
84            || unit_name.eq_ignore_ascii_case("dpcm")
85            || unit_name.eq_ignore_ascii_case("dppx")
86        {
87            DimensionKind::Resolution
88        } else if unit_name.eq_ignore_ascii_case("fr") {
89            DimensionKind::Flex
90        } else {
91            DimensionKind::Unknown
92        };
93
94        Ok(Dimension {
95            value,
96            unit,
97            kind,
98            span,
99        })
100    }
101}
102
103impl<'s> From<(token::Ident<'s>, Span)> for Ident<'s> {
104    fn from((token, span): (token::Ident<'s>, Span)) -> Self {
105        Ident {
106            name: token.name(),
107            raw: token.raw,
108            span,
109        }
110    }
111}
112
113impl<'s> From<(token::Ident<'s>, Span)> for InterpolableIdentStaticPart<'s> {
114    fn from((token, span): (token::Ident<'s>, Span)) -> Self {
115        InterpolableIdentStaticPart {
116            value: token.name(),
117            raw: token.raw,
118            span,
119        }
120    }
121}
122
123impl<'s> TryFrom<(token::Number<'s>, Span)> for Number<'s> {
124    type Error = Error;
125
126    fn try_from((token, span): (token::Number<'s>, Span)) -> PResult<Self> {
127        token
128            .raw
129            .parse()
130            .map_err(|_| Error {
131                kind: ErrorKind::InvalidNumber,
132                span: span.clone(),
133            })
134            .map(|value| Self {
135                value,
136                raw: token.raw,
137                span,
138            })
139    }
140}
141
142impl<'s> From<(token::StrTemplate<'s>, Span)> for InterpolableStrStaticPart<'s> {
143    fn from((token, span): (token::StrTemplate<'s>, Span)) -> Self {
144        let raw_without_quotes = if token.tail {
145            unsafe { token.raw.get_unchecked(0..token.raw.len() - 1) }
146        } else if token.head {
147            unsafe { token.raw.get_unchecked(1..token.raw.len()) }
148        } else {
149            token.raw
150        };
151        let value = if token.escaped {
152            util::handle_escape(raw_without_quotes)
153        } else {
154            Cow::from(raw_without_quotes)
155        };
156        Self {
157            value,
158            raw: token.raw,
159            span,
160        }
161    }
162}
163
164impl<'s> From<(token::UrlTemplate<'s>, Span)> for InterpolableUrlStaticPart<'s> {
165    fn from((token, span): (token::UrlTemplate<'s>, Span)) -> Self {
166        let value = if token.escaped {
167            util::handle_escape(token.raw)
168        } else {
169            Cow::from(token.raw)
170        };
171        Self {
172            value,
173            raw: token.raw,
174            span,
175        }
176    }
177}
178
179impl<'s> From<(token::Str<'s>, Span)> for Str<'s> {
180    fn from((str, span): (token::Str<'s>, Span)) -> Self {
181        let raw_without_quotes = unsafe { str.raw.get_unchecked(1..str.raw.len() - 1) };
182        let value = if str.escaped {
183            util::handle_escape(raw_without_quotes)
184        } else {
185            Cow::from(raw_without_quotes)
186        };
187        Self {
188            value,
189            raw: str.raw,
190            span,
191        }
192    }
193}