diff options
| author | Brian Anderson <andersrb@gmail.com> | 2012-12-12 17:13:41 -0800 |
|---|---|---|
| committer | Brian Anderson <andersrb@gmail.com> | 2012-12-12 17:13:41 -0800 |
| commit | 0494b078a9555f77d9cd4fbe2a4ff910bfba29b8 (patch) | |
| tree | f2bbe5ce3b3a42ca98902c66e8bff4a41a536f41 /src/libsyntax/ext | |
| parent | 0138d87f8f1b9f9614e439deb14cbaabad6d104c (diff) | |
| parent | 9a4c669867765d42bdd13fc09eb9a32b7a667a43 (diff) | |
| download | rust-0494b078a9555f77d9cd4fbe2a4ff910bfba29b8.tar.gz rust-0494b078a9555f77d9cd4fbe2a4ff910bfba29b8.zip | |
Merge pull request #4172 from graydon/remove-old-syntax-ext
Remove old syntax ext
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/auto_serialize.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 168 | ||||
| -rw-r--r-- | src/libsyntax/ext/concat_idents.rs | 35 | ||||
| -rw-r--r-- | src/libsyntax/ext/env.rs | 17 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 136 | ||||
| -rw-r--r-- | src/libsyntax/ext/fmt.rs | 11 | ||||
| -rw-r--r-- | src/libsyntax/ext/ident_to_str.rs | 20 | ||||
| -rw-r--r-- | src/libsyntax/ext/qquote.rs | 370 | ||||
| -rw-r--r-- | src/libsyntax/ext/quote.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/ext/simplext.rs | 750 | ||||
| -rw-r--r-- | src/libsyntax/ext/source_util.rs | 76 |
11 files changed, 149 insertions, 1437 deletions
diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 44fa8ac7a1b..9830a5b1434 100644 --- a/src/libsyntax/ext/auto_serialize.rs +++ b/src/libsyntax/ext/auto_serialize.rs @@ -309,7 +309,7 @@ priv impl ext_ctxt { fn lambda(blk: ast::blk) -> @ast::expr { let ext_cx = self; let blk_e = self.expr(blk.span, ast::expr_block(blk)); - #ast{ || $(blk_e) } + quote_expr!( || $blk_e ) } fn blk(span: span, stmts: ~[@ast::stmt]) -> ast::blk { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 312c6cc16f7..a5ed1f5e101 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -13,32 +13,19 @@ use parse::parser; use diagnostic::span_handler; use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom}; use ast_util::dummy_sp; +use parse::token; -// 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, // normal_tt, item_tt // -// also note that ast::mac has way too many cases and can probably -// be trimmed down substantially. - -// second argument is the span to blame for general argument problems -type syntax_expander_ = - fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> @ast::expr; -// second argument is the origin of the macro, if user-defined -type syntax_expander = {expander: syntax_expander_, span: Option<span>}; +// also note that ast::mac used to have a bunch of extraneous cases and +// is now probably a redundant AST node, can be merged with +// ast::mac_invoc_tt. type macro_def = {name: ~str, ext: syntax_extension}; -// macro_definer is obsolete, remove when #old_macros go away. -type macro_definer = - fn@(ext_ctxt, span, ast::mac_arg, ast::mac_body) -> macro_def; - type item_decorator = fn@(ext_ctxt, span, ast::meta_item, ~[@ast::item]) -> ~[@ast::item]; @@ -60,13 +47,7 @@ enum mac_result { enum syntax_extension { - // normal() is obsolete, remove when #old_macros go away. - normal(syntax_expander), - - // macro_defining() is obsolete, remove when #old_macros go away. - macro_defining(macro_definer), - - // #[auto_serialize] and such. will probably survive death of #old_macros + // #[auto_serialize] and such item_decorator(item_decorator), // Token-tree expanders @@ -80,8 +61,6 @@ enum syntax_extension { // A temporary hard-coded map of methods for expanding syntax extension // AST nodes into full ASTs fn syntax_expander_table() -> HashMap<~str, syntax_extension> { - fn builtin(f: syntax_expander_) -> syntax_extension - {normal({expander: f, span: None})} fn builtin_normal_tt(f: syntax_expander_tt_) -> syntax_extension { normal_tt({expander: f, span: None}) } @@ -89,28 +68,25 @@ fn syntax_expander_table() -> HashMap<~str, 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(~"fmt", + builtin_normal_tt(ext::fmt::expand_syntax_ext)); syntax_expanders.insert( ~"auto_serialize", item_decorator(ext::auto_serialize::expand_auto_serialize)); syntax_expanders.insert( ~"auto_deserialize", item_decorator(ext::auto_serialize::expand_auto_deserialize)); - syntax_expanders.insert(~"env", builtin(ext::env::expand_syntax_ext)); + syntax_expanders.insert(~"env", + builtin_normal_tt(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)); + builtin_normal_tt( + ext::concat_idents::expand_syntax_ext)); syntax_expanders.insert(~"log_syntax", builtin_normal_tt( ext::log_syntax::expand_syntax_ext)); - syntax_expanders.insert(~"ast", - builtin(ext::qquote::expand_ast)); syntax_expanders.insert(~"deriving_eq", item_decorator( ext::deriving::expand_deriving_eq)); @@ -133,21 +109,29 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { builtin_normal_tt(ext::quote::expand_quote_stmt)); syntax_expanders.insert(~"line", - builtin(ext::source_util::expand_line)); + builtin_normal_tt( + ext::source_util::expand_line)); syntax_expanders.insert(~"col", - builtin(ext::source_util::expand_col)); + builtin_normal_tt( + ext::source_util::expand_col)); syntax_expanders.insert(~"file", - builtin(ext::source_util::expand_file)); + builtin_normal_tt( + ext::source_util::expand_file)); syntax_expanders.insert(~"stringify", - builtin(ext::source_util::expand_stringify)); + builtin_normal_tt( + ext::source_util::expand_stringify)); syntax_expanders.insert(~"include", - builtin(ext::source_util::expand_include)); + builtin_normal_tt( + ext::source_util::expand_include)); syntax_expanders.insert(~"include_str", - builtin(ext::source_util::expand_include_str)); + builtin_normal_tt( + ext::source_util::expand_include_str)); syntax_expanders.insert(~"include_bin", - builtin(ext::source_util::expand_include_bin)); + builtin_normal_tt( + ext::source_util::expand_include_bin)); syntax_expanders.insert(~"module_path", - builtin(ext::source_util::expand_mod)); + builtin_normal_tt( + ext::source_util::expand_mod)); syntax_expanders.insert(~"proto", builtin_item_tt(ext::pipes::expand_proto)); syntax_expanders.insert( @@ -303,87 +287,39 @@ fn expr_to_ident(cx: ext_ctxt, } } -fn get_mac_args_no_max(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - min: uint, name: ~str) -> ~[@ast::expr] { - return get_mac_args(cx, sp, arg, min, None, name); +fn check_zero_tts(cx: ext_ctxt, sp: span, tts: &[ast::token_tree], + name: &str) { + if tts.len() != 0 { + cx.span_fatal(sp, fmt!("%s takes no arguments", name)); + } } -fn get_mac_args(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - min: uint, max: Option<uint>, name: ~str) -> ~[@ast::expr] { - match arg { - Some(expr) => match expr.node { - ast::expr_vec(elts, _) => { - let elts_len = vec::len(elts); - match max { - Some(max) if ! (min <= elts_len && elts_len <= max) => { - cx.span_fatal(sp, - fmt!("%s! takes between %u and %u arguments.", - name, min, max)); - } - None if ! (min <= elts_len) => { - cx.span_fatal(sp, fmt!("%s! needs at least %u arguments.", - name, min)); - } - _ => return elts /* we are good */ - } - } - _ => { - cx.span_fatal(sp, fmt!("%s!: malformed invocation", name)) - } - }, - None => cx.span_fatal(sp, fmt!("%s!: missing arguments", name)) +fn get_single_str_from_tts(cx: ext_ctxt, sp: span, tts: &[ast::token_tree], + name: &str) -> ~str { + if tts.len() != 1 { + cx.span_fatal(sp, fmt!("%s takes 1 argument.", name)); } -} -fn get_mac_body(cx: ext_ctxt, sp: span, args: ast::mac_body) - -> ast::mac_body_ -{ - match (args) { - Some(body) => body, - None => cx.span_fatal(sp, ~"missing macro body") + match tts[0] { + ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident), + _ => + cx.span_fatal(sp, fmt!("%s requires a string.", name)) } } -// 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. -fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree]) - -> ast::mac_arg { - 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, - matched_nonterminal}; - - // these spans won't matter, anyways - fn ms(m: matcher_) -> matcher { - {node: m, span: dummy_sp()} +fn get_exprs_from_tts(cx: ext_ctxt, tts: ~[ast::token_tree]) + -> ~[@ast::expr] { + let p = parse::new_parser_from_tts(cx.parse_sess(), + cx.cfg(), + tts); + let mut es = ~[]; + while p.token != token::EOF { + if es.len() != 0 { + p.eat(token::COMMA); + } + es.push(p.parse_expr()); } - let arg_nm = cx.parse_sess().interner.gensym(@~"arg"); - - let argument_gram = ~[ms(match_seq(~[ - ms(match_nonterminal(arg_nm, parse::token::special_idents::expr, 0u)) - ], Some(parse::token::COMMA), true, 0u, 1u))]; - - let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic, - cx.parse_sess().interner, None, arg); - let args = - match parse_or_else(cx.parse_sess(), cx.cfg(), arg_reader as reader, - argument_gram).get(arg_nm) { - @matched_seq(s, _) => { - do s.map() |lf| { - match *lf { - @matched_nonterminal(parse::token::nt_expr(arg)) => - arg, /* whew! list of exprs, here we come! */ - _ => fail ~"badly-structured parse result" - } - } - }, - _ => fail ~"badly-structured parse result" - }; - - return Some(@{id: parse::next_node_id(cx.parse_sess()), - callee_id: parse::next_node_id(cx.parse_sess()), - node: ast::expr_vec(args, ast::m_imm), span: sp}); + es } // diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index b6fb3a75938..a47b64bea3a 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -10,19 +10,32 @@ use base::*; -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args_no_max(cx,sp,arg,1u,~"concat_idents"); +fn expand_syntax_ext(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { let mut res_str = ~""; - for args.each |e| { - res_str += *cx.parse_sess().interner.get( - expr_to_ident(cx, *e, ~"expected an ident")); + for tts.eachi |i, e| { + if i & 1 == 1 { + match *e { + ast::tt_tok(_, token::COMMA) => (), + _ => cx.span_fatal(sp, ~"concat_idents! \ + expecting comma.") + } + } else { + match *e { + ast::tt_tok(_, token::IDENT(ident,_)) => + res_str += cx.str_of(ident), + _ => cx.span_fatal(sp, ~"concat_idents! \ + requires ident args.") + } + } } let res = cx.parse_sess().interner.intern(@res_str); - return @{id: cx.next_id(), - callee_id: cx.next_id(), - node: ast::expr_path(@{span: sp, global: false, idents: ~[res], - rp: None, types: ~[]}), - span: sp}; + let e = @{id: cx.next_id(), + callee_id: cx.next_id(), + node: ast::expr_path(@{span: sp, global: false, + idents: ~[res], + rp: None, types: ~[]}), + span: sp}; + mr_expr(e) } diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 51db63c819a..68db1b41781 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -18,18 +18,19 @@ use base::*; use build::mk_uniq_str; export expand_syntax_ext; -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args(cx, sp, arg, 1u, option::Some(1u), ~"env"); +fn expand_syntax_ext(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + + let var = get_single_str_from_tts(cx, sp, tts, "env!"); // FIXME (#2248): if this was more thorough it would manufacture an // Option<str> rather than just an maybe-empty string. - let var = expr_to_str(cx, args[0], ~"env! requires a string"); - match os::getenv(var) { - option::None => return mk_uniq_str(cx, sp, ~""), - option::Some(ref s) => return mk_uniq_str(cx, sp, (*s)) - } + let e = match os::getenv(var) { + option::None => mk_uniq_str(cx, sp, ~""), + option::Some(ref s) => mk_uniq_str(cx, sp, (*s)) + }; + mr_expr(e) } // diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e9d871752aa..a35f351451b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -10,11 +10,10 @@ use std::map::HashMap; -use ast::{crate, expr_, expr_mac, mac_invoc, mac_invoc_tt, +use ast::{crate, expr_, expr_mac, mac_invoc_tt, tt_delim, tt_tok, item_mac, stmt_, stmt_mac, stmt_expr, stmt_semi}; use fold::*; use ext::base::*; -use ext::qquote::{qq_helper}; use parse::{parser, parse_expr_from_source_str, new_parser_from_tts}; @@ -32,51 +31,6 @@ fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, expr_mac(ref mac) => { match (*mac).node { - // Old-style macros. For compatibility, will erase this whole - // block once we've transitioned. - mac_invoc(pth, args, body) => { - assert (vec::len(pth.idents) > 0u); - /* using idents and token::special_idents would make the - the macro names be hygienic */ - let extname = cx.parse_sess().interner.get(pth.idents[0]); - match exts.find(*extname) { - None => { - cx.span_fatal(pth.span, - fmt!("macro undefined: '%s'", *extname)) - } - Some(item_decorator(_)) => { - cx.span_fatal( - pth.span, - fmt!("%s can only be used as a decorator", *extname)); - } - Some(normal({expander: exp, span: exp_sp})) => { - - cx.bt_push(ExpandedFrom({call_site: s, - callie: {name: *extname, span: exp_sp}})); - let expanded = exp(cx, (*mac).span, args, body); - - //keep going, outside-in - let fully_expanded = fld.fold_expr(expanded).node; - cx.bt_pop(); - - (fully_expanded, s) - } - Some(macro_defining(ext)) => { - let named_extension = ext(cx, (*mac).span, args, body); - exts.insert(named_extension.name, named_extension.ext); - (ast::expr_rec(~[], None), s) - } - Some(normal_tt(_)) => { - cx.span_fatal(pth.span, - 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"); - } - } - } // Token-tree macros, these will be the only case when we're // finished transitioning. @@ -108,21 +62,6 @@ fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, (fully_expanded, s) } - Some(normal({expander: exp, span: exp_sp})) => { - cx.bt_push(ExpandedFrom({call_site: s, - callie: {name: *extname, span: exp_sp}})); - - //convert the new-style invoc for the old-style macro - let arg = base::tt_args_to_original_flavor(cx, pth.span, - (*tts)); - let expanded = exp(cx, (*mac).span, arg, None); - - //keep going, outside-in - let fully_expanded = fld.fold_expr(expanded).node; - cx.bt_pop(); - - (fully_expanded, s) - } _ => { cx.span_fatal(pth.span, fmt!("'%s' is not a tt-style macro", @@ -131,7 +70,6 @@ fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, } } - _ => cx.span_bug((*mac).span, ~"naked syntactic bit") } } _ => orig(e, s, fld) @@ -166,10 +104,14 @@ fn expand_mod_items(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, ast::meta_list(ref n, _) => (*n) }; match exts.find(mname) { - None | Some(normal(_)) | Some(macro_defining(_)) - | Some(normal_tt(_)) | Some(item_tt(*)) => items, + None | Some(normal_tt(_)) | Some(item_tt(*)) => items, Some(item_decorator(dec_fn)) => { - dec_fn(cx, attr.span, attr.node.value, items) + cx.bt_push(ExpandedFrom({call_site: attr.span, + callie: {name: copy mname, + span: None}})); + let r = dec_fn(cx, attr.span, attr.node.value, items); + cx.bt_pop(); + r } } } @@ -205,36 +147,16 @@ fn expand_item(exts: HashMap<~str, syntax_extension>, } } -// avoid excess indentation when a series of nested `match`es -// has only one "good" outcome -macro_rules! biased_match ( - ( ($e :expr) ~ ($p :pat) else $err :stmt ; - $( ($e_cdr:expr) ~ ($p_cdr:pat) else $err_cdr:stmt ; )* - => $body:expr - ) => ( - match $e { - $p => { - biased_match!($( ($e_cdr) ~ ($p_cdr) else $err_cdr ; )* - => $body) - } - _ => { $err } - } - ); - ( => $body:expr ) => ( $body ) -) - - // Support for item-position macro invocations, exactly the same // logic as for expression-position macro invocations. fn expand_item_mac(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, &&it: @ast::item, fld: ast_fold) -> Option<@ast::item> { - let (pth, tts) = biased_match!( - (it.node) ~ (item_mac({node: mac_invoc_tt(pth, ref tts), _})) else { - cx.span_bug(it.span, ~"invalid item macro invocation") - }; - => (pth, (*tts)) - ); + + let (pth, tts) = match it.node { + item_mac({node: mac_invoc_tt(pth, ref tts), _}) => (pth, (*tts)), + _ => cx.span_bug(it.span, ~"invalid item macro invocation") + }; let extname = cx.parse_sess().interner.get(pth.idents[0]); let expanded = match exts.find(*extname) { @@ -289,12 +211,15 @@ fn expand_stmt(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, orig: fn@(&&s: stmt_, span, ast_fold) -> (stmt_, span)) -> (stmt_, span) { - let (mac, pth, tts, semi) = biased_match! ( - (s) ~ (stmt_mac(ref mac, semi)) else return orig(s, sp, fld); - ((*mac).node) ~ (mac_invoc_tt(pth, ref tts)) else { - cx.span_bug((*mac).span, ~"naked syntactic bit") - }; - => ((*mac), pth, (*tts), semi)); + + let (mac, pth, tts, semi) = match s { + stmt_mac(ref mac, semi) => { + match (*mac).node { + mac_invoc_tt(pth, ref tts) => ((*mac), pth, (*tts), semi) + } + } + _ => return orig(s, sp, fld) + }; assert(vec::len(pth.idents) == 1u); let extname = cx.parse_sess().interner.get(pth.idents[0]); @@ -321,23 +246,6 @@ fn expand_stmt(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt, (fully_expanded, sp) } - Some(normal({expander: exp, span: exp_sp})) => { - cx.bt_push(ExpandedFrom({call_site: sp, - callie: {name: *extname, - span: exp_sp}})); - //convert the new-style invoc for the old-style macro - let arg = base::tt_args_to_original_flavor(cx, pth.span, tts); - let exp_expr = exp(cx, mac.span, arg, None); - let expanded = @{node: stmt_expr(exp_expr, cx.next_id()), - span: exp_expr.span}; - - //keep going, outside-in - let fully_expanded = fld.fold_stmt(expanded).node; - cx.bt_pop(); - - (fully_expanded, sp) - } - _ => { cx.span_fatal(pth.span, fmt!("'%s' is not a tt-style macro", *extname)) diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index e0d3bd03f42..46003624a76 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -21,9 +21,12 @@ use codemap::span; use ext::build::*; export expand_syntax_ext; -fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args_no_max(cx, sp, arg, 1u, ~"fmt"); +fn expand_syntax_ext(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + let args = get_exprs_from_tts(cx, copy tts); + if args.len() == 0 { + cx.span_fatal(sp, "fmt! takes at least 1 argument."); + } let fmt = expr_to_str(cx, args[0], ~"first argument to fmt! must be a string literal."); @@ -37,7 +40,7 @@ fn expand_syntax_ext(cx: ext_ctxt, sp: span, arg: ast::mac_arg, parse_fmt_err_(cx, fmtspan, s) }; let pieces = parse_fmt_string(fmt, parse_fmt_err); - return pieces_to_expr(cx, sp, pieces, args); + mr_expr(pieces_to_expr(cx, sp, pieces, args)) } // FIXME (#2249): A lot of these functions for producing expressions can diff --git a/src/libsyntax/ext/ident_to_str.rs b/src/libsyntax/ext/ident_to_str.rs deleted file mode 100644 index ededc1a5f7f..00000000000 --- a/src/libsyntax/ext/ident_to_str.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use base::*; -use build::mk_uniq_str; - -fn expand_syntax_ext(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args(cx,sp,arg,1u,option::Some(1u),~"ident_to_str"); - - return mk_uniq_str(cx, sp, *cx.parse_sess().interner.get( - expr_to_ident(cx, args[0u], ~"expected an ident"))); -} diff --git a/src/libsyntax/ext/qquote.rs b/src/libsyntax/ext/qquote.rs deleted file mode 100644 index e13dfe750b7..00000000000 --- a/src/libsyntax/ext/qquote.rs +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast::{crate, expr_, mac_invoc, - mac_aq, mac_var}; -use parse::parser; -use parse::parser::{Parser, parse_from_source_str}; -use dvec::DVec; -use parse::token::ident_interner; -use codemap::{CharPos, BytePos}; - -use fold::*; -use visit::*; -use ext::base::*; -use ext::build::*; -use print::*; -use io::*; - -use codemap::span; - -struct gather_item { - lo: BytePos, - hi: BytePos, - e: @ast::expr, - constr: ~str -} - -type aq_ctxt = @{lo: BytePos, gather: DVec<gather_item>}; -enum fragment { - from_expr(@ast::expr), - from_ty(@ast::Ty) -} - -fn ids_ext(cx: ext_ctxt, strs: ~[~str]) -> ~[ast::ident] { - strs.map(|str| cx.parse_sess().interner.intern(@*str)) -} -fn id_ext(cx: ext_ctxt, str: ~str) -> ast::ident { - cx.parse_sess().interner.intern(@str) -} - - -trait qq_helper { - fn span() -> span; - fn visit(aq_ctxt, vt<aq_ctxt>); - fn extract_mac() -> Option<ast::mac_>; - fn mk_parse_fn(ext_ctxt,span) -> @ast::expr; - fn get_fold_fn() -> ~str; -} - -impl @ast::crate: qq_helper { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_crate(*self, cx, v);} - fn extract_mac() -> Option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_crate"])) - } - fn get_fold_fn() -> ~str {~"fold_crate"} -} -impl @ast::expr: qq_helper { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_expr(self, cx, v);} - fn extract_mac() -> Option<ast::mac_> { - match (self.node) { - ast::expr_mac({node: ref mac, _}) => Some((*mac)), - _ => None - } - } - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_expr"])) - } - fn get_fold_fn() -> ~str {~"fold_expr"} -} -impl @ast::Ty: qq_helper { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_ty(self, cx, v);} - fn extract_mac() -> Option<ast::mac_> { - match (self.node) { - ast::ty_mac({node: ref mac, _}) => Some((*mac)), - _ => None - } - } - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_ty"])) - } - fn get_fold_fn() -> ~str {~"fold_ty"} -} -impl @ast::item: qq_helper { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_item(self, cx, v);} - fn extract_mac() -> Option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_item"])) - } - fn get_fold_fn() -> ~str {~"fold_item"} -} -impl @ast::stmt: qq_helper { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_stmt(self, cx, v);} - fn extract_mac() -> Option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", ~"parse_stmt"])) - } - fn get_fold_fn() -> ~str {~"fold_stmt"} -} -impl @ast::pat: qq_helper { - fn span() -> span {self.span} - fn visit(cx: aq_ctxt, v: vt<aq_ctxt>) {visit_pat(self, cx, v);} - fn extract_mac() -> Option<ast::mac_> {fail} - fn mk_parse_fn(cx: ext_ctxt, sp: span) -> @ast::expr { - mk_path(cx, sp, ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", - ~"parse_pat"])) - } - fn get_fold_fn() -> ~str {~"fold_pat"} -} - -fn gather_anti_quotes<N: qq_helper>(lo: BytePos, node: N) -> aq_ctxt -{ - let v = @{visit_expr: |node, &&cx, v| visit_aq(node, ~"from_expr", cx, v), - visit_ty: |node, &&cx, v| visit_aq(node, ~"from_ty", cx, v), - .. *default_visitor()}; - let cx = @{lo:lo, gather: DVec()}; - node.visit(cx, mk_vt(v)); - // FIXME (#2250): Maybe this is an overkill (merge_sort), it might - // be better to just keep the gather array in sorted order. - do cx.gather.swap |v| { - pure fn by_lo(a: &gather_item, b: &gather_item) -> bool { - a.lo < b.lo - } - std::sort::merge_sort(v, by_lo) - }; - return cx; -} - -fn visit_aq<T:qq_helper>(node: T, constr: ~str, &&cx: aq_ctxt, v: vt<aq_ctxt>) -{ - match (node.extract_mac()) { - Some(mac_aq(sp, e)) => { - cx.gather.push(gather_item { - lo: sp.lo - cx.lo, - hi: sp.hi - cx.lo, - e: e, - constr: constr}); - } - _ => node.visit(cx, v) - } -} - -fn is_space(c: char) -> bool { - parse::lexer::is_whitespace(c) -} - -fn expand_ast(ecx: ext_ctxt, _sp: span, - arg: ast::mac_arg, body: ast::mac_body) - -> @ast::expr -{ - let mut what = ~"expr"; - do arg.iter |arg| { - let args: ~[@ast::expr] = - match arg.node { - ast::expr_vec(elts, _) => elts, - _ => { - ecx.span_fatal - (_sp, ~"#ast requires arguments of the form `~[...]`.") - } - }; - if vec::len::<@ast::expr>(args) != 1u { - ecx.span_fatal(_sp, ~"#ast requires exactly one arg"); - } - match (args[0].node) { - ast::expr_path(@{idents: id, _}) if vec::len(id) == 1u - => what = *ecx.parse_sess().interner.get(id[0]), - _ => ecx.span_fatal(args[0].span, ~"expected an identifier") - } - } - let body = get_mac_body(ecx,_sp,body); - - return match what { - ~"crate" => finish(ecx, body, parse_crate), - ~"expr" => finish(ecx, body, parse_expr), - ~"ty" => finish(ecx, body, parse_ty), - ~"item" => finish(ecx, body, parse_item), - ~"stmt" => finish(ecx, body, parse_stmt), - ~"pat" => finish(ecx, body, parse_pat), - _ => ecx.span_fatal(_sp, ~"unsupported ast type") - }; -} - -fn parse_crate(p: Parser) -> @ast::crate { p.parse_crate_mod(~[]) } -fn parse_ty(p: Parser) -> @ast::Ty { p.parse_ty(false) } -fn parse_stmt(p: Parser) -> @ast::stmt { p.parse_stmt(~[]) } -fn parse_expr(p: Parser) -> @ast::expr { p.parse_expr() } -fn parse_pat(p: Parser) -> @ast::pat { p.parse_pat(true) } - -fn parse_item(p: Parser) -> @ast::item { - match p.parse_item(~[]) { - Some(item) => item, - None => fail ~"parse_item: parsing an item failed" - } -} - -fn finish<T: qq_helper> - (ecx: ext_ctxt, body: ast::mac_body_, f: fn (p: Parser) -> T) - -> @ast::expr -{ - let cm = ecx.codemap(); - let str = @cm.span_to_snippet(body.span); - debug!("qquote--str==%?", str); - let fname = cm.mk_substr_filename(body.span); - let node = parse_from_source_str - (f, fname, codemap::FssInternal(body.span), str, - ecx.cfg(), ecx.parse_sess()); - let loc = cm.lookup_char_pos(body.span.lo); - - let sp = node.span(); - let qcx = gather_anti_quotes(sp.lo, node); - let cx = qcx; - - for uint::range(1u, cx.gather.len()) |i| { - assert cx.gather[i-1u].lo < cx.gather[i].lo; - // ^^ check that the vector is sorted - assert cx.gather[i-1u].hi <= cx.gather[i].lo; - // ^^ check that the spans are non-overlapping - } - - let mut str2 = ~""; - enum state {active, skip(uint), blank}; - let mut state = active; - let mut i = BytePos(0u); - let mut j = 0u; - let g_len = cx.gather.len(); - for str::chars_each(*str) |ch| { - if (j < g_len && i == cx.gather[j].lo) { - assert ch == '$'; - let repl = fmt!("$%u ", j); - state = skip(str::char_len(repl)); - str2 += repl; - } - match copy state { - active => str::push_char(&mut str2, ch), - skip(1u) => state = blank, - skip(sk) => state = skip (sk-1u), - blank if is_space(ch) => str::push_char(&mut str2, ch), - blank => str::push_char(&mut str2, ' ') - } - i += BytePos(1u); - if (j < g_len && i == cx.gather[j].hi) { - assert ch == ')'; - state = active; - j += 1u; - } - } - - let cx = ecx; - - let cfg_call = || mk_call_( - cx, sp, mk_access(cx, sp, ids_ext(cx, ~[~"ext_cx"]), - id_ext(cx, ~"cfg")), ~[]); - - let parse_sess_call = || mk_call_( - cx, sp, mk_access(cx, sp, ids_ext(cx, ~[~"ext_cx"]), - id_ext(cx, ~"parse_sess")), ~[]); - - let pcall = mk_call(cx,sp, - ids_ext(cx, ~[~"syntax", ~"parse", ~"parser", - ~"parse_from_source_str"]), - ~[node.mk_parse_fn(cx,sp), - mk_uniq_str(cx,sp, fname), - mk_call(cx,sp, - ids_ext(cx, ~[~"syntax",~"ext", - ~"qquote", ~"mk_file_substr"]), - ~[mk_uniq_str(cx,sp, loc.file.name), - mk_uint(cx,sp, loc.line), - mk_uint(cx,sp, loc.col.to_uint())]), - mk_unary(cx,sp, ast::box(ast::m_imm), - mk_uniq_str(cx,sp, str2)), - cfg_call(), - parse_sess_call()] - ); - let mut rcall = pcall; - if (g_len > 0u) { - rcall = mk_call(cx,sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", - ~"replace"]), - ~[pcall, - mk_uniq_vec_e(cx,sp, qcx.gather.map_to_vec(|g| { - mk_call(cx,sp, - ids_ext(cx, ~[~"syntax", ~"ext", - ~"qquote", g.constr]), - ~[g.e])})), - mk_path(cx,sp, - ids_ext(cx, ~[~"syntax", ~"ext", ~"qquote", - node.get_fold_fn()]))]); - } - return rcall; -} - -fn replace<T>(node: T, repls: ~[fragment], ff: fn (ast_fold, T) -> T) - -> T -{ - let aft = default_ast_fold(); - let f_pre = @{fold_expr: |a,b,c|replace_expr(repls, a, b, c, - aft.fold_expr), - fold_ty: |a,b,c|replace_ty(repls, a, b, c, - aft.fold_ty), - .. *aft}; - return ff(make_fold(f_pre), node); -} -fn fold_crate(f: ast_fold, &&n: @ast::crate) -> @ast::crate { - @f.fold_crate(*n) -} -fn fold_expr(f: ast_fold, &&n: @ast::expr) -> @ast::expr {f.fold_expr(n)} -fn fold_ty(f: ast_fold, &&n: @ast::Ty) -> @ast::Ty {f.fold_ty(n)} -fn fold_item(f: ast_fold, &&n: @ast::item) -> @ast::item { - f.fold_item(n).get() //HACK: we know we don't drop items -} -fn fold_stmt(f: ast_fold, &&n: @ast::stmt) -> @ast::stmt {f.fold_stmt(n)} -fn fold_pat(f: ast_fold, &&n: @ast::pat) -> @ast::pat {f.fold_pat(n)} - -fn replace_expr(repls: ~[fragment], - e: ast::expr_, s: span, fld: ast_fold, - orig: fn@(ast::expr_, span, ast_fold)->(ast::expr_, span)) - -> (ast::expr_, span) -{ - match e { - ast::expr_mac({node: mac_var(i), _}) => match (repls[i]) { - from_expr(r) => (r.node, r.span), - _ => fail /* fixme error message */ - }, - _ => orig(e,s,fld) - } -} - -fn replace_ty(repls: ~[fragment], - e: ast::ty_, s: span, fld: ast_fold, - orig: fn@(ast::ty_, span, ast_fold)->(ast::ty_, span)) - -> (ast::ty_, span) -{ - match e { - ast::ty_mac({node: mac_var(i), _}) => match (repls[i]) { - from_ty(r) => (r.node, r.span), - _ => fail /* fixme error message */ - }, - _ => orig(e,s,fld) - } -} - -fn mk_file_substr(fname: ~str, line: uint, col: uint) -> - codemap::FileSubstr { - codemap::FssExternal({filename: fname, line: line, col: CharPos(col)}) -} - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 60918121e95..1e5d4ea8d16 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -406,7 +406,6 @@ fn mk_token(cx: ext_ctxt, sp: span, tok: token::Token) -> @ast::expr { AT => "AT", DOT => "DOT", DOTDOT => "DOTDOT", - ELLIPSIS => "ELLIPSIS", COMMA => "COMMA", SEMI => "SEMI", COLON => "COLON", diff --git a/src/libsyntax/ext/simplext.rs b/src/libsyntax/ext/simplext.rs deleted file mode 100644 index f13c5c9aff9..00000000000 --- a/src/libsyntax/ext/simplext.rs +++ /dev/null @@ -1,750 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use codemap::span; -use std::map::HashMap; -use dvec::DVec; - -use base::*; - -use fold::*; -use ast_util::respan; -use ast::{ident, path, Ty, blk_, expr, expr_path, - expr_vec, expr_mac, mac_invoc, node_id, expr_index}; - -export add_new_extension; - -fn path_to_ident(pth: @path) -> Option<ident> { - if vec::len(pth.idents) == 1u && vec::len(pth.types) == 0u { - return Some(pth.idents[0u]); - } - return None; -} - -//a vec of binders might be a little big. -type clause = {params: binders, body: @expr}; - -/* logically, an arb_depth should contain only one kind of matchable */ -enum arb_depth<T> { leaf(T), seq(@~[arb_depth<T>], span), } - - -enum matchable { - match_expr(@expr), - match_path(@path), - match_ident(ast::spanned<ident>), - match_ty(@Ty), - match_block(ast::blk), - match_exact, /* don't bind anything, just verify the AST traversal */ -} - -/* for when given an incompatible bit of AST */ -fn match_error(cx: ext_ctxt, m: matchable, expected: ~str) -> ! { - match m { - match_expr(x) => cx.span_fatal( - x.span, ~"this argument is an expr, expected " + expected), - match_path(x) => cx.span_fatal( - x.span, ~"this argument is a path, expected " + expected), - match_ident(x) => cx.span_fatal( - x.span, ~"this argument is an ident, expected " + expected), - match_ty(x) => cx.span_fatal( - x.span, ~"this argument is a type, expected " + expected), - match_block(ref x) => cx.span_fatal( - (*x).span, ~"this argument is a block, expected " + expected), - match_exact => cx.bug(~"what is a match_exact doing in a bindings?") - } -} - -// We can't make all the matchables in a match_result the same type because -// idents can be paths, which can be exprs. - -// If we want better match failure error messages (like in Fortifying Syntax), -// we'll want to return something indicating amount of progress and location -// of failure instead of `none`. -type match_result = Option<arb_depth<matchable>>; -type selector = fn@(matchable) -> match_result; - -fn elts_to_ell(cx: ext_ctxt, elts: ~[@expr]) -> - {pre: ~[@expr], rep: Option<@expr>, post: ~[@expr]} { - let mut idx: uint = 0u; - let mut res = None; - for elts.each |elt| { - match elt.node { - expr_mac(ref m) => match (*m).node { - ast::mac_ellipsis => { - if res.is_some() { - cx.span_fatal((*m).span, ~"only one ellipsis allowed"); - } - res = - Some({pre: vec::slice(elts, 0u, idx - 1u), - rep: Some(elts[idx - 1u]), - post: vec::slice(elts, idx + 1u, vec::len(elts))}); - } - _ => () - }, - _ => () - } - idx += 1u; - } - return match res { - Some(val) => val, - None => {pre: elts, rep: None, post: ~[]} - } -} - -fn option_flatten_map<T: Copy, U: Copy>(f: fn@(T) -> Option<U>, v: ~[T]) -> - Option<~[U]> { - let mut res = ~[]; - for v.each |elem| { - match f(*elem) { - None => return None, - Some(ref fv) => res.push((*fv)) - } - } - return Some(res); -} - -fn a_d_map(ad: arb_depth<matchable>, f: selector) -> match_result { - match ad { - leaf(ref x) => return f((*x)), - seq(ads, span) => match option_flatten_map(|x| a_d_map(x, f), *ads) { - None => return None, - Some(ts) => return Some(seq(@ts, span)) - } - } -} - -fn compose_sels(s1: selector, s2: selector) -> selector { - fn scomp(s1: selector, s2: selector, m: matchable) -> match_result { - return match s1(m) { - None => None, - Some(ref matches) => a_d_map((*matches), s2) - } - } - return { |x| scomp(s1, s2, x) }; -} - - - -type binders = - {real_binders: HashMap<ident, selector>, - literal_ast_matchers: DVec<selector>}; -type bindings = HashMap<ident, arb_depth<matchable>>; - -fn acumm_bindings(_cx: ext_ctxt, _b_dest: bindings, _b_src: bindings) { } - -/* these three functions are the big moving parts */ - -/* create the selectors needed to bind and verify the pattern */ - -fn pattern_to_selectors(cx: ext_ctxt, e: @expr) -> binders { - let res: binders = - {real_binders: HashMap(), - literal_ast_matchers: DVec()}; - //this oughta return binders instead, but macro args are a sequence of - //expressions, rather than a single expression - fn trivial_selector(m: matchable) -> match_result { - return Some(leaf(m)); - } - p_t_s_rec(cx, match_expr(e), trivial_selector, res); - move res -} - - - -/* use the selectors on the actual arguments to the macro to extract -bindings. Most of the work is done in p_t_s, which generates the -selectors. */ - -fn use_selectors_to_bind(b: binders, e: @expr) -> Option<bindings> { - let res = HashMap(); - //need to do this first, to check vec lengths. - for b.literal_ast_matchers.each |sel| { - match (*sel)(match_expr(e)) { None => return None, _ => () } - } - let mut never_mind: bool = false; - for b.real_binders.each |key, val| { - match val(match_expr(e)) { - None => never_mind = true, - Some(ref mtc) => { res.insert(key, (*mtc)); } - } - }; - //HACK: `ret` doesn't work in `for each` - if never_mind { return None; } - return Some(res); -} - -/* use the bindings on the body to generate the expanded code */ - -fn transcribe(cx: ext_ctxt, b: bindings, body: @expr) -> @expr { - let idx_path: @mut ~[uint] = @mut ~[]; - fn new_id(_old: node_id, cx: ext_ctxt) -> node_id { return cx.next_id(); } - fn new_span(cx: ext_ctxt, sp: span) -> span { - /* this discards information in the case of macro-defining macros */ - return span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()}; - } - let afp = default_ast_fold(); - let f_pre = - @{fold_ident: |x,y|transcribe_ident(cx, b, idx_path, x, y), - fold_path: |x,y|transcribe_path(cx, b, idx_path, x, y), - fold_expr: |x,y,z| - transcribe_expr(cx, b, idx_path, x, y, z, afp.fold_expr) - , - fold_ty: |x,y,z| - transcribe_type(cx, b, idx_path, - x, y, z, afp.fold_ty) - , - fold_block: |x,y,z| - transcribe_block(cx, b, idx_path, x, y, z, afp.fold_block) - , - map_exprs: |x,y| - transcribe_exprs(cx, b, idx_path, x, y) - , - new_id: |x|new_id(x, cx), - .. *afp}; - let f = make_fold(f_pre); - let result = f.fold_expr(body); - return result; -} - - -/* helper: descend into a matcher */ -pure fn follow(m: arb_depth<matchable>, idx_path: &[uint]) -> - arb_depth<matchable> { - let mut res: arb_depth<matchable> = m; - for vec::each(idx_path) |idx| { - res = match res { - leaf(_) => return res,/* end of the line */ - seq(new_ms, _) => new_ms[*idx] - } - } - return res; -} - -fn follow_for_trans(cx: ext_ctxt, mmaybe: Option<arb_depth<matchable>>, - idx_path: @mut ~[uint]) -> Option<matchable> { - match mmaybe { - None => return None, - Some(ref m) => { - return match follow((*m), *idx_path) { - seq(_, sp) => { - cx.span_fatal(sp, - ~"syntax matched under ... but not " + - ~"used that way.") - } - leaf(ref m) => return Some((*m)) - } - } - } - -} - -/* helper for transcribe_exprs: what vars from `b` occur in `e`? */ -fn free_vars(b: bindings, e: @expr, it: fn(ident)) { - let idents = HashMap(); - fn mark_ident(&&i: ident, _fld: ast_fold, b: bindings, - idents: HashMap<ident, ()>) -> ident { - if b.contains_key(i) { idents.insert(i, ()); } - return i; - } - // using fold is a hack: we want visit, but it doesn't hit idents ) : - // solve this with macros - let f_pre = - @{fold_ident: |x,y|mark_ident(x, y, b, idents), - .. *default_ast_fold()}; - let f = make_fold(f_pre); - f.fold_expr(e); // ignore result - for idents.each_key |x| { it(x); }; -} - -fn wrong_occurs(cx: ext_ctxt, l: ident, l_c: uint, r: ident, r_c: uint) - -> ~str { - fmt!("'%s' occurs %u times, but '%s' occurs %u times", - *cx.parse_sess().interner.get(l), l_c, - *cx.parse_sess().interner.get(r), r_c) -} - -/* handle sequences (anywhere in the AST) of exprs, either real or ...ed */ -fn transcribe_exprs(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint], - recur: fn@(&&v: @expr) -> @expr, - exprs: ~[@expr]) -> ~[@expr] { - match elts_to_ell(cx, exprs) { - {pre: pre, rep: repeat_me_maybe, post: post} => { - let mut res = vec::map(pre, |x| recur(*x)); - match repeat_me_maybe { - None => (), - Some(repeat_me) => { - let mut repeat: Option<{rep_count: uint, name: ident}> = None; - /* we need to walk over all the free vars in lockstep, except for - the leaves, which are just duplicated */ - do free_vars(b, repeat_me) |fv| { - let fv_depth = b.get(fv); - let cur_pos = follow(fv_depth, *idx_path); - match cur_pos { - leaf(_) => (), - seq(ms, _) => { - match repeat { - None => { - repeat = Some({rep_count: vec::len(*ms), name: fv}); - } - Some({rep_count: old_len, name: old_name}) => { - let len = vec::len(*ms); - if old_len != len { - let msg = wrong_occurs(cx, fv, len, - old_name, old_len); - cx.span_fatal(repeat_me.span, msg); - } - } - } - } - } - }; - match repeat { - None => { - cx.span_fatal(repeat_me.span, - ~"'...' surrounds an expression without any" + - ~" repeating syntax variables"); - } - Some({rep_count: rc, _}) => { - /* Whew, we now know how how many times to repeat */ - let mut idx: uint = 0u; - while idx < rc { - idx_path.push(idx); - res.push(recur(repeat_me)); // whew! - idx_path.pop(); - idx += 1u; - } - } - } - } - } - res = vec::append(res, vec::map(post, |x| recur(*x))); - return res; - } - } -} - - - -// substitute, in a position that's required to be an ident -fn transcribe_ident(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint], - &&i: ident, _fld: ast_fold) -> ident { - return match follow_for_trans(cx, b.find(i), idx_path) { - Some(match_ident(a_id)) => a_id.node, - Some(ref m) => match_error(cx, (*m), ~"an identifier"), - None => i - } -} - - -fn transcribe_path(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint], - p: path, _fld: ast_fold) -> path { - // Don't substitute into qualified names. - if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { return p; } - match follow_for_trans(cx, b.find(p.idents[0]), idx_path) { - Some(match_ident(id)) => { - {span: id.span, global: false, idents: ~[id.node], - rp: None, types: ~[]} - } - Some(match_path(a_pth)) => *a_pth, - Some(ref m) => match_error(cx, (*m), ~"a path"), - None => p - } -} - - -fn transcribe_expr(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint], - e: ast::expr_, s: span, fld: ast_fold, - orig: fn@(ast::expr_, span, ast_fold)->(ast::expr_, span)) - -> (ast::expr_, span) -{ - return match e { - expr_path(p) => { - // Don't substitute into qualified names. - if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { - (e, s); - } - match follow_for_trans(cx, b.find(p.idents[0]), idx_path) { - Some(match_ident(id)) => { - (expr_path(@{span: id.span, - global: false, - idents: ~[id.node], - rp: None, - types: ~[]}), id.span) - } - Some(match_path(a_pth)) => (expr_path(a_pth), s), - Some(match_expr(a_exp)) => (a_exp.node, a_exp.span), - Some(ref m) => match_error(cx, (*m), ~"an expression"), - None => orig(e, s, fld) - } - } - _ => orig(e, s, fld) - } -} - -fn transcribe_type(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint], - t: ast::ty_, s: span, fld: ast_fold, - orig: fn@(ast::ty_, span, ast_fold) -> (ast::ty_, span)) - -> (ast::ty_, span) -{ - return match t { - ast::ty_path(pth, _) => { - match path_to_ident(pth) { - Some(id) => { - match follow_for_trans(cx, b.find(id), idx_path) { - Some(match_ty(ty)) => (ty.node, ty.span), - Some(ref m) => match_error(cx, (*m), ~"a type"), - None => orig(t, s, fld) - } - } - None => orig(t, s, fld) - } - } - _ => orig(t, s, fld) - } -} - - -/* for parsing reasons, syntax variables bound to blocks must be used like -`{v}` */ - -fn transcribe_block(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint], - blk: blk_, s: span, fld: ast_fold, - orig: fn@(blk_, span, ast_fold) -> (blk_, span)) - -> (blk_, span) -{ - return match block_to_ident(blk) { - Some(id) => { - match follow_for_trans(cx, b.find(id), idx_path) { - Some(match_block(ref new_blk)) => { - ((*new_blk).node, (*new_blk).span) - } - - // possibly allow promotion of ident/path/expr to blocks? - Some(ref m) => match_error(cx, (*m), ~"a block"), - None => orig(blk, s, fld) - } - } - None => orig(blk, s, fld) - } -} - - -/* traverse the pattern, building instructions on how to bind the actual -argument. ps accumulates instructions on navigating the tree.*/ -fn p_t_s_rec(cx: ext_ctxt, m: matchable, s: selector, b: binders) { - - //it might be possible to traverse only exprs, not matchables - match m { - match_expr(e) => { - match e.node { - expr_path(p_pth) => p_t_s_r_path(cx, p_pth, s, b), - expr_vec(p_elts, _) => { - match elts_to_ell(cx, p_elts) { - {pre: pre, rep: Some(repeat_me), post: post} => { - p_t_s_r_length(cx, vec::len(pre) + vec::len(post), true, s, - b); - if vec::len(pre) > 0u { - p_t_s_r_actual_vector(cx, pre, true, s, b); - } - p_t_s_r_ellipses(cx, repeat_me, vec::len(pre), s, b); - - if vec::len(post) > 0u { - cx.span_unimpl(e.span, - ~"matching after `...` not yet supported"); - } - } - {pre: pre, rep: None, post: post} => { - if post.len() > 0 { - cx.bug(~"elts_to_ell provided an invalid result"); - } - p_t_s_r_length(cx, vec::len(pre), false, s, b); - p_t_s_r_actual_vector(cx, pre, false, s, b); - } - } - } - /* FIXME (#2251): handle embedded types and blocks, at least */ - expr_mac(ref mac) => { - p_t_s_r_mac(cx, (*mac), s, b); - } - _ => { - fn select(cx: ext_ctxt, m: matchable, pat: @expr) -> - match_result { - return match m { - match_expr(e) => { - if managed::ptr_eq(e, pat) { - // XXX: Is this right? - Some(leaf(match_exact)) - } else { - None - } - } - _ => cx.bug(~"broken traversal in p_t_s_r") - } - } - b.literal_ast_matchers.push(|x| select(cx, x, e)); - } - } - } - _ => cx.bug(~"undocumented invariant in p_t_s_rec") - } -} - - -/* make a match more precise */ -fn specialize_match(m: matchable) -> matchable { - return match m { - match_expr(e) => { - match e.node { - expr_path(pth) => { - match path_to_ident(pth) { - Some(id) => match_ident(respan(pth.span, id)), - None => match_path(pth) - } - } - _ => m - } - } - _ => m - } -} - -/* pattern_to_selectors helper functions */ -fn p_t_s_r_path(cx: ext_ctxt, p: @path, s: selector, b: binders) { - match path_to_ident(p) { - Some(p_id) => { - fn select(cx: ext_ctxt, m: matchable) -> match_result { - return match m { - match_expr(*) => Some(leaf(specialize_match(m))), - _ => cx.bug(~"broken traversal in p_t_s_r") - } - } - if b.real_binders.contains_key(p_id) { - cx.span_fatal(p.span, ~"duplicate binding identifier"); - } - b.real_binders.insert(p_id, compose_sels(s, |x| select(cx, x))); - } - None => () - } -} - -fn block_to_ident(blk: blk_) -> Option<ident> { - if vec::len(blk.stmts) != 0u { return None; } - return match blk.expr { - Some(expr) => match expr.node { - expr_path(pth) => path_to_ident(pth), - _ => None - }, - None => None - } -} - -fn p_t_s_r_mac(cx: ext_ctxt, mac: ast::mac, _s: selector, _b: binders) { - fn select_pt_1(cx: ext_ctxt, m: matchable, - fn_m: fn(ast::mac) -> match_result) -> match_result { - return match m { - match_expr(e) => match e.node { - expr_mac(ref mac) => fn_m((*mac)), - _ => None - }, - _ => cx.bug(~"broken traversal in p_t_s_r") - } - } - fn no_des(cx: ext_ctxt, sp: span, syn: ~str) -> ! { - cx.span_fatal(sp, ~"destructuring " + syn + ~" is not yet supported"); - } - match mac.node { - ast::mac_ellipsis => cx.span_fatal(mac.span, ~"misused `...`"), - ast::mac_invoc(_, _, _) => no_des(cx, mac.span, ~"macro calls"), - ast::mac_invoc_tt(_, _) => no_des(cx, mac.span, ~"macro calls"), - ast::mac_aq(_,_) => no_des(cx, mac.span, ~"antiquotes"), - ast::mac_var(_) => no_des(cx, mac.span, ~"antiquote variables") - } -} - -fn p_t_s_r_ellipses(cx: ext_ctxt, repeat_me: @expr, offset: uint, s: selector, - b: binders) { - fn select(cx: ext_ctxt, repeat_me: @expr, offset: uint, m: matchable) -> - match_result { - return match m { - match_expr(e) => { - match e.node { - expr_vec(arg_elts, _) => { - let mut elts = ~[]; - let mut idx = offset; - while idx < vec::len(arg_elts) { - elts.push(leaf(match_expr(arg_elts[idx]))); - idx += 1u; - } - - // using repeat_me.span is a little wacky, but the - // error we want to report is one in the macro def - Some(seq(@elts, repeat_me.span)) - } - _ => None - } - } - _ => cx.bug(~"broken traversal in p_t_s_r") - } - } - p_t_s_rec(cx, match_expr(repeat_me), - compose_sels(s, |x| select(cx, repeat_me, offset, x)), b); -} - - -fn p_t_s_r_length(cx: ext_ctxt, len: uint, at_least: bool, s: selector, - b: binders) { - fn len_select(_cx: ext_ctxt, m: matchable, at_least: bool, len: uint) -> - match_result { - return match m { - match_expr(e) => { - match e.node { - expr_vec(arg_elts, _) => { - let actual_len = vec::len(arg_elts); - if at_least && actual_len >= len || actual_len == len { - Some(leaf(match_exact)) - } else { None } - } - _ => None - } - } - _ => None - } - } - b.literal_ast_matchers.push( - compose_sels(s, |x| len_select(cx, x, at_least, len))); -} - -fn p_t_s_r_actual_vector(cx: ext_ctxt, elts: ~[@expr], _repeat_after: bool, - s: selector, b: binders) { - let mut idx: uint = 0u; - while idx < vec::len(elts) { - fn select(cx: ext_ctxt, m: matchable, idx: uint) -> match_result { - return match m { - match_expr(e) => { - match e.node { - expr_vec(arg_elts, _) => { - Some(leaf(match_expr(arg_elts[idx]))) - } - _ => None - } - } - _ => cx.bug(~"broken traversal in p_t_s_r") - } - } - p_t_s_rec(cx, match_expr(elts[idx]), - compose_sels(s, |x, copy idx| select(cx, x, idx)), b); - idx += 1u; - } -} - -fn add_new_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> base::macro_def { - let args = get_mac_args_no_max(cx, sp, arg, 0u, ~"macro"); - - let mut macro_name: Option<~str> = None; - let mut clauses: ~[@clause] = ~[]; - for args.each |arg| { - match arg.node { - expr_vec(elts, _) => { - if vec::len(elts) != 2u { - cx.span_fatal((*arg).span, - ~"extension clause must consist of ~[" + - ~"macro invocation, expansion body]"); - } - - - match elts[0u].node { - expr_mac(ref mac) => { - match (*mac).node { - mac_invoc(pth, invoc_arg, _) => { - match path_to_ident(pth) { - Some(id) => { - let id_str = cx.str_of(id); - match macro_name { - None => macro_name = Some(id_str), - Some(ref other_id) => if id_str != (*other_id) { - cx.span_fatal(pth.span, - ~"macro name must be " + - ~"consistent"); - } - } - }, - None => cx.span_fatal(pth.span, - ~"macro name must not be a path") - } - let arg = match invoc_arg { - Some(arg) => arg, - None => cx.span_fatal((*mac).span, - ~"macro must have arguments") - }; - clauses.push(@{params: pattern_to_selectors(cx, arg), - body: elts[1u]}); - - // FIXME (#2251): check duplicates (or just simplify - // the macro arg situation) - } - _ => { - cx.span_bug((*mac).span, ~"undocumented invariant in \ - add_extension"); - } - } - } - _ => { - cx.span_fatal(elts[0u].span, - ~"extension clause must" + - ~" start with a macro invocation."); - } - } - } - _ => { - cx.span_fatal((*arg).span, - ~"extension must be ~[clause, " + ~" ...]"); - } - } - } - - let ext = |a,b,c,d, move clauses| generic_extension(a,b,c,d,clauses); - - return {name: - match macro_name { - Some(ref id) => (*id), - None => cx.span_fatal(sp, ~"macro definition must have " + - ~"at least one clause") - }, - ext: normal({expander: ext, span: Some(arg.get().span)})}; - - fn generic_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body, - clauses: ~[@clause]) -> @expr { - let arg = match arg { - Some(arg) => arg, - None => cx.span_fatal(sp, ~"macro must have arguments") - }; - for clauses.each |c| { - match use_selectors_to_bind(c.params, arg) { - Some(bindings) => return transcribe(cx, bindings, c.body), - None => loop - } - } - cx.span_fatal(sp, ~"no clauses match macro invocation"); - } -} - - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index aa97646c054..8d2b9163f15 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -23,63 +23,58 @@ export expand_include_str; export expand_include_bin; /* line!(): expands to the current line number */ -fn expand_line(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - get_mac_args(cx, sp, arg, 0u, option::Some(0u), ~"line"); +fn expand_line(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + base::check_zero_tts(cx, sp, tts, "line!"); let loc = cx.codemap().lookup_char_pos(sp.lo); - return mk_uint(cx, sp, loc.line); + base::mr_expr(mk_uint(cx, sp, loc.line)) } /* col!(): expands to the current column number */ -fn expand_col(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - get_mac_args(cx, sp, arg, 0u, option::Some(0u), ~"col"); +fn expand_col(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + base::check_zero_tts(cx, sp, tts, "col!"); let loc = cx.codemap().lookup_char_pos(sp.lo); - return mk_uint(cx, sp, loc.col.to_uint()); + base::mr_expr(mk_uint(cx, sp, loc.col.to_uint())) } /* file!(): expands to the current filename */ /* The filemap (`loc.file`) contains a bunch more information we could spit * out if we wanted. */ -fn expand_file(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - get_mac_args(cx, sp, arg, 0u, option::Some(0u), ~"file"); +fn expand_file(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + base::check_zero_tts(cx, sp, tts, "file!"); let Loc { file: @FileMap { name: filename, _ }, _ } = cx.codemap().lookup_char_pos(sp.lo); - return mk_uniq_str(cx, sp, filename); + base::mr_expr(mk_uniq_str(cx, sp, filename)) } -fn expand_stringify(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args(cx, sp, arg, 1u, option::Some(1u), ~"stringify"); - let s = pprust::expr_to_str(args[0], cx.parse_sess().interner); - return mk_uniq_str(cx, sp, s); +fn expand_stringify(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + let s = pprust::tts_to_str(tts, cx.parse_sess().interner); + base::mr_expr(mk_uniq_str(cx, sp, s)) } -fn expand_mod(cx: ext_ctxt, sp: span, arg: ast::mac_arg, _body: ast::mac_body) - -> @ast::expr { - get_mac_args(cx, sp, arg, 0u, option::Some(0u), ~"file"); - return mk_uniq_str(cx, sp, - str::connect(cx.mod_path().map( - |x| cx.str_of(*x)), ~"::")); +fn expand_mod(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + base::check_zero_tts(cx, sp, tts, "module_path!"); + base::mr_expr(mk_uniq_str(cx, sp, + str::connect(cx.mod_path().map( + |x| cx.str_of(*x)), ~"::"))) } -fn expand_include(cx: ext_ctxt, sp: span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args(cx, sp, arg, 1u, option::Some(1u), ~"include"); - let file = expr_to_str(cx, args[0], ~"include_str! requires a string"); +fn expand_include(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + let file = get_single_str_from_tts(cx, sp, tts, "include!"); let p = parse::new_sub_parser_from_file( cx.parse_sess(), cx.cfg(), &res_rel_file(cx, sp, &Path(file)), sp); - return p.parse_expr(); + base::mr_expr(p.parse_expr()) } -fn expand_include_str(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args(cx,sp,arg,1u,option::Some(1u),~"include_str"); - - let file = expr_to_str(cx, args[0], ~"include_str! requires a string"); - +fn expand_include_str(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path(file))); match res { result::Ok(_) => { /* Continue. */ } @@ -88,21 +83,18 @@ fn expand_include_str(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, } } - return mk_uniq_str(cx, sp, result::unwrap(res)); + base::mr_expr(mk_uniq_str(cx, sp, result::unwrap(res))) } -fn expand_include_bin(cx: ext_ctxt, sp: codemap::span, arg: ast::mac_arg, - _body: ast::mac_body) -> @ast::expr { - let args = get_mac_args(cx,sp,arg,1u,option::Some(1u),~"include_bin"); - - let file = expr_to_str(cx, args[0], ~"include_bin! requires a string"); - +fn expand_include_bin(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) + -> base::mac_result { + let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); match io::read_whole_file(&res_rel_file(cx, sp, &Path(file))) { result::Ok(src) => { let u8_exprs = vec::map(src, |char| { mk_u8(cx, sp, *char) }); - return mk_base_vec_e(cx, sp, u8_exprs); + base::mr_expr(mk_base_vec_e(cx, sp, u8_exprs)) } result::Err(ref e) => { cx.parse_sess().span_diagnostic.handler().fatal((*e)) |
