rust/src/libsyntax/ext/simplext.rs

727 lines
24 KiB
Rust
Raw Normal View History

import codemap::span;
2012-06-10 00:49:59 -07:00
import std::map::{hashmap, str_hash, box_str_hash};
import dvec::{dvec, extensions};
2011-09-12 16:13:28 -07:00
import base::*;
import fold::*;
import ast_util::respan;
2012-04-23 13:04:46 +02:00
import 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> {
2012-04-23 13:04:46 +02:00
if vec::len(pth.idents) == 1u && vec::len(pth.types) == 0u {
2012-08-01 17:30:05 -07:00
return some(pth.idents[0u]);
2011-07-21 16:47:47 -07:00
}
2012-08-01 17:30:05 -07:00
return none;
2011-07-21 16:47:47 -07:00
}
2011-08-18 15:00:12 -07:00
//a vec of binders might be a little big.
type clause = {params: binders, body: @expr};
2011-07-21 16:47:47 -07:00
/* logically, an arb_depth should contain only one kind of matchable */
enum arb_depth<T> { leaf(T), seq(@~[arb_depth<T>], span), }
2011-07-21 16:47:47 -07:00
2012-01-19 14:24:03 -08:00
enum matchable {
2012-01-19 17:56:05 -08:00
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 */
2011-07-21 16:47:47 -07:00
}
/* for when given an incompatible bit of AST */
fn match_error(cx: ext_ctxt, m: matchable, expected: ~str) -> ! {
2012-08-06 12:34:08 -07:00
match m {
2012-08-03 19:59:04 -07:00
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(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?")
2011-07-21 16:47:47 -07:00
}
}
// 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;
2011-07-27 14:19:39 +02:00
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;
2012-06-30 16:19:07 -07:00
for elts.each |elt| {
2012-08-06 12:34:08 -07:00
match elt.node {
expr_mac(m) => match m.node {
2012-08-03 19:59:04 -07:00
ast::mac_ellipsis => {
if res != none {
cx.span_fatal(m.span, ~"only one ellipsis allowed");
2011-07-21 16:47:47 -07:00
}
res =
some({pre: vec::slice(elts, 0u, idx - 1u),
rep: some(elts[idx - 1u]),
post: vec::slice(elts, idx + 1u, vec::len(elts))});
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => ()
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => ()
}
2011-07-21 16:47:47 -07:00
idx += 1u;
}
2012-08-06 12:34:08 -07:00
return match res {
2012-08-03 19:59:04 -07:00
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 = ~[];
2012-06-30 16:19:07 -07:00
for v.each |elem| {
2012-08-06 12:34:08 -07:00
match f(elem) {
2012-08-03 19:59:04 -07:00
none => return none,
some(fv) => vec::push(res, fv)
}
2011-07-21 16:47:47 -07:00
}
2012-08-01 17:30:05 -07:00
return some(res);
2011-07-21 16:47:47 -07:00
}
fn a_d_map(ad: arb_depth<matchable>, f: selector) -> match_result {
2012-08-06 12:34:08 -07:00
match ad {
2012-08-03 19:59:04 -07:00
leaf(x) => return f(x),
2012-08-06 12:34:08 -07:00
seq(ads, span) => match option_flatten_map(|x| a_d_map(x, f), *ads) {
2012-08-03 19:59:04 -07:00
none => return none,
some(ts) => return some(seq(@ts, span))
2011-07-21 16:47:47 -07:00
}
}
}
2011-07-27 14:19:39 +02:00
fn compose_sels(s1: selector, s2: selector) -> selector {
fn scomp(s1: selector, s2: selector, m: matchable) -> match_result {
2012-08-06 12:34:08 -07:00
return match s1(m) {
2012-08-03 19:59:04 -07:00
none => none,
some(matches) => a_d_map(matches, s2)
2011-07-27 14:19:39 +02:00
}
}
2012-08-01 17:30:05 -07:00
return { |x| scomp(s1, s2, x) };
}
2011-07-21 16:47:47 -07:00
2011-07-27 14:19:39 +02:00
type binders =
2011-08-25 18:26:29 -07:00
{real_binders: hashmap<ident, selector>,
literal_ast_matchers: dvec<selector>};
2011-08-25 18:26:29 -07:00
type bindings = hashmap<ident, arb_depth<matchable>>;
2011-07-21 16:47:47 -07:00
fn acumm_bindings(_cx: ext_ctxt, _b_dest: bindings, _b_src: bindings) { }
2011-07-21 16:47:47 -07:00
/* 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 {
2011-07-27 14:19:39 +02:00
let res: binders =
2012-06-10 00:49:59 -07:00
{real_binders: box_str_hash::<selector>(),
literal_ast_matchers: dvec()};
2011-07-21 16:47:47 -07:00
//this oughta return binders instead, but macro args are a sequence of
//expressions, rather than a single expression
2012-08-01 17:30:05 -07:00
fn trivial_selector(m: matchable) -> match_result {
return some(leaf(m));
}
2011-07-21 16:47:47 -07:00
p_t_s_rec(cx, match_expr(e), trivial_selector, res);
2012-08-01 17:30:05 -07:00
return res;
2011-07-21 16:47:47 -07:00
}
/* 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> {
2012-06-10 00:49:59 -07:00
let res = box_str_hash::<arb_depth<matchable>>();
//need to do this first, to check vec lengths.
2012-06-30 16:19:07 -07:00
for b.literal_ast_matchers.each |sel| {
2012-08-06 12:34:08 -07:00
match sel(match_expr(e)) { none => return none, _ => () }
}
let mut never_mind: bool = false;
2012-06-30 16:19:07 -07:00
for b.real_binders.each |key, val| {
2012-08-06 12:34:08 -07:00
match val(match_expr(e)) {
2012-08-03 19:59:04 -07:00
none => never_mind = true,
some(mtc) => { res.insert(key, mtc); }
2011-07-21 16:47:47 -07:00
}
};
//HACK: `ret` doesn't work in `for each`
2012-08-01 17:30:05 -07:00
if never_mind { return none; }
return some(res);
2011-07-21 16:47:47 -07:00
}
/* 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 ~[];
2012-08-01 17:30:05 -07:00
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 */
2012-08-01 17:30:05 -07:00
return {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
}
2011-07-27 14:19:39 +02:00
let afp = default_ast_fold();
let f_pre =
2012-06-30 16:19:07 -07:00
@{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|
2012-06-19 19:34:01 -07:00
transcribe_expr(cx, b, idx_path, x, y, z, afp.fold_expr)
2012-06-30 16:19:07 -07:00
,
fold_ty: |x,y,z|
2012-06-19 19:34:01 -07:00
transcribe_type(cx, b, idx_path,
x, y, z, afp.fold_ty)
2012-06-30 16:19:07 -07:00
,
fold_block: |x,y,z|
2012-06-19 19:34:01 -07:00
transcribe_block(cx, b, idx_path, x, y, z, afp.fold_block)
2012-06-30 16:19:07 -07:00
,
map_exprs: |x,y|
2012-06-19 19:34:01 -07:00
transcribe_exprs(cx, b, idx_path, x, y)
2012-06-30 16:19:07 -07:00
,
new_id: |x|new_id(x, cx)
2012-05-21 18:28:39 -07:00
with *afp};
2011-07-27 14:19:39 +02:00
let f = make_fold(f_pre);
let result = f.fold_expr(body);
2012-08-01 17:30:05 -07:00
return result;
2011-07-21 16:47:47 -07:00
}
/* helper: descend into a matcher */
fn follow(m: arb_depth<matchable>, idx_path: @mut ~[uint]) ->
arb_depth<matchable> {
let mut res: arb_depth<matchable> = m;
2012-06-30 16:19:07 -07:00
for vec::each(*idx_path) |idx| {
2012-08-06 12:34:08 -07:00
res = match res {
2012-08-03 19:59:04 -07:00
leaf(_) => return res,/* end of the line */
seq(new_ms, _) => new_ms[idx]
2011-07-21 16:47:47 -07:00
}
}
2012-08-01 17:30:05 -07:00
return res;
2011-07-21 16:47:47 -07:00
}
fn follow_for_trans(cx: ext_ctxt, mmaybe: option<arb_depth<matchable>>,
idx_path: @mut ~[uint]) -> option<matchable> {
2012-08-06 12:34:08 -07:00
match mmaybe {
2012-08-03 19:59:04 -07:00
none => return none,
some(m) => {
2012-08-06 12:34:08 -07:00
return match follow(m, idx_path) {
2012-08-03 19:59:04 -07:00
seq(_, sp) => {
2011-07-27 14:19:39 +02:00
cx.span_fatal(sp,
~"syntax matched under ... but not " +
~"used that way.")
2011-07-27 14:19:39 +02:00
}
2012-08-03 19:59:04 -07:00
leaf(m) => return some(m)
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
}
}
/* helper for transcribe_exprs: what vars from `b` occur in `e`? */
2012-01-23 14:59:00 -08:00
fn free_vars(b: bindings, e: @expr, it: fn(ident)) {
2012-06-10 00:49:59 -07:00
let idents: hashmap<ident, ()> = box_str_hash::<()>();
fn mark_ident(&&i: ident, _fld: ast_fold, b: bindings,
idents: hashmap<ident, ()>) -> ident {
2011-09-02 15:34:58 -07:00
if b.contains_key(i) { idents.insert(i, ()); }
2012-08-01 17:30:05 -07:00
return i;
2011-07-21 16:47:47 -07:00
}
// using fold is a hack: we want visit, but it doesn't hit idents ) :
// solve this with macros
2011-07-27 14:19:39 +02:00
let f_pre =
2012-06-30 16:19:07 -07:00
@{fold_ident: |x,y|mark_ident(x, y, b, idents)
2012-05-21 18:28:39 -07:00
with *default_ast_fold()};
2011-07-27 14:19:39 +02:00
let f = make_fold(f_pre);
2011-07-21 16:47:47 -07:00
f.fold_expr(e); // ignore result
2012-06-30 16:19:07 -07:00
for idents.each_key |x| { it(x); };
2011-07-21 16:47:47 -07:00
}
/* 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@(&&@expr) -> @expr,
exprs: ~[@expr]) -> ~[@expr] {
2012-08-06 12:34:08 -07:00
match elts_to_ell(cx, exprs) {
2012-08-03 19:59:04 -07:00
{pre: pre, rep: repeat_me_maybe, post: post} => {
let mut res = vec::map(pre, recur);
2012-08-06 12:34:08 -07:00
match repeat_me_maybe {
2012-08-03 19:59:04 -07:00
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 */
2012-06-30 16:19:07 -07:00
do free_vars(b, repeat_me) |fv| {
2011-08-25 17:00:12 -07:00
let cur_pos = follow(b.get(fv), idx_path);
2012-08-06 12:34:08 -07:00
match cur_pos {
2012-08-03 19:59:04 -07:00
leaf(_) => (),
seq(ms, _) => {
2012-08-06 12:34:08 -07:00
match repeat {
2012-08-03 19:59:04 -07:00
none => {
2011-08-15 16:38:23 -07:00
repeat = some({rep_count: vec::len(*ms), name: fv});
}
2012-08-03 19:59:04 -07:00
some({rep_count: old_len, name: old_name}) => {
2011-08-15 16:38:23 -07:00
let len = vec::len(*ms);
if old_len != len {
let msg =
fmt!{"'%s' occurs %u times, but ", *fv, len} +
fmt!{"'%s' occurs %u times", *old_name,
old_len};
2011-09-02 15:34:58 -07:00
cx.span_fatal(repeat_me.span, msg);
}
}
2011-07-21 16:47:47 -07:00
}
}
}
};
2012-08-06 12:34:08 -07:00
match repeat {
2012-08-03 19:59:04 -07:00
none => {
cx.span_fatal(repeat_me.span,
~"'...' surrounds an expression without any" +
~" repeating syntax variables");
}
2012-08-03 19:59:04 -07:00
some({rep_count: rc, _}) => {
/* Whew, we now know how how many times to repeat */
let mut idx: uint = 0u;
while idx < rc {
2012-06-27 23:09:51 -07:00
vec::push(*idx_path, idx);
vec::push(res, recur(repeat_me)); // whew!
2011-08-15 16:38:23 -07:00
vec::pop(*idx_path);
idx += 1u;
}
}
2011-07-21 16:47:47 -07:00
}
}
}
2012-06-27 23:09:51 -07:00
res = vec::append(res, vec::map(post, recur));
2012-08-01 17:30:05 -07:00
return res;
2011-07-21 16:47:47 -07:00
}
}
}
2011-07-21 16:47:47 -07:00
// 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 {
2012-08-06 12:34:08 -07:00
return match follow_for_trans(cx, b.find(i), idx_path) {
2012-08-03 19:59:04 -07:00
some(match_ident(a_id)) => a_id.node,
some(m) => match_error(cx, m, ~"an identifier"),
none => i
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
fn transcribe_path(cx: ext_ctxt, b: bindings, idx_path: @mut ~[uint],
2012-04-23 13:04:46 +02:00
p: path, _fld: ast_fold) -> path {
2011-07-21 16:47:47 -07:00
// Don't substitute into qualified names.
2012-08-01 17:30:05 -07:00
if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { return p; }
2012-08-06 12:34:08 -07:00
match follow_for_trans(cx, b.find(p.idents[0]), idx_path) {
2012-08-03 19:59:04 -07:00
some(match_ident(id)) => {
{span: id.span, global: false, idents: ~[id.node],
rp: none, types: ~[]}
2012-04-23 13:04:46 +02:00
}
2012-08-03 19:59:04 -07:00
some(match_path(a_pth)) => *a_pth,
some(m) => match_error(cx, m, ~"a path"),
none => p
2012-04-23 13:04:46 +02:00
}
2011-07-21 16:47:47 -07:00
}
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)
{
2012-08-06 12:34:08 -07:00
return match e {
2012-08-03 19:59:04 -07:00
expr_path(p) => {
2011-07-27 14:19:39 +02:00
// Don't substitute into qualified names.
2012-04-23 13:04:46 +02:00
if vec::len(p.types) > 0u || vec::len(p.idents) != 1u {
(e, s);
2011-07-27 14:19:39 +02:00
}
2012-08-06 12:34:08 -07:00
match follow_for_trans(cx, b.find(p.idents[0]), idx_path) {
2012-08-03 19:59:04 -07:00
some(match_ident(id)) => {
2012-04-23 13:04:46 +02:00
(expr_path(@{span: id.span,
global: false,
idents: ~[id.node],
rp: none,
types: ~[]}), id.span)
2011-07-27 14:19:39 +02:00
}
2012-08-03 19:59:04 -07:00
some(match_path(a_pth)) => (expr_path(a_pth), s),
some(match_expr(a_exp)) => (a_exp.node, a_exp.span),
some(m) => match_error(cx, m, ~"an expression"),
none => orig(e, s, fld)
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => orig(e, s, fld)
2011-07-21 16:47:47 -07:00
}
}
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)
{
2012-08-06 12:34:08 -07:00
return match t {
2012-08-03 19:59:04 -07:00
ast::ty_path(pth, _) => {
2012-08-06 12:34:08 -07:00
match path_to_ident(pth) {
2012-08-03 19:59:04 -07:00
some(id) => {
2012-08-06 12:34:08 -07:00
match follow_for_trans(cx, b.find(id), idx_path) {
2012-08-03 19:59:04 -07:00
some(match_ty(ty)) => (ty.node, ty.span),
some(m) => match_error(cx, m, ~"a type"),
none => orig(t, s, fld)
2011-07-27 14:19:39 +02:00
}
}
2012-08-03 19:59:04 -07:00
none => orig(t, s, fld)
}
}
2012-08-03 19:59:04 -07:00
_ => orig(t, s, fld)
}
}
2011-07-21 16:47:47 -07:00
/* 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)
{
2012-08-06 12:34:08 -07:00
return match block_to_ident(blk) {
2012-08-03 19:59:04 -07:00
some(id) => {
2012-08-06 12:34:08 -07:00
match follow_for_trans(cx, b.find(id), idx_path) {
2012-08-03 19:59:04 -07:00
some(match_block(new_blk)) => (new_blk.node, new_blk.span),
2011-09-12 12:39:38 +02:00
2011-07-27 14:19:39 +02:00
// possibly allow promotion of ident/path/expr to blocks?
2012-08-03 19:59:04 -07:00
some(m) => match_error(cx, m, ~"a block"),
none => orig(blk, s, fld)
2011-07-27 14:19:39 +02:00
}
}
2012-08-03 19:59:04 -07:00
none => orig(blk, s, fld)
}
}
2011-07-21 16:47:47 -07:00
/* 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) {
2011-07-27 14:19:39 +02:00
2011-07-21 16:47:47 -07:00
//it might be possible to traverse only exprs, not matchables
2012-08-06 12:34:08 -07:00
match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => {
2012-08-06 12:34:08 -07:00
match e.node {
2012-08-03 19:59:04 -07:00
expr_path(p_pth) => p_t_s_r_path(cx, p_pth, s, b),
expr_vec(p_elts, _) => {
2012-08-06 12:34:08 -07:00
match elts_to_ell(cx, p_elts) {
2012-08-03 19:59:04 -07:00
{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);
}
2011-08-15 16:38:23 -07:00
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");
}
}
2012-08-03 19:59:04 -07:00
{pre: pre, rep: none, post: post} => {
if post != ~[] {
cx.bug(~"elts_to_ell provided an invalid result");
}
2011-08-15 16:38:23 -07:00
p_t_s_r_length(cx, vec::len(pre), false, s, b);
p_t_s_r_actual_vector(cx, pre, false, s, b);
}
2011-07-21 16:47:47 -07:00
}
}
/* FIXME (#2251): handle embedded types and blocks, at least */
2012-08-03 19:59:04 -07:00
expr_mac(mac) => {
p_t_s_r_mac(cx, mac, s, b);
}
2012-08-03 19:59:04 -07:00
_ => {
fn select(cx: ext_ctxt, m: matchable, pat: @expr) ->
2011-07-27 14:19:39 +02:00
match_result {
2012-08-06 12:34:08 -07:00
return match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => {
2011-07-27 14:19:39 +02:00
if e == pat { some(leaf(match_exact)) } else { none }
}
2012-08-03 19:59:04 -07:00
_ => cx.bug(~"broken traversal in p_t_s_r")
2011-07-27 14:19:39 +02:00
}
}
2012-06-30 16:19:07 -07:00
b.literal_ast_matchers.push(|x| select(cx, x, e));
2011-07-21 16:47:47 -07:00
}
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => cx.bug(~"undocumented invariant in p_t_s_rec")
}
}
2011-07-21 16:47:47 -07:00
/* make a match more precise */
fn specialize_match(m: matchable) -> matchable {
2012-08-06 12:34:08 -07:00
return match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => {
2012-08-06 12:34:08 -07:00
match e.node {
2012-08-03 19:59:04 -07:00
expr_path(pth) => {
2012-08-06 12:34:08 -07:00
match path_to_ident(pth) {
2012-08-03 19:59:04 -07:00
some(id) => match_ident(respan(pth.span, id)),
none => match_path(pth)
2011-07-27 14:19:39 +02:00
}
}
2012-08-03 19:59:04 -07:00
_ => m
2011-07-21 16:47:47 -07:00
}
}
2012-08-03 19:59:04 -07:00
_ => m
2011-07-21 16:47:47 -07:00
}
}
/* pattern_to_selectors helper functions */
fn p_t_s_r_path(cx: ext_ctxt, p: @path, s: selector, b: binders) {
2012-08-06 12:34:08 -07:00
match path_to_ident(p) {
2012-08-03 19:59:04 -07:00
some(p_id) => {
fn select(cx: ext_ctxt, m: matchable) -> match_result {
2012-08-06 12:34:08 -07:00
return match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => some(leaf(specialize_match(m))),
_ => cx.bug(~"broken traversal in p_t_s_r")
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
2011-08-25 17:00:12 -07:00
if b.real_binders.contains_key(p_id) {
cx.span_fatal(p.span, ~"duplicate binding identifier");
2011-07-21 16:47:47 -07:00
}
2012-06-30 16:19:07 -07:00
b.real_binders.insert(p_id, compose_sels(s, |x| select(cx, x)));
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
none => ()
}
}
fn block_to_ident(blk: blk_) -> option<ident> {
2012-08-01 17:30:05 -07:00
if vec::len(blk.stmts) != 0u { return none; }
2012-08-06 12:34:08 -07:00
return match blk.expr {
some(expr) => match expr.node {
2012-08-03 19:59:04 -07:00
expr_path(pth) => path_to_ident(pth),
_ => none
2011-07-27 14:19:39 +02:00
}
2012-08-03 19:59:04 -07:00
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,
2012-01-23 14:59:00 -08:00
fn_m: fn(ast::mac) -> match_result) -> match_result {
2012-08-06 12:34:08 -07:00
return match m {
match_expr(e) => match e.node {
2012-08-03 19:59:04 -07:00
expr_mac(mac) => fn_m(mac),
_ => none
2011-07-27 14:19:39 +02:00
}
2012-08-03 19:59:04 -07:00
_ => 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");
}
2012-08-06 12:34:08 -07:00
match mac.node {
2012-08-03 19:59:04 -07:00
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 {
2012-08-06 12:34:08 -07:00
return match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => {
2012-08-06 12:34:08 -07:00
match e.node {
2012-08-03 19:59:04 -07:00
expr_vec(arg_elts, _) => {
let mut elts = ~[];
let mut idx = offset;
2011-08-15 16:38:23 -07:00
while idx < vec::len(arg_elts) {
vec::push(elts, leaf(match_expr(arg_elts[idx])));
idx += 1u;
}
2011-07-27 14:19:39 +02:00
// 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))
2011-07-27 14:19:39 +02:00
}
2012-08-03 19:59:04 -07:00
_ => none
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => cx.bug(~"broken traversal in p_t_s_r")
2011-07-21 16:47:47 -07:00
}
}
2011-07-21 16:47:47 -07:00
p_t_s_rec(cx, match_expr(repeat_me),
2012-06-30 16:19:07 -07:00
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 {
2012-08-06 12:34:08 -07:00
return match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => {
2012-08-06 12:34:08 -07:00
match e.node {
2012-08-03 19:59:04 -07:00
expr_vec(arg_elts, _) => {
2011-08-15 16:38:23 -07:00
let actual_len = vec::len(arg_elts);
if at_least && actual_len >= len || actual_len == len {
2011-07-27 14:19:39 +02:00
some(leaf(match_exact))
} else { none }
}
2012-08-03 19:59:04 -07:00
_ => none
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => none
2011-07-21 16:47:47 -07:00
}
}
b.literal_ast_matchers.push(
2012-06-30 16:19:07 -07:00
compose_sels(s, |x| len_select(cx, x, at_least, len)));
}
2011-07-21 16:47:47 -07:00
fn p_t_s_r_actual_vector(cx: ext_ctxt, elts: ~[@expr], _repeat_after: bool,
s: selector, b: binders) {
let mut idx: uint = 0u;
2011-08-15 16:38:23 -07:00
while idx < vec::len(elts) {
fn select(cx: ext_ctxt, m: matchable, idx: uint) -> match_result {
2012-08-06 12:34:08 -07:00
return match m {
2012-08-03 19:59:04 -07:00
match_expr(e) => {
2012-08-06 12:34:08 -07:00
match e.node {
2012-08-03 19:59:04 -07:00
expr_vec(arg_elts, _) => {
some(leaf(match_expr(arg_elts[idx])))
2011-07-27 14:19:39 +02:00
}
2012-08-03 19:59:04 -07:00
_ => none
2011-07-27 14:19:39 +02:00
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => cx.bug(~"broken traversal in p_t_s_r")
2011-07-21 16:47:47 -07:00
}
}
p_t_s_rec(cx, match_expr(elts[idx]),
2012-06-30 16:19:07 -07:00
compose_sels(s, |x, copy idx| select(cx, x, idx)), b);
2011-07-21 16:47:47 -07:00
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] = ~[];
2012-06-30 16:19:07 -07:00
for args.each |arg| {
2012-08-06 12:34:08 -07:00
match arg.node {
2012-08-03 19:59:04 -07:00
expr_vec(elts, mutbl) => {
2011-08-15 16:38:23 -07:00
if vec::len(elts) != 2u {
2011-07-21 16:47:47 -07:00
cx.span_fatal((*arg).span,
~"extension clause must consist of ~[" +
~"macro invocation, expansion body]");
2011-07-21 16:47:47 -07:00
}
2011-07-27 14:19:39 +02:00
2012-08-06 12:34:08 -07:00
match elts[0u].node {
2012-08-03 19:59:04 -07:00
expr_mac(mac) => {
2012-08-06 12:34:08 -07:00
match mac.node {
2012-08-03 19:59:04 -07:00
mac_invoc(pth, invoc_arg, body) => {
2012-08-06 12:34:08 -07:00
match path_to_ident(pth) {
some(id) => match macro_name {
2012-08-03 19:59:04 -07:00
none => macro_name = some(id),
some(other_id) => if id != other_id {
cx.span_fatal(pth.span,
~"macro name must be " +
~"consistent");
2011-08-04 11:58:09 -07:00
}
}
2012-08-03 19:59:04 -07:00
none => cx.span_fatal(pth.span,
~"macro name must not be a path")
}
2012-08-06 12:34:08 -07:00
let arg = match invoc_arg {
2012-08-03 19:59:04 -07:00
some(arg) => arg,
none => cx.span_fatal(mac.span,
~"macro must have arguments")
};
2012-06-27 23:09:51 -07:00
vec::push(clauses,
@{params: pattern_to_selectors(cx, arg),
body: elts[1u]});
// FIXME (#2251): check duplicates (or just simplify
// the macro arg situation)
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => {
cx.span_bug(mac.span, ~"undocumented invariant in \
add_extension");
}
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => {
cx.span_fatal(elts[0u].span,
~"extension clause must" +
~" start with a macro invocation.");
2011-07-21 16:47:47 -07:00
}
}
2011-07-21 16:47:47 -07:00
}
2012-08-03 19:59:04 -07:00
_ => {
2011-07-27 14:19:39 +02:00
cx.span_fatal((*arg).span,
~"extension must be ~[clause, " + ~" ...]");
2011-07-21 16:47:47 -07:00
}
}
}
2012-06-30 16:19:07 -07:00
let ext = |a,b,c,d, move clauses| generic_extension(a,b,c,d,clauses);
2011-07-27 14:19:39 +02:00
2012-08-01 17:30:05 -07:00
return {ident:
2012-08-06 12:34:08 -07:00
match macro_name {
2012-08-03 19:59:04 -07:00
some(id) => id,
none => cx.span_fatal(sp, ~"macro definition must have " +
~"at least one clause")
2011-07-27 14:19:39 +02:00
},
ext: normal({expander: ext, span: some(option::get(arg).span)})};
fn generic_extension(cx: ext_ctxt, sp: span, arg: ast::mac_arg,
_body: ast::mac_body,
clauses: ~[@clause]) -> @expr {
2012-08-06 12:34:08 -07:00
let arg = match arg {
2012-08-03 19:59:04 -07:00
some(arg) => arg,
none => cx.span_fatal(sp, ~"macro must have arguments")
};
2012-06-30 16:19:07 -07:00
for clauses.each |c| {
2012-08-06 12:34:08 -07:00
match use_selectors_to_bind(c.params, arg) {
2012-08-03 19:59:04 -07:00
some(bindings) => return transcribe(cx, bindings, c.body),
none => again
}
}
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:
//