(index<- )        ./libsyntax/parse/attr.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  use ast;
  12  use codemap::{spanned, Spanned, mk_sp};
  13  use parse::common::*; //resolve bug?
  14  use parse::token;
  15  use parse::parser::Parser;
  16  use parse::token::INTERPOLATED;
  17  
  18  // a parser that can parse attributes.
  19  pub trait ParserAttr {
  20      fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> ;
  21      fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
  22      fn parse_inner_attrs_and_next(&mut self)
  23                                    -> (Vec<ast::Attribute> , Vec<ast::Attribute> );
  24      fn parse_meta_item(&mut self) -> @ast::MetaItem;
  25      fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> ;
  26      fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> ;
  27  }
  28  
  29  impl<'a> ParserAttr for Parser<'a> {
  30      // Parse attributes that appear before an item
  31      fn parse_outer_attributes(&mut self) -> Vec<ast::Attribute> {
  32          let mut attrsVec<ast::Attribute> = Vec::new();
  33          loop {
  34              debug!("parse_outer_attributes: self.token={:?}",
  35                     self.token);
  36              match self.token {
  37                token::POUND => {
  38                  attrs.push(self.parse_attribute(false));
  39                }
  40                token::DOC_COMMENT(s) => {
  41                  let attr = ::attr::mk_sugared_doc_attr(
  42                      self.id_to_interned_str(s),
  43                      self.span.lo,
  44                      self.span.hi
  45                  );
  46                  if attr.node.style != ast::AttrOuter {
  47                    self.fatal("expected outer comment");
  48                  }
  49                  attrs.push(attr);
  50                  self.bump();
  51                }
  52                _ => break
  53              }
  54          }
  55          return attrs;
  56      }
  57  
  58      // matches attribute = # ! [ meta_item ]
  59      //
  60      // if permit_inner is true, then a leading `!` indicates an inner
  61      // attribute
  62      fn parse_attribute(&mut self, permit_innerbool) -> ast::Attribute {
  63          debug!("parse_attributes: permit_inner={:?} self.token={:?}",
  64                 permit_inner, self.token);
  65          let (span, value, mut style) = match self.token {
  66              token::POUND => {
  67                  let lo = self.span.lo;
  68                  self.bump();
  69  
  70                  let style = if self.eat(&token::NOT) {
  71                      if !permit_inner {
  72                          self.span_err(self.span,
  73                                        "an inner attribute is not permitted in \
  74                                         this context");
  75                      }
  76                      ast::AttrInner
  77                  } else {
  78                      ast::AttrOuter
  79                  };
  80  
  81                  self.expect(&token::LBRACKET);
  82                  let meta_item = self.parse_meta_item();
  83                  self.expect(&token::RBRACKET);
  84  
  85                  let hi = self.span.hi;
  86                  (mk_sp(lo, hi), meta_item, style)
  87              }
  88              _ => {
  89                  let token_str = self.this_token_to_str();
  90                  self.fatal(format!("expected `\\#` but found `{}`",
  91                                     token_str));
  92              }
  93          };
  94  
  95          if permit_inner && self.eat(&token::SEMI) {
  96              self.span_warn(span, "this inner attribute syntax is deprecated. \
  97                             The new syntax is `#![foo]`, with a bang and no semicolon.");
  98              style = ast::AttrInner;
  99          }
 100  
 101          return Spanned {
 102              span: span,
 103              node: ast::Attribute_ {
 104                  style: style,
 105                  value: value,
 106                  is_sugared_doc: false
 107              }
 108          };
 109      }
 110  
 111      // Parse attributes that appear after the opening of an item. These should
 112      // be preceded by an exclaimation mark, but we accept and warn about one
 113      // terminated by a semicolon. In addition to a vector of inner attributes,
 114      // this function also returns a vector that may contain the first outer
 115      // attribute of the next item (since we can't know whether the attribute
 116      // is an inner attribute of the containing item or an outer attribute of
 117      // the first contained item until we see the semi).
 118  
 119      // matches inner_attrs* outer_attr?
 120      // you can make the 'next' field an Option, but the result is going to be
 121      // more useful as a vector.
 122      fn parse_inner_attrs_and_next(&mut self)
 123                                    -> (Vec<ast::Attribute> , Vec<ast::Attribute> ) {
 124          let mut inner_attrsVec<ast::Attribute> = Vec::new();
 125          let mut next_outer_attrsVec<ast::Attribute> = Vec::new();
 126          loop {
 127              let attr = match self.token {
 128                  token::POUND => {
 129                      self.parse_attribute(true)
 130                  }
 131                  token::DOC_COMMENT(s) => {
 132                      self.bump();
 133                      ::attr::mk_sugared_doc_attr(self.id_to_interned_str(s),
 134                                                  self.span.lo,
 135                                                  self.span.hi)
 136                  }
 137                  _ => {
 138                      break;
 139                  }
 140              };
 141              if attr.node.style == ast::AttrInner {
 142                  inner_attrs.push(attr);
 143              } else {
 144                  next_outer_attrs.push(attr);
 145                  break;
 146              }
 147          }
 148          (inner_attrs, next_outer_attrs)
 149      }
 150  
 151      // matches meta_item = IDENT
 152      // | IDENT = lit
 153      // | IDENT meta_seq
 154      fn parse_meta_item(&mut self) -> @ast::MetaItem {
 155          match self.token {
 156              token::INTERPOLATED(token::NtMeta(e)) => {
 157                  self.bump();
 158                  return e
 159              }
 160              _ => {}
 161          }
 162  
 163          let lo = self.span.lo;
 164          let ident = self.parse_ident();
 165          let name = self.id_to_interned_str(ident);
 166          match self.token {
 167              token::EQ => {
 168                  self.bump();
 169                  let lit = self.parse_lit();
 170                  // FIXME #623 Non-string meta items are not serialized correctly;
 171                  // just forbid them for now
 172                  match lit.node {
 173                      ast::LitStr(..) => {}
 174                      _ => {
 175                          self.span_err(
 176                              lit.span,
 177                              "non-string literals are not allowed in meta-items");
 178                      }
 179                  }
 180                  let hi = self.span.hi;
 181                  @spanned(lo, hi, ast::MetaNameValue(name, lit))
 182              }
 183              token::LPAREN => {
 184                  let inner_items = self.parse_meta_seq();
 185                  let hi = self.span.hi;
 186                  @spanned(lo, hi, ast::MetaList(name, inner_items))
 187              }
 188              _ => {
 189                  let hi = self.last_span.hi;
 190                  @spanned(lo, hi, ast::MetaWord(name))
 191              }
 192          }
 193      }
 194  
 195      // matches meta_seq = ( COMMASEP(meta_item) )
 196      fn parse_meta_seq(&mut self) -> Vec<@ast::MetaItem> {
 197          self.parse_seq(&token::LPAREN,
 198                         &token::RPAREN,
 199                         seq_sep_trailing_disallowed(token::COMMA),
 200                         |p| p.parse_meta_item()).node
 201      }
 202  
 203      fn parse_optional_meta(&mut self) -> Vec<@ast::MetaItem> {
 204          match self.token {
 205              token::LPAREN => self.parse_meta_seq(),
 206              _ => Vec::new()
 207          }
 208      }
 209  }