Make macro-system type and constructor names more uniform; more comments.

This commit is contained in:
Graydon Hoare 2012-07-27 19:14:46 -07:00
parent eabd233dcd
commit e11e90f31c
9 changed files with 230 additions and 194 deletions

View file

@ -362,33 +362,53 @@ type capture_item = @{
#[auto_serialize] #[auto_serialize]
type capture_clause = @~[capture_item]; type capture_clause = @~[capture_item];
//
// When the main rust parser encounters a syntax-extension invocation, it
// parses the arguments to the invocation as a token-tree. This is a very
// loose structure, such that all sorts of different AST-fragments can
// be passed to syntax extensions using a uniform type.
//
// If the syntax extension is an MBE macro, it will attempt to match its
// LHS "matchers" against the provided token tree, and if it finds a
// match, will transcribe the RHS token tree, splicing in any captured
// early_parser::matched_nonterminals into the tt_nonterminals it finds.
//
// The RHS of an MBE macro is the only place a tt_nonterminal or tt_seq
// makes any real sense. You could write them elsewhere but nothing
// else knows what to do with them, so you'll probably get a syntax
// error.
//
#[auto_serialize] #[auto_serialize]
#[doc="For macro invocations; parsing is delegated to the macro"] #[doc="For macro invocations; parsing is delegated to the macro"]
enum token_tree { enum token_tree {
tt_tok(span, token::token),
tt_delim(~[token_tree]), tt_delim(~[token_tree]),
tt_flat(span, token::token), // These only make sense for right-hand-sides of MBE macros
/* These only make sense for right-hand-sides of MBE macros*/ tt_seq(span, ~[token_tree], option<token::token>, bool),
tt_dotdotdot(span, ~[token_tree], option<token::token>, bool), tt_nonterminal(span, ident)
tt_interpolate(span, ident)
} }
#[auto_serialize]
type matcher = spanned<matcher_>;
#[auto_serialize]
// //
// Matchers are nodes defined-by and recognized-by the main rust parser and // Matchers are nodes defined-by and recognized-by the main rust parser and
// language, but they're only ever found inside syntax-extension invocations. // language, but they're only ever found inside syntax-extension invocations;
// They represent a small sub-language for pattern-matching token-trees, and // indeed, the only thing that ever _activates_ the rules in the rust parser
// are thus primarily used by the macro-defining extension itself. // for parsing a matcher is a matcher looking for the 'mtcs' nonterminal
// itself. Matchers represent a small sub-language for pattern-matching
// token-trees, and are thus primarily used by the macro-defining extension
// itself.
// //
// mtc_tok ===> A matcher that matches a single token, // match_tok
// denoted by the token itself. So long as // ---------
// there's no $ involved. //
// A matcher that matches a single token, denoted by the token itself. So
// long as there's no $ involved.
// //
// //
// mtc_rep ===> A matcher that matches a sequence of // match_seq
// sub-matchers, denoted various ways: // ---------
//
// A matcher that matches a sequence of sub-matchers, denoted various
// possible ways:
// //
// $(M)* zero or more Ms // $(M)* zero or more Ms
// $(M)+ one or more Ms // $(M)+ one or more Ms
@ -396,12 +416,14 @@ type matcher = spanned<matcher_>;
// $(A B C);* zero or more semi-separated 'A B C' seqs // $(A B C);* zero or more semi-separated 'A B C' seqs
// //
// //
// mtc_bb ===> A matcher that matches one of a few interesting named rust // match_nonterminal
// nonterminals, such as types, expressions, items, or raw // -----------------
// token-trees. A black-box matcher on expr, for example, binds an //
// expr to a given ident, and that ident can re-occur as an // A matcher that matches one of a few interesting named rust
// interpolation in the RHS of a macro-by-example rule. For // nonterminals, such as types, expressions, items, or raw token-trees. A
// example: // black-box matcher on expr, for example, binds an expr to a given ident,
// and that ident can re-occur as an interpolation in the RHS of a
// macro-by-example rule. For example:
// //
// $foo:expr => 1 + $foo // interpolate an expr // $foo:expr => 1 + $foo // interpolate an expr
// $foo:tt => $foo // interpolate a token-tree // $foo:tt => $foo // interpolate a token-tree
@ -411,21 +433,25 @@ type matcher = spanned<matcher_>;
// //
// As a final, horrifying aside, note that macro-by-example's input is // As a final, horrifying aside, note that macro-by-example's input is
// also matched by one of these matchers. Holy self-referential! It is matched // also matched by one of these matchers. Holy self-referential! It is matched
// by an mtc_rep, specifically this one: // by an match_seq, specifically this one:
// //
// $( $lhs:mtcs => $rhs:tt );+ // $( $lhs:mtcs => $rhs:tt );+
// //
// If you understand that, you have closed to loop and understand the whole // If you understand that, you have closed to loop and understand the whole
// macro system. Congratulations. // macro system. Congratulations.
// //
#[auto_serialize]
type matcher = spanned<matcher_>;
#[auto_serialize]
enum matcher_ { enum matcher_ {
/* match one token */ // match one token
mtc_tok(token::token), match_tok(token::token),
/* match repetitions of a sequence: body, separator, zero ok?, // match repetitions of a sequence: body, separator, zero ok?,
lo, hi position-in-match-array used: */ // lo, hi position-in-match-array used:
mtc_rep(~[matcher], option<token::token>, bool, uint, uint), match_seq(~[matcher], option<token::token>, bool, uint, uint),
/* parse a Rust NT: name to bind, name of NT, position in match array : */ // parse a Rust NT: name to bind, name of NT, position in match array:
mtc_bb(ident, ident, uint) match_nonterminal(ident, ident, uint)
} }
#[auto_serialize] #[auto_serialize]

View file

@ -4,18 +4,6 @@ import diagnostic::span_handler;
import codemap::{codemap, span, expn_info, expanded_from}; import codemap::{codemap, span, expn_info, expanded_from};
import std::map::str_hash; import std::map::str_hash;
// Nomenclature / abbreviations in the ext modules:
//
// ms: matcher span, wraps a matcher with fake span
// mtc: matcher
// mtcs: matchers
// tt: token tree
// bt: backtrace
// cx: expansion context
// mr: macro result
//
// obsolete old-style #macro code: // obsolete old-style #macro code:
// //
// syntax_expander, normal, macro_defining, macro_definer, // syntax_expander, normal, macro_defining, macro_definer,
@ -288,17 +276,18 @@ fn get_mac_body(cx: ext_ctxt, sp: span, args: ast::mac_body)
// using new syntax. This will be obsolete when #old_macros go away. // using new syntax. This will be obsolete when #old_macros go away.
fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree]) fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree])
-> ast::mac_arg { -> ast::mac_arg {
import ast::{matcher, matcher_, mtc_tok, mtc_rep, mtc_bb}; import ast::{matcher, matcher_, match_tok, match_seq, match_nonterminal};
import parse::lexer::{new_tt_reader, tt_reader_as_reader, reader}; import parse::lexer::{new_tt_reader, tt_reader_as_reader, reader};
import tt::earley_parser::{parse_or_else, seq, leaf}; import tt::earley_parser::{parse_or_else, matched_seq,
matched_nonterminal};
// these spans won't matter, anyways // these spans won't matter, anyways
fn ms(m: matcher_) -> matcher { fn ms(m: matcher_) -> matcher {
{node: m, span: {lo: 0u, hi: 0u, expn_info: none}} {node: m, span: {lo: 0u, hi: 0u, expn_info: none}}
} }
let argument_gram = ~[ms(mtc_rep(~[ let argument_gram = ~[ms(match_seq(~[
ms(mtc_bb(@~"arg",@~"expr", 0u)) ms(match_nonterminal(@~"arg",@~"expr", 0u))
], some(parse::token::COMMA), true, 0u, 1u))]; ], some(parse::token::COMMA), true, 0u, 1u))];
let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic, let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
@ -306,10 +295,10 @@ fn tt_args_to_original_flavor(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree])
let args = let args =
alt parse_or_else(cx.parse_sess(), cx.cfg(), arg_reader as reader, alt parse_or_else(cx.parse_sess(), cx.cfg(), arg_reader as reader,
argument_gram).get(@~"arg") { argument_gram).get(@~"arg") {
@seq(s, _) { @matched_seq(s, _) {
do s.map() |lf| { do s.map() |lf| {
alt lf { alt lf {
@leaf(parse::token::w_expr(arg)) { @matched_nonterminal(parse::token::nt_expr(arg)) {
arg /* whew! list of exprs, here we come! */ arg /* whew! list of exprs, here we come! */
} }
_ { fail ~"badly-structured parse result"; } _ { fail ~"badly-structured parse result"; }

View file

@ -1,7 +1,7 @@
import std::map::hashmap; import std::map::hashmap;
import ast::{crate, expr_, expr_mac, mac_invoc, mac_invoc_tt, import ast::{crate, expr_, expr_mac, mac_invoc, mac_invoc_tt,
tt_delim, tt_flat, item_mac}; tt_delim, tt_tok, item_mac};
import fold::*; import fold::*;
import ext::base::*; import ext::base::*;
import ext::qquote::{qq_helper}; import ext::qquote::{qq_helper};

View file

@ -1,6 +1,6 @@
// Earley-like parser for macros. // Earley-like parser for macros.
import parse::token; import parse::token;
import parse::token::{token, EOF, to_str, whole_nt}; import parse::token::{token, EOF, to_str, nonterminal};
import parse::lexer::*; //resolve bug? import parse::lexer::*; //resolve bug?
//import parse::lexer::{reader, tt_reader, tt_reader_as_reader}; //import parse::lexer::{reader, tt_reader, tt_reader_as_reader};
import parse::parser::{parser,SOURCE_FILE}; import parse::parser::{parser,SOURCE_FILE};
@ -8,20 +8,22 @@ import parse::parser::{parser,SOURCE_FILE};
import parse::common::*; //resolve bug? import parse::common::*; //resolve bug?
import parse::parse_sess; import parse::parse_sess;
import dvec::{dvec, extensions}; import dvec::{dvec, extensions};
import ast::{matcher, mtc_tok, mtc_rep, mtc_bb, ident}; import ast::{matcher, match_tok, match_seq, match_nonterminal, ident};
import ast_util::mk_sp; import ast_util::mk_sp;
import std::map::{hashmap, box_str_hash}; import std::map::{hashmap, box_str_hash};
/* This is an Earley-like parser, without support for nonterminals. This /* This is an Earley-like parser, without support for in-grammar nonterminals,
means that there are no completer or predictor rules, and therefore no need to onlyl calling out to the main rust parser for named nonterminals (which it
store one column per token: instead, there's a set of current Earley items and commits to fully when it hits one in a grammar). This means that there are no
a set of next ones. Instead of NTs, we have a special case for Kleene completer or predictor rules, and therefore no need to store one column per
star. The big-O, in pathological cases, is worse than traditional Earley token: instead, there's a set of current Earley items and a set of next
parsing, but it's an easier fit for Macro-by-Example-style rules, and I think ones. Instead of NTs, we have a special case for Kleene star. The big-O, in
the overhead is lower. */ pathological cases, is worse than traditional Earley parsing, but it's an
easier fit for Macro-by-Example-style rules, and I think the overhead is
lower. */
/* to avoid costly uniqueness checks, we require that `mtc_rep` always has a /* to avoid costly uniqueness checks, we require that `match_seq` always has a
nonempty body. */ nonempty body. */
enum matcher_pos_up { /* to break a circularity */ enum matcher_pos_up { /* to break a circularity */
@ -40,7 +42,7 @@ type matcher_pos = ~{
sep: option<token>, sep: option<token>,
mut idx: uint, mut idx: uint,
mut up: matcher_pos_up, // mutable for swapping only mut up: matcher_pos_up, // mutable for swapping only
matches: ~[dvec<@arb_depth>], matches: ~[dvec<@named_match>],
match_lo: uint, match_hi: uint, match_lo: uint, match_hi: uint,
sp_lo: uint, sp_lo: uint,
}; };
@ -55,9 +57,9 @@ fn copy_up(&& mpu: matcher_pos_up) -> matcher_pos {
fn count_names(ms: &[matcher]) -> uint { fn count_names(ms: &[matcher]) -> uint {
vec::foldl(0u, ms, |ct, m| { vec::foldl(0u, ms, |ct, m| {
ct + alt m.node { ct + alt m.node {
mtc_tok(_) { 0u } match_tok(_) { 0u }
mtc_rep(more_ms, _, _, _, _) { count_names(more_ms) } match_seq(more_ms, _, _, _, _) { count_names(more_ms) }
mtc_bb(_,_,_) { 1u } match_nonterminal(_,_,_) { 1u }
}}) }})
} }
@ -67,9 +69,13 @@ fn initial_matcher_pos(ms: ~[matcher], sep: option<token>, lo: uint)
let mut match_idx_hi = 0u; let mut match_idx_hi = 0u;
for ms.each() |elt| { for ms.each() |elt| {
alt elt.node { alt elt.node {
mtc_tok(_) {} match_tok(_) {}
mtc_rep(_,_,_,_,hi) { match_idx_hi = hi; } //it is monotonic... match_seq(_,_,_,_,hi) {
mtc_bb(_,_,pos) { match_idx_hi = pos+1u; } //...so latest is highest match_idx_hi = hi; // it is monotonic...
}
match_nonterminal(_,_,pos) {
match_idx_hi = pos+1u; // ...so latest is highest
}
} }
} }
~{elts: ms, sep: sep, mut idx: 0u, mut up: matcher_pos_up(none), ~{elts: ms, sep: sep, mut idx: 0u, mut up: matcher_pos_up(none),
@ -77,38 +83,42 @@ fn initial_matcher_pos(ms: ~[matcher], sep: option<token>, lo: uint)
match_lo: 0u, match_hi: match_idx_hi, sp_lo: lo} match_lo: 0u, match_hi: match_idx_hi, sp_lo: lo}
} }
// arb_depth is a pattern-match result for a single black-box matcher // named_match is a pattern-match result for a single ast::match_nonterminal:
// (ast::mtc_bb): so it is associated with a single ident in a parse, and all // so it is associated with a single ident in a parse, and all
// leaves in the arb_depth have the same nonterminal type (expr, item, // matched_nonterminals in the named_match have the same nonterminal type
// etc). All the leaves in a single arb_depth correspond to a single mtc_bb in // (expr, item, etc). All the leaves in a single named_match correspond to a
// the ast::matcher that produced it. // single matcher_nonterminal in the ast::matcher that produced it.
// //
// It should probably be renamed, it has more or less exact correspondence to // It should probably be renamed, it has more or less exact correspondence to
// ast::match nodes, and the in-memory structure of a particular arb_depth // ast::match nodes, and the in-memory structure of a particular named_match
// represents the match that occurred when a particular subset of an // represents the match that occurred when a particular subset of an
// ast::match -- those ast::matcher nodes leading to a single mtc_bb -- was // ast::match -- those ast::matcher nodes leading to a single
// applied to a particular token tree. // match_nonterminal -- was applied to a particular token tree.
// //
// The width of each seq in the arb_depth, and the identity of the leaf nodes, // The width of each matched_seq in the named_match, and the identity of the
// will depend on the token tree it was applied to: each seq corresponds to a // matched_nonterminals, will depend on the token tree it was applied to: each
// single mtc_rep in the originating ast::matcher. The depth of the arb_depth // matched_seq corresponds to a single match_seq in the originating
// structure will therefore depend only on the nesting depth of mtc_reps in // ast::matcher. The depth of the named_match structure will therefore depend
// the originating ast::matcher it was derived from. // only on the nesting depth of ast::match_seqs in the originating
// ast::matcher it was derived from.
enum arb_depth { leaf(whole_nt), seq(~[@arb_depth], codemap::span) } enum named_match {
matched_seq(~[@named_match], codemap::span),
matched_nonterminal(nonterminal)
}
type earley_item = matcher_pos; type earley_item = matcher_pos;
fn nameize(p_s: parse_sess, ms: ~[matcher], res: ~[@arb_depth]) fn nameize(p_s: parse_sess, ms: ~[matcher], res: ~[@named_match])
-> hashmap<ident,@arb_depth> { -> hashmap<ident,@named_match> {
fn n_rec(p_s: parse_sess, m: matcher, res: ~[@arb_depth], fn n_rec(p_s: parse_sess, m: matcher, res: ~[@named_match],
ret_val: hashmap<ident, @arb_depth>) { ret_val: hashmap<ident, @named_match>) {
alt m { alt m {
{node: mtc_tok(_), span: _} { } {node: match_tok(_), span: _} { }
{node: mtc_rep(more_ms, _, _, _, _), span: _} { {node: match_seq(more_ms, _, _, _, _), span: _} {
for more_ms.each() |next_m| { n_rec(p_s, next_m, res, ret_val) }; for more_ms.each() |next_m| { n_rec(p_s, next_m, res, ret_val) };
} }
{node: mtc_bb(bind_name, _, idx), span: sp} { {node: match_nonterminal(bind_name, _, idx), span: sp} {
if ret_val.contains_key(bind_name) { if ret_val.contains_key(bind_name) {
p_s.span_diagnostic.span_fatal(sp, ~"Duplicated bind name: " p_s.span_diagnostic.span_fatal(sp, ~"Duplicated bind name: "
+ *bind_name) + *bind_name)
@ -117,18 +127,18 @@ fn nameize(p_s: parse_sess, ms: ~[matcher], res: ~[@arb_depth])
} }
} }
} }
let ret_val = box_str_hash::<@arb_depth>(); let ret_val = box_str_hash::<@named_match>();
for ms.each() |m| { n_rec(p_s, m, res, ret_val) } for ms.each() |m| { n_rec(p_s, m, res, ret_val) }
ret ret_val; ret ret_val;
} }
enum parse_result { enum parse_result {
success(hashmap<ident, @arb_depth>), success(hashmap<ident, @named_match>),
failure(codemap::span, ~str) failure(codemap::span, ~str)
} }
fn parse_or_else(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, fn parse_or_else(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader,
ms: ~[matcher]) -> hashmap<ident, @arb_depth> { ms: ~[matcher]) -> hashmap<ident, @named_match> {
alt parse(sess, cfg, rdr, ms) { alt parse(sess, cfg, rdr, ms) {
success(m) { m } success(m) { m }
failure(sp, str) { failure(sp, str) {
@ -182,7 +192,9 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
for uint::range(ei.match_lo, ei.match_hi) |idx| { for uint::range(ei.match_lo, ei.match_hi) |idx| {
let sub = ei.matches[idx].get(); let sub = ei.matches[idx].get();
new_pos.matches[idx] new_pos.matches[idx]
.push(@seq(sub, mk_sp(ei.sp_lo,sp.hi))); .push(@matched_seq(sub,
mk_sp(ei.sp_lo,
sp.hi)));
} }
new_pos.idx += 1u; new_pos.idx += 1u;
@ -212,20 +224,21 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
} else { } else {
alt copy ei.elts[idx].node { alt copy ei.elts[idx].node {
/* need to descend into sequence */ /* need to descend into sequence */
mtc_rep(matchers, sep, zero_ok, match_idx_lo, match_idx_hi){ match_seq(matchers, sep, zero_ok,
match_idx_lo, match_idx_hi){
if zero_ok { if zero_ok {
let new_ei = copy ei; let new_ei = copy ei;
new_ei.idx += 1u; new_ei.idx += 1u;
//we specifically matched zero repeats. //we specifically matched zero repeats.
for uint::range(match_idx_lo, match_idx_hi) |idx| { for uint::range(match_idx_lo, match_idx_hi) |idx| {
new_ei.matches[idx].push(@seq(~[], sp)); new_ei.matches[idx].push(@matched_seq(~[], sp));
} }
vec::push(cur_eis, new_ei); vec::push(cur_eis, new_ei);
} }
let matches = vec::map(ei.matches, // fresh, same size: let matches = vec::map(ei.matches, // fresh, same size:
|_m| dvec::<@arb_depth>()); |_m| dvec::<@named_match>());
let ei_t <- ei; let ei_t <- ei;
vec::push(cur_eis, ~{ vec::push(cur_eis, ~{
elts: matchers, sep: sep, mut idx: 0u, elts: matchers, sep: sep, mut idx: 0u,
@ -235,8 +248,8 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
sp_lo: sp.lo sp_lo: sp.lo
}); });
} }
mtc_bb(_,_,_) { vec::push(bb_eis, ei) } match_nonterminal(_,_,_) { vec::push(bb_eis, ei) }
mtc_tok(t) { match_tok(t) {
let ei_t <- ei; let ei_t <- ei;
if t == tok { ei_t.idx += 1u; vec::push(next_eis, ei_t)} if t == tok { ei_t.idx += 1u; vec::push(next_eis, ei_t)}
} }
@ -260,7 +273,7 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
|| bb_eis.len() > 1u { || bb_eis.len() > 1u {
let nts = str::connect(vec::map(bb_eis, |ei| { let nts = str::connect(vec::map(bb_eis, |ei| {
alt ei.elts[ei.idx].node { alt ei.elts[ei.idx].node {
mtc_bb(bind,name,_) { match_nonterminal(bind,name,_) {
#fmt["%s ('%s')", *name, *bind] #fmt["%s ('%s')", *name, *bind]
} }
_ { fail; } } }), ~" or "); _ { fail; } } }), ~" or ");
@ -282,8 +295,8 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
let ei = vec::pop(bb_eis); let ei = vec::pop(bb_eis);
alt ei.elts[ei.idx].node { alt ei.elts[ei.idx].node {
mtc_bb(_, name, idx) { match_nonterminal(_, name, idx) {
ei.matches[idx].push(@leaf( ei.matches[idx].push(@matched_nonterminal(
parse_nt(rust_parser, *name))); parse_nt(rust_parser, *name)));
ei.idx += 1u; ei.idx += 1u;
} }
@ -305,31 +318,31 @@ fn parse(sess: parse_sess, cfg: ast::crate_cfg, rdr: reader, ms: ~[matcher])
} }
} }
fn parse_nt(p: parser, name: ~str) -> whole_nt { fn parse_nt(p: parser, name: ~str) -> nonterminal {
alt name { alt name {
~"item" { alt p.parse_item(~[], ast::public) { ~"item" { alt p.parse_item(~[], ast::public) {
some(i) { token::w_item(i) } some(i) { token::nt_item(i) }
none { p.fatal(~"expected an item keyword") } none { p.fatal(~"expected an item keyword") }
}} }}
~"block" { token::w_block(p.parse_block()) } ~"block" { token::nt_block(p.parse_block()) }
~"stmt" { token::w_stmt(p.parse_stmt(~[])) } ~"stmt" { token::nt_stmt(p.parse_stmt(~[])) }
~"pat" { token::w_pat(p.parse_pat()) } ~"pat" { token::nt_pat(p.parse_pat()) }
~"expr" { token::w_expr(p.parse_expr()) } ~"expr" { token::nt_expr(p.parse_expr()) }
~"ty" { token::w_ty(p.parse_ty(false /* no need to disambiguate*/)) } ~"ty" { token::nt_ty(p.parse_ty(false /* no need to disambiguate*/)) }
// this could be handled like a token, since it is one // this could be handled like a token, since it is one
~"ident" { alt copy p.token { ~"ident" { alt copy p.token {
token::IDENT(sn,b) { p.bump(); token::w_ident(sn,b) } token::IDENT(sn,b) { p.bump(); token::nt_ident(sn,b) }
_ { p.fatal(~"expected ident, found " _ { p.fatal(~"expected ident, found "
+ token::to_str(*p.reader.interner(), copy p.token)) } + token::to_str(*p.reader.interner(), copy p.token)) }
} } } }
~"path" { token::w_path(p.parse_path_with_tps(false)) } ~"path" { token::nt_path(p.parse_path_with_tps(false)) }
~"tt" { ~"tt" {
p.quote_depth += 1u; //but in theory, non-quoted tts might be useful p.quote_depth += 1u; //but in theory, non-quoted tts might be useful
let res = token::w_tt(@p.parse_token_tree()); let res = token::nt_tt(@p.parse_token_tree());
p.quote_depth -= 1u; p.quote_depth -= 1u;
res res
} }
~"mtcs" { token::w_mtcs(p.parse_matchers()) } ~"matchers" { token::nt_matchers(p.parse_matchers()) }
_ { p.fatal(~"Unsupported builtin nonterminal parser: " + name)} _ { p.fatal(~"Unsupported builtin nonterminal parser: " + name)}
} }
} }

View file

@ -1,10 +1,12 @@
import base::{ext_ctxt, mac_result, mr_expr, mr_def, expr_tt}; import base::{ext_ctxt, mac_result, mr_expr, mr_def, expr_tt};
import codemap::span; import codemap::span;
import ast::{ident, matcher_, matcher, mtc_tok, mtc_bb, mtc_rep, tt_delim}; import ast::{ident, matcher_, matcher, match_tok,
match_nonterminal, match_seq, tt_delim};
import parse::lexer::{new_tt_reader, tt_reader_as_reader, reader}; import parse::lexer::{new_tt_reader, tt_reader_as_reader, reader};
import parse::token::{FAT_ARROW, SEMI, LBRACE, RBRACE, w_mtcs, w_tt}; import parse::token::{FAT_ARROW, SEMI, LBRACE, RBRACE, nt_matchers, nt_tt};
import parse::parser::{parser, SOURCE_FILE}; import parse::parser::{parser, SOURCE_FILE};
import earley_parser::{parse, success, failure, arb_depth, seq, leaf}; import earley_parser::{parse, success, failure, named_match,
matched_seq, matched_nonterminal};
import std::map::hashmap; import std::map::hashmap;
@ -17,10 +19,10 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
} }
let argument_gram = ~[ let argument_gram = ~[
ms(mtc_rep(~[ ms(match_seq(~[
ms(mtc_bb(@~"lhs",@~"mtcs", 0u)), ms(match_nonterminal(@~"lhs",@~"matchers", 0u)),
ms(mtc_tok(FAT_ARROW)), ms(match_tok(FAT_ARROW)),
ms(mtc_bb(@~"rhs",@~"tt", 1u)), ms(match_nonterminal(@~"rhs",@~"tt", 1u)),
], some(SEMI), false, 0u, 2u))]; ], some(SEMI), false, 0u, 2u))];
let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic, let arg_reader = new_tt_reader(cx.parse_sess().span_diagnostic,
@ -32,16 +34,16 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
}; };
let lhses = alt arguments.get(@~"lhs") { let lhses = alt arguments.get(@~"lhs") {
@seq(s, sp) { s } @matched_seq(s, sp) { s }
_ { cx.span_bug(sp, ~"wrong-structured lhs") } _ { cx.span_bug(sp, ~"wrong-structured lhs") }
}; };
let rhses = alt arguments.get(@~"rhs") { let rhses = alt arguments.get(@~"rhs") {
@seq(s, sp) { s } @matched_seq(s, sp) { s }
_ { cx.span_bug(sp, ~"wrong-structured rhs") } _ { cx.span_bug(sp, ~"wrong-structured rhs") }
}; };
fn generic_extension(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree], fn generic_extension(cx: ext_ctxt, sp: span, arg: ~[ast::token_tree],
lhses: ~[@arb_depth], rhses: ~[@arb_depth]) lhses: ~[@named_match], rhses: ~[@named_match])
-> mac_result { -> mac_result {
let mut best_fail_spot = {lo: 0u, hi: 0u, expn_info: none}; let mut best_fail_spot = {lo: 0u, hi: 0u, expn_info: none};
let mut best_fail_msg = ~"internal error: ran no matchers"; let mut best_fail_msg = ~"internal error: ran no matchers";
@ -51,12 +53,12 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
for lhses.eachi() |i, lhs| { for lhses.eachi() |i, lhs| {
alt lhs { alt lhs {
@leaf(w_mtcs(mtcs)) { @matched_nonterminal(nt_matchers(mtcs)) {
let arg_rdr = new_tt_reader(s_d, itr, none, arg) as reader; let arg_rdr = new_tt_reader(s_d, itr, none, arg) as reader;
alt parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtcs) { alt parse(cx.parse_sess(), cx.cfg(), arg_rdr, mtcs) {
success(m) { success(m) {
let rhs = alt rhses[i] { let rhs = alt rhses[i] {
@leaf(w_tt(@tt)) { tt } @matched_nonterminal(nt_tt(@tt)) { tt }
_ { cx.span_bug(sp, ~"bad thing in rhs") } _ { cx.span_bug(sp, ~"bad thing in rhs") }
}; };
let trncbr = new_tt_reader(s_d, itr, some(m), ~[rhs]); let trncbr = new_tt_reader(s_d, itr, some(m), ~[rhs]);

View file

@ -1,10 +1,10 @@
import util::interner::interner; import util::interner::interner;
import diagnostic::span_handler; import diagnostic::span_handler;
import ast::{token_tree,tt_delim,tt_flat,tt_dotdotdot,tt_interpolate,ident}; import ast::{token_tree, tt_delim, tt_tok, tt_seq, tt_nonterminal,ident};
import earley_parser::{arb_depth,seq,leaf}; import earley_parser::{named_match, matched_seq, matched_nonterminal};
import codemap::span; import codemap::span;
import parse::token::{EOF,ACTUALLY,IDENT,token,w_ident}; import parse::token::{EOF, INTERPOLATED, IDENT, token, nt_ident};
import std::map::{hashmap,box_str_hash}; import std::map::{hashmap, box_str_hash};
export tt_reader, new_tt_reader, dup_tt_reader, tt_next_token; export tt_reader, new_tt_reader, dup_tt_reader, tt_next_token;
@ -28,7 +28,7 @@ type tt_reader = @{
interner: @interner<@~str>, interner: @interner<@~str>,
mut cur: tt_frame, mut cur: tt_frame,
/* for MBE-style macro transcription */ /* for MBE-style macro transcription */
interpolations: std::map::hashmap<ident, @arb_depth>, interpolations: std::map::hashmap<ident, @named_match>,
mut repeat_idx: ~[mut uint], mut repeat_idx: ~[mut uint],
mut repeat_len: ~[uint], mut repeat_len: ~[uint],
/* cached: */ /* cached: */
@ -37,17 +37,17 @@ type tt_reader = @{
}; };
/** This can do Macro-By-Example transcription. On the other hand, if /** This can do Macro-By-Example transcription. On the other hand, if
* `src` contains no `tt_dotdotdot`s and `tt_interpolate`s, `interp` can (and * `src` contains no `tt_seq`s and `tt_nonterminal`s, `interp` can (and
* should) be none. */ * should) be none. */
fn new_tt_reader(sp_diag: span_handler, itr: @interner<@~str>, fn new_tt_reader(sp_diag: span_handler, itr: @interner<@~str>,
interp: option<std::map::hashmap<ident,@arb_depth>>, interp: option<std::map::hashmap<ident,@named_match>>,
src: ~[ast::token_tree]) src: ~[ast::token_tree])
-> tt_reader { -> tt_reader {
let r = @{sp_diag: sp_diag, interner: itr, let r = @{sp_diag: sp_diag, interner: itr,
mut cur: @{readme: src, mut idx: 0u, dotdotdoted: false, mut cur: @{readme: src, mut idx: 0u, dotdotdoted: false,
sep: none, up: tt_frame_up(option::none)}, sep: none, up: tt_frame_up(option::none)},
interpolations: alt interp { /* just a convienience */ interpolations: alt interp { /* just a convienience */
none { std::map::box_str_hash::<@arb_depth>() } none { std::map::box_str_hash::<@named_match>() }
some(x) { x } some(x) { x }
}, },
mut repeat_idx: ~[mut], mut repeat_len: ~[], mut repeat_idx: ~[mut], mut repeat_len: ~[],
@ -79,18 +79,22 @@ pure fn dup_tt_reader(&&r: tt_reader) -> tt_reader {
} }
pure fn lookup_cur_ad_by_ad(r: tt_reader, start: @arb_depth) -> @arb_depth { pure fn lookup_cur_matched_by_matched(r: tt_reader,
pure fn red(&&ad: @arb_depth, &&idx: uint) -> @arb_depth { start: @named_match) -> @named_match {
pure fn red(&&ad: @named_match, &&idx: uint) -> @named_match {
alt *ad { alt *ad {
leaf(_) { ad /* end of the line; duplicate henceforth */ } matched_nonterminal(_) {
seq(ads, _) { ads[idx] } // end of the line; duplicate henceforth
ad
}
matched_seq(ads, _) { ads[idx] }
} }
} }
vec::foldl(start, r.repeat_idx, red) vec::foldl(start, r.repeat_idx, red)
} }
fn lookup_cur_ad(r: tt_reader, name: ident) -> @arb_depth { fn lookup_cur_matched(r: tt_reader, name: ident) -> @named_match {
lookup_cur_ad_by_ad(r, r.interpolations.get(name)) lookup_cur_matched_by_matched(r, r.interpolations.get(name))
} }
enum lis { enum lis {
lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str) lis_unconstrained, lis_constraint(uint, ident), lis_contradiction(~str)
@ -116,15 +120,15 @@ fn lockstep_iter_size(&&t: token_tree, &&r: tt_reader) -> lis {
} }
} }
alt t { alt t {
tt_delim(tts) | tt_dotdotdot(_, tts, _, _) { tt_delim(tts) | tt_seq(_, tts, _, _) {
vec::foldl(lis_unconstrained, tts, {|lis, tt| vec::foldl(lis_unconstrained, tts, {|lis, tt|
lis_merge(lis, lockstep_iter_size(tt, r)) }) lis_merge(lis, lockstep_iter_size(tt, r)) })
} }
tt_flat(*) { lis_unconstrained } tt_tok(*) { lis_unconstrained }
tt_interpolate(_, name) { tt_nonterminal(_, name) {
alt *lookup_cur_ad(r, name) { alt *lookup_cur_matched(r, name) {
leaf(_) { lis_unconstrained } matched_nonterminal(_) { lis_unconstrained }
seq(ads, _) { lis_constraint(ads.len(), name) } matched_seq(ads, _) { lis_constraint(ads.len(), name) }
} }
} }
} }
@ -166,20 +170,20 @@ fn tt_next_token(&&r: tt_reader) -> {tok: token, sp: span} {
} }
} }
loop { /* because it's easiest, this handles `tt_delim` not starting loop { /* because it's easiest, this handles `tt_delim` not starting
with a `tt_flat`, even though it won't happen */ with a `tt_tok`, even though it won't happen */
alt r.cur.readme[r.cur.idx] { alt r.cur.readme[r.cur.idx] {
tt_delim(tts) { tt_delim(tts) {
r.cur = @{readme: tts, mut idx: 0u, dotdotdoted: false, r.cur = @{readme: tts, mut idx: 0u, dotdotdoted: false,
sep: none, up: tt_frame_up(option::some(r.cur)) }; sep: none, up: tt_frame_up(option::some(r.cur)) };
// if this could be 0-length, we'd need to potentially recur here // if this could be 0-length, we'd need to potentially recur here
} }
tt_flat(sp, tok) { tt_tok(sp, tok) {
r.cur_span = sp; r.cur_tok = tok; r.cur_span = sp; r.cur_tok = tok;
r.cur.idx += 1u; r.cur.idx += 1u;
ret ret_val; ret ret_val;
} }
tt_dotdotdot(sp, tts, sep, zerok) { tt_seq(sp, tts, sep, zerok) {
alt lockstep_iter_size(tt_dotdotdot(sp, tts, sep, zerok), r) { alt lockstep_iter_size(tt_seq(sp, tts, sep, zerok), r) {
lis_unconstrained { lis_unconstrained {
r.sp_diag.span_fatal( r.sp_diag.span_fatal(
sp, /* blame macro writer */ sp, /* blame macro writer */
@ -211,22 +215,22 @@ fn tt_next_token(&&r: tt_reader) -> {tok: token, sp: span} {
} }
} }
// FIXME #2887: think about span stuff here // FIXME #2887: think about span stuff here
tt_interpolate(sp, ident) { tt_nonterminal(sp, ident) {
alt *lookup_cur_ad(r, ident) { alt *lookup_cur_matched(r, ident) {
/* sidestep the interpolation tricks for ident because /* sidestep the interpolation tricks for ident because
(a) idents can be in lots of places, so it'd be a pain (a) idents can be in lots of places, so it'd be a pain
(b) we actually can, since it's a token. */ (b) we actually can, since it's a token. */
leaf(w_ident(sn,b)) { matched_nonterminal(nt_ident(sn,b)) {
r.cur_span = sp; r.cur_tok = IDENT(sn,b); r.cur_span = sp; r.cur_tok = IDENT(sn,b);
r.cur.idx += 1u; r.cur.idx += 1u;
ret ret_val; ret ret_val;
} }
leaf(w_nt) { matched_nonterminal(nt) {
r.cur_span = sp; r.cur_tok = ACTUALLY(w_nt); r.cur_span = sp; r.cur_tok = INTERPOLATED(nt);
r.cur.idx += 1u; r.cur.idx += 1u;
ret ret_val; ret ret_val;
} }
seq(*) { matched_seq(*) {
r.sp_diag.span_fatal( r.sp_diag.span_fatal(
copy r.cur_span, /* blame the macro writer */ copy r.cur_span, /* blame the macro writer */
#fmt["variable '%s' is still repeating at this depth", #fmt["variable '%s' is still repeating at this depth",

View file

@ -86,7 +86,7 @@ impl parser_common of parser_common for parser {
fn parse_ident() -> ast::ident { fn parse_ident() -> ast::ident {
alt copy self.token { alt copy self.token {
token::IDENT(i, _) { self.bump(); ret self.get_str(i); } token::IDENT(i, _) { self.bump(); ret self.get_str(i); }
token::ACTUALLY(token::w_ident(*)) { self.bug( token::INTERPOLATED(token::nt_ident(*)) { self.bug(
~"ident interpolation not converted to real token"); } ~"ident interpolation not converted to real token"); }
_ { self.fatal(~"expected ident, found `" _ { self.fatal(~"expected ident, found `"
+ token_to_str(self.reader, self.token) + token_to_str(self.reader, self.token)

View file

@ -3,7 +3,7 @@ import print::pprust::expr_to_str;
import result::result; import result::result;
import either::{either, left, right}; import either::{either, left, right};
import std::map::{hashmap, str_hash}; import std::map::{hashmap, str_hash};
import token::{can_begin_expr, is_ident, is_plain_ident, ACTUALLY}; import token::{can_begin_expr, is_ident, is_plain_ident, INTERPOLATED};
import codemap::{span,fss_none}; import codemap::{span,fss_none};
import util::interner; import util::interner;
import ast_util::{spanned, respan, mk_sp, ident_to_path, operator_prec}; import ast_util::{spanned, respan, mk_sp, ident_to_path, operator_prec};
@ -39,15 +39,15 @@ import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
item_ty, lit, lit_, lit_bool, lit_float, lit_int, item_ty, lit, lit_, lit_bool, lit_float, lit_int,
lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const, lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const,
m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis,
mac_invoc, mac_invoc_tt, mac_var, matcher, mac_invoc, mac_invoc_tt, mac_var, matcher, match_nonterminal,
method, mode, mt, mtc_bb, mtc_rep, mtc_tok, mul, mutability, neg, match_seq, match_tok, method, mode, mt, mul, mutability, neg,
noreturn, not, pat, pat_box, pat_enum, pat_ident, pat_lit, noreturn, not, pat, pat_box, pat_enum, pat_ident, pat_lit,
pat_range, pat_rec, pat_tup, pat_uniq, pat_wild, path, private, pat_range, pat_rec, pat_tup, pat_uniq, pat_wild, path, private,
proto, proto_any, proto_bare, proto_block, proto_box, proto_uniq, proto, proto_any, proto_bare, proto_block, proto_box, proto_uniq,
provided, public, pure_fn, purity, re_anon, re_named, region, provided, public, pure_fn, purity, re_anon, re_named, region,
rem, required, ret_style, return_val, shl, shr, stmt, stmt_decl, rem, required, ret_style, return_val, shl, shr, stmt, stmt_decl,
stmt_expr, stmt_semi, subtract, token_tree, trait_method, stmt_expr, stmt_semi, subtract, token_tree, trait_method,
trait_ref, tt_delim, tt_dotdotdot, tt_flat, tt_interpolate, ty, trait_ref, tt_delim, tt_seq, tt_tok, tt_nonterminal, ty,
ty_, ty_bot, ty_box, ty_field, ty_fn, ty_infer, ty_mac, ty_, ty_bot, ty_box, ty_field, ty_fn, ty_infer, ty_mac,
ty_method, ty_nil, ty_param, ty_path, ty_ptr, ty_rec, ty_rptr, ty_method, ty_nil, ty_param, ty_path, ty_ptr, ty_rec, ty_rptr,
ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length, unchecked_blk, ty_tup, ty_u32, ty_uniq, ty_vec, ty_fixed_length, unchecked_blk,
@ -104,14 +104,14 @@ type item_info = (ident, item_, option<~[attribute]>);
/* The expr situation is not as complex as I thought it would be. /* The expr situation is not as complex as I thought it would be.
The important thing is to make sure that lookahead doesn't balk The important thing is to make sure that lookahead doesn't balk
at ACTUALLY tokens */ at INTERPOLATED tokens */
macro_rules! maybe_whole_expr{ macro_rules! maybe_whole_expr {
{$p:expr} => { alt copy $p.token { {$p:expr} => { alt copy $p.token {
ACTUALLY(token::w_expr(e)) { INTERPOLATED(token::nt_expr(e)) {
$p.bump(); $p.bump();
ret pexpr(e); ret pexpr(e);
} }
ACTUALLY(token::w_path(pt)) { INTERPOLATED(token::nt_path(pt)) {
$p.bump(); $p.bump();
ret $p.mk_pexpr($p.span.lo, $p.span.lo, ret $p.mk_pexpr($p.span.lo, $p.span.lo,
expr_path(pt)); expr_path(pt));
@ -122,7 +122,7 @@ macro_rules! maybe_whole_expr{
macro_rules! maybe_whole { macro_rules! maybe_whole {
{$p:expr, $constructor:path} => { alt copy $p.token { {$p:expr, $constructor:path} => { alt copy $p.token {
ACTUALLY($constructor(x)) { $p.bump(); ret x; } INTERPOLATED($constructor(x)) { $p.bump(); ret x; }
_ {} _ {}
}} }}
} }
@ -133,7 +133,7 @@ fn dummy() {
/* we will need this to bootstrap maybe_whole! */ /* we will need this to bootstrap maybe_whole! */
#macro[[#maybe_whole_path[p], #macro[[#maybe_whole_path[p],
alt p.token { alt p.token {
ACTUALLY(token::w_path(pt)) { p.bump(); ret pt; } INTERPOLATED(token::nt_path(pt)) { p.bump(); ret pt; }
_ {} }]]; _ {} }]];
} }
@ -1090,7 +1090,7 @@ class parser {
} }
} }
fn parse_tt_flat(p: parser, delim_ok: bool) -> token_tree { fn parse_tt_tok(p: parser, delim_ok: bool) -> token_tree {
alt p.token { alt p.token {
token::RPAREN | token::RBRACE | token::RBRACKET token::RPAREN | token::RBRACE | token::RBRACKET
if !delim_ok { if !delim_ok {
@ -1110,14 +1110,14 @@ class parser {
seq_sep_none(), seq_sep_none(),
|p| p.parse_token_tree()); |p| p.parse_token_tree());
let (s, z) = p.parse_sep_and_zerok(); let (s, z) = p.parse_sep_and_zerok();
ret tt_dotdotdot(mk_sp(sp.lo ,p.span.hi), seq.node, s, z); ret tt_seq(mk_sp(sp.lo ,p.span.hi), seq.node, s, z);
} else { } else {
ret tt_interpolate(sp, p.parse_ident()); ret tt_nonterminal(sp, p.parse_ident());
} }
} }
_ { /* ok */ } _ { /* ok */ }
} }
let res = tt_flat(p.span, p.token); let res = tt_tok(p.span, p.token);
p.bump(); p.bump();
ret res; ret res;
} }
@ -1126,14 +1126,14 @@ class parser {
token::LPAREN | token::LBRACE | token::LBRACKET { token::LPAREN | token::LBRACE | token::LBRACKET {
let ket = flip(self.token); let ket = flip(self.token);
tt_delim(vec::append( tt_delim(vec::append(
~[parse_tt_flat(self, true)], ~[parse_tt_tok(self, true)],
vec::append( vec::append(
self.parse_seq_to_before_end( self.parse_seq_to_before_end(
ket, seq_sep_none(), ket, seq_sep_none(),
|p| p.parse_token_tree()), |p| p.parse_token_tree()),
~[parse_tt_flat(self, true)]))) ~[parse_tt_tok(self, true)])))
} }
_ { parse_tt_flat(self, false) } _ { parse_tt_tok(self, false) }
}; };
} }
@ -1177,17 +1177,17 @@ class parser {
self.fatal(~"repetition body must be nonempty"); self.fatal(~"repetition body must be nonempty");
} }
let (sep, zerok) = self.parse_sep_and_zerok(); let (sep, zerok) = self.parse_sep_and_zerok();
mtc_rep(ms, sep, zerok, name_idx_lo, *name_idx) match_seq(ms, sep, zerok, name_idx_lo, *name_idx)
} else { } else {
let bound_to = self.parse_ident(); let bound_to = self.parse_ident();
self.expect(token::COLON); self.expect(token::COLON);
let nt_name = self.parse_ident(); let nt_name = self.parse_ident();
let m = mtc_bb(bound_to, nt_name, *name_idx); let m = match_nonterminal(bound_to, nt_name, *name_idx);
*name_idx += 1u; *name_idx += 1u;
m m
} }
} else { } else {
let m = mtc_tok(self.token); let m = match_tok(self.token);
self.bump(); self.bump();
m m
}; };

View file

@ -79,7 +79,7 @@ enum token {
UNDERSCORE, UNDERSCORE,
/* For interpolation */ /* For interpolation */
ACTUALLY(whole_nt), INTERPOLATED(nonterminal),
DOC_COMMENT(str_num), DOC_COMMENT(str_num),
EOF, EOF,
@ -87,17 +87,17 @@ enum token {
#[auto_serialize] #[auto_serialize]
/// For interpolation during macro expansion. /// For interpolation during macro expansion.
enum whole_nt { enum nonterminal {
w_item(@ast::item), nt_item(@ast::item),
w_block(ast::blk), nt_block(ast::blk),
w_stmt(@ast::stmt), nt_stmt(@ast::stmt),
w_pat( @ast::pat), nt_pat( @ast::pat),
w_expr(@ast::expr), nt_expr(@ast::expr),
w_ty( @ast::ty), nt_ty( @ast::ty),
w_ident(str_num, bool), nt_ident(str_num, bool),
w_path(@ast::path), nt_path(@ast::path),
w_tt( @ast::token_tree), //needs @ed to break a circularity nt_tt( @ast::token_tree), //needs @ed to break a circularity
w_mtcs(~[ast::matcher]) nt_matchers(~[ast::matcher])
} }
fn binop_to_str(o: binop) -> ~str { fn binop_to_str(o: binop) -> ~str {
@ -184,14 +184,14 @@ fn to_str(in: interner<@~str>, t: token) -> ~str {
/* Other */ /* Other */
DOC_COMMENT(s) { *interner::get(in, s) } DOC_COMMENT(s) { *interner::get(in, s) }
EOF { ~"<eof>" } EOF { ~"<eof>" }
ACTUALLY(w_nt) { INTERPOLATED(nt) {
~"an interpolated " + ~"an interpolated " +
alt w_nt { alt nt {
w_item(*) { ~"item" } w_block(*) { ~"block" } nt_item(*) { ~"item" } nt_block(*) { ~"block" }
w_stmt(*) { ~"statement" } w_pat(*) { ~"pattern" } nt_stmt(*) { ~"statement" } nt_pat(*) { ~"pattern" }
w_expr(*) { ~"expression" } w_ty(*) { ~"type" } nt_expr(*) { ~"expression" } nt_ty(*) { ~"type" }
w_ident(*) { ~"identifier" } w_path(*) { ~"path" } nt_ident(*) { ~"identifier" } nt_path(*) { ~"path" }
w_tt(*) { ~"tt" } w_mtcs(*) { ~"matcher sequence" } nt_tt(*) { ~"tt" } nt_matchers(*) { ~"matcher sequence" }
} }
} }
} }
@ -219,8 +219,10 @@ pure fn can_begin_expr(t: token) -> bool {
BINOP(OR) { true } // in lambda syntax BINOP(OR) { true } // in lambda syntax
OROR { true } // in lambda syntax OROR { true } // in lambda syntax
MOD_SEP { true } MOD_SEP { true }
ACTUALLY(w_expr(*)) | ACTUALLY(w_ident(*)) | ACTUALLY(w_block(*)) INTERPOLATED(nt_expr(*))
| ACTUALLY(w_path(*)) { true } | INTERPOLATED(nt_ident(*))
| INTERPOLATED(nt_block(*))
| INTERPOLATED(nt_path(*)) { true }
_ { false } _ { false }
} }
} }