diff options
| -rw-r--r-- | src/comp/driver/rustc.rs | 10 | ||||
| -rw-r--r-- | src/comp/driver/session.rs | 27 | ||||
| -rw-r--r-- | src/comp/middle/trans.rs | 4 | ||||
| -rw-r--r-- | src/comp/middle/tstate/pre_post_conditions.rs | 5 | ||||
| -rw-r--r-- | src/comp/middle/tstate/states.rs | 4 | ||||
| -rw-r--r-- | src/comp/middle/typeck.rs | 6 | ||||
| -rw-r--r-- | src/comp/rustc.rc | 1 | ||||
| -rw-r--r-- | src/comp/syntax/ast.rs | 2 | ||||
| -rw-r--r-- | src/comp/syntax/ext/base.rs | 23 | ||||
| -rw-r--r-- | src/comp/syntax/ext/expand.rs | 65 | ||||
| -rw-r--r-- | src/comp/syntax/ext/simplext.rs | 272 | ||||
| -rw-r--r-- | src/comp/syntax/fold.rs | 4 | ||||
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 59 | ||||
| -rw-r--r-- | src/comp/syntax/print/pprust.rs | 2 | ||||
| -rw-r--r-- | src/comp/syntax/visit.rs | 6 | ||||
| -rw-r--r-- | src/comp/syntax/walk.rs | 8 | ||||
| -rw-r--r-- | src/test/compile-fail/macro-2.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/macro.rs | 4 | ||||
| -rw-r--r-- | src/test/run-pass/macro-2.rs | 2 | ||||
| -rw-r--r-- | src/test/run-pass/macro-3.rs | 2 | ||||
| -rw-r--r-- | src/test/run-pass/macro.rs | 2 |
21 files changed, 336 insertions, 174 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs index 823560b0082..a8c9738eb4a 100644 --- a/src/comp/driver/rustc.rs +++ b/src/comp/driver/rustc.rs @@ -80,10 +80,10 @@ fn parse_input(session::session sess, &ast::crate_cfg cfg, str input) -> @ast::crate { ret if (str::ends_with(input, ".rc")) { parser::parse_crate_from_crate_file - (input, cfg, sess.get_codemap()) + (input, cfg, sess.get_parse_sess()) } else if (str::ends_with(input, ".rs")) { parser::parse_crate_from_source_file - (input, cfg, sess.get_codemap()) + (input, cfg, sess.get_parse_sess()) } else { sess.fatal("unknown input file type: " + input); fail }; } @@ -110,6 +110,9 @@ fn compile_input(session::session sess, ast::crate_cfg cfg, str input, crate = time(time_passes, "building test harness", bind front::test::modify_for_testing(crate)); } + crate = time(time_passes, "expansion", + bind syntax::ext::expand::expand_crate(sess, crate)); + auto ast_map = time(time_passes, "ast indexing", bind middle::ast_map::map_crate(*crate)); time(time_passes, "external crate/lib resolution", @@ -357,7 +360,8 @@ fn build_session(@session::options sopts) -> session::session { auto target_cfg = build_target_config(); auto cstore = cstore::mk_cstore(); ret session::session(target_cfg, sopts, cstore, - codemap::new_codemap(), 0u); + @rec(cm=codemap::new_codemap(), mutable next_id=0), + 0u); } fn parse_pretty(session::session sess, &str name) -> pp_mode { diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs index 8a1f5d791ce..8da3e40baa6 100644 --- a/src/comp/driver/session.rs +++ b/src/comp/driver/session.rs @@ -11,6 +11,7 @@ import std::option::some; import std::option::none; import std::str; import std::vec; +import syntax::parse::parser::parse_sess; tag os { os_win32; os_macos; os_linux; } @@ -47,26 +48,26 @@ type crate_metadata = rec(str name, vec[u8] data); obj session(@config targ_cfg, @options opts, metadata::cstore::cstore cstore, - codemap::codemap cm, + parse_sess parse_sess, mutable uint err_count) { fn get_targ_cfg() -> @config { ret targ_cfg; } fn get_opts() -> @options { ret opts; } fn get_cstore() -> metadata::cstore::cstore { cstore } fn span_fatal(span sp, str msg) -> ! { // FIXME: Use constants, but rustboot doesn't know how to export them. - codemap::emit_error(some(sp), msg, cm); + codemap::emit_error(some(sp), msg, parse_sess.cm); fail; } fn fatal(str msg) -> ! { - codemap::emit_error(none, msg, cm); + codemap::emit_error(none, msg, parse_sess.cm); fail; } fn span_err(span sp, str msg) { - codemap::emit_error(some(sp), msg, cm); + codemap::emit_error(some(sp), msg, parse_sess.cm); err_count += 1u; } fn err(str msg) { - codemap::emit_error(none, msg, cm); + codemap::emit_error(none, msg, parse_sess.cm); err_count += 1u; } fn abort_if_errors() { @@ -76,17 +77,17 @@ obj session(@config targ_cfg, } fn span_warn(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - codemap::emit_warning(some(sp), msg, cm); + codemap::emit_warning(some(sp), msg, parse_sess.cm); } fn warn(str msg) { - codemap::emit_warning(none, msg, cm); + codemap::emit_warning(none, msg, parse_sess.cm); } fn span_note(span sp, str msg) { // FIXME: Use constants, but rustboot doesn't know how to export them. - codemap::emit_note(some(sp), msg, cm); + codemap::emit_note(some(sp), msg, parse_sess.cm); } fn note(str msg) { - codemap::emit_note(none, msg, cm); + codemap::emit_note(none, msg, parse_sess.cm); } fn span_bug(span sp, str msg) -> ! { self.span_fatal(sp, #fmt("internal compiler error %s", msg)); @@ -98,9 +99,13 @@ obj session(@config targ_cfg, self.span_bug(sp, "unimplemented " + msg); } fn unimpl(str msg) -> ! { self.bug("unimplemented " + msg); } - fn get_codemap() -> codemap::codemap { ret cm; } + fn get_codemap() -> codemap::codemap { ret parse_sess.cm; } fn lookup_pos(uint pos) -> codemap::loc { - ret codemap::lookup_pos(cm, pos); + ret codemap::lookup_pos(parse_sess.cm, pos); + } + fn get_parse_sess() -> parse_sess { ret parse_sess; } + fn next_node_id() -> ast::node_id { + ret syntax::parse::parser::next_node_id(parse_sess); } fn span_str(span sp) -> str { ret codemap::span_to_str(sp, self.get_codemap()); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 9f4abee52d4..5c39b5d2f74 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -6378,8 +6378,8 @@ fn trans_expr_out(&@block_ctxt cx, &@ast::expr e, out_method output) -> case (ast::expr_rec(?args, ?base)) { ret trans_rec(cx, args, base, e.id); } - case (ast::expr_ext(_, _, _, ?expanded)) { - ret trans_expr(cx, expanded); + case (ast::expr_ext(_, _, _)) { + ret cx.fcx.lcx.ccx.sess.bug("unexpanded macro"); } case (ast::expr_fail(?expr)) { ret trans_fail_expr(cx, some(e.span), expr); diff --git a/src/comp/middle/tstate/pre_post_conditions.rs b/src/comp/middle/tstate/pre_post_conditions.rs index cc108961f19..dae56fdf1cb 100644 --- a/src/comp/middle/tstate/pre_post_conditions.rs +++ b/src/comp/middle/tstate/pre_post_conditions.rs @@ -570,9 +570,8 @@ fn find_pre_post_expr(&fn_ctxt fcx, @expr e) { case (expr_break) { clear_pp(expr_pp(fcx.ccx, e)); } case (expr_cont) { clear_pp(expr_pp(fcx.ccx, e)); } case (expr_port(_)) { clear_pp(expr_pp(fcx.ccx, e)); } - case (expr_ext(_, _, _, ?expanded)) { - find_pre_post_expr(fcx, expanded); - copy_pre_post(fcx.ccx, e.id, expanded); + case (expr_ext(_, _, _)) { + fcx.ccx.tcx.sess.bug("unexpanded macro"); } case (expr_anon_obj(?anon_obj, _)) { alt (anon_obj.with_obj) { diff --git a/src/comp/middle/tstate/states.rs b/src/comp/middle/tstate/states.rs index aaca848acf9..f3f78924442 100644 --- a/src/comp/middle/tstate/states.rs +++ b/src/comp/middle/tstate/states.rs @@ -367,8 +367,8 @@ fn find_pre_post_state_expr(&fn_ctxt fcx, &prestate pres, @expr e) -> bool { case (expr_chan(?ex)) { ret find_pre_post_state_sub(fcx, pres, ex, e.id, none); } - case (expr_ext(_, _, _, ?expanded)) { - ret find_pre_post_state_sub(fcx, pres, expanded, e.id, none); + case (expr_ext(_, _, _)) { + fcx.ccx.tcx.sess.bug("unexpanded macro"); } case (expr_put(?maybe_e)) { alt (maybe_e) { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 5f13134e06d..3a9b1f6c396 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -1780,10 +1780,8 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) { } write::ty_only_fixup(fcx, id, tpt._1); } - case (ast::expr_ext(?p, ?args, ?body, ?expanded)) { - check_expr(fcx, expanded); - auto t = expr_ty(fcx.ccx.tcx, expanded); - write::ty_only_fixup(fcx, id, t); + case (ast::expr_ext(_,_,_)) { + fcx.ccx.tcx.sess.bug("unexpanded macro"); } case (ast::expr_fail(?expr_opt)) { alt (expr_opt) { diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc index a76602ecda6..79cec1a725c 100644 --- a/src/comp/rustc.rc +++ b/src/comp/rustc.rc @@ -53,6 +53,7 @@ mod syntax { mod fmt; mod env; mod simplext; + mod expand; } mod print { mod pprust; diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index 26cefb3c0d6..a75aa4d8c23 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -305,7 +305,7 @@ tag expr_ { expr_field(@expr, ident); expr_index(@expr, @expr); expr_path(path); - expr_ext(path, (@expr)[], option::t[str], @expr); + expr_ext(path, (@expr)[], option::t[str]); expr_fail(option::t[@expr]); expr_break; expr_cont; diff --git a/src/comp/syntax/ext/base.rs b/src/comp/syntax/ext/base.rs index 0990b3bdacb..84319cf5f38 100644 --- a/src/comp/syntax/ext/base.rs +++ b/src/comp/syntax/ext/base.rs @@ -2,7 +2,7 @@ import std::ivec; import std::vec; import std::option; import std::map::hashmap; -import parse::parser::parse_sess; +import driver::session::session; import codemap::span; import std::map::new_str_hash; import codemap; @@ -41,14 +41,14 @@ type ext_ctxt = span_msg_fn span_unimpl, next_id_fn next_id); -fn mk_ctxt(&parse_sess sess) -> ext_ctxt { - fn ext_span_fatal_(&codemap::codemap cm, span sp, str msg) -> ! { - codemap::emit_error(option::some(sp), msg, cm); +fn mk_ctxt(&session sess) -> ext_ctxt { + fn ext_span_fatal_(&session sess, span sp, str msg) -> ! { + sess.span_err(sp, msg); fail; } - auto ext_span_fatal = bind ext_span_fatal_(sess.cm, _, _); - fn ext_span_unimpl_(&codemap::codemap cm, span sp, str msg) -> ! { - codemap::emit_error(option::some(sp), "unimplemented " + msg, cm); + auto ext_span_fatal = bind ext_span_fatal_(sess, _, _); + fn ext_span_unimpl_(&session sess, span sp, str msg) -> ! { + sess.span_err(sp, "unimplemented " + msg); fail; } @@ -59,9 +59,12 @@ fn mk_ctxt(&parse_sess sess) -> ext_ctxt { // the extensions the file name of the crate being compiled so they can // use it to guess whether paths should be prepended with "std::". This is // super-ugly and needs a better solution. - auto crate_file_name_hack = sess.cm.files.(0).name; - auto ext_span_unimpl = bind ext_span_unimpl_(sess.cm, _, _); - auto ext_next_id = bind parse::parser::next_node_id(sess); + auto crate_file_name_hack = sess.get_codemap().files.(0).name; + auto ext_span_unimpl = bind ext_span_unimpl_(sess, _, _); + fn ext_next_id_(&session sess) -> ast::node_id { + ret sess.next_node_id(); // temporary, until bind works better + } + auto ext_next_id = bind ext_next_id_(sess); ret rec(crate_file_name_hack=crate_file_name_hack, span_fatal=ext_span_fatal, span_unimpl=ext_span_unimpl, diff --git a/src/comp/syntax/ext/expand.rs b/src/comp/syntax/ext/expand.rs new file mode 100644 index 00000000000..3af9fdc5070 --- /dev/null +++ b/src/comp/syntax/ext/expand.rs @@ -0,0 +1,65 @@ + +import codemap::emit_error; +import driver::session; +import syntax::ast::crate; +import syntax::ast::expr_; +import syntax::ast::expr_ext; +import syntax::fold::*; + +import std::option::none; +import std::option::some; + +import std::map::hashmap; +import std::ivec; + +fn expand_expr(&hashmap[str, base::syntax_extension] exts, + &session::session sess, &expr_ e, ast_fold fld, + &fn(&ast::expr_, ast_fold) -> expr_ orig) -> expr_ { + ret alt(e) { + case (expr_ext(?pth, ?args, ?body)) { + assert(ivec::len(pth.node.idents) > 0u); + auto extname = pth.node.idents.(0); + auto ext_cx = base::mk_ctxt(sess); + alt (exts.find(extname)) { + case (none) { + emit_error(some(pth.span), "unknown syntax expander: '" + + extname + "'", sess.get_codemap()); + fail + } + case (some(base::normal(?ext))) { + //keep going, outside-in + fld.fold_expr(ext(ext_cx, pth.span, args, body)).node + } + case (some(base::macro_defining(?ext))) { + auto named_extension = ext(ext_cx, pth.span, args, body); + exts.insert(named_extension._0, named_extension._1); + ast::expr_tup([]) + } + } + + } + case (_) { orig(e, fld) } + }; +} + +fn expand_crate(&session::session sess, &@crate c) -> @crate { + auto exts = ext::base::syntax_expander_table(); + auto afp = default_ast_fold(); + auto f_pre = + rec(fold_expr = bind expand_expr(exts, sess, _, _, afp.fold_expr) + with *afp); + auto f = make_fold(f_pre); + auto res = @f.fold_crate(*c); + dummy_out(f); //temporary: kill circular reference + ret res; + +} + +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: diff --git a/src/comp/syntax/ext/simplext.rs b/src/comp/syntax/ext/simplext.rs index 46b1fd636ce..59505a5a89a 100644 --- a/src/comp/syntax/ext/simplext.rs +++ b/src/comp/syntax/ext/simplext.rs @@ -16,121 +16,245 @@ import base::expr_to_str; import base::expr_to_ident; import fold::*; +import ast::respan; import ast::ident; +import ast::path; import ast::path_; import ast::expr_path; +import ast::expr_vec; +import ast::expr_ext; export add_new_extension; - -//temporary, until 'position' shows up in the snapshot -fn position[T](&T x, &vec[T] v) -> option::t[uint] { - let uint i = 0u; - while (i < len(v)) { - if (x == v.(i)) { ret some[uint](i); } - i += 1u; +fn lookup(&vec[invk_binding] ibs, ident i) -> option::t[invk_binding] { + for (invk_binding ib in ibs) { + alt (ib) { + case (ident_binding(?p_id, _)) { if (i == p_id) { ret some(ib); }} + case (path_binding(?p_id, _)) { if (i == p_id) { ret some(ib); }} + case (expr_binding(?p_id, _)) { if (i == p_id) { ret some(ib); }} + } } - ret none[uint]; + ret none; } // substitute, in a position that's required to be an ident -fn subst_ident(&ext_ctxt cx, &(@ast::expr)[] args, - @vec[ident] param_names, &ident i, ast_fold fld) -> ident { - alt (position(i, *param_names)) { - case (some[uint](?idx)) { - ret expr_to_ident(cx, args.(idx), - "This argument is expanded as an " - + "identifier; it must be one."); +fn subst_ident(&ext_ctxt cx, &(invk_binding)[] ibs, &ident i, ast_fold fld) + -> ident { + ret alt (lookup(ibs, i)) { + case (some(ident_binding(_, ?a_id))) { a_id.node } + case (some(path_binding(_, ?pth))) { + cx.span_fatal(pth.span, "This argument is expanded as an " + + "identifier; it must be one.") } - case (none[uint]) { - ret i; + case (some(expr_binding(_, ?expr))) { + cx.span_fatal(expr.span, "This argument is expanded as an " + + "identifier; it must be one.") } + case (none) { i } } } -fn subst_path(&ext_ctxt cx, &(@ast::expr)[] args, - @vec[ident] param_names, &path_ p, ast_fold fld) -> path_ { + +fn subst_path(&ext_ctxt cx, &(invk_binding)[] ibs, &path_ p, ast_fold fld) + -> path_ { // Don't substitute into qualified names. if (ivec::len(p.types) > 0u || ivec::len(p.idents) != 1u) { ret p; } - alt (position(p.idents.(0), *param_names)) { - case (some[uint](?idx)) { - alt (args.(idx).node) { - case (expr_path(?new_path)) { - ret new_path.node; - } - case (_) { - cx.span_fatal(args.(idx).span, - "This argument is expanded as a path; " - + "it must be one."); - } - } + ret alt (lookup(ibs, p.idents.(0))) { + case (some(ident_binding(_, ?id))) { + rec(global=false, idents=~[id.node], types=~[]) } - case (none[uint]) { ret p; } + case (some(path_binding(_, ?a_pth))) { a_pth.node } + case (some(expr_binding(_, ?expr))) { + cx.span_fatal(expr.span, "This argument is expanded as an " + + "path; it must be one.") + } + case (none) { p } } } -fn subst_expr(&ext_ctxt cx, &(@ast::expr)[] args, @vec[ident] param_names, - &ast::expr_ e, ast_fold fld, - fn(&ast::expr_, ast_fold) -> ast::expr_ orig) -> ast::expr_ { +fn subst_expr(&ext_ctxt cx, &(invk_binding)[] ibs, &ast::expr_ e, + ast_fold fld, fn(&ast::expr_, ast_fold) -> ast::expr_ orig) + -> ast::expr_ { ret alt(e) { case (expr_path(?p)){ // Don't substitute into qualified names. - if (ivec::len(p.node.types) > 0u || - ivec::len(p.node.idents) != 1u) { e } - alt (position(p.node.idents.(0), *param_names)) { - case (some[uint](?idx)) { - args.(idx).node + if (ivec::len(p.node.types) > 0u || + ivec::len(p.node.idents) != 1u) { e } + alt (lookup(ibs, p.node.idents.(0))) { + case (some(ident_binding(_, ?id))) { + expr_path(respan(id.span, + rec(global=false, + idents=~[id.node],types=~[]))) } - case (none[uint]) { e } + case (some(path_binding(_, ?a_pth))) { expr_path(*a_pth) } + case (some(expr_binding(_, ?a_exp))) { a_exp.node } + case (none) { orig(e,fld) } } } case (_) { orig(e,fld) } } } +type pat_ext = rec(vec[@ast::expr] invk, @ast::expr body); + +// maybe box? +tag invk_binding { + expr_binding(ident, @ast::expr); + path_binding(ident, @ast::path); + ident_binding(ident, ast::spanned[ident]); +} + +fn path_to_ident(&path pth) -> option::t[ident] { + if (ivec::len(pth.node.idents) == 1u + && ivec::len(pth.node.types) == 0u) { + ret some(pth.node.idents.(0u)); + } + ret none; +} fn add_new_extension(&ext_ctxt cx, span sp, &(@ast::expr)[] args, option::t[str] body) -> tup(str, syntax_extension) { - if (ivec::len(args) < 2u) { - cx.span_fatal(sp, "malformed extension description"); + let option::t[str] macro_name = none; + let vec[pat_ext] pat_exts = []; + for (@ast::expr arg in args) { + alt(arg.node) { + case(expr_vec(?elts, ?mut, ?seq_kind)) { + + if (len(elts) != 2u) { + cx.span_fatal((*arg).span, + "extension clause must consist of [" + + "macro invocation, expansion body]"); + } + alt(elts.(0u).node) { + case(expr_ext(?pth, ?invk_args, ?body)) { + let str clause_name = alt(path_to_ident(pth)) { + case (some(?id)) { id } + case (none) { + cx.span_fatal + (elts.(0u).span, + "macro name must not be a path") + } + }; + if (macro_name == none) { + macro_name = some(clause_name); + } else if (macro_name != some(clause_name)) { + cx.span_fatal(elts.(0u).span, "macros must have" + + " only one name"); + } + pat_exts += [rec(invk=invk_args, body=elts.(1u))]; + } + case(_) { + cx.span_fatal(elts.(0u).span, "extension clause must" + + " start with a macro invocation."); + } + } + } + case(_) { + cx.span_fatal((*arg).span, "extension must be [clause, " + + " ...]"); + } + } } - fn generic_extension(&ext_ctxt cx, span sp, &(@ast::expr)[] args, - option::t[str] body, @vec[ident] param_names, - @ast::expr dest_form) -> @ast::expr { - if (ivec::len(args) != len(*param_names)) { - cx.span_fatal(sp, #fmt("extension expects %u arguments, got %u", - len(*param_names), ivec::len(args))); + auto ext = bind generic_extension(_,_,_,_,@pat_exts); + + ret tup(alt (macro_name) { + case (some(?id)) { id } + case (none) { + cx.span_fatal(sp, "macro definition must have " + + "at least one clause") + } + }, + normal(ext)); + + + fn generic_extension(&ext_ctxt cx, span sp, &vec[@ast::expr] args, + option::t[str] body, @vec[pat_ext] clauses) + -> @ast::expr { + + /* returns a list of bindings, or none if the match fails. */ + fn match_invk(@ast::expr pattern, @ast::expr argument) + -> option::t[vec[invk_binding]] { + auto pat = pattern.node; + auto arg = argument.node; + ret alt (pat) { + case (expr_vec(?p_elts, _, _)) { + alt (arg) { + case (expr_vec(?a_elts, _, _)) { + if (vec::len(p_elts) != vec::len(a_elts)) { + none[vec[invk_binding]] + } + let uint i = 0u; + let vec[invk_binding] res = []; + while (i < vec::len(p_elts)) { + alt (match_invk(p_elts.(i), a_elts.(i))) { + case (some(?v)) { res += v; } + case (none) { ret none; } + } + i += 1u; + } + some(res) + } + case (_) { none } + } + } + case (expr_path(?p_pth)) { + alt (path_to_ident(p_pth)) { + case (some(?p_id)) { + /* let's bind! */ + alt (arg) { + case (expr_path(?a_pth)) { + alt (path_to_ident(a_pth)) { + case (some(?a_id)) { + some([ident_binding + (p_id, respan(argument.span, + a_id))]) + } + case (none) { + some([path_binding(p_id, @a_pth)]) + } + } + } + case (_) { + some([expr_binding(p_id, argument)]) + } + } + } + // FIXME this still compares on internal spans + case (_) { if(pat == arg) { some([]) } else { none } } + } + } + // FIXME this still compares on internal spans + case (_) { if (pat == arg) { some([]) } else { none } } + } } - // FIXME: This binds to alias arguments. - auto afp = default_ast_fold(); - auto f_pre = - rec(fold_ident = bind subst_ident(cx, args, param_names, _, _), - fold_path = bind subst_path(cx, args, param_names, _, _), - fold_expr = bind subst_expr(cx, args, param_names, _, _, - afp.fold_expr) + for (pat_ext pe in *clauses) { + if (vec::len(args) != vec::len(pe.invk)) { cont; } + let uint i = 0u; + let vec[invk_binding] bindings = []; + while (i < vec::len(args)) { + alt (match_invk(pe.invk.(i), args.(i))) { + case (some(?v)) { bindings += v; } + case (none) { cont } + } + i += 1u; + } + auto afp = default_ast_fold(); + auto f_pre = + rec(fold_ident = bind subst_ident(cx, bindings, _, _), + fold_path = bind subst_path(cx, bindings, _, _), + fold_expr = bind subst_expr(cx, bindings, _, _, + afp.fold_expr) with *afp); - auto f = make_fold(f_pre); - auto result = f.fold_expr(dest_form); - dummy_out(f); //temporary: kill circular reference - ret result; - - } - - let vec[ident] param_names = vec::empty[ident](); - let uint idx = 1u; - while(1u+idx < ivec::len(args)) { - param_names += - [expr_to_ident(cx, args.(idx), - "this parameter name must be an identifier.")]; - idx += 1u; + auto f = make_fold(f_pre); + auto result = f.fold_expr(pe.body); + dummy_out(f); //temporary: kill circular reference + ret result; + } + cx.span_fatal(sp, "no clauses match macro invocation"); } - - ret tup(expr_to_str(cx, args.(0), "first arg must be a literal string."), - normal(bind generic_extension(_,_,_,_,@param_names, - args.(ivec::len(args)-1u)))); } diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index 659a527dbe2..1487ff3e2e0 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -414,11 +414,11 @@ fn noop_fold_expr(&expr_ e, ast_fold fld) -> expr_ { case (expr_path(?pth)) { expr_path(fld.fold_path(pth)) } - case (expr_ext(?pth, ?args, ?body, ?expanded)) { + case (expr_ext(?pth, ?args, ?body)) { expr_ext(fld.fold_path(pth), ivec::map(fld.fold_expr, args), body, fld.fold_expr(expanded)) } - case (expr_fail(_)) { e } + case (expr_fail(?e)) { expr_fail(option::map(fld.fold_expr, e)) } case (expr_break()) { e } case (expr_cont()) { e } case (expr_ret(?e)) { diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 7d6fc8561cc..7a711b1dbfa 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -50,7 +50,6 @@ type parser = fn get_reader() -> lexer::reader ; fn get_filemap() -> codemap::filemap ; fn get_bad_expr_words() -> hashmap[str, ()] ; - fn get_syntax_expanders() -> hashmap[str, ex::syntax_extension] ; fn get_chpos() -> uint ; fn get_id() -> ast::node_id ; fn get_sess() -> parse_sess; @@ -82,8 +81,7 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr, mutable restriction restr, lexer::reader rdr, vec[op_spec] precs, - hashmap[str, ()] bad_words, - hashmap[str, ex::syntax_extension] syntax_expanders) { + hashmap[str, ()] bad_words) { fn peek() -> token::token { ret tok; } fn bump() { // log rdr.get_filename() @@ -116,9 +114,6 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr, fn get_reader() -> lexer::reader { ret rdr; } fn get_filemap() -> codemap::filemap { ret rdr.get_filemap(); } fn get_bad_expr_words() -> hashmap[str, ()] { ret bad_words; } - fn get_syntax_expanders() -> hashmap[str, ex::syntax_extension] { - ret syntax_expanders; - } fn get_chpos() -> uint { ret rdr.get_chpos(); } fn get_id() -> ast::node_id { ret next_node_id(sess); } fn get_sess() -> parse_sess { ret sess; } @@ -129,8 +124,7 @@ fn new_parser(parse_sess sess, ast::crate_cfg cfg, lexer::reader rdr, auto npos = rdr.get_chpos(); ret stdio_parser(sess, cfg, ftype, lexer::next_token(rdr), npos, npos, npos, UNRESTRICTED, rdr, - prec_table(), bad_expr_word_table(), - ex::syntax_expander_table()); + prec_table(), bad_expr_word_table()); } // These are the words that shouldn't be allowed as value identifiers, @@ -1028,38 +1022,7 @@ fn parse_syntax_ext_naked(&parser p, uint lo) -> @ast::expr { auto es = parse_seq_ivec(token::LPAREN, token::RPAREN, some(token::COMMA), parse_expr, p); auto hi = es.span.hi; - auto ext_span = rec(lo=lo, hi=hi); - auto ex = expand_syntax_ext(p, ext_span, pth, es.node, none); - ret mk_expr(p, lo, hi, ex); -} - -/* - * FIXME: This is a crude approximation of the syntax-extension system, - * for purposes of prototyping and/or hard-wiring any extensions we - * wish to use while bootstrapping. The eventual aim is to permit - * loading rust crates to process extensions. - */ -fn expand_syntax_ext(&parser p, span sp, &ast::path path, - &(@ast::expr)[] args, option::t[str] body) -> - ast::expr_ { - assert (ivec::len(path.node.idents) > 0u); - auto extname = path.node.idents.(0); - alt (p.get_syntax_expanders().find(extname)) { - case (none) { p.fatal("unknown syntax expander: '" + extname + "'"); } - case (some(ex::normal(?ext))) { - auto ext_cx = ex::mk_ctxt(p.get_sess()); - ret ast::expr_ext(path, args, body, ext(ext_cx, sp, args, body)); - } - // because we have expansion inside parsing, new macros are only - // visible further down the file - case (some(ex::macro_defining(?ext))) { - auto ext_cx = ex::mk_ctxt(p.get_sess()); - auto name_and_extension = ext(ext_cx, sp, args, body); - p.get_syntax_expanders().insert(name_and_extension._0, - name_and_extension._1); - ret ast::expr_tup(~[]); - } - } + ret mk_expr(p, lo, hi, ast::expr_ext(pth, es.node, none)); } fn parse_self_method(&parser p) -> @ast::expr { @@ -1698,7 +1661,7 @@ fn stmt_ends_with_semi(&ast::stmt stmt) -> bool { case (ast::expr_field(_, _)) { true } case (ast::expr_index(_, _)) { true } case (ast::expr_path(_)) { true } - case (ast::expr_ext(_, _, _, _)) { true } + case (ast::expr_ext(_, _, _)) { true } case (ast::expr_fail(_)) { true } case (ast::expr_break) { true } case (ast::expr_cont) { true } @@ -2443,10 +2406,9 @@ fn parse_native_view(&parser p) -> (@ast::view_item)[] { } fn parse_crate_from_source_file(&str input, &ast::crate_cfg cfg, - &codemap::codemap cm) -> @ast::crate { - auto sess = @rec(cm=cm, mutable next_id=0); + &parse_sess sess) -> @ast::crate { auto p = new_parser_from_file(sess, cfg, input, 0u); - ret parse_crate_mod(p, cfg); + ret parse_crate_mod(p, cfg, sess); } fn parse_crate_from_source_str(&str name, &str source, &ast::crate_cfg cfg, @@ -2458,12 +2420,12 @@ fn parse_crate_from_source_str(&str name, &str source, &ast::crate_cfg cfg, auto itr = @interner::mk(str::hash, str::eq); auto rdr = lexer::new_reader(sess.cm, source, filemap, itr); auto p = new_parser(sess, cfg, rdr, ftype); - ret parse_crate_mod(p, cfg); + ret parse_crate_mod(p, cfg, sess); } // Parses a source module as a crate -fn parse_crate_mod(&parser p, &ast::crate_cfg cfg) -> @ast::crate { - +fn parse_crate_mod(&parser p, &ast::crate_cfg cfg, parse_sess sess) + -> @ast::crate { auto lo = p.get_lo_pos(); auto crate_attrs = parse_inner_attrs_and_next(p); auto first_item_outer_attrs = crate_attrs._1; @@ -2570,8 +2532,7 @@ fn parse_crate_directives(&parser p, token::token term, } fn parse_crate_from_crate_file(&str input, &ast::crate_cfg cfg, - &codemap::codemap cm) -> @ast::crate { - auto sess = @rec(cm=cm, mutable next_id=0); + &parse_sess sess) -> @ast::crate { auto p = new_parser_from_file(sess, cfg, input, 0u); auto lo = p.get_lo_pos(); auto prefix = std::fs::dirname(p.get_filemap().name); diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 8fb5770e641..9566fef32e6 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -961,7 +961,7 @@ fn print_expr(&ps s, &@ast::expr expr) { print_expr(s, expr); pclose(s); } - case (ast::expr_ext(?path, ?args, ?body, _)) { + case (ast::expr_ext(?path, ?args, ?body)) { word(s.s, "#"); print_path(s, path); if (ivec::len(args) > 0u) { diff --git a/src/comp/syntax/visit.rs b/src/comp/syntax/visit.rs index 71d44e29f80..b1d928939ef 100644 --- a/src/comp/syntax/visit.rs +++ b/src/comp/syntax/visit.rs @@ -362,8 +362,10 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) { case (expr_path(?p)) { for (@ty tp in p.node.types) { v.visit_ty(tp, e, v); } } - case (expr_ext(_, _, _, ?expansion)) { - v.visit_expr(expansion, e, v); + case (expr_ext(_, ?args, _)) { + for(@ast::expr arg in args) { + vt(v).visit_expr(arg, e, v); + } } case (expr_fail(?eo)) { visit_expr_opt(eo, e, v); diff --git a/src/comp/syntax/walk.rs b/src/comp/syntax/walk.rs index bc188b8c604..1902c5e69a9 100644 --- a/src/comp/syntax/walk.rs +++ b/src/comp/syntax/walk.rs @@ -367,10 +367,10 @@ fn walk_expr(&ast_visitor v, @ast::expr e) { case (ast::expr_path(?p)) { for (@ast::ty tp in p.node.types) { walk_ty(v, tp); } } - case (ast::expr_ext(_, ?args, ?body, ?expansion)) { - // Only walk expansion, not args/body. - - walk_expr(v, expansion); + case (ast::expr_ext(_, ?args, _)) { + for (@ast::expr e in args) { + walk_expr(v, e); + } } case (ast::expr_fail(?eo)) { walk_expr_opt(v, eo); } case (ast::expr_break) { } diff --git a/src/test/compile-fail/macro-2.rs b/src/test/compile-fail/macro-2.rs index c2a706228c9..a48413af656 100644 --- a/src/test/compile-fail/macro-2.rs +++ b/src/test/compile-fail/macro-2.rs @@ -1,6 +1,6 @@ //error-pattern:expanded as an identifier fn main() { - #macro("mylambda", x, body, {fn f(int x) -> int {ret body}; f}); + #macro([#mylambda(x, body), {fn f(int x) -> int {ret body}; f}]); assert(#mylambda(y*1, y*2)(8) == 16); } \ No newline at end of file diff --git a/src/test/compile-fail/macro.rs b/src/test/compile-fail/macro.rs index b69ad18cda0..4ce021a9d74 100644 --- a/src/test/compile-fail/macro.rs +++ b/src/test/compile-fail/macro.rs @@ -1,7 +1,7 @@ -//error-pattern:expects 0 arguments, got 16 +//error-pattern:no clauses match fn main() { - #macro("trivial", 1*2*4*2*1); + #macro([#trivial(), 1*2*4*2*1]); assert(#trivial(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) == 16); } diff --git a/src/test/run-pass/macro-2.rs b/src/test/run-pass/macro-2.rs index a75d6707455..7d07b19a085 100644 --- a/src/test/run-pass/macro-2.rs +++ b/src/test/run-pass/macro-2.rs @@ -1,5 +1,5 @@ fn main() { - #macro("mylambda", x, body, {fn f(int x) -> int {ret body}; f}); + #macro([#mylambda(x,body), {fn f(int x) -> int { ret body }; f}]); assert(#mylambda(y,y*2)(8) == 16); } \ No newline at end of file diff --git a/src/test/run-pass/macro-3.rs b/src/test/run-pass/macro-3.rs index aa9169ed126..6b48a9a1bcb 100644 --- a/src/test/run-pass/macro-3.rs +++ b/src/test/run-pass/macro-3.rs @@ -1,5 +1,5 @@ fn main() { - #macro("trivial", 1*2*4*2*1); + #macro([#trivial(), 1*2*4*2*1]); assert(#trivial() == 16); } diff --git a/src/test/run-pass/macro.rs b/src/test/run-pass/macro.rs index 77ff122e7c6..3618228b191 100644 --- a/src/test/run-pass/macro.rs +++ b/src/test/run-pass/macro.rs @@ -1,4 +1,4 @@ fn main() { - #macro("m1", a, a*4); + #macro([#m1(a), a*4]); assert (#m1(2) == 8); } \ No newline at end of file |
