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