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(), 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)
} }

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>>> { -> 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,

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 // 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()),

View file

@ -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
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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()
}) })
} }

View file

@ -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>`

View file

@ -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",

View file

@ -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 } );