diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a817faad0691..4c0be731df4b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -704,6 +704,7 @@ enum item_ { item_trait(~[ty_param], region_param, ~[ty_method]), item_impl(~[ty_param], region_param, option<@trait_ref> /* trait */, @ty /* self */, ~[@method]), + item_mac(mac), } #[auto_serialize] diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 28e5c2c5f171..0e6cce27b2b8 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -17,12 +17,18 @@ type item_decorator = type syntax_expander_tt = {expander: syntax_expander_tt_, span: option}; type syntax_expander_tt_ = fn@(ext_ctxt, span, ast::token_tree) -> @ast::expr; +type syntax_expander_tt_item + = {expander: syntax_expander_tt_item_, span: option}; +type syntax_expander_tt_item_ + = fn@(ext_ctxt, span, ast::ident, ast::token_tree) -> @ast::item; + enum syntax_extension { normal(syntax_expander), macro_defining(macro_definer), item_decorator(item_decorator), - normal_tt(syntax_expander_tt) + normal_tt(syntax_expander_tt), + item_tt(syntax_expander_tt_item), } // A temporary hard-coded map of methods for expanding syntax extension @@ -30,6 +36,9 @@ enum syntax_extension { fn syntax_expander_table() -> hashmap { fn builtin(f: syntax_expander_) -> syntax_extension {normal({expander: f, span: none})} + fn builtin_item_tt(f: syntax_expander_tt_item_) -> syntax_extension { + item_tt({expander: f, span: none}) + } let syntax_expanders = str_hash::(); syntax_expanders.insert("fmt", builtin(ext::fmt::expand_syntax_ext)); syntax_expanders.insert("auto_serialize", @@ -61,6 +70,8 @@ fn syntax_expander_table() -> hashmap { builtin(ext::source_util::expand_include_bin)); syntax_expanders.insert("mod", builtin(ext::source_util::expand_mod)); + syntax_expanders.insert("proto", + builtin_item_tt(ext::pipes::expand_proto)); ret syntax_expanders; } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a037d87166ae..63b3c0881e14 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1,7 +1,7 @@ import std::map::hashmap; import ast::{crate, expr_, expr_mac, mac_invoc, mac_invoc_tt, - tt_delim, tt_flat}; + tt_delim, tt_flat, item_mac}; import fold::*; import ext::base::*; import ext::qquote::{qq_helper}; @@ -52,6 +52,10 @@ fn expand_expr(exts: hashmap, cx: ext_ctxt, #fmt["this tt-style macro should be \ invoked '%s!{...}'", *extname]) } + some(item_tt(*)) { + cx.span_fatal(pth.span, + "cannot use item macros in this context"); + } } } mac_invoc_tt(pth, tt) { @@ -109,7 +113,7 @@ fn expand_mod_items(exts: hashmap, cx: ext_ctxt, }; alt exts.find(*mname) { none | some(normal(_)) | some(macro_defining(_)) - | some(normal_tt(_)) { + | some(normal_tt(_)) | some(item_tt(*)) { items } @@ -124,7 +128,8 @@ fn expand_mod_items(exts: hashmap, cx: ext_ctxt, } /* record module we enter for `#mod` */ -fn expand_item(cx: ext_ctxt, &&it: @ast::item, fld: ast_fold, +fn expand_item(exts: hashmap, + cx: ext_ctxt, &&it: @ast::item, fld: ast_fold, orig: fn@(&&@ast::item, ast_fold) -> @ast::item) -> @ast::item { @@ -132,12 +137,41 @@ fn expand_item(cx: ext_ctxt, &&it: @ast::item, fld: ast_fold, ast::item_mod(_) | ast::item_foreign_mod(_) {true} _ {false} }; + let it = alt it.node { + ast::item_mac(*) { + expand_item_mac(exts, cx, it) + } + _ { it } + }; if is_mod { cx.mod_push(it.ident); } let ret_val = orig(it, fld); if is_mod { cx.mod_pop(); } ret ret_val; } +fn expand_item_mac(exts: hashmap, + cx: ext_ctxt, &&it: @ast::item) -> @ast::item { + alt it.node { + item_mac({node: mac_invoc_tt(pth, tt), span}) { + let extname = pth.idents[0]; + alt exts.find(*extname) { + none { + cx.span_fatal(pth.span, + #fmt("macro undefined: '%s'", *extname)) + } + some(item_tt(expand)) { + expand.expander(cx, it.span, it.ident, tt) + } + _ { cx.span_fatal(it.span, + #fmt("%s is not a legal here", *extname)) } + } + } + _ { + cx.span_bug(it.span, "invalid item macro invocation"); + } + } +} + fn new_span(cx: ext_ctxt, sp: span) -> span { /* this discards information in the case of macro-defining macros */ ret {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()}; @@ -166,7 +200,7 @@ fn expand_crate(parse_sess: parse::parse_sess, let f_pre = @{fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr), fold_mod: |a,b| expand_mod_items(exts, cx, a, b, afp.fold_mod), - fold_item: |a,b| expand_item(cx, a, b, afp.fold_item), + fold_item: |a,b| expand_item(exts, cx, a, b, afp.fold_item), new_span: |a|new_span(cx, a) with *afp}; let f = make_fold(f_pre); diff --git a/src/libsyntax/ext/pipes.rs b/src/libsyntax/ext/pipes.rs new file mode 100644 index 000000000000..23bd95226c37 --- /dev/null +++ b/src/libsyntax/ext/pipes.rs @@ -0,0 +1,10 @@ + +import codemap::span; +import ext::base::ext_ctxt; + +fn expand_proto(cx: ext_ctxt, span: span, id: ast::ident, tt: ast::token_tree) + -> @ast::item +{ + cx.span_unimpl(span, + "Protocol compiler") +} \ No newline at end of file diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index ad55c85496b3..75977ba61693 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -283,6 +283,10 @@ fn noop_fold_item_underscore(i: item_, fld: ast_fold) -> item_ { rp, /* FIXME (#2543) */ copy methods) } + item_mac(m) { + // TODO: we might actually want to do something here. + item_mac(m) + } }; } diff --git a/src/libsyntax/parse.rs b/src/libsyntax/parse.rs index 9c143257e9ea..b2d06311e673 100644 --- a/src/libsyntax/parse.rs +++ b/src/libsyntax/parse.rs @@ -12,6 +12,9 @@ export parse_crate_from_source_str; export parse_expr_from_source_str, parse_item_from_source_str; export parse_from_source_str; +// this used to be `import common::parser_common`, but it was causing +// unresolved import errors. Maybe resolve3 will fix it. +import common::*; import parser::parser; //import attr::parser_attr; import attr::*; //resolve bug? @@ -20,8 +23,7 @@ import common::*; //resolve bug? import ast::node_id; import util::interner; // FIXME (#1935): resolve badness -import lexer::{string_reader_as_reader, tt_reader_as_reader, reader, - string_reader, tt_reader}; +import lexer::*; import diagnostic::{span_handler, mk_span_handler, mk_handler, emitter}; type parse_sess = @{ diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index d7ae4995520e..e62de46f5dbf 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -1,7 +1,6 @@ import either::{either, left, right}; import ast_util::spanned; import common::*; //resolve bug? -//import common::{parser_common, seq_sep_trailing_disallowed}; export attr_or_ext; export parser_attr; diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index d4331ee766f8..16059b473bbb 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -92,6 +92,15 @@ impl parser_common for parser { self.token_is_keyword(word, self.token) } + fn is_any_keyword(tok: token::token) -> bool { + alt tok { + token::IDENT(sid, false) { + self.keywords.contains_key(*self.get_str(sid)) + } + _ { false } + } + } + fn eat_keyword(word: str) -> bool { self.require_keyword(word); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8bac3e0d751e..2f4fe783b490 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -9,7 +9,7 @@ import lexer::reader; import prec::{as_prec, token_to_binop}; import attr::parser_attr; import common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed, - seq_sep_none, token_to_str, parser_common}; + seq_sep_none, token_to_str}; import dvec::{dvec, extensions}; import vec::{push}; import ast::*; @@ -2595,6 +2595,21 @@ class parser { self.parse_item_impl() } else if self.eat_keyword("class") { self.parse_item_class() + } else if !self.is_any_keyword(copy self.token) + && self.look_ahead(1) == token::NOT + { + // item macro. + let pth = self.parse_path_without_tps(); + #error("parsing invocation of %s", *pth.idents[0]); + self.expect(token::NOT); + let id = self.parse_ident(); + let tt = self.parse_token_tree(); + let m = ast::mac_invoc_tt(pth, tt); + let m: ast::mac = {node: m, + span: {lo: self.span.lo, + hi: self.span.hi, + expn_info: none}}; + (id, item_mac(m), none) } else { ret none; }; some(self.mk_item(lo, self.last_span.hi, ident, item_, vis, alt extra_attrs { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8e85de17613c..5220ecdce936 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -589,6 +589,9 @@ fn print_item(s: ps, &&item: @ast::item) { for methods.each |meth| { print_ty_method(s, meth); } bclose(s, item.span); } + ast::item_mac(_m) { + fail "item macros unimplemented" + } } s.ann.post(ann_node); } diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 9cf5528e1a34..5a384f04cb33 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -78,4 +78,6 @@ mod ext { mod log_syntax; mod auto_serialize; mod source_util; + + mod pipes; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 25c61535fcf8..ed54ad3308b0 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -163,6 +163,7 @@ fn visit_item(i: @item, e: E, v: vt) { v.visit_ty(m.decl.output, e, v); } } + item_mac(_m) { fail "item macros unimplemented" } } } diff --git a/src/rustc/metadata/encoder.rs b/src/rustc/metadata/encoder.rs index 8da5ac9420fe..46a3cd84be3b 100644 --- a/src/rustc/metadata/encoder.rs +++ b/src/rustc/metadata/encoder.rs @@ -217,6 +217,7 @@ fn encode_module_item_paths(ebml_w: ebml::writer, ecx: @encode_ctxt, } } item_impl(*) {} + item_mac(*) { fail "item macros unimplemented" } } } } @@ -749,6 +750,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item, encode_path(ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); } + item_mac(*) { fail "item macros unimplemented" } } } diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index 51c48f6a64c0..d8b1f4db6401 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -1352,6 +1352,7 @@ fn found_def_item(i: @ast::item, ns: namespace) -> option { } } ast::item_impl(*) { /* ??? */ } + ast::item_mac(*) { fail "item macros unimplemented" } } ret none; } @@ -1658,6 +1659,9 @@ fn index_mod(md: ast::_mod) -> mod_index { // add the class name itself add_to_index(index, it.ident, mie_item(it)); } + ast::item_mac(*) { + fail "item macros unimplemented" + } } } ret index; diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index b7dc314c801c..6ca613d52810 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -13,7 +13,7 @@ import syntax::ast::{expr_binary, expr_cast, expr_field, expr_fn}; import syntax::ast::{expr_fn_block, expr_index, expr_new, expr_path}; import syntax::ast::{expr_unary, fn_decl, foreign_item, foreign_item_fn}; import syntax::ast::{ident, trait_ref, impure_fn, instance_var, item}; -import syntax::ast::{item_class, item_const, item_enum, item_fn}; +import syntax::ast::{item_class, item_const, item_enum, item_fn, item_mac}; import syntax::ast::{item_foreign_mod, item_trait, item_impl, item_mod}; import syntax::ast::{item_ty, local, local_crate, method, node_id, pat}; import syntax::ast::{pat_enum, pat_ident, path, prim_ty, stmt_decl, ty}; @@ -871,6 +871,10 @@ class Resolver { (*name_bindings).define_type(def_ty(local_def(item.id))); visit_item(item, new_parent, visitor); } + + item_mac(*) { + fail "item macros unimplemented" + } } } @@ -2854,6 +2858,10 @@ class Resolver { item_const(*) { visit_item(item, (), visitor); } + + item_mac(*) { + fail "item macros unimplemented" + } } self.xray_context = orig_xray_flag; diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs index edf76f423039..f9b031f1a51d 100644 --- a/src/rustc/middle/trans/reachable.rs +++ b/src/rustc/middle/trans/reachable.rs @@ -148,6 +148,7 @@ fn traverse_public_item(cx: ctx, item: @item) { } item_const(*) | item_enum(*) | item_trait(*) {} + item_mac(*) { fail "item macros unimplemented" } } } diff --git a/src/rustc/middle/tstate/pre_post_conditions.rs b/src/rustc/middle/tstate/pre_post_conditions.rs index 0561a04544a6..545f6ad6aa97 100644 --- a/src/rustc/middle/tstate/pre_post_conditions.rs +++ b/src/rustc/middle/tstate/pre_post_conditions.rs @@ -55,6 +55,7 @@ fn find_pre_post_item(ccx: crate_ctxt, i: item) { item_impl(_, _, _, _, ms) { for ms.each |m| { find_pre_post_method(ccx, m); } } + item_mac(*) { fail "item macros unimplemented" } } } diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index 84ed98be6f4b..4bae90d22144 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -537,6 +537,7 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item) } ast::item_impl(*) | ast::item_mod(_) | ast::item_foreign_mod(_) { fail; } + ast::item_mac(*) { fail "item macros unimplemented" } } } diff --git a/src/test/run-pass/pipe-pingpong-proto.rs b/src/test/run-pass/pipe-pingpong-proto.rs new file mode 100644 index 000000000000..0afacb99c159 --- /dev/null +++ b/src/test/run-pass/pipe-pingpong-proto.rs @@ -0,0 +1,17 @@ +// xfail-test + +// An example to make sure the protocol parsing syntax extension works. + +proto! pingpong { + ping:send { + ping -> pong + } + + pong:recv { + pong -> ping + } +} + +fn main() { + // TODO: do something with the protocol +} \ No newline at end of file