]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/mod.rs
eb71003d3d0cfbf27f90dc992e6a1a41d520f7c5
[rust.git] / src / libsyntax / parse / mod.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The main parser interface
12
13 use rustc_data_structures::sync::{Lrc, Lock};
14 use ast::{self, CrateConfig, NodeId};
15 use early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId};
16 use source_map::{SourceMap, FilePathMapping};
17 use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
18 use errors::{Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
19 use feature_gate::UnstableFeatures;
20 use parse::parser::Parser;
21 use ptr::P;
22 use symbol::Symbol;
23 use tokenstream::{TokenStream, TokenTree};
24 use diagnostics::plugin::ErrorMap;
25
26 use rustc_data_structures::fx::FxHashSet;
27 use std::borrow::Cow;
28 use std::iter;
29 use std::path::{Path, PathBuf};
30 use std::str;
31
32 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
33
34 #[macro_use]
35 pub mod parser;
36
37 pub mod lexer;
38 pub mod token;
39 pub mod attr;
40
41 pub mod classify;
42
43 /// Info about a parsing session.
44 pub struct ParseSess {
45     pub span_diagnostic: Handler,
46     pub unstable_features: UnstableFeatures,
47     pub config: CrateConfig,
48     pub missing_fragment_specifiers: Lock<FxHashSet<Span>>,
49     /// Places where raw identifiers were used. This is used for feature gating
50     /// raw identifiers
51     pub raw_identifier_spans: Lock<Vec<Span>>,
52     /// The registered diagnostics codes
53     crate registered_diagnostics: Lock<ErrorMap>,
54     /// Used to determine and report recursive mod inclusions
55     included_mod_stack: Lock<Vec<PathBuf>>,
56     source_map: Lrc<SourceMap>,
57     pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
58 }
59
60 impl ParseSess {
61     pub fn new(file_path_mapping: FilePathMapping) -> Self {
62         let cm = Lrc::new(SourceMap::new(file_path_mapping));
63         let handler = Handler::with_tty_emitter(ColorConfig::Auto,
64                                                 true,
65                                                 false,
66                                                 Some(cm.clone()));
67         ParseSess::with_span_handler(handler, cm)
68     }
69
70     pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> ParseSess {
71         ParseSess {
72             span_diagnostic: handler,
73             unstable_features: UnstableFeatures::from_environment(),
74             config: FxHashSet::default(),
75             missing_fragment_specifiers: Lock::new(FxHashSet::default()),
76             raw_identifier_spans: Lock::new(Vec::new()),
77             registered_diagnostics: Lock::new(ErrorMap::new()),
78             included_mod_stack: Lock::new(vec![]),
79             source_map,
80             buffered_lints: Lock::new(vec![]),
81         }
82     }
83
84     pub fn source_map(&self) -> &SourceMap {
85         &self.source_map
86     }
87
88     pub fn buffer_lint<S: Into<MultiSpan>>(&self,
89         lint_id: BufferedEarlyLintId,
90         span: S,
91         id: NodeId,
92         msg: &str,
93     ) {
94         self.buffered_lints.with_lock(|buffered_lints| {
95             buffered_lints.push(BufferedEarlyLint{
96                 span: span.into(),
97                 id,
98                 msg: msg.into(),
99                 lint_id,
100             });
101         });
102     }
103 }
104
105 #[derive(Clone)]
106 pub struct Directory<'a> {
107     pub path: Cow<'a, Path>,
108     pub ownership: DirectoryOwnership,
109 }
110
111 #[derive(Copy, Clone)]
112 pub enum DirectoryOwnership {
113     Owned {
114         // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`
115         relative: Option<ast::Ident>,
116     },
117     UnownedViaBlock,
118     UnownedViaMod(bool /* legacy warnings? */),
119 }
120
121 // a bunch of utility functions of the form parse_<thing>_from_<source>
122 // where <thing> includes crate, expr, item, stmt, tts, and one that
123 // uses a HOF to parse anything, and <source> includes file and
124 // source_str.
125
126 pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> {
127     let mut parser = new_parser_from_file(sess, input);
128     parser.parse_crate_mod()
129 }
130
131 pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess)
132                                        -> PResult<'a, Vec<ast::Attribute>> {
133     let mut parser = new_parser_from_file(sess, input);
134     parser.parse_inner_attributes()
135 }
136
137 pub fn parse_crate_from_source_str(name: FileName, source: String, sess: &ParseSess)
138                                        -> PResult<ast::Crate> {
139     new_parser_from_source_str(sess, name, source).parse_crate_mod()
140 }
141
142 pub fn parse_crate_attrs_from_source_str(name: FileName, source: String, sess: &ParseSess)
143                                              -> PResult<Vec<ast::Attribute>> {
144     new_parser_from_source_str(sess, name, source).parse_inner_attributes()
145 }
146
147 crate fn parse_expr_from_source_str(name: FileName, source: String, sess: &ParseSess)
148                                       -> PResult<P<ast::Expr>> {
149     new_parser_from_source_str(sess, name, source).parse_expr()
150 }
151
152 /// Parses an item.
153 ///
154 /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err`
155 /// when a syntax error occurred.
156 crate fn parse_item_from_source_str(name: FileName, source: String, sess: &ParseSess)
157                                       -> PResult<Option<P<ast::Item>>> {
158     new_parser_from_source_str(sess, name, source).parse_item()
159 }
160
161 crate fn parse_stmt_from_source_str(name: FileName, source: String, sess: &ParseSess)
162                                       -> PResult<Option<ast::Stmt>> {
163     new_parser_from_source_str(sess, name, source).parse_stmt()
164 }
165
166 pub fn parse_stream_from_source_str(name: FileName, source: String, sess: &ParseSess,
167                                     override_span: Option<Span>)
168                                     -> TokenStream {
169     source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span)
170 }
171
172 /// Create a new parser from a source string
173 pub fn new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String)
174                                       -> Parser {
175     panictry_buffer!(&sess.span_diagnostic, maybe_new_parser_from_source_str(sess, name, source))
176 }
177
178 /// Create a new parser from a source string. Returns any buffered errors from lexing the initial
179 /// token stream.
180 pub fn maybe_new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String)
181     -> Result<Parser, Vec<Diagnostic>>
182 {
183     let mut parser = maybe_source_file_to_parser(sess,
184                                                  sess.source_map().new_source_file(name, source))?;
185     parser.recurse_into_file_modules = false;
186     Ok(parser)
187 }
188
189 /// Create a new parser, handling errors as appropriate
190 /// if the file doesn't exist
191 pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a> {
192     source_file_to_parser(sess, file_to_source_file(sess, path, None))
193 }
194
195 /// Given a session, a crate config, a path, and a span, add
196 /// the file at the given path to the source_map, and return a parser.
197 /// On an error, use the given span as the source of the problem.
198 crate fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
199                                     path: &Path,
200                                     directory_ownership: DirectoryOwnership,
201                                     module_name: Option<String>,
202                                     sp: Span) -> Parser<'a> {
203     let mut p = source_file_to_parser(sess, file_to_source_file(sess, path, Some(sp)));
204     p.directory.ownership = directory_ownership;
205     p.root_module_name = module_name;
206     p
207 }
208
209 /// Given a source_file and config, return a parser
210 fn source_file_to_parser(sess: & ParseSess, source_file: Lrc<SourceFile>) -> Parser {
211     panictry_buffer!(&sess.span_diagnostic,
212                      maybe_source_file_to_parser(sess, source_file))
213 }
214
215 /// Given a source_file and config, return a parser. Returns any buffered errors from lexing the
216 /// initial token stream.
217 fn maybe_source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>)
218     -> Result<Parser, Vec<Diagnostic>>
219 {
220     let end_pos = source_file.end_pos;
221     let mut parser = stream_to_parser(sess, maybe_file_to_stream(sess, source_file, None)?);
222
223     if parser.token == token::Eof && parser.span.is_dummy() {
224         parser.span = Span::new(end_pos, end_pos, parser.span.ctxt());
225     }
226
227     Ok(parser)
228 }
229
230 // must preserve old name for now, because quote! from the *existing*
231 // compiler expands into it
232 pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser {
233     stream_to_parser(sess, tts.into_iter().collect())
234 }
235
236
237 // base abstractions
238
239 /// Given a session and a path and an optional span (for error reporting),
240 /// add the path to the session's source_map and return the new source_file.
241 fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
242                    -> Lrc<SourceFile> {
243     match sess.source_map().load_file(path) {
244         Ok(source_file) => source_file,
245         Err(e) => {
246             let msg = format!("couldn't read {}: {}", path.display(), e);
247             match spanopt {
248                 Some(sp) => sess.span_diagnostic.span_fatal(sp, &msg).raise(),
249                 None => sess.span_diagnostic.fatal(&msg).raise()
250             }
251         }
252     }
253 }
254
255 /// Given a source_file, produce a sequence of token-trees
256 pub fn source_file_to_stream(sess: &ParseSess,
257                              source_file: Lrc<SourceFile>,
258                              override_span: Option<Span>) -> TokenStream {
259     panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span))
260 }
261
262 /// Given a source file, produce a sequence of token-trees. Returns any buffered errors from
263 /// parsing the token tream.
264 pub fn maybe_file_to_stream(sess: &ParseSess,
265                             source_file: Lrc<SourceFile>,
266                             override_span: Option<Span>) -> Result<TokenStream, Vec<Diagnostic>> {
267     let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
268     srdr.real_token();
269
270     match srdr.parse_all_token_trees() {
271         Ok(stream) => Ok(stream),
272         Err(err) => {
273             let mut buffer = Vec::with_capacity(1);
274             err.buffer(&mut buffer);
275             Err(buffer)
276         }
277     }
278 }
279
280 /// Given stream and the `ParseSess`, produce a parser
281 pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser {
282     Parser::new(sess, stream, None, true, false)
283 }
284
285 /// Parse a string representing a character literal into its final form.
286 /// Rather than just accepting/rejecting a given literal, unescapes it as
287 /// well. Can take any slice prefixed by a character escape. Returns the
288 /// character and the number of characters consumed.
289 fn char_lit(lit: &str, diag: Option<(Span, &Handler)>) -> (char, isize) {
290     use std::char;
291
292     // Handle non-escaped chars first.
293     if lit.as_bytes()[0] != b'\\' {
294         // If the first byte isn't '\\' it might part of a multi-byte char, so
295         // get the char with chars().
296         let c = lit.chars().next().unwrap();
297         return (c, 1);
298     }
299
300     // Handle escaped chars.
301     match lit.as_bytes()[1] as char {
302         '"' => ('"', 2),
303         'n' => ('\n', 2),
304         'r' => ('\r', 2),
305         't' => ('\t', 2),
306         '\\' => ('\\', 2),
307         '\'' => ('\'', 2),
308         '0' => ('\0', 2),
309         'x' => {
310             let v = u32::from_str_radix(&lit[2..4], 16).unwrap();
311             let c = char::from_u32(v).unwrap();
312             (c, 4)
313         }
314         'u' => {
315             assert_eq!(lit.as_bytes()[2], b'{');
316             let idx = lit.find('}').unwrap();
317
318             // All digits and '_' are ascii, so treat each byte as a char.
319             let mut v: u32 = 0;
320             for c in lit[3..idx].bytes() {
321                 let c = char::from(c);
322                 if c != '_' {
323                     let x = c.to_digit(16).unwrap();
324                     v = v.checked_mul(16).unwrap().checked_add(x).unwrap();
325                 }
326             }
327             let c = char::from_u32(v).unwrap_or_else(|| {
328                 if let Some((span, diag)) = diag {
329                     let mut diag = diag.struct_span_err(span, "invalid unicode character escape");
330                     if v > 0x10FFFF {
331                         diag.help("unicode escape must be at most 10FFFF").emit();
332                     } else {
333                         diag.help("unicode escape must not be a surrogate").emit();
334                     }
335                 }
336                 '\u{FFFD}'
337             });
338             (c, (idx + 1) as isize)
339         }
340         _ => panic!("lexer should have rejected a bad character escape {}", lit)
341     }
342 }
343
344 /// Parse a string representing a string literal into its final form. Does
345 /// unescaping.
346 pub fn str_lit(lit: &str, diag: Option<(Span, &Handler)>) -> String {
347     debug!("str_lit: given {}", lit.escape_default());
348     let mut res = String::with_capacity(lit.len());
349
350     let error = |i| format!("lexer should have rejected {} at {}", lit, i);
351
352     /// Eat everything up to a non-whitespace
353     fn eat<'a>(it: &mut iter::Peekable<str::CharIndices<'a>>) {
354         loop {
355             match it.peek().map(|x| x.1) {
356                 Some(' ') | Some('\n') | Some('\r') | Some('\t') => {
357                     it.next();
358                 },
359                 _ => { break; }
360             }
361         }
362     }
363
364     let mut chars = lit.char_indices().peekable();
365     while let Some((i, c)) = chars.next() {
366         match c {
367             '\\' => {
368                 let ch = chars.peek().unwrap_or_else(|| {
369                     panic!("{}", error(i))
370                 }).1;
371
372                 if ch == '\n' {
373                     eat(&mut chars);
374                 } else if ch == '\r' {
375                     chars.next();
376                     let ch = chars.peek().unwrap_or_else(|| {
377                         panic!("{}", error(i))
378                     }).1;
379
380                     if ch != '\n' {
381                         panic!("lexer accepted bare CR");
382                     }
383                     eat(&mut chars);
384                 } else {
385                     // otherwise, a normal escape
386                     let (c, n) = char_lit(&lit[i..], diag);
387                     for _ in 0..n - 1 { // we don't need to move past the first \
388                         chars.next();
389                     }
390                     res.push(c);
391                 }
392             },
393             '\r' => {
394                 let ch = chars.peek().unwrap_or_else(|| {
395                     panic!("{}", error(i))
396                 }).1;
397
398                 if ch != '\n' {
399                     panic!("lexer accepted bare CR");
400                 }
401                 chars.next();
402                 res.push('\n');
403             }
404             c => res.push(c),
405         }
406     }
407
408     res.shrink_to_fit(); // probably not going to do anything, unless there was an escape.
409     debug!("parse_str_lit: returning {}", res);
410     res
411 }
412
413 /// Parse a string representing a raw string literal into its final form. The
414 /// only operation this does is convert embedded CRLF into a single LF.
415 fn raw_str_lit(lit: &str) -> String {
416     debug!("raw_str_lit: given {}", lit.escape_default());
417     let mut res = String::with_capacity(lit.len());
418
419     let mut chars = lit.chars().peekable();
420     while let Some(c) = chars.next() {
421         if c == '\r' {
422             if *chars.peek().unwrap() != '\n' {
423                 panic!("lexer accepted bare CR");
424             }
425             chars.next();
426             res.push('\n');
427         } else {
428             res.push(c);
429         }
430     }
431
432     res.shrink_to_fit();
433     res
434 }
435
436 // check if `s` looks like i32 or u1234 etc.
437 fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
438     s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
439 }
440
441 macro_rules! err {
442     ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => {
443         match $opt_diag {
444             Some(($span, $diag)) => { $($body)* }
445             None => return None,
446         }
447     }
448 }
449
450 crate fn lit_token(lit: token::Lit, suf: Option<Symbol>, diag: Option<(Span, &Handler)>)
451                  -> (bool /* suffix illegal? */, Option<ast::LitKind>) {
452     use ast::LitKind;
453
454     match lit {
455        token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))),
456        token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str(), diag).0))),
457
458         // There are some valid suffixes for integer and float literals,
459         // so all the handling is done internally.
460         token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)),
461         token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)),
462
463         token::Str_(mut sym) => {
464             // If there are no characters requiring special treatment we can
465             // reuse the symbol from the Token. Otherwise, we must generate a
466             // new symbol because the string in the LitKind is different to the
467             // string in the Token.
468             let s = &sym.as_str();
469             if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') {
470                 sym = Symbol::intern(&str_lit(s, diag));
471             }
472             (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked)))
473         }
474         token::StrRaw(mut sym, n) => {
475             // Ditto.
476             let s = &sym.as_str();
477             if s.contains('\r') {
478                 sym = Symbol::intern(&raw_str_lit(s));
479             }
480             (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n))))
481         }
482         token::ByteStr(i) => {
483             (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str()))))
484         }
485         token::ByteStrRaw(i, _) => {
486             (true, Some(LitKind::ByteStr(Lrc::new(i.to_string().into_bytes()))))
487         }
488     }
489 }
490
491 fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
492                       -> Option<ast::LitKind> {
493     debug!("filtered_float_lit: {}, {:?}", data, suffix);
494     let suffix = match suffix {
495         Some(suffix) => suffix,
496         None => return Some(ast::LitKind::FloatUnsuffixed(data)),
497     };
498
499     Some(match &*suffix.as_str() {
500         "f32" => ast::LitKind::Float(data, ast::FloatTy::F32),
501         "f64" => ast::LitKind::Float(data, ast::FloatTy::F64),
502         suf => {
503             err!(diag, |span, diag| {
504                 if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) {
505                     // if it looks like a width, lets try to be helpful.
506                     let msg = format!("invalid width `{}` for float literal", &suf[1..]);
507                     diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit()
508                 } else {
509                     let msg = format!("invalid suffix `{}` for float literal", suf);
510                     diag.struct_span_err(span, &msg)
511                         .help("valid suffixes are `f32` and `f64`")
512                         .emit();
513                 }
514             });
515
516             ast::LitKind::FloatUnsuffixed(data)
517         }
518     })
519 }
520 fn float_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
521                  -> Option<ast::LitKind> {
522     debug!("float_lit: {:?}, {:?}", s, suffix);
523     // FIXME #2252: bounds checking float literals is deferred until trans
524
525     // Strip underscores without allocating a new String unless necessary.
526     let s2;
527     let s = if s.chars().any(|c| c == '_') {
528         s2 = s.chars().filter(|&c| c != '_').collect::<String>();
529         &s2
530     } else {
531         s
532     };
533
534     filtered_float_lit(Symbol::intern(s), suffix, diag)
535 }
536
537 /// Parse a string representing a byte literal into its final form. Similar to `char_lit`
538 fn byte_lit(lit: &str) -> (u8, usize) {
539     let err = |i| format!("lexer accepted invalid byte literal {} step {}", lit, i);
540
541     if lit.len() == 1 {
542         (lit.as_bytes()[0], 1)
543     } else {
544         assert_eq!(lit.as_bytes()[0], b'\\', "{}", err(0));
545         let b = match lit.as_bytes()[1] {
546             b'"' => b'"',
547             b'n' => b'\n',
548             b'r' => b'\r',
549             b't' => b'\t',
550             b'\\' => b'\\',
551             b'\'' => b'\'',
552             b'0' => b'\0',
553             _ => {
554                 match u64::from_str_radix(&lit[2..4], 16).ok() {
555                     Some(c) =>
556                         if c > 0xFF {
557                             panic!(err(2))
558                         } else {
559                             return (c as u8, 4)
560                         },
561                     None => panic!(err(3))
562                 }
563             }
564         };
565         (b, 2)
566     }
567 }
568
569 fn byte_str_lit(lit: &str) -> Lrc<Vec<u8>> {
570     let mut res = Vec::with_capacity(lit.len());
571
572     let error = |i| panic!("lexer should have rejected {} at {}", lit, i);
573
574     /// Eat everything up to a non-whitespace
575     fn eat<I: Iterator<Item=(usize, u8)>>(it: &mut iter::Peekable<I>) {
576         loop {
577             match it.peek().map(|x| x.1) {
578                 Some(b' ') | Some(b'\n') | Some(b'\r') | Some(b'\t') => {
579                     it.next();
580                 },
581                 _ => { break; }
582             }
583         }
584     }
585
586     // byte string literals *must* be ASCII, but the escapes don't have to be
587     let mut chars = lit.bytes().enumerate().peekable();
588     loop {
589         match chars.next() {
590             Some((i, b'\\')) => {
591                 match chars.peek().unwrap_or_else(|| error(i)).1 {
592                     b'\n' => eat(&mut chars),
593                     b'\r' => {
594                         chars.next();
595                         if chars.peek().unwrap_or_else(|| error(i)).1 != b'\n' {
596                             panic!("lexer accepted bare CR");
597                         }
598                         eat(&mut chars);
599                     }
600                     _ => {
601                         // otherwise, a normal escape
602                         let (c, n) = byte_lit(&lit[i..]);
603                         // we don't need to move past the first \
604                         for _ in 0..n - 1 {
605                             chars.next();
606                         }
607                         res.push(c);
608                     }
609                 }
610             },
611             Some((i, b'\r')) => {
612                 if chars.peek().unwrap_or_else(|| error(i)).1 != b'\n' {
613                     panic!("lexer accepted bare CR");
614                 }
615                 chars.next();
616                 res.push(b'\n');
617             }
618             Some((_, c)) => res.push(c),
619             None => break,
620         }
621     }
622
623     Lrc::new(res)
624 }
625
626 fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
627                    -> Option<ast::LitKind> {
628     // s can only be ascii, byte indexing is fine
629
630     // Strip underscores without allocating a new String unless necessary.
631     let s2;
632     let mut s = if s.chars().any(|c| c == '_') {
633         s2 = s.chars().filter(|&c| c != '_').collect::<String>();
634         &s2
635     } else {
636         s
637     };
638
639     debug!("integer_lit: {}, {:?}", s, suffix);
640
641     let mut base = 10;
642     let orig = s;
643     let mut ty = ast::LitIntType::Unsuffixed;
644
645     if s.starts_with('0') && s.len() > 1 {
646         match s.as_bytes()[1] {
647             b'x' => base = 16,
648             b'o' => base = 8,
649             b'b' => base = 2,
650             _ => { }
651         }
652     }
653
654     // 1f64 and 2f32 etc. are valid float literals.
655     if let Some(suf) = suffix {
656         if looks_like_width_suffix(&['f'], &suf.as_str()) {
657             let err = match base {
658                 16 => Some("hexadecimal float literal is not supported"),
659                 8 => Some("octal float literal is not supported"),
660                 2 => Some("binary float literal is not supported"),
661                 _ => None,
662             };
663             if let Some(err) = err {
664                 err!(diag, |span, diag| diag.span_err(span, err));
665             }
666             return filtered_float_lit(Symbol::intern(s), Some(suf), diag)
667         }
668     }
669
670     if base != 10 {
671         s = &s[2..];
672     }
673
674     if let Some(suf) = suffix {
675         if suf.as_str().is_empty() {
676             err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some"));
677         }
678         ty = match &*suf.as_str() {
679             "isize" => ast::LitIntType::Signed(ast::IntTy::Isize),
680             "i8"  => ast::LitIntType::Signed(ast::IntTy::I8),
681             "i16" => ast::LitIntType::Signed(ast::IntTy::I16),
682             "i32" => ast::LitIntType::Signed(ast::IntTy::I32),
683             "i64" => ast::LitIntType::Signed(ast::IntTy::I64),
684             "i128" => ast::LitIntType::Signed(ast::IntTy::I128),
685             "usize" => ast::LitIntType::Unsigned(ast::UintTy::Usize),
686             "u8"  => ast::LitIntType::Unsigned(ast::UintTy::U8),
687             "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16),
688             "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32),
689             "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64),
690             "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128),
691             suf => {
692                 // i<digits> and u<digits> look like widths, so lets
693                 // give an error message along those lines
694                 err!(diag, |span, diag| {
695                     if looks_like_width_suffix(&['i', 'u'], suf) {
696                         let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
697                         diag.struct_span_err(span, &msg)
698                             .help("valid widths are 8, 16, 32, 64 and 128")
699                             .emit();
700                     } else {
701                         let msg = format!("invalid suffix `{}` for numeric literal", suf);
702                         diag.struct_span_err(span, &msg)
703                             .help("the suffix must be one of the integral types \
704                                    (`u32`, `isize`, etc)")
705                             .emit();
706                     }
707                 });
708
709                 ty
710             }
711         }
712     }
713
714     debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \
715            string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix);
716
717     Some(match u128::from_str_radix(s, base) {
718         Ok(r) => ast::LitKind::Int(r, ty),
719         Err(_) => {
720             // small bases are lexed as if they were base 10, e.g, the string
721             // might be `0b10201`. This will cause the conversion above to fail,
722             // but these cases have errors in the lexer: we don't want to emit
723             // two errors, and we especially don't want to emit this error since
724             // it isn't necessarily true.
725             let already_errored = base < 10 &&
726                 s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
727
728             if !already_errored {
729                 err!(diag, |span, diag| diag.span_err(span, "int literal is too large"));
730             }
731             ast::LitKind::Int(0, ty)
732         }
733     })
734 }
735
736 /// `SeqSep` : a sequence separator (token)
737 /// and whether a trailing separator is allowed.
738 pub struct SeqSep {
739     pub sep: Option<token::Token>,
740     pub trailing_sep_allowed: bool,
741 }
742
743 impl SeqSep {
744     pub fn trailing_allowed(t: token::Token) -> SeqSep {
745         SeqSep {
746             sep: Some(t),
747             trailing_sep_allowed: true,
748         }
749     }
750
751     pub fn none() -> SeqSep {
752         SeqSep {
753             sep: None,
754             trailing_sep_allowed: false,
755         }
756     }
757 }
758
759 #[cfg(test)]
760 mod tests {
761     use super::*;
762     use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION};
763     use ast::{self, Ident, PatKind};
764     use attr::first_attr_value_str_by_name;
765     use parse;
766     use print::pprust::item_to_string;
767     use tokenstream::{DelimSpan, TokenTree};
768     use util::parser_testing::string_to_stream;
769     use util::parser_testing::{string_to_expr, string_to_item};
770     use with_globals;
771
772     // produce a syntax_pos::span
773     fn sp(a: u32, b: u32) -> Span {
774         Span::new(BytePos(a), BytePos(b), NO_EXPANSION)
775     }
776
777     #[should_panic]
778     #[test] fn bad_path_expr_1() {
779         with_globals(|| {
780             string_to_expr("::abc::def::return".to_string());
781         })
782     }
783
784     // check the token-tree-ization of macros
785     #[test]
786     fn string_to_tts_macro () {
787         with_globals(|| {
788             let tts: Vec<_> =
789                 string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect();
790             let tts: &[TokenTree] = &tts[..];
791
792             match (tts.len(), tts.get(0), tts.get(1), tts.get(2), tts.get(3)) {
793                 (
794                     4,
795                     Some(&TokenTree::Token(_, token::Ident(name_macro_rules, false))),
796                     Some(&TokenTree::Token(_, token::Not)),
797                     Some(&TokenTree::Token(_, token::Ident(name_zip, false))),
798                     Some(&TokenTree::Delimited(_, macro_delim, ref macro_tts)),
799                 )
800                 if name_macro_rules.name == "macro_rules"
801                 && name_zip.name == "zip" => {
802                     let tts = &macro_tts.stream().trees().collect::<Vec<_>>();
803                     match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) {
804                         (
805                             3,
806                             Some(&TokenTree::Delimited(_, first_delim, ref first_tts)),
807                             Some(&TokenTree::Token(_, token::FatArrow)),
808                             Some(&TokenTree::Delimited(_, second_delim, ref second_tts)),
809                         )
810                         if macro_delim == token::Paren => {
811                             let tts = &first_tts.stream().trees().collect::<Vec<_>>();
812                             match (tts.len(), tts.get(0), tts.get(1)) {
813                                 (
814                                     2,
815                                     Some(&TokenTree::Token(_, token::Dollar)),
816                                     Some(&TokenTree::Token(_, token::Ident(ident, false))),
817                                 )
818                                 if first_delim == token::Paren && ident.name == "a" => {},
819                                 _ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
820                             }
821                             let tts = &second_tts.stream().trees().collect::<Vec<_>>();
822                             match (tts.len(), tts.get(0), tts.get(1)) {
823                                 (
824                                     2,
825                                     Some(&TokenTree::Token(_, token::Dollar)),
826                                     Some(&TokenTree::Token(_, token::Ident(ident, false))),
827                                 )
828                                 if second_delim == token::Paren && ident.name == "a" => {},
829                                 _ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
830                             }
831                         },
832                         _ => panic!("value 2: {:?} {:?}", macro_delim, macro_tts),
833                     }
834                 },
835                 _ => panic!("value: {:?}",tts),
836             }
837         })
838     }
839
840     #[test]
841     fn string_to_tts_1() {
842         with_globals(|| {
843             let tts = string_to_stream("fn a (b : i32) { b; }".to_string());
844
845             let expected = TokenStream::concat(vec![
846                 TokenTree::Token(sp(0, 2), token::Ident(Ident::from_str("fn"), false)).into(),
847                 TokenTree::Token(sp(3, 4), token::Ident(Ident::from_str("a"), false)).into(),
848                 TokenTree::Delimited(
849                     DelimSpan::from_pair(sp(5, 6), sp(13, 14)),
850                     token::DelimToken::Paren,
851                     TokenStream::concat(vec![
852                         TokenTree::Token(sp(6, 7),
853                                          token::Ident(Ident::from_str("b"), false)).into(),
854                         TokenTree::Token(sp(8, 9), token::Colon).into(),
855                         TokenTree::Token(sp(10, 13),
856                                          token::Ident(Ident::from_str("i32"), false)).into(),
857                     ]).into(),
858                 ).into(),
859                 TokenTree::Delimited(
860                     DelimSpan::from_pair(sp(15, 16), sp(20, 21)),
861                     token::DelimToken::Brace,
862                     TokenStream::concat(vec![
863                         TokenTree::Token(sp(17, 18),
864                                          token::Ident(Ident::from_str("b"), false)).into(),
865                         TokenTree::Token(sp(18, 19), token::Semi).into(),
866                     ]).into(),
867                 ).into()
868             ]);
869
870             assert_eq!(tts, expected);
871         })
872     }
873
874     #[test] fn parse_use() {
875         with_globals(|| {
876             let use_s = "use foo::bar::baz;";
877             let vitem = string_to_item(use_s.to_string()).unwrap();
878             let vitem_s = item_to_string(&vitem);
879             assert_eq!(&vitem_s[..], use_s);
880
881             let use_s = "use foo::bar as baz;";
882             let vitem = string_to_item(use_s.to_string()).unwrap();
883             let vitem_s = item_to_string(&vitem);
884             assert_eq!(&vitem_s[..], use_s);
885         })
886     }
887
888     #[test] fn parse_extern_crate() {
889         with_globals(|| {
890             let ex_s = "extern crate foo;";
891             let vitem = string_to_item(ex_s.to_string()).unwrap();
892             let vitem_s = item_to_string(&vitem);
893             assert_eq!(&vitem_s[..], ex_s);
894
895             let ex_s = "extern crate foo as bar;";
896             let vitem = string_to_item(ex_s.to_string()).unwrap();
897             let vitem_s = item_to_string(&vitem);
898             assert_eq!(&vitem_s[..], ex_s);
899         })
900     }
901
902     fn get_spans_of_pat_idents(src: &str) -> Vec<Span> {
903         let item = string_to_item(src.to_string()).unwrap();
904
905         struct PatIdentVisitor {
906             spans: Vec<Span>
907         }
908         impl<'a> ::visit::Visitor<'a> for PatIdentVisitor {
909             fn visit_pat(&mut self, p: &'a ast::Pat) {
910                 match p.node {
911                     PatKind::Ident(_ , ref spannedident, _) => {
912                         self.spans.push(spannedident.span.clone());
913                     }
914                     _ => {
915                         ::visit::walk_pat(self, p);
916                     }
917                 }
918             }
919         }
920         let mut v = PatIdentVisitor { spans: Vec::new() };
921         ::visit::walk_item(&mut v, &item);
922         return v.spans;
923     }
924
925     #[test] fn span_of_self_arg_pat_idents_are_correct() {
926         with_globals(|| {
927
928             let srcs = ["impl z { fn a (&self, &myarg: i32) {} }",
929                         "impl z { fn a (&mut self, &myarg: i32) {} }",
930                         "impl z { fn a (&'a self, &myarg: i32) {} }",
931                         "impl z { fn a (self, &myarg: i32) {} }",
932                         "impl z { fn a (self: Foo, &myarg: i32) {} }",
933                         ];
934
935             for &src in &srcs {
936                 let spans = get_spans_of_pat_idents(src);
937                 let (lo, hi) = (spans[0].lo(), spans[0].hi());
938                 assert!("self" == &src[lo.to_usize()..hi.to_usize()],
939                         "\"{}\" != \"self\". src=\"{}\"",
940                         &src[lo.to_usize()..hi.to_usize()], src)
941             }
942         })
943     }
944
945     #[test] fn parse_exprs () {
946         with_globals(|| {
947             // just make sure that they parse....
948             string_to_expr("3 + 4".to_string());
949             string_to_expr("a::z.froob(b,&(987+3))".to_string());
950         })
951     }
952
953     #[test] fn attrs_fix_bug () {
954         with_globals(|| {
955             string_to_item("pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
956                    -> Result<Box<Writer>, String> {
957     #[cfg(windows)]
958     fn wb() -> c_int {
959       (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
960     }
961
962     #[cfg(unix)]
963     fn wb() -> c_int { O_WRONLY as c_int }
964
965     let mut fflags: c_int = wb();
966 }".to_string());
967         })
968     }
969
970     #[test] fn crlf_doc_comments() {
971         with_globals(|| {
972             let sess = ParseSess::new(FilePathMapping::empty());
973
974             let name_1 = FileName::Custom("crlf_source_1".to_string());
975             let source = "/// doc comment\r\nfn foo() {}".to_string();
976             let item = parse_item_from_source_str(name_1, source, &sess)
977                 .unwrap().unwrap();
978             let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
979             assert_eq!(doc, "/// doc comment");
980
981             let name_2 = FileName::Custom("crlf_source_2".to_string());
982             let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
983             let item = parse_item_from_source_str(name_2, source, &sess)
984                 .unwrap().unwrap();
985             let docs = item.attrs.iter().filter(|a| a.path == "doc")
986                         .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>();
987             let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()];
988             assert_eq!(&docs[..], b);
989
990             let name_3 = FileName::Custom("clrf_source_3".to_string());
991             let source = "/** doc comment\r\n *  with CRLF */\r\nfn foo() {}".to_string();
992             let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap();
993             let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap();
994             assert_eq!(doc, "/** doc comment\n *  with CRLF */");
995         });
996     }
997
998     #[test]
999     fn ttdelim_span() {
1000         with_globals(|| {
1001             let sess = ParseSess::new(FilePathMapping::empty());
1002             let expr = parse::parse_expr_from_source_str(PathBuf::from("foo").into(),
1003                 "foo!( fn main() { body } )".to_string(), &sess).unwrap();
1004
1005             let tts: Vec<_> = match expr.node {
1006                 ast::ExprKind::Mac(ref mac) => mac.node.stream().trees().collect(),
1007                 _ => panic!("not a macro"),
1008             };
1009
1010             let span = tts.iter().rev().next().unwrap().span();
1011
1012             match sess.source_map().span_to_snippet(span) {
1013                 Ok(s) => assert_eq!(&s[..], "{ body }"),
1014                 Err(_) => panic!("could not get snippet"),
1015             }
1016         });
1017     }
1018
1019     // This tests that when parsing a string (rather than a file) we don't try
1020     // and read in a file for a module declaration and just parse a stub.
1021     // See `recurse_into_file_modules` in the parser.
1022     #[test]
1023     fn out_of_line_mod() {
1024         with_globals(|| {
1025             let sess = ParseSess::new(FilePathMapping::empty());
1026             let item = parse_item_from_source_str(
1027                 PathBuf::from("foo").into(),
1028                 "mod foo { struct S; mod this_does_not_exist; }".to_owned(),
1029                 &sess,
1030             ).unwrap().unwrap();
1031
1032             if let ast::ItemKind::Mod(ref m) = item.node {
1033                 assert!(m.items.len() == 2);
1034             } else {
1035                 panic!();
1036             }
1037         });
1038     }
1039 }