]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/source_util.rs
70aa9472c855ba2f5e869319980c2c0619653105
[rust.git] / src / libsyntax / ext / source_util.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the
2 // COPYRIGHT 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 use ast;
12 use codemap;
13 use codemap::{FileMap, Loc, Pos, ExpandedFrom, span};
14 use codemap::{CallInfo, NameAndSpan};
15 use ext::base::*;
16 use ext::base;
17 use ext::build::{mk_base_vec_e, mk_uint, mk_u8, mk_base_str};
18 use parse;
19 use print::pprust;
20
21 // These macros all relate to the file system; they either return
22 // the column/row/filename of the expression, or they include
23 // a given file into the current one.
24
25 /* line!(): expands to the current line number */
26 pub fn expand_line(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
27     -> base::MacResult {
28     base::check_zero_tts(cx, sp, tts, "line!");
29
30     let topmost = topmost_expn_info(cx.backtrace().get());
31     let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo);
32
33     base::MRExpr(mk_uint(cx, topmost.call_site, loc.line))
34 }
35
36 /* col!(): expands to the current column number */
37 pub fn expand_col(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
38     -> base::MacResult {
39     base::check_zero_tts(cx, sp, tts, "col!");
40
41     let topmost = topmost_expn_info(cx.backtrace().get());
42     let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo);
43     base::MRExpr(mk_uint(cx, topmost.call_site, loc.col.to_uint()))
44 }
45
46 /* file!(): expands to the current filename */
47 /* The filemap (`loc.file`) contains a bunch more information we could spit
48  * out if we wanted. */
49 pub fn expand_file(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
50     -> base::MacResult {
51     base::check_zero_tts(cx, sp, tts, "file!");
52
53     let topmost = topmost_expn_info(cx.backtrace().get());
54     let Loc { file: @FileMap { name: filename, _ }, _ } =
55         cx.codemap().lookup_char_pos(topmost.call_site.lo);
56     base::MRExpr(mk_base_str(cx, topmost.call_site, filename))
57 }
58
59 pub fn expand_stringify(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
60     -> base::MacResult {
61     let s = pprust::tts_to_str(tts, cx.parse_sess().interner);
62     base::MRExpr(mk_base_str(cx, sp, s))
63 }
64
65 pub fn expand_mod(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
66     -> base::MacResult {
67     base::check_zero_tts(cx, sp, tts, "module_path!");
68     base::MRExpr(mk_base_str(cx, sp,
69                               str::connect(cx.mod_path().map(
70                                   |x| cx.str_of(*x)), ~"::")))
71 }
72
73 // include! : parse the given file as an expr
74 // This is generally a bad idea because it's going to behave
75 // unhygienically.
76 pub fn expand_include(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
77     -> base::MacResult {
78     let file = get_single_str_from_tts(cx, sp, tts, "include!");
79     let p = parse::new_sub_parser_from_file(
80         cx.parse_sess(), cx.cfg(),
81         &res_rel_file(cx, sp, &Path(file)), sp);
82     base::MRExpr(p.parse_expr())
83 }
84
85 // include_str! : read the given file, insert it as a literal string expr
86 pub fn expand_include_str(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
87     -> base::MacResult {
88     let file = get_single_str_from_tts(cx, sp, tts, "include_str!");
89     let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file)));
90     match res {
91       result::Ok(_) => { /* Continue. */ }
92       result::Err(ref e) => {
93         cx.parse_sess().span_diagnostic.handler().fatal((*e));
94       }
95     }
96
97     base::MRExpr(mk_base_str(cx, sp, result::unwrap(res)))
98 }
99
100 pub fn expand_include_bin(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree])
101     -> base::MacResult {
102     let file = get_single_str_from_tts(cx, sp, tts, "include_bin!");
103     match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) {
104       result::Ok(src) => {
105         let u8_exprs = vec::map(src, |char| {
106             mk_u8(cx, sp, *char)
107         });
108         base::MRExpr(mk_base_vec_e(cx, sp, u8_exprs))
109       }
110       result::Err(ref e) => {
111         cx.parse_sess().span_diagnostic.handler().fatal((*e))
112       }
113     }
114 }
115
116 // recur along an ExpnInfo chain to find the original expression
117 fn topmost_expn_info(expn_info: @codemap::ExpnInfo) -> @codemap::ExpnInfo {
118     match *expn_info {
119         ExpandedFrom(CallInfo { call_site: ref call_site, _ }) => {
120             match call_site.expn_info {
121                 Some(next_expn_info) => {
122                     match *next_expn_info {
123                         ExpandedFrom(CallInfo {
124                             callee: NameAndSpan { name: ref name, _ },
125                             _
126                         }) => {
127                             // Don't recurse into file using "include!"
128                             if *name == ~"include" {
129                                 expn_info
130                             } else {
131                                 topmost_expn_info(next_expn_info)
132                             }
133                         }
134                     }
135                 },
136                 None => expn_info
137             }
138         }
139     }
140 }
141
142 // resolve a file-system path to an absolute file-system path (if it
143 // isn't already)
144 fn res_rel_file(cx: @ext_ctxt, sp: codemap::span, arg: &Path) -> Path {
145     // NB: relative paths are resolved relative to the compilation unit
146     if !arg.is_absolute {
147         let cu = Path(cx.codemap().span_to_filename(sp));
148         cu.dir_path().push_many(arg.components)
149     } else {
150         copy *arg
151     }
152 }
153
154 //
155 // Local Variables:
156 // mode: rust
157 // fill-column: 78;
158 // indent-tabs-mode: nil
159 // c-basic-offset: 4
160 // buffer-file-coding-system: utf-8-unix
161 // End:
162 //