Add elipses, reorganize the macro components into their own AST node.

This commit is contained in:
Paul Stansifer 2011-07-08 16:35:09 -07:00
parent 425732311a
commit 48dbee6b47
14 changed files with 206 additions and 103 deletions

View file

@ -6378,7 +6378,7 @@ 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(_, _, _)) {
case (ast::expr_mac(_)) {
ret cx.fcx.lcx.ccx.sess.bug("unexpanded macro");
}
case (ast::expr_fail(?expr)) {

View file

@ -570,7 +570,7 @@ 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(_, _, _)) {
case (expr_mac(_)) {
fcx.ccx.tcx.sess.bug("unexpanded macro");
}
case (expr_anon_obj(?anon_obj, _)) {

View file

@ -367,7 +367,7 @@ 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(_, _, _)) {
case (expr_mac(_)) {
fcx.ccx.tcx.sess.bug("unexpanded macro");
}
case (expr_put(?maybe_e)) {

View file

@ -1780,7 +1780,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
}
write::ty_only_fixup(fcx, id, tpt._1);
}
case (ast::expr_ext(_,_,_)) {
case (ast::expr_mac(_)) {
fcx.ccx.tcx.sess.bug("unexpanded macro");
}
case (ast::expr_fail(?expr_opt)) {

View file

@ -305,7 +305,6 @@ tag expr_ {
expr_field(@expr, ident);
expr_index(@expr, @expr);
expr_path(path);
expr_ext(path, (@expr)[], option::t[str]);
expr_fail(option::t[@expr]);
expr_break;
expr_cont;
@ -323,7 +322,18 @@ tag expr_ {
to expr_if_check. */
expr_if_check(@expr, block, option::t[@expr]);
expr_port(option::t[@ty]);
expr_chan(@expr);
expr_anon_obj(anon_obj, ty_param[]);
expr_mac(mac);
}
type mac = spanned[mac_];
tag mac_ {
mac_invoc(path, (@expr)[], option::t[str]);
mac_embed_type(@ty);
mac_embed_block(block);
mac_elipsis;
}
type lit = spanned[lit_];
@ -433,6 +443,7 @@ tag ty_ {
ty_path(path, node_id);
ty_type;
ty_constr(@ty, (@constr)[]);
ty_mac(mac);
}

View file

@ -3,7 +3,8 @@ import codemap::emit_error;
import driver::session;
import syntax::ast::crate;
import syntax::ast::expr_;
import syntax::ast::expr_ext;
import syntax::ast::expr_mac;
import syntax::ast::mac_invoc;
import syntax::fold::*;
import std::option::none;
@ -16,27 +17,39 @@ 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());
case (expr_mac(?mac)) {
alt(mac.node) {
case (mac_invoc(?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 (_) {
emit_error(some(mac.span), "naked syntactic bit",
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) }
};

View file

@ -22,11 +22,12 @@ import ast::path;
import ast::path_;
import ast::expr_path;
import ast::expr_vec;
import ast::expr_ext;
import ast::expr_mac;
import ast::mac_invoc;
export add_new_extension;
fn lookup(&vec[invk_binding] ibs, ident i) -> option::t[invk_binding] {
fn lookup(&(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); }}
@ -96,7 +97,7 @@ fn subst_expr(&ext_ctxt cx, &(invk_binding)[] ibs, &ast::expr_ e,
}
}
type pat_ext = rec(vec[@ast::expr] invk, @ast::expr body);
type pat_ext = rec((@ast::expr)[] invk, @ast::expr body);
// maybe box?
tag invk_binding {
@ -113,6 +114,24 @@ fn path_to_ident(&path pth) -> option::t[ident] {
ret none;
}
fn process_clause(&ext_ctxt cx, &mutable vec[pat_ext] pes,
&mutable option::t[str] macro_name, &path pth,
&(@ast::expr)[] invoc_args, @ast::expr body) {
let str clause_name = alt(path_to_ident(pth)) {
case (some(?id)) { id }
case (none) {
cx.span_fatal(pth.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(pth.span, "#macro can only introduce one name");
}
pes += [rec(invk=invoc_args, body=body)];
}
fn add_new_extension(&ext_ctxt cx, span sp, &(@ast::expr)[] args,
option::t[str] body) -> tup(str, syntax_extension) {
let option::t[str] macro_name = none;
@ -121,28 +140,19 @@ fn add_new_extension(&ext_ctxt cx, span sp, &(@ast::expr)[] args,
alt(arg.node) {
case(expr_vec(?elts, ?mut, ?seq_kind)) {
if (len(elts) != 2u) {
if (ivec::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")
case(expr_mac(?mac)) {
alt (mac.node) {
case (mac_invoc(?pth, ?invoc_args, ?body)) {
process_clause(cx, pat_exts, macro_name,
pth, invoc_args, elts.(1u));
}
};
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"
@ -169,25 +179,25 @@ fn add_new_extension(&ext_ctxt cx, span sp, &(@ast::expr)[] args,
normal(ext));
fn generic_extension(&ext_ctxt cx, span sp, &vec[@ast::expr] args,
fn generic_extension(&ext_ctxt cx, span sp, &(@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]] {
-> option::t[(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)) {
if (ivec::len(p_elts) != ivec::len(a_elts)) {
none[vec[invk_binding]]
}
let uint i = 0u;
let vec[invk_binding] res = [];
while (i < vec::len(p_elts)) {
let (invk_binding)[] res = ~[];
while (i < ivec::len(p_elts)) {
alt (match_invk(p_elts.(i), a_elts.(i))) {
case (some(?v)) { res += v; }
case (none) { ret none; }
@ -207,34 +217,36 @@ fn add_new_extension(&ext_ctxt cx, span sp, &(@ast::expr)[] args,
case (expr_path(?a_pth)) {
alt (path_to_ident(a_pth)) {
case (some(?a_id)) {
some([ident_binding
(p_id, respan(argument.span,
some(~[ident_binding
(p_id,
respan(argument.span,
a_id))])
}
case (none) {
some([path_binding(p_id, @a_pth)])
some(~[path_binding(p_id,
@a_pth)])
}
}
}
case (_) {
some([expr_binding(p_id, argument)])
some(~[expr_binding(p_id, argument)])
}
}
}
// FIXME this still compares on internal spans
case (_) { if(pat == arg) { some([]) } else { none } }
case (_) { if(pat == arg) { some(~[]) } else { none }}
}
}
// FIXME this still compares on internal spans
case (_) { if (pat == arg) { some([]) } else { none } }
case (_) { if (pat == arg) { some(~[]) } else { none }}
}
}
for (pat_ext pe in *clauses) {
if (vec::len(args) != vec::len(pe.invk)) { cont; }
if (ivec::len(args) != ivec::len(pe.invk)) { cont; }
let uint i = 0u;
let vec[invk_binding] bindings = [];
while (i < vec::len(args)) {
let (invk_binding)[] bindings = ~[];
while (i < ivec::len(args)) {
alt (match_invk(pe.invk.(i), args.(i))) {
case (some(?v)) { bindings += v; }
case (none) { cont }

View file

@ -126,6 +126,25 @@ fn fold_arg_(&arg a, ast_fold fld) -> arg {
ret rec(mode=a.mode, ty=fld.fold_ty(a.ty),
ident=fld.fold_ident(a.ident), id=a.id);
}
//used in noop_fold_expr, and possibly elsewhere in the future
fn fold_mac_(&mac m, ast_fold fld) -> mac {
ret rec(node=
alt(m.node) {
case (mac_invoc(?pth,?args,?body)) {
mac_invoc(fld.fold_path(pth),
ivec::map(fld.fold_expr, args), body)
}
case (mac_embed_type(?ty)) {
mac_embed_type(fld.fold_ty(ty))
}
case (mac_embed_block(?block)) {
mac_embed_block(fld.fold_block(block))
}
case (mac_elipsis) { mac_elipsis }
},
span=m.span);
}
@ -319,6 +338,7 @@ fn noop_fold_expr(&expr_ e, ast_fold fld) -> expr_ {
}
auto fold_anon_obj = bind fold_anon_obj_(_,fld);
auto fold_mac = bind fold_mac_(_,fld);
ret alt (e) {
case (expr_vec(?exprs, ?mut, ?seq_kind)) {
@ -414,10 +434,6 @@ 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)) {
expr_ext(fld.fold_path(pth), ivec::map(fld.fold_expr, args),
body, fld.fold_expr(expanded))
}
case (expr_fail(?e)) { expr_fail(option::map(fld.fold_expr, e)) }
case (expr_break()) { e }
case (expr_cont()) { e }
@ -445,11 +461,8 @@ fn noop_fold_expr(&expr_ e, ast_fold fld) -> expr_ {
case (expr_anon_obj(?ao, ?typms)) {
expr_anon_obj(fold_anon_obj(ao), typms)
}
case (expr_embeded_type(?ty)) {
expr_embeded_type(fld.fold_ty(ty))
}
case (expr_embeded_block(?blk)) {
expr_embeded_block(fld.fold_block(blk))
case (expr_mac(?mac)) {
expr_mac(fold_mac(mac))
}
}
}

View file

@ -365,7 +365,15 @@ fn next_token(&reader rdr) -> token::token {
case ('?') { rdr.bump(); ret token::QUES; }
case (';') { rdr.bump(); ret token::SEMI; }
case (',') { rdr.bump(); ret token::COMMA; }
case ('.') { rdr.bump(); ret token::DOT; }
case ('.') {
rdr.bump();
if (rdr.curr() == '.' && rdr.next() == '.') {
rdr.bump();
rdr.bump();
ret token::ELIPSIS;
}
ret token::DOT;
}
case ('(') { rdr.bump(); ret token::LPAREN; }
case (')') { rdr.bump(); ret token::RPAREN; }
case ('{') { rdr.bump(); ret token::LBRACE; }

View file

@ -740,6 +740,12 @@ fn mk_expr(&parser p, uint lo, uint hi, &ast::expr_ node) -> @ast::expr {
span=rec(lo=lo, hi=hi));
}
fn mk_mac_expr(&parser p, uint lo, uint hi, &ast::mac_ m) -> @ast::expr {
ret @rec(id=p.get_id(),
node=ast::expr_mac(rec(node=m, span=rec(lo=lo, hi=hi))),
span=rec(lo=lo, hi=hi));
}
fn parse_bottom_expr(&parser p) -> @ast::expr {
auto lo = p.get_lo_pos();
auto hi = p.get_hi_pos();
@ -800,11 +806,14 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
ex = ast::expr_vec(es, mut, ast::sk_rc);
} else if (p.peek() == token::POUND_LT) {
p.bump();
ex = ast::expr_embeded_type(parse_ty(p));
auto ty = parse_ty(p);
expect(p, token::GT);
/* hack: early return to take advantage of specialized function */
ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_embed_type(ty))
} else if (p.peek() == token::POUND_LBRACE) {
p.bump();
ex = ast::expr_embeded_block(parse_block_tail(p));
auto blk = ast::mac_embed_block(parse_block_tail(p));
ret mk_mac_expr(p, lo, p.get_hi_pos(), blk);
} else if (p.peek() == token::TILDE) {
p.bump();
alt (p.peek()) {
@ -899,7 +908,7 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
ex = ast::expr_bind(e, es.node);
} else if (p.peek() == token::POUND) {
auto ex_ext = parse_syntax_ext(p);
lo = ex_ext.span.lo;
hi = ex_ext.span.hi;
ex = ex_ext.node;
} else if (eat_word(p, "fail")) {
if (can_begin_expr(p.peek())) {
@ -913,18 +922,22 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
} else if (eat_word(p, "log")) {
auto e = parse_expr(p);
ex = ast::expr_log(1, e);
hi = e.span.hi;
} else if (eat_word(p, "log_err")) {
auto e = parse_expr(p);
ex = ast::expr_log(0, e);
hi = e.span.hi;
} else if (eat_word(p, "assert")) {
auto e = parse_expr(p);
ex = ast::expr_assert(e);
hi = e.span.hi;
} else if (eat_word(p, "check")) {
/* Should be a predicate (pure boolean function) applied to
arguments that are all either slot variables or literals.
but the typechecker enforces that. */
auto e = parse_expr(p);
hi = e.span.hi;
ex = ast::expr_check(ast::checked, e);
} else if (eat_word(p, "claim")) {
/* Same rules as check, except that if check-claims
@ -932,6 +945,7 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
claims into check */
auto e = parse_expr(p);
hi = e.span.hi;
ex = ast::expr_check(ast::unchecked, e);
} else if (eat_word(p, "ret")) {
alt (p.peek()) {
@ -946,8 +960,10 @@ fn parse_bottom_expr(&parser p) -> @ast::expr {
}
} else if (eat_word(p, "break")) {
ex = ast::expr_break;
hi = p.get_hi_pos();
} else if (eat_word(p, "cont")) {
ex = ast::expr_cont;
hi = p.get_hi_pos();
} else if (eat_word(p, "put")) {
alt (p.peek()) {
case (token::SEMI) { ex = ast::expr_put(none); }
@ -1022,7 +1038,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;
ret mk_expr(p, lo, hi, ast::expr_ext(pth, es.node, none));
ret mk_mac_expr(p, lo, hi, ast::mac_invoc(pth, es.node, none));
}
fn parse_self_method(&parser p) -> @ast::expr {
@ -1661,7 +1677,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_mac(_)) { true }
case (ast::expr_fail(_)) { true }
case (ast::expr_break) { true }
case (ast::expr_cont) { true }

View file

@ -43,6 +43,7 @@ tag token {
/* Structural symbols */
AT;
DOT;
ELIPSIS;
COMMA;
SEMI;
COLON;

View file

@ -602,11 +602,19 @@ fn print_stmt(&ps s, &ast::stmt st) {
maybe_print_trailing_comment(s, st.span, none[uint]);
}
fn print_block(&ps s, ast::block blk) {
fn print_block(&ps s, &ast::block blk) {
print_possibly_embedded_block(s, blk, false);
}
fn print_possibly_embedded_block(&ps s, &ast::block blk, bool embedded) {
maybe_print_comment(s, blk.span.lo);
auto ann_node = node_block(s, blk);
s.ann.pre(ann_node);
bopen(s);
if (embedded) {
word(s.s, "#{"); end(s);
} else {
bopen(s);
}
for (@ast::stmt st in blk.node.stmts) { print_stmt(s, *st) }
alt (blk.node.expr) {
case (some(?expr)) {
@ -662,6 +670,33 @@ fn print_if(&ps s, &@ast::expr test, &ast::block block,
do_else(s, elseopt);
}
fn print_mac(&ps s, &ast::mac m) {
alt (m.node) {
case (ast::mac_invoc(?path, ?args, ?body)) {
word(s.s, "#");
print_path(s, path);
if (ivec::len(args) > 0u) {
popen(s);
commasep_exprs(s, inconsistent, args);
pclose(s);
}
// FIXME: extension 'body'
}
case (ast::mac_embed_type(?ty)) {
word(s.s, "#<");
print_type(s, *ty);
word(s.s, ">");
}
case (ast::mac_embed_block(?blk)) {
print_possibly_embedded_block(s, blk, true);
}
case (ast::mac_elipsis) {
word(s.s, "...");
}
}
}
fn print_expr(&ps s, &@ast::expr expr) {
maybe_print_comment(s, expr.span.lo);
ibox(s, indent_unit);
@ -961,16 +996,8 @@ fn print_expr(&ps s, &@ast::expr expr) {
print_expr(s, expr);
pclose(s);
}
case (ast::expr_ext(?path, ?args, ?body)) {
word(s.s, "#");
print_path(s, path);
if (ivec::len(args) > 0u) {
popen(s);
commasep_exprs(s, inconsistent, args);
pclose(s);
}
// FIXME: extension 'body'
case (ast::expr_mac(?m)) {
print_mac(s, m);
}
case (ast::expr_port(?ot)) {
word(s.s, "port");

View file

@ -256,6 +256,15 @@ fn visit_exprs[E](&(@expr)[] exprs, &E e, &vt[E] v) {
for (@expr ex in exprs) { v.visit_expr(ex, e, v); }
}
fn visit_mac[E](mac m, &E e, &vt[E] v) {
alt(m.node) {
case (ast::mac_invoc(?pth, ?args, ?body)) { visit_exprs(args, e, v); }
case (ast::mac_embed_type(?ty)) { v.visit_ty(ty, e, v); }
case (ast::mac_embed_block(?blk)) { v.visit_block(blk, e, v); }
case (ast::mac_elipsis) { }
}
}
fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
alt (ex.node) {
case (expr_vec(?es, _, _)) { visit_exprs(es, e, v); }
@ -362,11 +371,6 @@ 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(_, ?args, _)) {
for(@ast::expr arg in args) {
vt(v).visit_expr(arg, e, v);
}
}
case (expr_fail(?eo)) {
visit_expr_opt(eo, e, v);
}
@ -399,11 +403,8 @@ fn visit_expr[E](&@expr ex, &E e, &vt[E] v) {
m.node.id, e, v);
}
}
case (expr_embeded_type(?ty)) {
vt(v).visit_ty(ty, e, v);
}
case (expr_embeded_block(?blk)) {
vt(v).visit_block(blk, e, v);
case (expr_mac(?mac)) {
visit_mac(mac, e, v);
}
}
}

View file

@ -269,6 +269,15 @@ fn walk_exprs(&ast_visitor v, &(@ast::expr)[] exprs) {
for (@ast::expr e in exprs) { walk_expr(v, e); }
}
fn walk_mac(&ast_visitor v, ast::mac mac) {
alt(mac.node) {
case (ast::mac_invoc(?pth, ?args, ?body)) { walk_exprs(v, args); }
case (ast::mac_embed_type(?ty)) { walk_ty(v, ty); }
case (ast::mac_embed_block(?blk)) { walk_block(v, blk); }
case (ast::mac_elipsis) { }
}
}
fn walk_expr(&ast_visitor v, @ast::expr e) {
if (!v.keep_going()) { ret; }
v.visit_expr_pre(e);
@ -367,11 +376,6 @@ 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, _)) {
for (@ast::expr e in args) {
walk_expr(v, e);
}
}
case (ast::expr_fail(?eo)) { walk_expr_opt(v, eo); }
case (ast::expr_break) { }
case (ast::expr_cont) { }
@ -410,11 +414,8 @@ fn walk_expr(&ast_visitor v, @ast::expr e) {
v.visit_method_post(m);
}
}
case (ast::expr_embeded_type(?ty)) {
walk_ty(v, ty);
}
case (ast::expr_embeded_block(?blk)) {
walk_block(v, blk);
case (ast::expr_mac(?mac)) {
walk_mac(v, mac);
}
}
v.visit_expr_post(e);