seq_macro/
parse.rs

1use crate::{Kind, Radix, Range, Value};
2use proc_macro::token_stream::IntoIter as TokenIter;
3use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree};
4use std::borrow::Borrow;
5use std::cmp;
6use std::fmt::Display;
7use std::iter::FromIterator;
8
9pub(crate) struct SyntaxError {
10    message: String,
11    span: Span,
12}
13
14impl SyntaxError {
15    pub(crate) fn into_compile_error(self) -> TokenStream {
16        // compile_error! { $message }
17        TokenStream::from_iter(vec![
18            TokenTree::Ident(Ident::new("compile_error", self.span)),
19            TokenTree::Punct({
20                let mut punct = Punct::new('!', Spacing::Alone);
21                punct.set_span(self.span);
22                punct
23            }),
24            TokenTree::Group({
25                let mut group = Group::new(Delimiter::Brace, {
26                    TokenStream::from_iter(vec![TokenTree::Literal({
27                        let mut string = Literal::string(&self.message);
28                        string.set_span(self.span);
29                        string
30                    })])
31                });
32                group.set_span(self.span);
33                group
34            }),
35        ])
36    }
37}
38
39fn next_token(iter: &mut TokenIter) -> Result<TokenTree, SyntaxError> {
40    iter.next().ok_or_else(|| SyntaxError {
41        message: "unexpected end of input".to_owned(),
42        span: Span::call_site(),
43    })
44}
45
46fn syntax<T: Borrow<TokenTree>, M: Display>(token: T, message: M) -> SyntaxError {
47    SyntaxError {
48        message: message.to_string(),
49        span: token.borrow().span(),
50    }
51}
52
53pub(crate) fn require_ident(iter: &mut TokenIter) -> Result<Ident, SyntaxError> {
54    match next_token(iter)? {
55        TokenTree::Ident(ident) => Ok(ident),
56        other => Err(syntax(other, "expected ident")),
57    }
58}
59
60pub(crate) fn require_keyword(iter: &mut TokenIter, keyword: &str) -> Result<(), SyntaxError> {
61    let token = next_token(iter)?;
62    if let TokenTree::Ident(ident) = &token {
63        if ident.to_string() == keyword {
64            return Ok(());
65        }
66    }
67    Err(syntax(token, format!("expected `{}`", keyword)))
68}
69
70pub(crate) fn require_value(iter: &mut TokenIter) -> Result<Value, SyntaxError> {
71    let mut token = next_token(iter)?;
72
73    loop {
74        match token {
75            TokenTree::Group(group) => {
76                let delimiter = group.delimiter();
77                let mut stream = group.stream().into_iter();
78                token = TokenTree::Group(group);
79                if delimiter != Delimiter::None {
80                    break;
81                }
82                let first = match stream.next() {
83                    Some(first) => first,
84                    None => break,
85                };
86                match stream.next() {
87                    Some(_) => break,
88                    None => token = first,
89                }
90            }
91            TokenTree::Literal(lit) => {
92                return parse_literal(&lit).ok_or_else(|| {
93                    let token = TokenTree::Literal(lit);
94                    syntax(token, "expected unsuffixed integer literal")
95                });
96            }
97            _ => break,
98        }
99    }
100
101    Err(syntax(token, "expected integer"))
102}
103
104pub(crate) fn require_if_punct(iter: &mut TokenIter, ch: char) -> Result<bool, SyntaxError> {
105    let present = match iter.clone().next() {
106        Some(TokenTree::Punct(_)) => {
107            require_punct(iter, ch)?;
108            true
109        }
110        _ => false,
111    };
112    Ok(present)
113}
114
115pub(crate) fn require_punct(iter: &mut TokenIter, ch: char) -> Result<(), SyntaxError> {
116    let token = next_token(iter)?;
117    if let TokenTree::Punct(punct) = &token {
118        if punct.as_char() == ch {
119            return Ok(());
120        }
121    }
122    Err(syntax(token, format!("expected `{}`", ch)))
123}
124
125pub(crate) fn require_braces(iter: &mut TokenIter) -> Result<TokenStream, SyntaxError> {
126    let token = next_token(iter)?;
127    if let TokenTree::Group(group) = &token {
128        if group.delimiter() == Delimiter::Brace {
129            return Ok(group.stream());
130        }
131    }
132    Err(syntax(token, "expected curly braces"))
133}
134
135pub(crate) fn require_end(iter: &mut TokenIter) -> Result<(), SyntaxError> {
136    match iter.next() {
137        Some(token) => Err(syntax(token, "unexpected token")),
138        None => Ok(()),
139    }
140}
141
142pub(crate) fn validate_range(
143    begin: Value,
144    end: Value,
145    inclusive: bool,
146) -> Result<Range, SyntaxError> {
147    let kind = if begin.kind == end.kind {
148        begin.kind
149    } else {
150        let expected = match begin.kind {
151            Kind::Int => "integer",
152            Kind::Byte => "byte",
153            Kind::Char => "character",
154        };
155        return Err(SyntaxError {
156            message: format!("expected {} literal", expected),
157            span: end.span,
158        });
159    };
160
161    let suffix = if begin.suffix.is_empty() {
162        end.suffix
163    } else if end.suffix.is_empty() || begin.suffix == end.suffix {
164        begin.suffix
165    } else {
166        return Err(SyntaxError {
167            message: format!("expected suffix `{}`", begin.suffix),
168            span: end.span,
169        });
170    };
171
172    let radix = if begin.radix == end.radix {
173        begin.radix
174    } else if begin.radix == Radix::LowerHex && end.radix == Radix::UpperHex
175        || begin.radix == Radix::UpperHex && end.radix == Radix::LowerHex
176    {
177        Radix::UpperHex
178    } else {
179        let expected = match begin.radix {
180            Radix::Binary => "binary",
181            Radix::Octal => "octal",
182            Radix::Decimal => "base 10",
183            Radix::LowerHex | Radix::UpperHex => "hexadecimal",
184        };
185        return Err(SyntaxError {
186            message: format!("expected {} literal", expected),
187            span: end.span,
188        });
189    };
190
191    Ok(Range {
192        begin: begin.int,
193        end: end.int,
194        inclusive,
195        kind,
196        suffix,
197        width: cmp::min(begin.width, end.width),
198        radix,
199    })
200}
201
202fn parse_literal(lit: &Literal) -> Option<Value> {
203    let span = lit.span();
204    let repr = lit.to_string();
205    assert!(!repr.starts_with('_'));
206
207    if repr.starts_with("b'") && repr.ends_with('\'') && repr.len() == 4 {
208        return Some(Value {
209            int: repr.as_bytes()[2] as u64,
210            kind: Kind::Byte,
211            suffix: String::new(),
212            width: 0,
213            radix: Radix::Decimal,
214            span,
215        });
216    }
217
218    if repr.starts_with('\'') && repr.ends_with('\'') && repr.chars().count() == 3 {
219        return Some(Value {
220            int: repr[1..].chars().next().unwrap() as u64,
221            kind: Kind::Char,
222            suffix: String::new(),
223            width: 0,
224            radix: Radix::Decimal,
225            span,
226        });
227    }
228
229    let (mut radix, radix_n) = if repr.starts_with("0b") {
230        (Radix::Binary, 2)
231    } else if repr.starts_with("0o") {
232        (Radix::Octal, 8)
233    } else if repr.starts_with("0x") {
234        (Radix::LowerHex, 16)
235    } else if repr.starts_with("0X") {
236        (Radix::UpperHex, 16)
237    } else {
238        (Radix::Decimal, 10)
239    };
240
241    let mut iter = repr.char_indices();
242    let mut digits = String::new();
243    let mut suffix = String::new();
244
245    if radix != Radix::Decimal {
246        let _ = iter.nth(1);
247    }
248
249    for (i, ch) in iter {
250        match ch {
251            '_' => continue,
252            '0'..='9' => digits.push(ch),
253            'A'..='F' if radix == Radix::LowerHex => {
254                digits.push(ch);
255                radix = Radix::UpperHex;
256            }
257            'a'..='f' | 'A'..='F' if radix_n == 16 => digits.push(ch),
258            '.' => return None,
259            _ => {
260                if digits.is_empty() {
261                    return None;
262                }
263                suffix = repr;
264                suffix.replace_range(..i, "");
265                break;
266            }
267        }
268    }
269
270    let int = u64::from_str_radix(&digits, radix_n).ok()?;
271    let kind = Kind::Int;
272    let width = digits.len();
273    Some(Value {
274        int,
275        kind,
276        suffix,
277        width,
278        radix,
279        span,
280    })
281}