attr.rs 7.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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 parser_attr {
20 21 22 23 24 25 26
    fn parse_outer_attributes(&mut self) -> ~[ast::Attribute];
    fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute;
    fn parse_inner_attrs_and_next(&mut self)
                                  -> (~[ast::Attribute], ~[ast::Attribute]);
    fn parse_meta_item(&mut self) -> @ast::MetaItem;
    fn parse_meta_seq(&mut self) -> ~[@ast::MetaItem];
    fn parse_optional_meta(&mut self) -> ~[@ast::MetaItem];
27 28
}

29
impl parser_attr for Parser {
30
    // Parse attributes that appear before an item
31
    fn parse_outer_attributes(&mut self) -> ~[ast::Attribute] {
32
        let mut attrs: ~[ast::Attribute] = ~[];
33
        loop {
34
            debug!("parse_outer_attributes: self.token={:?}",
35
                   self.token);
36
            match *self.token {
A
Alex Crichton 已提交
37
              token::INTERPOLATED(token::nt_attr(..)) => {
38 39
                attrs.push(self.parse_attribute(false));
              }
B
Brian Anderson 已提交
40
              token::POUND => {
41
                if self.look_ahead(1, |t| *t != token::LBRACKET) {
42 43
                    break;
                }
44
                attrs.push(self.parse_attribute(false));
45
              }
B
Brian Anderson 已提交
46
              token::DOC_COMMENT(s) => {
47
                let attr = ::attr::mk_sugared_doc_attr(
48
                    self.id_to_str(s),
E
Erick Tryzelaar 已提交
49 50 51
                    self.span.lo,
                    self.span.hi
                );
52
                if attr.node.style != ast::AttrOuter {
53
                  self.fatal("expected outer comment");
54
                }
55
                attrs.push(attr);
56 57
                self.bump();
              }
B
Brian Anderson 已提交
58
              _ => break
59
            }
60
        }
B
Brian Anderson 已提交
61
        return attrs;
62 63
    }

64 65 66 67
    // matches attribute = # [ meta_item ]
    //
    // if permit_inner is true, then a trailing `;` indicates an inner
    // attribute
68
    fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute {
69
        debug!("parse_attributes: permit_inner={:?} self.token={:?}",
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
               permit_inner, self.token);
        let (span, value) = match *self.token {
            INTERPOLATED(token::nt_attr(attr)) => {
                assert!(attr.node.style == ast::AttrOuter);
                self.bump();
                (attr.span, attr.node.value)
            }
            token::POUND => {
                let lo = self.span.lo;
                self.bump();
                self.expect(&token::LBRACKET);
                let meta_item = self.parse_meta_item();
                self.expect(&token::RBRACKET);
                let hi = self.span.hi;
                (mk_sp(lo, hi), meta_item)
            }
            _ => {
87
                let token_str = self.this_token_to_str();
A
Alex Crichton 已提交
88
                self.fatal(format!("expected `\\#` but found `{}`",
89
                                   token_str));
90 91 92 93 94 95 96 97
            }
        };
        let style = if permit_inner && *self.token == token::SEMI {
            self.bump();
            ast::AttrInner
        } else {
            ast::AttrOuter
        };
98
        return Spanned {
99 100 101 102 103 104 105
            span: span,
            node: ast::Attribute_ {
                style: style,
                value: value,
                is_sugared_doc: false
            }
        };
106
    }
107

108 109 110 111 112 113
    // Parse attributes that appear after the opening of an item, each
    // 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).
114

J
John Clements 已提交
115
    // matches inner_attrs* outer_attr?
116 117
    // you can make the 'next' field an Option, but the result is going to be
    // more useful as a vector.
118
    fn parse_inner_attrs_and_next(&mut self)
119
                                  -> (~[ast::Attribute], ~[ast::Attribute]) {
120 121
        let mut inner_attrs: ~[ast::Attribute] = ~[];
        let mut next_outer_attrs: ~[ast::Attribute] = ~[];
122
        loop {
123
            let attr = match *self.token {
A
Alex Crichton 已提交
124
                token::INTERPOLATED(token::nt_attr(..)) => {
125
                    self.parse_attribute(true)
126
                }
127 128 129 130 131 132 133 134
                token::POUND => {
                    if self.look_ahead(1, |t| *t != token::LBRACKET) {
                        // This is an extension
                        break;
                    }
                    self.parse_attribute(true)
                }
                token::DOC_COMMENT(s) => {
135
                    self.bump();
136 137 138
                    ::attr::mk_sugared_doc_attr(self.id_to_str(s),
                                                self.span.lo,
                                                self.span.hi)
139
                }
140 141
                _ => {
                    break;
142
                }
143 144 145 146 147 148
            };
            if attr.node.style == ast::AttrInner {
                inner_attrs.push(attr);
            } else {
                next_outer_attrs.push(attr);
                break;
149
            }
150
        }
151
        (inner_attrs, next_outer_attrs)
152 153
    }

J
John Clements 已提交
154 155 156
    // matches meta_item = IDENT
    // | IDENT = lit
    // | IDENT meta_seq
157
    fn parse_meta_item(&mut self) -> @ast::MetaItem {
158
        let lo = self.span.lo;
159 160
        let ident = self.parse_ident();
        let name = self.id_to_str(ident);
161
        match *self.token {
162 163 164
            token::EQ => {
                self.bump();
                let lit = self.parse_lit();
165 166 167
                // FIXME #623 Non-string meta items are not serialized correctly;
                // just forbid them for now
                match lit.node {
A
Alex Crichton 已提交
168
                    ast::lit_str(..) => (),
169 170 171 172 173 174
                    _ => {
                        self.span_err(
                            lit.span,
                            "non-string literals are not allowed in meta-items");
                    }
                }
175
                let hi = self.span.hi;
176
                @spanned(lo, hi, ast::MetaNameValue(name, lit))
177 178 179
            }
            token::LPAREN => {
                let inner_items = self.parse_meta_seq();
180
                let hi = self.span.hi;
181
                @spanned(lo, hi, ast::MetaList(name, inner_items))
182 183
            }
            _ => {
S
Seo Sanghyeon 已提交
184
                let hi = self.last_span.hi;
185
                @spanned(lo, hi, ast::MetaWord(name))
186
            }
187 188 189
        }
    }

J
John Clements 已提交
190
    // matches meta_seq = ( COMMASEP(meta_item) )
191
    fn parse_meta_seq(&mut self) -> ~[@ast::MetaItem] {
192 193 194 195
        self.parse_seq(&token::LPAREN,
                       &token::RPAREN,
                       seq_sep_trailing_disallowed(token::COMMA),
                       |p| p.parse_meta_item()).node
196 197
    }

198
    fn parse_optional_meta(&mut self) -> ~[@ast::MetaItem] {
199
        match *self.token {
E
Erick Tryzelaar 已提交
200 201
            token::LPAREN => self.parse_meta_seq(),
            _ => ~[]
B
Brian Anderson 已提交
202
        }
203
    }
204
}