]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/source_util.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / libsyntax / ext / source_util.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
223e47cc
LB
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
11use ast;
3157f602 12use syntax_pos::{self, Pos, Span};
223e47cc
LB
13use ext::base::*;
14use ext::base;
970d7e83 15use ext::build::AstBuilder;
1a4d82fc 16use parse::token;
223e47cc
LB
17use parse;
18use print::pprust;
1a4d82fc 19use ptr::P;
3157f602 20use tokenstream;
1a4d82fc 21use util::small_vector::SmallVector;
223e47cc 22
c34b1796
AL
23use std::fs::File;
24use std::io::prelude::*;
25use std::path::{Path, PathBuf};
1a4d82fc 26use std::rc::Rc;
223e47cc
LB
27
28// These macros all relate to the file system; they either return
29// the column/row/filename of the expression, or they include
30// a given file into the current one.
31
1a4d82fc 32/// line!(): expands to the current line number
3157f602 33pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc 34 -> Box<base::MacResult+'static> {
223e47cc
LB
35 base::check_zero_tts(cx, sp, tts, "line!");
36
d9579d0f 37 let topmost = cx.expansion_cause();
1a4d82fc 38 let loc = cx.codemap().lookup_char_pos(topmost.lo);
223e47cc 39
c34b1796 40 base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
223e47cc
LB
41}
42
1a4d82fc 43/* column!(): expands to the current column number */
3157f602 44pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc
JJ
45 -> Box<base::MacResult+'static> {
46 base::check_zero_tts(cx, sp, tts, "column!");
223e47cc 47
d9579d0f 48 let topmost = cx.expansion_cause();
1a4d82fc 49 let loc = cx.codemap().lookup_char_pos(topmost.lo);
c34b1796
AL
50
51 base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32))
223e47cc
LB
52}
53
1a4d82fc
JJ
54/// file!(): expands to the current filename */
55/// The filemap (`loc.file`) contains a bunch more information we could spit
56/// out if we wanted.
3157f602 57pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc 58 -> Box<base::MacResult+'static> {
223e47cc
LB
59 base::check_zero_tts(cx, sp, tts, "file!");
60
d9579d0f 61 let topmost = cx.expansion_cause();
1a4d82fc 62 let loc = cx.codemap().lookup_char_pos(topmost.lo);
c34b1796
AL
63 let filename = token::intern_and_get_ident(&loc.file.name);
64 base::MacEager::expr(cx.expr_str(topmost, filename))
223e47cc
LB
65}
66
3157f602 67pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc
JJ
68 -> Box<base::MacResult+'static> {
69 let s = pprust::tts_to_string(tts);
c34b1796 70 base::MacEager::expr(cx.expr_str(sp,
85aaf69f 71 token::intern_and_get_ident(&s[..])))
223e47cc
LB
72}
73
3157f602 74pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc 75 -> Box<base::MacResult+'static> {
223e47cc 76 base::check_zero_tts(cx, sp, tts, "module_path!");
9e0c209e
SL
77 let mod_path = &cx.current_expansion.module.mod_path;
78 let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
79
c34b1796 80 base::MacEager::expr(cx.expr_str(
1a4d82fc 81 sp,
85aaf69f 82 token::intern_and_get_ident(&string[..])))
223e47cc
LB
83}
84
1a4d82fc
JJ
85/// include! : parse the given file as an expr
86/// This is generally a bad idea because it's going to behave
87/// unhygienically.
3157f602 88pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc
JJ
89 -> Box<base::MacResult+'cx> {
90 let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
91 Some(f) => f,
92 None => return DummyResult::expr(sp),
93 };
94 // The file will be added to the code map by the parser
c30ab7b3
SL
95 let path = res_rel_file(cx, sp, Path::new(&file));
96 let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, true, None, sp);
1a4d82fc
JJ
97
98 struct ExpandResult<'a> {
99 p: parse::parser::Parser<'a>,
100 }
101 impl<'a> base::MacResult for ExpandResult<'a> {
102 fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
92a42be0 103 Some(panictry!(self.p.parse_expr()))
1a4d82fc
JJ
104 }
105 fn make_items(mut self: Box<ExpandResult<'a>>)
106 -> Option<SmallVector<P<ast::Item>>> {
107 let mut ret = SmallVector::zero();
85aaf69f 108 while self.p.token != token::Eof {
92a42be0 109 match panictry!(self.p.parse_item()) {
1a4d82fc 110 Some(item) => ret.push(item),
9cc50fc6
SL
111 None => panic!(self.p.diagnostic().span_fatal(self.p.span,
112 &format!("expected item, found `{}`",
113 self.p.this_token_to_string())))
1a4d82fc
JJ
114 }
115 }
116 Some(ret)
117 }
223e47cc 118 }
1a4d82fc 119
d9579d0f 120 Box::new(ExpandResult { p: p })
223e47cc
LB
121}
122
1a4d82fc 123// include_str! : read the given file, insert it as a literal string expr
3157f602 124pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc
JJ
125 -> Box<base::MacResult+'static> {
126 let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
127 Some(f) => f,
128 None => return DummyResult::expr(sp)
129 };
c34b1796
AL
130 let file = res_rel_file(cx, sp, Path::new(&file));
131 let mut bytes = Vec::new();
132 match File::open(&file).and_then(|mut f| f.read_to_end(&mut bytes)) {
133 Ok(..) => {}
1a4d82fc
JJ
134 Err(e) => {
135 cx.span_err(sp,
85aaf69f 136 &format!("couldn't read {}: {}",
1a4d82fc 137 file.display(),
85aaf69f 138 e));
1a4d82fc
JJ
139 return DummyResult::expr(sp);
140 }
1a4d82fc
JJ
141 };
142 match String::from_utf8(bytes) {
143 Ok(src) => {
144 // Add this input file to the code map to make it available as
145 // dependency information
85aaf69f
SL
146 let filename = format!("{}", file.display());
147 let interned = token::intern_and_get_ident(&src[..]);
3157f602 148 cx.codemap().new_filemap_and_lines(&filename, None, &src);
1a4d82fc 149
c34b1796 150 base::MacEager::expr(cx.expr_str(sp, interned))
1a4d82fc
JJ
151 }
152 Err(_) => {
153 cx.span_err(sp,
85aaf69f
SL
154 &format!("{} wasn't a utf-8 file",
155 file.display()));
1a4d82fc
JJ
156 return DummyResult::expr(sp);
157 }
223e47cc
LB
158 }
159}
160
3157f602 161pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
1a4d82fc
JJ
162 -> Box<base::MacResult+'static> {
163 let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
164 Some(f) => f,
165 None => return DummyResult::expr(sp)
166 };
c34b1796
AL
167 let file = res_rel_file(cx, sp, Path::new(&file));
168 let mut bytes = Vec::new();
169 match File::open(&file).and_then(|mut f| f.read_to_end(&mut bytes)) {
1a4d82fc
JJ
170 Err(e) => {
171 cx.span_err(sp,
85aaf69f 172 &format!("couldn't read {}: {}", file.display(), e));
1a4d82fc
JJ
173 return DummyResult::expr(sp);
174 }
c34b1796 175 Ok(..) => {
9346a6ac
AL
176 // Add this input file to the code map to make it available as
177 // dependency information, but don't enter it's contents
178 let filename = format!("{}", file.display());
3157f602 179 cx.codemap().new_filemap_and_lines(&filename, None, "");
9346a6ac 180
7453a54e 181 base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Rc::new(bytes))))
223e47cc
LB
182 }
183 }
184}
185
186// resolve a file-system path to an absolute file-system path (if it
187// isn't already)
3157f602 188fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
223e47cc 189 // NB: relative paths are resolved relative to the compilation unit
1a4d82fc 190 if !arg.is_absolute() {
3157f602
XL
191 let callsite = cx.codemap().source_callsite(sp);
192 let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite));
1a4d82fc
JJ
193 cu.pop();
194 cu.push(arg);
195 cu
223e47cc 196 } else {
c34b1796 197 arg.to_path_buf()
223e47cc
LB
198 }
199}