syntax: use lookahead to distinguish inner and outer attributes, instead of passing the latter around.

This commit is contained in:
Eduard Burtescu 2015-03-13 11:34:51 +02:00
parent 79dd393a4f
commit 9889aae13e
11 changed files with 325 additions and 512 deletions

View file

@ -361,8 +361,7 @@ pub mod rt {
parse::parse_stmt_from_source_str("<quote expansion>".to_string(),
s,
self.cfg(),
Vec::new(),
self.parse_sess())
self.parse_sess()).expect("parse error")
}
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,
tts: &[ast::TokenTree])
-> 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)
}
@ -415,8 +414,7 @@ pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt,
sp: Span,
tts: &[ast::TokenTree])
-> Box<base::MacResult+'cx> {
let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes",
vec!(), tts);
let expanded = expand_parse_call(cx, sp, "parse_item", vec!(), tts);
base::MacEager::expr(expanded)
}
@ -448,9 +446,7 @@ pub fn expand_quote_stmt(cx: &mut ExtCtxt,
sp: Span,
tts: &[ast::TokenTree])
-> Box<base::MacResult+'static> {
let e_attrs = cx.expr_vec_ng(sp);
let expanded = expand_parse_call(cx, sp, "parse_stmt",
vec!(e_attrs), tts);
let expanded = expand_parse_call(cx, sp, "parse_stmt", vec!(), tts);
base::MacEager::expr(expanded)
}

View file

@ -115,7 +115,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree
-> Option<SmallVector<P<ast::Item>>> {
let mut ret = SmallVector::zero();
while self.p.token != token::Eof {
match self.p.parse_item_with_outer_attributes() {
match self.p.parse_item() {
Some(item) => ret.push(item),
None => self.p.span_fatal(
self.p.span,

View file

@ -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
p.check_unknown_macro_variable();
match name {
"item" => match p.parse_item(Vec::new()) {
"item" => match p.parse_item() {
Some(i) => token::NtItem(i),
None => p.fatal("expected an item keyword")
},
"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()),
"expr" => token::NtExpr(p.parse_expr()),
"ty" => token::NtTy(p.parse_ty()),

View file

@ -17,7 +17,6 @@ use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
use ext::tt::macro_parser::{parse, parse_or_else};
use parse::lexer::new_tt_reader;
use parse::parser::Parser;
use parse::attr::ParserAttr;
use parse::token::{self, special_idents, gensym_ident, NtTT, Token};
use parse::token::Token::*;
use print;
@ -68,15 +67,8 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
}
fn make_items(self: Box<ParserAnyMacro<'a>>) -> Option<SmallVector<P<ast::Item>>> {
let mut ret = SmallVector::zero();
loop {
let mut parser = self.parser.borrow_mut();
// 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
}
while let Some(item) = self.parser.borrow_mut().parse_item() {
ret.push(item);
}
self.ensure_complete_parse(false);
Some(ret)
@ -89,7 +81,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
let mut parser = self.parser.borrow_mut();
match parser.token {
token::Eof => break,
_ => ret.push(parser.parse_impl_item_with_outer_attributes())
_ => ret.push(parser.parse_impl_item())
}
}
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>> {
let attrs = self.parser.borrow_mut().parse_outer_attributes();
let ret = self.parser.borrow_mut().parse_stmt(attrs);
let ret = self.parser.borrow_mut().parse_stmt();
self.ensure_complete_parse(true);
Some(ret)
ret
}
}

View file

@ -19,9 +19,8 @@ use ptr::P;
/// A parser that can parse attributes.
pub trait ParserAttr {
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_inner_attrs_and_next(&mut self)
-> (Vec<ast::Attribute>, Vec<ast::Attribute>);
fn parse_meta_item(&mut self) -> P<ast::MetaItem>;
fn parse_meta_seq(&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
/// 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,
/// 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).
/// terminated by a semicolon.
/// matches inner_attrs* outer_attr?
/// you can make the 'next' field an Option, but the result is going to be
/// more useful as a vector.
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();
/// matches inner_attrs*
fn parse_inner_attributes(&mut self) -> Vec<ast::Attribute> {
let mut attrs: Vec<ast::Attribute> = vec![];
loop {
let attr = match self.token {
match self.token {
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) => {
// we need to get the position of this token before we bump.
let Span { lo, hi, .. } = self.span;
self.bump();
attr::mk_sugared_doc_attr(attr::mk_attr_id(),
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(),
self.id_to_interned_str(s.ident()),
lo,
hi)
}
_ => {
break;
}
};
lo, hi);
if attr.node.style == ast::AttrInner {
inner_attrs.push(attr);
attrs.push(attr);
self.bump();
} else {
next_outer_attrs.push(attr);
break;
}
}
(inner_attrs, next_outer_attrs)
_ => break
}
}
attrs
}
/// matches meta_item = IDENT

View file

@ -96,9 +96,7 @@ pub fn parse_crate_attrs_from_file(
cfg: ast::CrateConfig,
sess: &ParseSess
) -> Vec<ast::Attribute> {
let mut parser = new_parser_from_file(sess, cfg, input);
let (inner, _) = parser.parse_inner_attrs_and_next();
inner
new_parser_from_file(sess, cfg, input).parse_inner_attributes()
}
pub fn parse_crate_from_source_str(name: String,
@ -122,8 +120,7 @@ pub fn parse_crate_attrs_from_source_str(name: String,
cfg,
name,
source);
let (inner, _) = maybe_aborted(p.parse_inner_attrs_and_next(),p);
inner
maybe_aborted(p.parse_inner_attributes(), p)
}
pub fn parse_expr_from_source_str(name: String,
@ -141,7 +138,7 @@ pub fn parse_item_from_source_str(name: String,
sess: &ParseSess)
-> Option<P<ast::Item>> {
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,
@ -156,16 +153,15 @@ pub fn parse_meta_from_source_str(name: String,
pub fn parse_stmt_from_source_str(name: String,
source: String,
cfg: ast::CrateConfig,
attrs: Vec<ast::Attribute> ,
sess: &ParseSess)
-> P<ast::Stmt> {
-> Option<P<ast::Stmt>> {
let mut p = new_parser_from_source_str(
sess,
cfg,
name,
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`

View file

@ -39,7 +39,7 @@ use ast::{LitStr, LitInt, Local, LocalLet};
use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
use ast::{MutTy, BiMul, Mutability};
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, NodeId, UnNot};
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct};
use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle};
use ast::{PolyTraitRef, QSelf};
@ -117,11 +117,6 @@ pub enum BoundParsingMode {
Modified,
}
/// The `Err` case indicates a failure to parse any kind of item.
/// The attributes are returned.
type MaybeItem = Result<P<Item>, Vec<Attribute>>;
/// Possibly accept an `token::Interpolated` expression (a pre-parsed expression
/// dropped into the token stream, which happens while parsing the result of
/// macro expansion). Placement of these is not as complex as I feared it would
@ -208,7 +203,7 @@ macro_rules! maybe_whole {
}
}
);
(Some $p:expr, $constructor:ident) => (
(Some deref $p:expr, $constructor:ident) => (
{
let found = match ($p).token {
token::Interpolated(token::$constructor(_)) => {
@ -217,7 +212,7 @@ macro_rules! maybe_whole {
_ => None
};
if let Some(token::Interpolated(token::$constructor(x))) = found {
return Some(x.clone());
return Some((*x).clone());
}
}
);
@ -1240,41 +1235,6 @@ impl<'a> Parser<'a> {
}
}
/// Parses `type Foo;` in a trait declaration only. The `type` keyword has
/// already been parsed.
fn parse_assoc_ty_in_trait(&mut self, attrs: Vec<Attribute>)
-> P<TraitItem> {
let TyParam {id, ident, bounds, default, span} = self.parse_ty_param();
self.expect(&token::Semi);
P(TraitItem {
id: id,
ident: ident,
attrs: attrs,
node: TypeTraitItem(bounds, default),
span: span,
})
}
/// Parses `type Foo = TYPE;` in an implementation declaration only. The
/// `type` keyword has already been parsed.
fn parse_assoc_ty_in_impl(&mut self, attrs: Vec<Attribute>, vis: Visibility)
-> P<ImplItem> {
let lo = self.span.lo;
let ident = self.parse_ident();
self.expect(&token::Eq);
let typ = self.parse_ty_sum();
let hi = self.span.hi;
self.expect(&token::Semi);
P(ImplItem {
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
ident: ident,
vis: vis,
attrs: attrs,
node: TypeImplItem(typ),
})
}
/// Parse the items in a trait declaration
pub fn parse_trait_items(&mut self) -> Vec<P<TraitItem>> {
self.parse_unspanned_seq(
@ -1282,13 +1242,14 @@ impl<'a> Parser<'a> {
&token::CloseDelim(token::Brace),
seq_sep_none(),
|p| {
let lo = p.span.lo;
let mut attrs = p.parse_outer_attributes();
if p.eat_keyword(keywords::Type) {
p.parse_assoc_ty_in_trait(attrs)
let (name, node) = if p.eat_keyword(keywords::Type) {
let TyParam {ident, bounds, default, ..} = p.parse_ty_param();
p.expect(&token::Semi);
(ident, TypeTraitItem(bounds, default))
} else {
let lo = p.span.lo;
let style = p.parse_unsafety();
let abi = if p.eat_keyword(keywords::Extern) {
p.parse_opt_abi().unwrap_or(abi::C)
@ -1316,7 +1277,6 @@ impl<'a> Parser<'a> {
explicit_self: explicit_self,
};
let hi = p.last_span.hi;
let body = match p.token {
token::Semi => {
p.bump();
@ -1337,15 +1297,16 @@ impl<'a> Parser<'a> {
token_str)[..])
}
};
(ident, ast::MethodTraitItem(sig, body))
};
P(TraitItem {
id: ast::DUMMY_NODE_ID,
ident: ident,
ident: name,
attrs: attrs,
node: ast::MethodTraitItem(sig, body),
span: mk_sp(lo, hi),
node: node,
span: mk_sp(lo, p.last_span.hi),
})
}
})
}
@ -3647,41 +3608,47 @@ impl<'a> Parser<'a> {
})
}
/// Get an expected item after attributes error message.
fn expected_item_err(attrs: &[Attribute]) -> &'static str {
match attrs.last() {
/// Emit an expected item after attributes error.
fn expected_item_err(&self, attrs: &[Attribute]) {
let message = match attrs.last() {
Some(&Attribute { node: ast::Attribute_ { is_sugared_doc: true, .. }, .. }) => {
"expected item after doc comment"
}
_ => "expected item after attributes",
}
};
self.span_err(self.last_span, message);
}
/// Parse a statement. may include decl.
/// Precondition: any attributes are parsed already
pub fn parse_stmt(&mut self, item_attrs: Vec<Attribute>) -> P<Stmt> {
maybe_whole!(self, NtStmt);
pub fn parse_stmt(&mut self) -> Option<P<Stmt>> {
self.parse_stmt_().map(P)
}
fn parse_stmt_(&mut self) -> Option<Stmt> {
maybe_whole!(Some deref self, NtStmt);
fn check_expected_item(p: &mut Parser, attrs: &[Attribute]) {
// If we have attributes then we should have an item
if !attrs.is_empty() {
let last_span = p.last_span;
p.span_err(last_span, Parser::expected_item_err(attrs));
p.expected_item_err(attrs);
}
}
let lo = self.span.lo;
if self.check_keyword(keywords::Let) {
check_expected_item(self, &item_attrs[..]);
let attrs = self.parse_outer_attributes();
Some(if self.check_keyword(keywords::Let) {
check_expected_item(self, &attrs);
self.expect_keyword(keywords::Let);
let decl = self.parse_let();
P(spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID)))
spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID))
} else if self.token.is_ident()
&& !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not) {
// it's a macro invocation:
check_expected_item(self, &item_attrs[..]);
check_expected_item(self, &attrs);
// Potential trouble: if we allow macros with paths instead of
// idents, we'd need to look ahead past the whole path here...
@ -3728,12 +3695,11 @@ impl<'a> Parser<'a> {
};
if id.name == token::special_idents::invalid.name {
P(spanned(lo,
hi,
spanned(lo, hi,
StmtMac(P(spanned(lo,
hi,
MacInvocTT(pth, tts, EMPTY_CTXT))),
style)))
style))
} else {
// if it has a special ident, it's definitely an item
//
@ -3747,35 +3713,38 @@ impl<'a> Parser<'a> {
followed by a semicolon");
}
}
P(spanned(lo, hi, StmtDecl(
spanned(lo, hi, StmtDecl(
P(spanned(lo, hi, DeclItem(
self.mk_item(
lo, hi, id /*id is good here*/,
ItemMac(spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT))),
Inherited, Vec::new(/*no attrs*/))))),
ast::DUMMY_NODE_ID)))
ast::DUMMY_NODE_ID))
}
} else {
let found_attrs = !item_attrs.is_empty();
let item_err = Parser::expected_item_err(&item_attrs[..]);
match self.parse_item_(item_attrs, false) {
Ok(i) => {
match self.parse_item_(attrs, false) {
Some(i) => {
let hi = i.span.hi;
let decl = P(spanned(lo, hi, DeclItem(i)));
P(spanned(lo, hi, StmtDecl(decl, ast::DUMMY_NODE_ID)))
spanned(lo, hi, StmtDecl(decl, ast::DUMMY_NODE_ID))
}
Err(_) => {
if found_attrs {
let last_span = self.last_span;
self.span_err(last_span, item_err);
None => {
// Do not attempt to parse an expression if we're done here.
if self.token == token::Semi {
self.bump();
return None;
}
if self.token == token::CloseDelim(token::Brace) {
return None;
}
// Remainder are line-expr stmts.
let e = self.parse_expr_res(RESTRICTION_STMT_EXPR);
P(spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)))
}
spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID))
}
}
})
}
/// Is this expression a successfully-parsed statement?
@ -3798,61 +3767,35 @@ impl<'a> Parser<'a> {
"place this code inside a block");
}
return self.parse_block_tail_(lo, DefaultBlock, Vec::new());
self.parse_block_tail(lo, DefaultBlock)
}
/// Parse a block. Inner attrs are allowed.
fn parse_inner_attrs_and_block(&mut self)
-> (Vec<Attribute> , P<Block>) {
fn parse_inner_attrs_and_block(&mut self) -> (Vec<Attribute>, P<Block>) {
maybe_whole!(pair_empty self, NtBlock);
let lo = self.span.lo;
self.expect(&token::OpenDelim(token::Brace));
let (inner, next) = self.parse_inner_attrs_and_next();
(inner, self.parse_block_tail_(lo, DefaultBlock, next))
}
/// Precondition: already parsed the '{'.
fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> P<Block> {
self.parse_block_tail_(lo, s, Vec::new())
(self.parse_inner_attributes(),
self.parse_block_tail(lo, DefaultBlock))
}
/// Parse the rest of a block expression or function body
fn parse_block_tail_(&mut self, lo: BytePos, s: BlockCheckMode,
first_item_attrs: Vec<Attribute>) -> P<Block> {
/// Precondition: already parsed the '{'.
fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> P<Block> {
let mut stmts = vec![];
let mut expr = None;
let mut attributes_box = first_item_attrs;
while self.token != token::CloseDelim(token::Brace) {
// parsing items even when they're not allowed lets us give
// better error messages and recover more gracefully.
attributes_box.push_all(&self.parse_outer_attributes());
match self.token {
token::Semi => {
if !attributes_box.is_empty() {
let last_span = self.last_span;
self.span_err(last_span,
Parser::expected_item_err(&attributes_box[..]));
attributes_box = Vec::new();
}
self.bump(); // empty
}
token::CloseDelim(token::Brace) => {
// fall through and out.
}
_ => {
let stmt = self.parse_stmt(attributes_box);
attributes_box = Vec::new();
stmt.and_then(|Spanned {node, span}| match node {
StmtExpr(e, stmt_id) => {
self.handle_expression_like_statement(e,
stmt_id,
span,
&mut stmts,
&mut expr);
while !self.eat(&token::CloseDelim(token::Brace)) {
let Spanned {node, span} = if let Some(s) = self.parse_stmt_() {
s
} else {
// Found only `;` or `}`.
continue;
};
match node {
StmtExpr(e, _) => {
self.handle_expression_like_statement(e, span, &mut stmts, &mut expr);
}
StmtMac(mac, MacStmtWithoutBraces) => {
// statement macro without braces; might be an
@ -3860,22 +3803,19 @@ impl<'a> Parser<'a> {
match self.token {
token::Semi => {
stmts.push(P(Spanned {
node: StmtMac(mac,
MacStmtWithSemicolon),
node: StmtMac(mac, MacStmtWithSemicolon),
span: span,
}));
self.bump();
}
_ => {
let e = self.mk_mac_expr(span.lo,
span.hi,
let e = self.mk_mac_expr(span.lo, span.hi,
mac.and_then(|m| m.node));
let e = self.parse_dot_or_call_expr_with(e);
let e = self.parse_more_binops(e, 0);
let e = self.parse_assign_expr_with(e);
self.handle_expression_like_statement(
e,
ast::DUMMY_NODE_ID,
span,
&mut stmts,
&mut expr);
@ -3887,8 +3827,7 @@ impl<'a> Parser<'a> {
match self.token {
token::Semi => {
stmts.push(P(Spanned {
node: StmtMac(m,
MacStmtWithSemicolon),
node: StmtMac(m, MacStmtWithSemicolon),
span: span,
}));
self.bump();
@ -3896,9 +3835,7 @@ impl<'a> Parser<'a> {
token::CloseDelim(token::Brace) => {
// if a block ends in `m!(arg)` without
// a `;`, it must be an expr
expr = Some(
self.mk_mac_expr(span.lo,
span.hi,
expr = Some(self.mk_mac_expr(span.lo, span.hi,
m.and_then(|x| x.node)));
}
_ => {
@ -3919,32 +3856,21 @@ impl<'a> Parser<'a> {
span: span
}));
}
})
}
}
}
if !attributes_box.is_empty() {
let last_span = self.last_span;
self.span_err(last_span,
Parser::expected_item_err(&attributes_box[..]));
}
let hi = self.span.hi;
self.bump();
P(ast::Block {
stmts: stmts,
expr: expr,
id: ast::DUMMY_NODE_ID,
rules: s,
span: mk_sp(lo, hi),
span: mk_sp(lo, self.last_span.hi),
})
}
fn handle_expression_like_statement(
&mut self,
e: P<Expr>,
stmt_id: NodeId,
span: Span,
stmts: &mut Vec<P<Stmt>>,
last_block_expr: &mut Option<P<Expr>>) {
@ -3964,14 +3890,14 @@ impl<'a> Parser<'a> {
expn_id: span.expn_id,
};
stmts.push(P(Spanned {
node: StmtSemi(e, stmt_id),
node: StmtSemi(e, ast::DUMMY_NODE_ID),
span: span_with_semi,
}));
}
token::CloseDelim(token::Brace) => *last_block_expr = Some(e),
_ => {
stmts.push(P(Spanned {
node: StmtExpr(e, stmt_id),
node: StmtExpr(e, ast::DUMMY_NODE_ID),
span: span
}));
}
@ -4626,14 +4552,30 @@ impl<'a> Parser<'a> {
}
/// Parse an impl item.
pub fn parse_impl_item_with_outer_attributes(&mut self) -> P<ImplItem> {
let attrs = self.parse_outer_attributes();
pub fn parse_impl_item(&mut self) -> P<ImplItem> {
let lo = self.span.lo;
let mut attrs = self.parse_outer_attributes();
let vis = self.parse_visibility();
if self.eat_keyword(keywords::Type) {
self.parse_assoc_ty_in_impl(attrs, vis)
let (name, node) = if self.eat_keyword(keywords::Type) {
let name = self.parse_ident();
self.expect(&token::Eq);
let typ = self.parse_ty_sum();
self.expect(&token::Semi);
(name, TypeImplItem(typ))
} else {
self.parse_method(attrs, vis)
}
let (name, inner_attrs, node) = self.parse_impl_method(vis);
attrs.extend(inner_attrs.into_iter());
(name, node)
};
P(ImplItem {
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, self.last_span.hi),
ident: name,
vis: vis,
attrs: attrs,
node: node
})
}
fn complain_if_pub_macro(&mut self, visa: Visibility, span: Span) {
@ -4647,15 +4589,10 @@ impl<'a> Parser<'a> {
}
}
/// Parse a method in a trait impl, starting with `attrs` attributes.
pub fn parse_method(&mut self,
attrs: Vec<Attribute>,
vis: Visibility)
-> P<ImplItem> {
let lo = self.span.lo;
/// Parse a method or a macro invocation in a trait impl.
fn parse_impl_method(&mut self, vis: Visibility)
-> (Ident, Vec<ast::Attribute>, ast::ImplItem_) {
// code copied from parse_macro_use_or_failure... abstraction!
let (method_, hi, new_attrs, ident) = {
if !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not)
&& (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
@ -4680,8 +4617,7 @@ impl<'a> Parser<'a> {
if delim != token::Brace {
self.expect(&token::Semi)
}
(ast::MacImplItem(m), self.span.hi, attrs,
token::special_idents::invalid)
(token::special_idents::invalid, vec![], ast::MacImplItem(m))
} else {
let unsafety = self.parse_unsafety();
let abi = if self.eat_keyword(keywords::Extern) {
@ -4697,26 +4633,14 @@ impl<'a> Parser<'a> {
});
self.parse_where_clause(&mut generics);
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
let body_span = body.span;
let mut new_attrs = attrs;
new_attrs.push_all(&inner_attrs[..]);
(MethodImplItem(ast::MethodSig {
(ident, inner_attrs, MethodImplItem(ast::MethodSig {
generics: generics,
abi: abi,
explicit_self: explicit_self,
unsafety: unsafety,
decl: decl
}, body), body_span.hi, new_attrs, ident)
}, body))
}
};
P(ImplItem {
id: ast::DUMMY_NODE_ID,
attrs: new_attrs,
vis: vis,
ident: ident,
node: method_,
span: mk_sp(lo, hi),
})
}
/// Parse trait Foo { ... }
@ -4747,28 +4671,6 @@ impl<'a> Parser<'a> {
(ident, ItemTrait(unsafety, tps, bounds, meths), None)
}
fn parse_impl_items(&mut self) -> (Vec<P<ImplItem>>, Vec<Attribute>) {
let mut impl_items = Vec::new();
self.expect(&token::OpenDelim(token::Brace));
let (inner_attrs, mut method_attrs) =
self.parse_inner_attrs_and_next();
loop {
method_attrs.extend(self.parse_outer_attributes().into_iter());
if method_attrs.is_empty() && self.eat(&token::CloseDelim(token::Brace)) {
break;
}
let vis = self.parse_visibility();
impl_items.push(if self.eat_keyword(keywords::Type) {
self.parse_assoc_ty_in_impl(method_attrs, vis)
} else {
self.parse_method(method_attrs, vis)
});
method_attrs = vec![];
}
(impl_items, inner_attrs)
}
/// Parses items implementations variants
/// impl<T> Foo { ... }
/// impl<T> ToString for &'static T { ... }
@ -4835,7 +4737,14 @@ impl<'a> Parser<'a> {
ty = self.parse_ty_sum();
}
self.parse_where_clause(&mut generics);
let (impl_items, attrs) = self.parse_impl_items();
self.expect(&token::OpenDelim(token::Brace));
let attrs = self.parse_inner_attributes();
let mut impl_items = vec![];
while !self.eat(&token::CloseDelim(token::Brace)) {
impl_items.push(self.parse_impl_item());
}
(ast_util::impl_pretty_name(&opt_trait, Some(&*ty)),
ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items),
@ -5074,53 +4983,16 @@ impl<'a> Parser<'a> {
}
}
/// Given a termination token and a vector of already-parsed
/// attributes (of length 0 or 1), parse all of the items in a module
fn parse_mod_items(&mut self,
term: token::Token,
first_item_attrs: Vec<Attribute>,
inner_lo: BytePos)
-> Mod {
// Parse all of the items up to closing or an attribute.
let mut attrs = first_item_attrs;
attrs.push_all(&self.parse_outer_attributes());
/// Given a termination token, parse all of the items in a module
fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> Mod {
let mut items = vec![];
loop {
match self.parse_item_(attrs, true) {
Err(returned_attrs) => {
attrs = returned_attrs;
break
}
Ok(item) => {
attrs = self.parse_outer_attributes();
items.push(item)
}
}
while let Some(item) = self.parse_item() {
items.push(item);
}
// don't think this other loop is even necessary....
while self.token != term {
let mut attrs = mem::replace(&mut attrs, vec![]);
attrs.push_all(&self.parse_outer_attributes());
debug!("parse_mod_items: parse_item_(attrs={:?})", attrs);
match self.parse_item_(attrs, true /* macros allowed */) {
Ok(item) => items.push(item),
Err(_) => {
if !self.eat(term) {
let token_str = self.this_token_to_string();
self.fatal(&format!("expected item, found `{}`",
token_str))
}
}
}
if !attrs.is_empty() {
// We parsed attributes for the first item but didn't find it
let last_span = self.last_span;
self.span_err(last_span,
Parser::expected_item_err(&attrs[..]));
self.fatal(&format!("expected item, found `{}`", token_str))
}
ast::Mod {
@ -5158,12 +5030,11 @@ impl<'a> Parser<'a> {
let mod_inner_lo = self.span.lo;
let old_owns_directory = self.owns_directory;
self.owns_directory = true;
let (inner, next) = self.parse_inner_attrs_and_next();
let m = self.parse_mod_items(token::CloseDelim(token::Brace), next, mod_inner_lo);
self.expect(&token::CloseDelim(token::Brace));
let attrs = self.parse_inner_attributes();
let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo);
self.owns_directory = old_owns_directory;
self.pop_mod_path();
(id, ItemMod(m), Some(inner))
(id, ItemMod(m), Some(attrs))
}
}
@ -5290,11 +5161,10 @@ impl<'a> Parser<'a> {
Some(name),
id_sp);
let mod_inner_lo = p0.span.lo;
let (mod_attrs, next) = p0.parse_inner_attrs_and_next();
let first_item_outer_attrs = next;
let m0 = p0.parse_mod_items(token::Eof, first_item_outer_attrs, mod_inner_lo);
let mod_attrs = p0.parse_inner_attributes();
let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo);
self.sess.included_mod_stack.borrow_mut().pop();
return (ast::ItemMod(m0), mod_attrs);
(ast::ItemMod(m0), mod_attrs)
}
/// Parse a function declaration from a foreign module
@ -5341,20 +5211,6 @@ impl<'a> Parser<'a> {
})
}
/// At this point, this is essentially a wrapper for
/// parse_foreign_items.
fn parse_foreign_mod_items(&mut self,
abi: abi::Abi,
first_item_attrs: Vec<Attribute>)
-> ForeignMod {
let foreign_items = self.parse_foreign_items(first_item_attrs);
assert!(self.token == token::CloseDelim(token::Brace));
ast::ForeignMod {
abi: abi,
items: foreign_items
}
}
/// Parse extern crate links
///
/// # Examples
@ -5433,24 +5289,31 @@ impl<'a> Parser<'a> {
lo: BytePos,
opt_abi: Option<abi::Abi>,
visibility: Visibility,
attrs: Vec<Attribute>)
mut attrs: Vec<Attribute>)
-> P<Item> {
self.expect(&token::OpenDelim(token::Brace));
let abi = opt_abi.unwrap_or(abi::C);
let (inner, next) = self.parse_inner_attrs_and_next();
let m = self.parse_foreign_mod_items(abi, next);
attrs.extend(self.parse_inner_attributes().into_iter());
let mut foreign_items = vec![];
while let Some(item) = self.parse_foreign_item() {
foreign_items.push(item);
}
self.expect(&token::CloseDelim(token::Brace));
let last_span = self.last_span;
let m = ast::ForeignMod {
abi: abi,
items: foreign_items
};
self.mk_item(lo,
last_span.hi,
special_idents::invalid,
ItemForeignMod(m),
visibility,
maybe_append(attrs, Some(inner)))
attrs)
}
/// Parse type Foo = Bar;
@ -5592,12 +5455,11 @@ impl<'a> Parser<'a> {
}
}
/// Parse one of the items allowed by the flags; on failure,
/// return `Err(remaining_attrs)`.
/// Parse one of the items allowed by the flags.
/// NB: this function no longer parses the items inside an
/// extern crate.
fn parse_item_(&mut self, attrs: Vec<Attribute>,
macros_allowed: bool) -> MaybeItem {
macros_allowed: bool) -> Option<P<Item>> {
let nt_item = match self.token {
token::Interpolated(token::NtItem(ref item)) => {
Some((**item).clone())
@ -5610,7 +5472,7 @@ impl<'a> Parser<'a> {
let mut attrs = attrs;
mem::swap(&mut item.attrs, &mut attrs);
item.attrs.extend(attrs.into_iter());
return Ok(P(item));
return Some(P(item));
}
None => {}
}
@ -5631,12 +5493,12 @@ impl<'a> Parser<'a> {
item_,
visibility,
attrs);
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Extern) {
if self.eat_keyword(keywords::Crate) {
return Ok(self.parse_item_extern_crate(lo, visibility, attrs));
return Some(self.parse_item_extern_crate(lo, visibility, attrs));
}
let opt_abi = self.parse_opt_abi();
@ -5653,9 +5515,9 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
} else if self.check(&token::OpenDelim(token::Brace)) {
return Ok(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs));
return Some(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs));
}
let span = self.span;
@ -5681,7 +5543,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Const) {
// CONST ITEM
@ -5698,7 +5560,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Trait))
@ -5715,7 +5577,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.check_keyword(keywords::Unsafe) &&
self.look_ahead(1, |t| t.is_keyword(keywords::Impl))
@ -5731,7 +5593,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.check_keyword(keywords::Fn) {
// FUNCTION ITEM
@ -5745,7 +5607,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.check_keyword(keywords::Unsafe)
&& self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) {
@ -5766,7 +5628,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Mod) {
// MODULE ITEM
@ -5779,7 +5641,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Type) {
// TYPE ITEM
@ -5791,7 +5653,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Enum) {
// ENUM ITEM
@ -5803,7 +5665,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Trait) {
// TRAIT ITEM
@ -5816,7 +5678,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Impl) {
// IMPL ITEM
@ -5828,7 +5690,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
if self.eat_keyword(keywords::Struct) {
// STRUCT ITEM
@ -5840,31 +5702,35 @@ impl<'a> Parser<'a> {
item_,
visibility,
maybe_append(attrs, extra_attrs));
return Ok(item);
return Some(item);
}
self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility)
}
/// Parse a foreign item; on failure, return `Err(remaining_attrs)`.
fn parse_foreign_item(&mut self, attrs: Vec<Attribute>)
-> Result<P<ForeignItem>, Vec<Attribute>> {
/// Parse a foreign item.
fn parse_foreign_item(&mut self) -> Option<P<ForeignItem>> {
let lo = self.span.lo;
let attrs = self.parse_outer_attributes();
let visibility = self.parse_visibility();
if self.check_keyword(keywords::Static) {
// FOREIGN STATIC ITEM
return Ok(self.parse_item_foreign_static(visibility, attrs));
return Some(self.parse_item_foreign_static(visibility, attrs));
}
if self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) {
// FOREIGN FUNCTION ITEM
return Ok(self.parse_item_foreign_fn(visibility, attrs));
return Some(self.parse_item_foreign_fn(visibility, attrs));
}
// FIXME #5668: this will occur for a macro invocation:
let item = try!(self.parse_macro_use_or_failure(attrs, true, lo, visibility));
match self.parse_macro_use_or_failure(attrs, true, lo, visibility) {
Some(item) => {
self.span_fatal(item.span, "macros cannot expand to foreign items");
}
None => None
}
}
/// This is the fall-through for parsing items.
fn parse_macro_use_or_failure(
@ -5873,7 +5739,7 @@ impl<'a> Parser<'a> {
macros_allowed: bool,
lo: BytePos,
visibility: Visibility
) -> MaybeItem {
) -> Option<P<Item>> {
if macros_allowed && !self.token.is_any_keyword()
&& self.look_ahead(1, |t| *t == token::Not)
&& (self.look_ahead(2, |t| t.is_plain_ident())
@ -5925,7 +5791,7 @@ impl<'a> Parser<'a> {
item_,
visibility,
attrs);
return Ok(item);
return Some(item);
}
// FAILURE TO PARSE ITEM
@ -5936,16 +5802,22 @@ impl<'a> Parser<'a> {
self.span_fatal(last_span, "unmatched visibility `pub`");
}
}
Err(attrs)
if !attrs.is_empty() {
self.expected_item_err(&attrs);
}
None
}
// HACK(eddyb) staging required for `quote_item!`.
#[cfg(stage0)] // SNAP 270a677
pub fn parse_item_with_outer_attributes(&mut self) -> Option<P<Item>> {
let attrs = self.parse_outer_attributes();
self.parse_item(attrs)
self.parse_item()
}
pub fn parse_item(&mut self, attrs: Vec<Attribute>) -> Option<P<Item>> {
self.parse_item_(attrs, true).ok()
pub fn parse_item(&mut self) -> Option<P<Item>> {
let attrs = self.parse_outer_attributes();
self.parse_item_(attrs, true)
}
/// Matches view_path : MOD? non_global_path as IDENT
@ -6051,52 +5923,13 @@ impl<'a> Parser<'a> {
P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path)))
}
/// Parses a sequence of foreign items. Stops when it finds program
/// text that can't be parsed as an item
fn parse_foreign_items(&mut self, first_item_attrs: Vec<Attribute>)
-> Vec<P<ForeignItem>> {
let mut attrs = first_item_attrs;
attrs.push_all(&self.parse_outer_attributes());
let mut foreign_items = Vec::new();
loop {
match self.parse_foreign_item(attrs) {
Ok(foreign_item) => {
foreign_items.push(foreign_item);
}
Err(returned_attrs) => {
if self.check(&token::CloseDelim(token::Brace)) {
attrs = returned_attrs;
break
}
self.unexpected();
}
}
attrs = self.parse_outer_attributes();
}
if !attrs.is_empty() {
let last_span = self.last_span;
self.span_err(last_span,
Parser::expected_item_err(&attrs[..]));
}
foreign_items
}
/// Parses a source module as a crate. This is the main
/// entry point for the parser.
pub fn parse_crate_mod(&mut self) -> Crate {
let lo = self.span.lo;
// parse the crate's inner attrs, maybe (oops) one
// of the attrs of an item:
let (inner, next) = self.parse_inner_attrs_and_next();
let first_item_outer_attrs = next;
// parse the items inside the crate:
let m = self.parse_mod_items(token::Eof, first_item_outer_attrs, lo);
ast::Crate {
module: m,
attrs: inner,
attrs: self.parse_inner_attributes(),
module: self.parse_mod_items(&token::Eof, lo),
config: self.cfg.clone(),
span: mk_sp(lo, self.span.lo),
exported_macros: Vec::new(),

View file

@ -58,14 +58,14 @@ pub fn string_to_expr (source_str : String) -> P<ast::Expr> {
/// Parse a string, return an item
pub fn string_to_item (source_str : String) -> Option<P<ast::Item>> {
with_error_checking_parse(source_str, |p| {
p.parse_item(Vec::new())
p.parse_item()
})
}
/// Parse a string, return a stmt
pub fn string_to_stmt(source_str : String) -> P<ast::Stmt> {
with_error_checking_parse(source_str, |p| {
p.parse_stmt(Vec::new())
p.parse_stmt().unwrap()
})
}

View file

@ -8,4 +8,4 @@
// option. This file may not be copied, modified, or distributed
// 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>`

View file

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:expected one of `!` or `[`, found `vec`
// error-pattern:expected `[`, found `vec`
mod blade_runner {
#vec[doc(
brief = "Blade Runner is probably the best movie ever",

View file

@ -25,7 +25,7 @@ fn syntax_extension(cx: &ExtCtxt) {
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 _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 _e: P<syntax::ast::Expr> = quote_expr!(cx, match foo { $p_toks => 10 } );