syntax: use lookahead to distinguish inner and outer attributes, instead of passing the latter around.
This commit is contained in:
parent
79dd393a4f
commit
9889aae13e
11 changed files with 325 additions and 512 deletions
|
@ -361,8 +361,7 @@ pub mod rt {
|
||||||
parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
|
parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
|
||||||
s,
|
s,
|
||||||
self.cfg(),
|
self.cfg(),
|
||||||
Vec::new(),
|
self.parse_sess()).expect("parse error")
|
||||||
self.parse_sess())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&self, s: String) -> P<ast::Expr> {
|
fn parse_expr(&self, s: String) -> P<ast::Expr> {
|
||||||
|
@ -407,7 +406,7 @@ pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
tts: &[ast::TokenTree])
|
tts: &[ast::TokenTree])
|
||||||
-> Box<base::MacResult+'cx> {
|
-> Box<base::MacResult+'cx> {
|
||||||
let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts);
|
let expanded = expand_parse_call(cx, sp, "parse_expr", vec!(), tts);
|
||||||
base::MacEager::expr(expanded)
|
base::MacEager::expr(expanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,8 +414,7 @@ pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
tts: &[ast::TokenTree])
|
tts: &[ast::TokenTree])
|
||||||
-> Box<base::MacResult+'cx> {
|
-> Box<base::MacResult+'cx> {
|
||||||
let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes",
|
let expanded = expand_parse_call(cx, sp, "parse_item", vec!(), tts);
|
||||||
vec!(), tts);
|
|
||||||
base::MacEager::expr(expanded)
|
base::MacEager::expr(expanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,9 +446,7 @@ pub fn expand_quote_stmt(cx: &mut ExtCtxt,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
tts: &[ast::TokenTree])
|
tts: &[ast::TokenTree])
|
||||||
-> Box<base::MacResult+'static> {
|
-> Box<base::MacResult+'static> {
|
||||||
let e_attrs = cx.expr_vec_ng(sp);
|
let expanded = expand_parse_call(cx, sp, "parse_stmt", vec!(), tts);
|
||||||
let expanded = expand_parse_call(cx, sp, "parse_stmt",
|
|
||||||
vec!(e_attrs), tts);
|
|
||||||
base::MacEager::expr(expanded)
|
base::MacEager::expr(expanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree
|
||||||
-> Option<SmallVector<P<ast::Item>>> {
|
-> Option<SmallVector<P<ast::Item>>> {
|
||||||
let mut ret = SmallVector::zero();
|
let mut ret = SmallVector::zero();
|
||||||
while self.p.token != token::Eof {
|
while self.p.token != token::Eof {
|
||||||
match self.p.parse_item_with_outer_attributes() {
|
match self.p.parse_item() {
|
||||||
Some(item) => ret.push(item),
|
Some(item) => ret.push(item),
|
||||||
None => self.p.span_fatal(
|
None => self.p.span_fatal(
|
||||||
self.p.span,
|
self.p.span,
|
||||||
|
|
|
@ -521,12 +521,15 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal {
|
||||||
// check at the beginning and the parser checks after each bump
|
// check at the beginning and the parser checks after each bump
|
||||||
p.check_unknown_macro_variable();
|
p.check_unknown_macro_variable();
|
||||||
match name {
|
match name {
|
||||||
"item" => match p.parse_item(Vec::new()) {
|
"item" => match p.parse_item() {
|
||||||
Some(i) => token::NtItem(i),
|
Some(i) => token::NtItem(i),
|
||||||
None => p.fatal("expected an item keyword")
|
None => p.fatal("expected an item keyword")
|
||||||
},
|
},
|
||||||
"block" => token::NtBlock(p.parse_block()),
|
"block" => token::NtBlock(p.parse_block()),
|
||||||
"stmt" => token::NtStmt(p.parse_stmt(Vec::new())),
|
"stmt" => match p.parse_stmt() {
|
||||||
|
Some(s) => token::NtStmt(s),
|
||||||
|
None => p.fatal("expected a statement")
|
||||||
|
},
|
||||||
"pat" => token::NtPat(p.parse_pat()),
|
"pat" => token::NtPat(p.parse_pat()),
|
||||||
"expr" => token::NtExpr(p.parse_expr()),
|
"expr" => token::NtExpr(p.parse_expr()),
|
||||||
"ty" => token::NtTy(p.parse_ty()),
|
"ty" => token::NtTy(p.parse_ty()),
|
||||||
|
|
|
@ -17,7 +17,6 @@ use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
||||||
use ext::tt::macro_parser::{parse, parse_or_else};
|
use ext::tt::macro_parser::{parse, parse_or_else};
|
||||||
use parse::lexer::new_tt_reader;
|
use parse::lexer::new_tt_reader;
|
||||||
use parse::parser::Parser;
|
use parse::parser::Parser;
|
||||||
use parse::attr::ParserAttr;
|
|
||||||
use parse::token::{self, special_idents, gensym_ident, NtTT, Token};
|
use parse::token::{self, special_idents, gensym_ident, NtTT, Token};
|
||||||
use parse::token::Token::*;
|
use parse::token::Token::*;
|
||||||
use print;
|
use print;
|
||||||
|
@ -68,15 +67,8 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||||
}
|
}
|
||||||
fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
|
fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
|
||||||
let mut ret = SmallVector::zero();
|
let mut ret = SmallVector::zero();
|
||||||
loop {
|
while let Some(item) = self.parser.borrow_mut().parse_item() {
|
||||||
let mut parser = self.parser.borrow_mut();
|
ret.push(item);
|
||||||
// so... do outer attributes attached to the macro invocation
|
|
||||||
// just disappear? This question applies to make_impl_items, as
|
|
||||||
// well.
|
|
||||||
match parser.parse_item_with_outer_attributes() {
|
|
||||||
Some(item) => ret.push(item),
|
|
||||||
None => break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.ensure_complete_parse(false);
|
self.ensure_complete_parse(false);
|
||||||
Some(ret)
|
Some(ret)
|
||||||
|
@ -89,7 +81,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||||
let mut parser = self.parser.borrow_mut();
|
let mut parser = self.parser.borrow_mut();
|
||||||
match parser.token {
|
match parser.token {
|
||||||
token::Eof => break,
|
token::Eof => break,
|
||||||
_ => ret.push(parser.parse_impl_item_with_outer_attributes())
|
_ => ret.push(parser.parse_impl_item())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.ensure_complete_parse(false);
|
self.ensure_complete_parse(false);
|
||||||
|
@ -97,10 +89,9 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_stmt(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Stmt>> {
|
fn make_stmt(self: Box<ParserAnyMacro<'a>>) -> Option<P<ast::Stmt>> {
|
||||||
let attrs = self.parser.borrow_mut().parse_outer_attributes();
|
let ret = self.parser.borrow_mut().parse_stmt();
|
||||||
let ret = self.parser.borrow_mut().parse_stmt(attrs);
|
|
||||||
self.ensure_complete_parse(true);
|
self.ensure_complete_parse(true);
|
||||||
Some(ret)
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,8 @@ use ptr::P;
|
||||||
/// A parser that can parse attributes.
|
/// A parser that can parse attributes.
|
||||||
pub trait ParserAttr {
|
pub trait ParserAttr {
|
||||||
fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute>;
|
fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute>;
|
||||||
|
fn parse_inner_attributes(&mut self) -> Vec<ast::Attribute>;
|
||||||
fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
|
fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
|
||||||
fn parse_inner_attrs_and_next(&mut self)
|
|
||||||
-> (Vec<ast::Attribute>, Vec<ast::Attribute>);
|
|
||||||
fn parse_meta_item(&mut self) -> P<ast::MetaItem>;
|
fn parse_meta_item(&mut self) -> P<ast::MetaItem>;
|
||||||
fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>>;
|
fn parse_meta_seq(&mut self) -> Vec<P<ast::MetaItem>>;
|
||||||
fn parse_optional_meta(&mut self) -> Vec<P<ast::MetaItem>>;
|
fn parse_optional_meta(&mut self) -> Vec<P<ast::MetaItem>>;
|
||||||
|
@ -118,45 +117,40 @@ impl<'a> ParserAttr for Parser<'a> {
|
||||||
|
|
||||||
/// Parse attributes that appear after the opening of an item. These should
|
/// Parse attributes that appear after the opening of an item. These should
|
||||||
/// be preceded by an exclamation mark, but we accept and warn about one
|
/// be preceded by an exclamation mark, but we accept and warn about one
|
||||||
/// terminated by a semicolon. In addition to a vector of inner attributes,
|
/// terminated by a semicolon.
|
||||||
/// this function also returns a vector that may contain the first outer
|
|
||||||
/// attribute of the next item (since we can't know whether the attribute
|
|
||||||
/// is an inner attribute of the containing item or an outer attribute of
|
|
||||||
/// the first contained item until we see the semi).
|
|
||||||
|
|
||||||
/// matches inner_attrs* outer_attr?
|
/// matches inner_attrs*
|
||||||
/// you can make the 'next' field an Option, but the result is going to be
|
fn parse_inner_attributes(&mut self) -> Vec<ast::Attribute> {
|
||||||
/// more useful as a vector.
|
let mut attrs: Vec<ast::Attribute> = vec![];
|
||||||
fn parse_inner_attrs_and_next(&mut self)
|
|
||||||
-> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
|
|
||||||
let mut inner_attrs: Vec<ast::Attribute> = Vec::new();
|
|
||||||
let mut next_outer_attrs: Vec<ast::Attribute> = Vec::new();
|
|
||||||
loop {
|
loop {
|
||||||
let attr = match self.token {
|
match self.token {
|
||||||
token::Pound => {
|
token::Pound => {
|
||||||
self.parse_attribute(true)
|
// Don't even try to parse if it's not an inner attribute.
|
||||||
|
if !self.look_ahead(1, |t| t == &token::Not) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attr = self.parse_attribute(true);
|
||||||
|
assert!(attr.node.style == ast::AttrInner);
|
||||||
|
attrs.push(attr);
|
||||||
}
|
}
|
||||||
token::DocComment(s) => {
|
token::DocComment(s) => {
|
||||||
// we need to get the position of this token before we bump.
|
// we need to get the position of this token before we bump.
|
||||||
let Span { lo, hi, .. } = self.span;
|
let Span { lo, hi, .. } = self.span;
|
||||||
self.bump();
|
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(),
|
||||||
attr::mk_sugared_doc_attr(attr::mk_attr_id(),
|
self.id_to_interned_str(s.ident()),
|
||||||
self.id_to_interned_str(s.ident()),
|
lo, hi);
|
||||||
lo,
|
if attr.node.style == ast::AttrInner {
|
||||||
hi)
|
attrs.push(attr);
|
||||||
|
self.bump();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => break
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if attr.node.style == ast::AttrInner {
|
|
||||||
inner_attrs.push(attr);
|
|
||||||
} else {
|
|
||||||
next_outer_attrs.push(attr);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(inner_attrs, next_outer_attrs)
|
attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
/// matches meta_item = IDENT
|
/// matches meta_item = IDENT
|
||||||
|
|
|
@ -96,9 +96,7 @@ pub fn parse_crate_attrs_from_file(
|
||||||
cfg: ast::CrateConfig,
|
cfg: ast::CrateConfig,
|
||||||
sess: &ParseSess
|
sess: &ParseSess
|
||||||
) -> Vec<ast::Attribute> {
|
) -> Vec<ast::Attribute> {
|
||||||
let mut parser = new_parser_from_file(sess, cfg, input);
|
new_parser_from_file(sess, cfg, input).parse_inner_attributes()
|
||||||
let (inner, _) = parser.parse_inner_attrs_and_next();
|
|
||||||
inner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_crate_from_source_str(name: String,
|
pub fn parse_crate_from_source_str(name: String,
|
||||||
|
@ -122,8 +120,7 @@ pub fn parse_crate_attrs_from_source_str(name: String,
|
||||||
cfg,
|
cfg,
|
||||||
name,
|
name,
|
||||||
source);
|
source);
|
||||||
let (inner, _) = maybe_aborted(p.parse_inner_attrs_and_next(),p);
|
maybe_aborted(p.parse_inner_attributes(), p)
|
||||||
inner
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_expr_from_source_str(name: String,
|
pub fn parse_expr_from_source_str(name: String,
|
||||||
|
@ -141,7 +138,7 @@ pub fn parse_item_from_source_str(name: String,
|
||||||
sess: &ParseSess)
|
sess: &ParseSess)
|
||||||
-> Option<P<ast::Item>> {
|
-> Option<P<ast::Item>> {
|
||||||
let mut p = new_parser_from_source_str(sess, cfg, name, source);
|
let mut p = new_parser_from_source_str(sess, cfg, name, source);
|
||||||
maybe_aborted(p.parse_item_with_outer_attributes(),p)
|
maybe_aborted(p.parse_item(),p)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_meta_from_source_str(name: String,
|
pub fn parse_meta_from_source_str(name: String,
|
||||||
|
@ -156,16 +153,15 @@ pub fn parse_meta_from_source_str(name: String,
|
||||||
pub fn parse_stmt_from_source_str(name: String,
|
pub fn parse_stmt_from_source_str(name: String,
|
||||||
source: String,
|
source: String,
|
||||||
cfg: ast::CrateConfig,
|
cfg: ast::CrateConfig,
|
||||||
attrs: Vec<ast::Attribute> ,
|
|
||||||
sess: &ParseSess)
|
sess: &ParseSess)
|
||||||
-> P<ast::Stmt> {
|
-> Option<P<ast::Stmt>> {
|
||||||
let mut p = new_parser_from_source_str(
|
let mut p = new_parser_from_source_str(
|
||||||
sess,
|
sess,
|
||||||
cfg,
|
cfg,
|
||||||
name,
|
name,
|
||||||
source
|
source
|
||||||
);
|
);
|
||||||
maybe_aborted(p.parse_stmt(attrs),p)
|
maybe_aborted(p.parse_stmt(), p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
|
// Note: keep in sync with `with_hygiene::parse_tts_from_source_str`
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -58,14 +58,14 @@ pub fn string_to_expr (source_str : String) -> P<ast::Expr> {
|
||||||
/// Parse a string, return an item
|
/// Parse a string, return an item
|
||||||
pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
|
pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
|
||||||
with_error_checking_parse(source_str, |p| {
|
with_error_checking_parse(source_str, |p| {
|
||||||
p.parse_item(Vec::new())
|
p.parse_item()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a string, return a stmt
|
/// Parse a string, return a stmt
|
||||||
pub fn string_to_stmt(source_str : String) -> P<ast::Stmt> {
|
pub fn string_to_stmt(source_str : String) -> P<ast::Stmt> {
|
||||||
with_error_checking_parse(source_str, |p| {
|
with_error_checking_parse(source_str, |p| {
|
||||||
p.parse_stmt(Vec::new())
|
p.parse_stmt().unwrap()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,4 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
# //~ ERROR 11:1: 11:2 error: expected one of `!` or `[`, found `<eof>`
|
# //~ ERROR 11:1: 11:2 error: expected `[`, found `<eof>`
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// error-pattern:expected one of `!` or `[`, found `vec`
|
// error-pattern:expected `[`, found `vec`
|
||||||
mod blade_runner {
|
mod blade_runner {
|
||||||
#vec[doc(
|
#vec[doc(
|
||||||
brief = "Blade Runner is probably the best movie ever",
|
brief = "Blade Runner is probably the best movie ever",
|
||||||
|
|
|
@ -25,7 +25,7 @@ fn syntax_extension(cx: &ExtCtxt) {
|
||||||
let a: P<syntax::ast::Expr> = quote_expr!(cx, 1 + 2);
|
let a: P<syntax::ast::Expr> = quote_expr!(cx, 1 + 2);
|
||||||
let _b: Option<P<syntax::ast::Item>> = quote_item!(cx, static foo : int = $e_toks; );
|
let _b: Option<P<syntax::ast::Item>> = quote_item!(cx, static foo : int = $e_toks; );
|
||||||
let _c: P<syntax::ast::Pat> = quote_pat!(cx, (x, 1 .. 4, *) );
|
let _c: P<syntax::ast::Pat> = quote_pat!(cx, (x, 1 .. 4, *) );
|
||||||
let _d: P<syntax::ast::Stmt> = quote_stmt!(cx, let x = $a; );
|
let _d: Option<P<syntax::ast::Stmt>> = quote_stmt!(cx, let x = $a; );
|
||||||
let _d: syntax::ast::Arm = quote_arm!(cx, (ref x, ref y) = (x, y) );
|
let _d: syntax::ast::Arm = quote_arm!(cx, (ref x, ref y) = (x, y) );
|
||||||
let _e: P<syntax::ast::Expr> = quote_expr!(cx, match foo { $p_toks => 10 } );
|
let _e: P<syntax::ast::Expr> = quote_expr!(cx, match foo { $p_toks => 10 } );
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue