base.rs 13.9 KB
Newer Older
B
Brian Anderson 已提交
1
use std::map::HashMap;
P
Patrick Walton 已提交
2 3
use parse::parser;
use diagnostic::span_handler;
4
use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom};
5
use ast_util::dummy_sp;
6

7 8 9 10 11 12 13 14 15 16 17 18 19
// obsolete old-style #macro code:
//
//    syntax_expander, normal, macro_defining, macro_definer,
//    builtin
//
// new-style macro! tt code:
//
//    syntax_expander_tt, syntax_expander_tt_item, mac_result,
//    expr_tt, item_tt
//
// also note that ast::mac has way too many cases and can probably
// be trimmed down substantially.

20
// second argument is the span to blame for general argument problems
K
Kevin Atkinson 已提交
21
type syntax_expander_ =
22
    fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> @ast::expr;
23
// second argument is the origin of the macro, if user-defined
B
Brian Anderson 已提交
24
type syntax_expander = {expander: syntax_expander_, span: Option<span>};
25

P
Paul Stansifer 已提交
26
type macro_def = {name: ~str, ext: syntax_extension};
27 28

// macro_definer is obsolete, remove when #old_macros go away.
M
Marijn Haverbeke 已提交
29
type macro_definer =
30
    fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def;
31

32
type item_decorator =
33
    fn@(ext_ctxt, span, ast::meta_item, ~[@ast::item]) -> ~[@ast::item];
34

B
Brian Anderson 已提交
35
type syntax_expander_tt = {expander: syntax_expander_tt_, span: Option<span>};
36 37
type syntax_expander_tt_ = fn@(ext_ctxt, span, ~[ast::token_tree])
    -> mac_result;
38

39
type syntax_expander_tt_item
B
Brian Anderson 已提交
40
    = {expander: syntax_expander_tt_item_, span: Option<span>};
41
type syntax_expander_tt_item_
42
    = fn@(ext_ctxt, span, ast::ident, ~[ast::token_tree]) -> mac_result;
43 44

enum mac_result {
45
    mr_expr(@ast::expr),
46
    mr_item(@ast::item),
47
    mr_expr_or_item(fn@()-> @ast::expr, fn@()-> Option<@ast::item>),
48 49
    mr_def(macro_def)
}
50

P
Patrick Walton 已提交
51
enum syntax_extension {
52 53

    // normal() is obsolete, remove when #old_macros go away.
P
Patrick Walton 已提交
54
    normal(syntax_expander),
55 56

    // macro_defining() is obsolete, remove when #old_macros go away.
P
Patrick Walton 已提交
57
    macro_defining(macro_definer),
58

59
    // #[auto_serialize] and such. will probably survive death of #old_macros
60
    item_decorator(item_decorator),
61

62
    // Token-tree expanders
63
    expr_tt(syntax_expander_tt),
64
    item_tt(syntax_expander_tt_item),
65
}
66 67 68

// A temporary hard-coded map of methods for expanding syntax extension
// AST nodes into full ASTs
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
    fn builtin(f: syntax_expander_) -> syntax_extension
        {normal({expander: f, span: None})}
    fn builtin_expr_tt(f: syntax_expander_tt_) -> syntax_extension {
        expr_tt({expander: f, span: None})
    }
    fn builtin_item_tt(f: syntax_expander_tt_item_) -> syntax_extension {
        item_tt({expander: f, span: None})
    }
    let syntax_expanders = HashMap();
    syntax_expanders.insert(~"macro",
                            macro_defining(ext::simplext::add_new_extension));
    syntax_expanders.insert(~"macro_rules",
                            builtin_item_tt(
                                ext::tt::macro_rules::add_new_extension));
    syntax_expanders.insert(~"fmt", builtin(ext::fmt::expand_syntax_ext));
    syntax_expanders.insert(
        ~"auto_serialize",
87
        item_decorator(ext::auto_serialize::expand_auto_serialize));
88 89
    syntax_expanders.insert(
        ~"auto_deserialize",
90
        item_decorator(ext::auto_serialize::expand_auto_deserialize));
91 92 93 94 95 96 97 98 99 100
    syntax_expanders.insert(~"env", builtin(ext::env::expand_syntax_ext));
    syntax_expanders.insert(~"concat_idents",
                            builtin(ext::concat_idents::expand_syntax_ext));
    syntax_expanders.insert(~"ident_to_str",
                            builtin(ext::ident_to_str::expand_syntax_ext));
    syntax_expanders.insert(~"log_syntax",
                            builtin_expr_tt(
                                ext::log_syntax::expand_syntax_ext));
    syntax_expanders.insert(~"ast",
                            builtin(ext::qquote::expand_ast));
101 102 103
    syntax_expanders.insert(~"deriving_eq",
                            item_decorator(
                                ext::deriving::expand_deriving_eq));
104 105 106
    syntax_expanders.insert(~"deriving_iter_bytes",
                            item_decorator(
                                ext::deriving::expand_deriving_iter_bytes));
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

    // Quasi-quoting expanders
    syntax_expanders.insert(~"quote_tokens",
                            builtin_expr_tt(ext::quote::expand_quote_tokens));
    syntax_expanders.insert(~"quote_expr",
                            builtin_expr_tt(ext::quote::expand_quote_expr));
    syntax_expanders.insert(~"quote_type",
                            builtin_expr_tt(ext::quote::expand_quote_type));
    syntax_expanders.insert(~"quote_item",
                            builtin_expr_tt(ext::quote::expand_quote_item));
    syntax_expanders.insert(~"quote_pat",
                            builtin_expr_tt(ext::quote::expand_quote_pat));
    syntax_expanders.insert(~"quote_stmt",
                            builtin_expr_tt(ext::quote::expand_quote_stmt));

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    syntax_expanders.insert(~"line",
                            builtin(ext::source_util::expand_line));
    syntax_expanders.insert(~"col",
                            builtin(ext::source_util::expand_col));
    syntax_expanders.insert(~"file",
                            builtin(ext::source_util::expand_file));
    syntax_expanders.insert(~"stringify",
                            builtin(ext::source_util::expand_stringify));
    syntax_expanders.insert(~"include",
                            builtin(ext::source_util::expand_include));
    syntax_expanders.insert(~"include_str",
                            builtin(ext::source_util::expand_include_str));
    syntax_expanders.insert(~"include_bin",
                            builtin(ext::source_util::expand_include_bin));
    syntax_expanders.insert(~"module_path",
                            builtin(ext::source_util::expand_mod));
    syntax_expanders.insert(~"proto",
                            builtin_item_tt(ext::pipes::expand_proto));
    syntax_expanders.insert(
        ~"trace_macros",
        builtin_expr_tt(ext::trace_macros::expand_trace_macros));
    return syntax_expanders;
}
145 146 147 148

// One of these is made during expansion and incrementally updated as we go;
// when a macro expansion occurs, the resulting nodes have the backtrace()
// -> expn_info of their expansion context stored into their span.
149
trait ext_ctxt {
150
    fn codemap() -> @CodeMap;
151
    fn parse_sess() -> parse::parse_sess;
152
    fn cfg() -> ast::crate_cfg;
153
    fn print_backtrace();
154
    fn backtrace() -> Option<@ExpnInfo>;
155 156
    fn mod_push(mod_name: ast::ident);
    fn mod_pop();
157
    fn mod_path() -> ~[ast::ident];
158
    fn bt_push(ei: codemap::ExpnInfo);
159
    fn bt_pop();
T
Tim Chevalier 已提交
160 161 162 163 164 165
    fn span_fatal(sp: span, msg: &str) -> !;
    fn span_err(sp: span, msg: &str);
    fn span_warn(sp: span, msg: &str);
    fn span_unimpl(sp: span, msg: &str) -> !;
    fn span_bug(sp: span, msg: &str) -> !;
    fn bug(msg: &str) -> !;
166
    fn next_id() -> ast::node_id;
E
Eric Holk 已提交
167 168
    pure fn trace_macros() -> bool;
    fn set_trace_macros(x: bool);
P
Paul Stansifer 已提交
169 170 171
    /* for unhygienic identifier transformation */
    fn str_of(id: ast::ident) -> ~str;
    fn ident_of(st: ~str) -> ast::ident;
172
}
173

174
fn mk_ctxt(parse_sess: parse::parse_sess,
175
           cfg: ast::crate_cfg) -> ext_ctxt {
176
    type ctxt_repr = {parse_sess: parse::parse_sess,
177
                      cfg: ast::crate_cfg,
178
                      mut backtrace: Option<@ExpnInfo>,
E
Eric Holk 已提交
179 180
                      mut mod_path: ~[ast::ident],
                      mut trace_mac: bool};
B
Brian Anderson 已提交
181
    impl ctxt_repr: ext_ctxt {
182
        fn codemap() -> @CodeMap { self.parse_sess.cm }
183
        fn parse_sess() -> parse::parse_sess { self.parse_sess }
184
        fn cfg() -> ast::crate_cfg { self.cfg }
185
        fn print_backtrace() { }
186
        fn backtrace() -> Option<@ExpnInfo> { self.backtrace }
187
        fn mod_push(i: ast::ident) { self.mod_path.push(i); }
N
Niko Matsakis 已提交
188
        fn mod_pop() { self.mod_path.pop(); }
B
Brian Anderson 已提交
189
        fn mod_path() -> ~[ast::ident] { return self.mod_path; }
190
        fn bt_push(ei: codemap::ExpnInfo) {
191
            match ei {
192
              ExpandedFrom({call_site: cs, callie: callie}) => {
K
Kevin Atkinson 已提交
193
                self.backtrace =
194
                    Some(@ExpandedFrom({
195 196
                        call_site: span {lo: cs.lo, hi: cs.hi,
                                         expn_info: self.backtrace},
K
Kevin Atkinson 已提交
197 198 199
                        callie: callie}));
              }
            }
200 201
        }
        fn bt_pop() {
202
            match self.backtrace {
203 204 205
              Some(@ExpandedFrom({
                  call_site: span {expn_info: prev, _}, _
              })) => {
K
Kevin Atkinson 已提交
206
                self.backtrace = prev
207
              }
B
Brian Anderson 已提交
208
              _ => self.bug(~"tried to pop without a push")
209 210
            }
        }
T
Tim Chevalier 已提交
211
        fn span_fatal(sp: span, msg: &str) -> ! {
212
            self.print_backtrace();
213
            self.parse_sess.span_diagnostic.span_fatal(sp, msg);
214
        }
T
Tim Chevalier 已提交
215
        fn span_err(sp: span, msg: &str) {
216
            self.print_backtrace();
217
            self.parse_sess.span_diagnostic.span_err(sp, msg);
218
        }
T
Tim Chevalier 已提交
219
        fn span_warn(sp: span, msg: &str) {
220 221 222
            self.print_backtrace();
            self.parse_sess.span_diagnostic.span_warn(sp, msg);
        }
T
Tim Chevalier 已提交
223
        fn span_unimpl(sp: span, msg: &str) -> ! {
224
            self.print_backtrace();
225
            self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
226
        }
T
Tim Chevalier 已提交
227
        fn span_bug(sp: span, msg: &str) -> ! {
228
            self.print_backtrace();
229 230
            self.parse_sess.span_diagnostic.span_bug(sp, msg);
        }
T
Tim Chevalier 已提交
231
        fn bug(msg: &str) -> ! {
232 233 234 235
            self.print_backtrace();
            self.parse_sess.span_diagnostic.handler().bug(msg);
        }
        fn next_id() -> ast::node_id {
B
Brian Anderson 已提交
236
            return parse::next_node_id(self.parse_sess);
237
        }
E
Eric Holk 已提交
238 239 240 241 242 243
        pure fn trace_macros() -> bool {
            self.trace_mac
        }
        fn set_trace_macros(x: bool) {
            self.trace_mac = x
        }
P
Paul Stansifer 已提交
244 245 246 247 248 249 250

        fn str_of(id: ast::ident) -> ~str {
            *self.parse_sess.interner.get(id)
        }
        fn ident_of(st: ~str) -> ast::ident {
            self.parse_sess.interner.intern(@st)
        }
251
    }
252
    let imp: ctxt_repr = {
253 254
        parse_sess: parse_sess,
        cfg: cfg,
B
Brian Anderson 已提交
255
        mut backtrace: None,
E
Eric Holk 已提交
256 257
        mut mod_path: ~[],
        mut trace_mac: false
258
    };
T
Tim Chevalier 已提交
259
    move ((move imp) as ext_ctxt)
260
}
261

262
fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str {
263 264
    match expr.node {
      ast::expr_lit(l) => match l.node {
B
Brian Anderson 已提交
265
        ast::lit_str(s) => return *s,
266
        _ => cx.span_fatal(l.span, err_msg)
267
      },
268
      _ => cx.span_fatal(expr.span, err_msg)
269 270 271
    }
}

272 273 274
fn expr_to_ident(cx: ext_ctxt,
                 expr: @ast::expr,
                 err_msg: ~str) -> ast::ident {
275
    match expr.node {
B
Brian Anderson 已提交
276
      ast::expr_path(p) => {
277
        if vec::len(p.types) > 0u || vec::len(p.idents) != 1u {
278 279 280
            cx.span_fatal(expr.span, err_msg);
        }
        return p.idents[0];
M
Marijn Haverbeke 已提交
281
      }
282
      _ => cx.span_fatal(expr.span, err_msg)
283 284 285
    }
}

286
fn get_mac_args_no_max(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
287
                       min: uint, name: ~str) -> ~[@ast::expr] {
B
Brian Anderson 已提交
288
    return get_mac_args(cx, sp, arg, min, None, name);
289 290 291
}

fn get_mac_args(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
B
Brian Anderson 已提交
292
                min: uint, max: Option<uint>, name: ~str) -> ~[@ast::expr] {
293
    match arg {
B
Brian Anderson 已提交
294
      Some(expr) => match expr.node {
B
Brian Anderson 已提交
295
        ast::expr_vec(elts, _) => {
296
            let elts_len = vec::len(elts);
297
              match max {
B
Brian Anderson 已提交
298
                Some(max) if ! (min <= elts_len && elts_len <= max) => {
B
Brian Anderson 已提交
299
                  cx.span_fatal(sp,
300
                                fmt!("%s! takes between %u and %u arguments.",
P
Paul Stansifer 已提交
301
                                     name, min, max));
B
Brian Anderson 已提交
302
                }
B
Brian Anderson 已提交
303
                None if ! (min <= elts_len) => {
304
                  cx.span_fatal(sp, fmt!("%s! needs at least %u arguments.",
P
Paul Stansifer 已提交
305
                                         name, min));
B
Brian Anderson 已提交
306
                }
P
Paul Stansifer 已提交
307
                _ => return elts /* we are good */
308 309
              }
          }
B
Brian Anderson 已提交
310
        _ => {
311
            cx.span_fatal(sp, fmt!("%s!: malformed invocation", name))
P
Paul Stansifer 已提交
312
        }
313
      },
314
      None => cx.span_fatal(sp, fmt!("%s!: missing arguments", name))
315 316 317
    }
}

318 319 320
fn get_mac_body(cx: ext_ctxt, sp: span, args: ast::mac_body)
    -> ast::mac_body_
{
321
    match (args) {
B
Brian Anderson 已提交
322 323
      Some(body) => body,
      None => cx.span_fatal(sp, ~"missing macro body")
324 325
    }
}
326

327 328 329
// Massage syntactic form of new-style arguments to internal representation
// of old-style macro args, such that old-style macro can be run and invoked
// using new syntax. This will be obsolete when #old_macros go away.
330 331
fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree])
    -> ast::mac_arg {
332 333 334
    use ast::{matcher, matcher_, match_tok, match_seq, match_nonterminal};
    use parse::lexer::{new_tt_reader, reader};
    use tt::macro_parser::{parse_or_else, matched_seq,
335
                              matched_nonterminal};
336 337 338

    // these spans won't matter, anyways
    fn ms(m: matcher_) -> matcher {
339
        {node: m, span: dummy_sp()}
340
    }
P
Paul Stansifer 已提交
341
    let arg_nm = cx.parse_sess().interner.gensym(@~"arg");
342

343
    let argument_gram = ~[ms(match_seq(~[
P
Paul Stansifer 已提交
344
        ms(match_nonterminal(arg_nm, parse::token::special_idents::expr, 0u))
B
Brian Anderson 已提交
345
    ], Some(parse::token::COMMA), true, 0u, 1u))];
346 347

    let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
B
Brian Anderson 已提交
348
                                   cx.parse_sess().interner, None, arg);
349
    let args =
350
        match parse_or_else(cx.parse_sess(), cx.cfg(), arg_reader as reader,
P
Paul Stansifer 已提交
351 352 353
                          argument_gram).get(arg_nm) {
          @matched_seq(s, _) => {
            do s.map() |lf| {
354
                match *lf {
P
Paul Stansifer 已提交
355 356 357 358
                  @matched_nonterminal(parse::token::nt_expr(arg)) =>
                    arg, /* whew! list of exprs, here we come! */
                  _ => fail ~"badly-structured parse result"
                }
359
            }
360
          },
B
Brian Anderson 已提交
361
          _ => fail ~"badly-structured parse result"
362 363
        };

B
Brian Anderson 已提交
364
    return Some(@{id: parse::next_node_id(cx.parse_sess()),
365 366 367 368
               callee_id: parse::next_node_id(cx.parse_sess()),
               node: ast::expr_vec(args, ast::m_imm), span: sp});
}

369 370 371 372 373 374 375 376 377
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//