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 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}