Move macro expansion to a separate phase, change macro syntax, and add parse_sess to session.

This commit is contained in:
Paul Stansifer 2011-07-06 15:22:23 -07:00
parent 80cf4ecd3b
commit 425732311a
21 changed files with 336 additions and 174 deletions

View file

@ -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 {

View file

@ -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());

View file

@ -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);

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {

View file

@ -53,6 +53,7 @@ mod syntax {
mod fmt;
mod env;
mod simplext;
mod expand;
}
mod print {
mod pprust;

View file

@ -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;

View file

@ -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,

View file

@ -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:

View file

@ -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;
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");
}
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;
}
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))));
}

View file

@ -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)) {

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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) { }

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -1,5 +1,5 @@
fn main() {
#macro("trivial", 1*2*4*2*1);
#macro([#trivial(), 1*2*4*2*1]);
assert(#trivial() == 16);
}

View file

@ -1,4 +1,4 @@
fn main() {
#macro("m1", a, a*4);
#macro([#m1(a), a*4]);
assert (#m1(2) == 8);
}