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