3 use diagnostic::span_handler;
4 use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom};
5 use ast_util::dummy_sp;
7 // obsolete old-style #macro code:
9 // syntax_expander, normal, macro_defining, macro_definer,
12 // new-style macro! tt code:
14 // syntax_expander_tt, syntax_expander_tt_item, mac_result,
17 // also note that ast::mac has way too many cases and can probably
18 // be trimmed down substantially.
20 // second argument is the span to blame for general argument problems
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
24 type syntax_expander = {expander: syntax_expander_, span: Option<span>};
26 type macro_def = {name: ~str, ext: syntax_extension};
28 // macro_definer is obsolete, remove when #old_macros go away.
30 fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def;
33 fn@(ext_ctxt, span, ast::meta_item, ~[@ast::item]) -> ~[@ast::item];
35 type syntax_expander_tt = {expander: syntax_expander_tt_, span: Option<span>};
36 type syntax_expander_tt_ = fn@(ext_ctxt, span, ~[ast::token_tree])
39 type syntax_expander_tt_item
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;
50 enum syntax_extension {
52 // normal() is obsolete, remove when #old_macros go away.
53 normal(syntax_expander),
55 // macro_defining() is obsolete, remove when #old_macros go away.
56 macro_defining(macro_definer),
58 // #[auto_serialize] and such. will probably survive death of #old_macros
59 item_decorator(item_decorator),
61 // Token-tree expanders
62 expr_tt(syntax_expander_tt),
63 item_tt(syntax_expander_tt_item),
66 // A temporary hard-coded map of methods for expanding syntax extension
67 // AST nodes into full ASTs
68 fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
69 fn builtin(f: syntax_expander_) -> syntax_extension
70 {normal({expander: f, span: None})}
71 fn builtin_expr_tt(f: syntax_expander_tt_) -> syntax_extension {
72 expr_tt({expander: f, span: None})
74 fn builtin_item_tt(f: syntax_expander_tt_item_) -> syntax_extension {
75 item_tt({expander: f, span: None})
77 let syntax_expanders = HashMap();
78 syntax_expanders.insert(~"macro",
79 macro_defining(ext::simplext::add_new_extension));
80 syntax_expanders.insert(~"macro_rules",
82 ext::tt::macro_rules::add_new_extension));
83 syntax_expanders.insert(~"fmt", builtin(ext::fmt::expand_syntax_ext));
84 syntax_expanders.insert(
86 item_decorator(ext::auto_serialize::expand_auto_serialize));
87 syntax_expanders.insert(
89 item_decorator(ext::auto_serialize::expand_auto_deserialize));
90 syntax_expanders.insert(~"env", builtin(ext::env::expand_syntax_ext));
91 syntax_expanders.insert(~"concat_idents",
92 builtin(ext::concat_idents::expand_syntax_ext));
93 syntax_expanders.insert(~"ident_to_str",
94 builtin(ext::ident_to_str::expand_syntax_ext));
95 syntax_expanders.insert(~"log_syntax",
97 ext::log_syntax::expand_syntax_ext));
98 syntax_expanders.insert(~"ast",
99 builtin(ext::qquote::expand_ast));
101 // Quasi-quoting expanders
102 syntax_expanders.insert(~"quote_tokens",
103 builtin_expr_tt(ext::quote::expand_quote_tokens));
104 syntax_expanders.insert(~"quote_expr",
105 builtin_expr_tt(ext::quote::expand_quote_expr));
106 syntax_expanders.insert(~"quote_type",
107 builtin_expr_tt(ext::quote::expand_quote_type));
108 syntax_expanders.insert(~"quote_item",
109 builtin_expr_tt(ext::quote::expand_quote_item));
110 syntax_expanders.insert(~"quote_pat",
111 builtin_expr_tt(ext::quote::expand_quote_pat));
112 syntax_expanders.insert(~"quote_stmt",
113 builtin_expr_tt(ext::quote::expand_quote_stmt));
115 syntax_expanders.insert(~"line",
116 builtin(ext::source_util::expand_line));
117 syntax_expanders.insert(~"col",
118 builtin(ext::source_util::expand_col));
119 syntax_expanders.insert(~"file",
120 builtin(ext::source_util::expand_file));
121 syntax_expanders.insert(~"stringify",
122 builtin(ext::source_util::expand_stringify));
123 syntax_expanders.insert(~"include",
124 builtin(ext::source_util::expand_include));
125 syntax_expanders.insert(~"include_str",
126 builtin(ext::source_util::expand_include_str));
127 syntax_expanders.insert(~"include_bin",
128 builtin(ext::source_util::expand_include_bin));
129 syntax_expanders.insert(~"module_path",
130 builtin(ext::source_util::expand_mod));
131 syntax_expanders.insert(~"proto",
132 builtin_item_tt(ext::pipes::expand_proto));
133 syntax_expanders.insert(
135 builtin_expr_tt(ext::trace_macros::expand_trace_macros));
136 return syntax_expanders;
139 // One of these is made during expansion and incrementally updated as we go;
140 // when a macro expansion occurs, the resulting nodes have the backtrace()
141 // -> expn_info of their expansion context stored into their span.
143 fn codemap() -> @CodeMap;
144 fn parse_sess() -> parse::parse_sess;
145 fn cfg() -> ast::crate_cfg;
146 fn print_backtrace();
147 fn backtrace() -> Option<@ExpnInfo>;
148 fn mod_push(mod_name: ast::ident);
150 fn mod_path() -> ~[ast::ident];
151 fn bt_push(ei: codemap::ExpnInfo);
153 fn span_fatal(sp: span, msg: &str) -> !;
154 fn span_err(sp: span, msg: &str);
155 fn span_warn(sp: span, msg: &str);
156 fn span_unimpl(sp: span, msg: &str) -> !;
157 fn span_bug(sp: span, msg: &str) -> !;
158 fn bug(msg: &str) -> !;
159 fn next_id() -> ast::node_id;
160 pure fn trace_macros() -> bool;
161 fn set_trace_macros(x: bool);
162 /* for unhygienic identifier transformation */
163 fn str_of(id: ast::ident) -> ~str;
164 fn ident_of(st: ~str) -> ast::ident;
167 fn mk_ctxt(parse_sess: parse::parse_sess,
168 cfg: ast::crate_cfg) -> ext_ctxt {
169 type ctxt_repr = {parse_sess: parse::parse_sess,
171 mut backtrace: Option<@ExpnInfo>,
172 mut mod_path: ~[ast::ident],
173 mut trace_mac: bool};
174 impl ctxt_repr: ext_ctxt {
175 fn codemap() -> @CodeMap { self.parse_sess.cm }
176 fn parse_sess() -> parse::parse_sess { self.parse_sess }
177 fn cfg() -> ast::crate_cfg { self.cfg }
178 fn print_backtrace() { }
179 fn backtrace() -> Option<@ExpnInfo> { self.backtrace }
180 fn mod_push(i: ast::ident) { self.mod_path.push(i); }
181 fn mod_pop() { self.mod_path.pop(); }
182 fn mod_path() -> ~[ast::ident] { return self.mod_path; }
183 fn bt_push(ei: codemap::ExpnInfo) {
185 ExpandedFrom({call_site: cs, callie: callie}) => {
188 call_site: span {lo: cs.lo, hi: cs.hi,
189 expn_info: self.backtrace},
195 match self.backtrace {
197 call_site: span {expn_info: prev, _}, _
199 self.backtrace = prev
201 _ => self.bug(~"tried to pop without a push")
204 fn span_fatal(sp: span, msg: &str) -> ! {
205 self.print_backtrace();
206 self.parse_sess.span_diagnostic.span_fatal(sp, msg);
208 fn span_err(sp: span, msg: &str) {
209 self.print_backtrace();
210 self.parse_sess.span_diagnostic.span_err(sp, msg);
212 fn span_warn(sp: span, msg: &str) {
213 self.print_backtrace();
214 self.parse_sess.span_diagnostic.span_warn(sp, msg);
216 fn span_unimpl(sp: span, msg: &str) -> ! {
217 self.print_backtrace();
218 self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
220 fn span_bug(sp: span, msg: &str) -> ! {
221 self.print_backtrace();
222 self.parse_sess.span_diagnostic.span_bug(sp, msg);
224 fn bug(msg: &str) -> ! {
225 self.print_backtrace();
226 self.parse_sess.span_diagnostic.handler().bug(msg);
228 fn next_id() -> ast::node_id {
229 return parse::next_node_id(self.parse_sess);
231 pure fn trace_macros() -> bool {
234 fn set_trace_macros(x: bool) {
238 fn str_of(id: ast::ident) -> ~str {
239 *self.parse_sess.interner.get(id)
241 fn ident_of(st: ~str) -> ast::ident {
242 self.parse_sess.interner.intern(@st)
245 let imp: ctxt_repr = {
246 parse_sess: parse_sess,
252 move ((move imp) as ext_ctxt)
255 fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str {
257 ast::expr_lit(l) => match l.node {
258 ast::lit_str(s) => return *s,
259 _ => cx.span_fatal(l.span, err_msg)
261 _ => cx.span_fatal(expr.span, err_msg)
265 fn expr_to_ident(cx: ext_ctxt,
267 err_msg: ~str) -> ast::ident {
269 ast::expr_path(p) => {
270 if vec::len(p.types) > 0u || vec::len(p.idents) != 1u {
271 cx.span_fatal(expr.span, err_msg);
275 _ => cx.span_fatal(expr.span, err_msg)
279 fn get_mac_args_no_max(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
280 min: uint, name: ~str) -> ~[@ast::expr] {
281 return get_mac_args(cx, sp, arg, min, None, name);
284 fn get_mac_args(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
285 min: uint, max: Option<uint>, name: ~str) -> ~[@ast::expr] {
287 Some(expr) => match expr.node {
288 ast::expr_vec(elts, _) => {
289 let elts_len = vec::len(elts);
291 Some(max) if ! (min <= elts_len && elts_len <= max) => {
293 fmt!("%s! takes between %u and %u arguments.",
296 None if ! (min <= elts_len) => {
297 cx.span_fatal(sp, fmt!("%s! needs at least %u arguments.",
300 _ => return elts /* we are good */
304 cx.span_fatal(sp, fmt!("%s!: malformed invocation", name))
307 None => cx.span_fatal(sp, fmt!("%s!: missing arguments", name))
311 fn get_mac_body(cx: ext_ctxt, sp: span, args: ast::mac_body)
316 None => cx.span_fatal(sp, ~"missing macro body")
320 // Massage syntactic form of new-style arguments to internal representation
321 // of old-style macro args, such that old-style macro can be run and invoked
322 // using new syntax. This will be obsolete when #old_macros go away.
323 fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree])
325 use ast::{matcher, matcher_, match_tok, match_seq, match_nonterminal};
326 use parse::lexer::{new_tt_reader, reader};
327 use tt::macro_parser::{parse_or_else, matched_seq,
328 matched_nonterminal};
330 // these spans won't matter, anyways
331 fn ms(m: matcher_) -> matcher {
332 {node: m, span: dummy_sp()}
334 let arg_nm = cx.parse_sess().interner.gensym(@~"arg");
336 let argument_gram = ~[ms(match_seq(~[
337 ms(match_nonterminal(arg_nm, parse::token::special_idents::expr, 0u))
338 ], Some(parse::token::COMMA), true, 0u, 1u))];
340 let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
341 cx.parse_sess().interner, None, arg);
343 match parse_or_else(cx.parse_sess(), cx.cfg(), arg_reader as reader,
344 argument_gram).get(arg_nm) {
345 @matched_seq(s, _) => {
348 @matched_nonterminal(parse::token::nt_expr(arg)) =>
349 arg, /* whew! list of exprs, here we come! */
350 _ => fail ~"badly-structured parse result"
354 _ => fail ~"badly-structured parse result"
357 return Some(@{id: parse::next_node_id(cx.parse_sess()),
358 callee_id: parse::next_node_id(cx.parse_sess()),
359 node: ast::expr_vec(args, ast::m_imm), span: sp});
366 // indent-tabs-mode: nil
368 // buffer-file-coding-system: utf-8-unix