]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/attr.rs
cc580155d70cfd26f736c0f900270386fe6affcf
[rust.git] / src / libsyntax / parse / attr.rs
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;
13 use codemap::BytePos;
14 use parse::common::*; //resolve bug?
15 use parse::token;
16 use parse::parser::Parser;
17
18 // a parser that can parse attributes.
19 pub trait parser_attr {
20     fn parse_outer_attributes(&self) -> ~[ast::attribute];
21     fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute;
22     fn parse_attribute_naked(
23         &self,
24         style: ast::attr_style,
25         lo: BytePos
26     ) -> ast::attribute;
27     fn parse_inner_attrs_and_next(&self) ->
28         (~[ast::attribute], ~[ast::attribute]);
29     fn parse_meta_item(&self) -> @ast::meta_item;
30     fn parse_meta_seq(&self) -> ~[@ast::meta_item];
31     fn parse_optional_meta(&self) -> ~[@ast::meta_item];
32 }
33
34 impl parser_attr for Parser {
35
36     // Parse attributes that appear before an item
37     fn parse_outer_attributes(&self) -> ~[ast::attribute] {
38         let mut attrs: ~[ast::attribute] = ~[];
39         loop {
40             match *self.token {
41               token::POUND => {
42                 if self.look_ahead(1u) != token::LBRACKET {
43                     break;
44                 }
45                 attrs += ~[self.parse_attribute(ast::attr_outer)];
46               }
47               token::DOC_COMMENT(s) => {
48                 let attr = ::attr::mk_sugared_doc_attr(
49                     copy *self.id_to_str(s),
50                     self.span.lo,
51                     self.span.hi
52                 );
53                 if attr.node.style != ast::attr_outer {
54                   self.fatal(~"expected outer comment");
55                 }
56                 attrs += ~[attr];
57                 self.bump();
58               }
59               _ => break
60             }
61         }
62         return attrs;
63     }
64
65     // matches attribute = # attribute_naked
66     fn parse_attribute(&self, style: ast::attr_style) -> ast::attribute {
67         let lo = self.span.lo;
68         self.expect(&token::POUND);
69         return self.parse_attribute_naked(style, lo);
70     }
71
72     // matches attribute_naked = [ meta_item ]
73     fn parse_attribute_naked(&self, style: ast::attr_style, lo: BytePos) ->
74         ast::attribute {
75         self.expect(&token::LBRACKET);
76         let meta_item = self.parse_meta_item();
77         self.expect(&token::RBRACKET);
78         let hi = self.span.hi;
79         return spanned(lo, hi, ast::attribute_ { style: style,
80                                                  value: meta_item,
81                                                  is_sugared_doc: false });
82     }
83
84     // Parse attributes that appear after the opening of an item, each
85     // terminated by a semicolon. In addition to a vector of inner attributes,
86     // this function also returns a vector that may contain the first outer
87     // attribute of the next item (since we can't know whether the attribute
88     // is an inner attribute of the containing item or an outer attribute of
89     // the first contained item until we see the semi).
90
91     // matches inner_attrs* outer_attr?
92     // you can make the 'next' field an Option, but the result is going to be
93     // more useful as a vector.
94     fn parse_inner_attrs_and_next(&self) ->
95         (~[ast::attribute], ~[ast::attribute]) {
96         let mut inner_attrs: ~[ast::attribute] = ~[];
97         let mut next_outer_attrs: ~[ast::attribute] = ~[];
98         loop {
99             match *self.token {
100               token::POUND => {
101                 if self.look_ahead(1u) != token::LBRACKET {
102                     // This is an extension
103                     break;
104                 }
105                 let attr = self.parse_attribute(ast::attr_inner);
106                 if *self.token == token::SEMI {
107                     self.bump();
108                     inner_attrs += ~[attr];
109                 } else {
110                     // It's not really an inner attribute
111                     let outer_attr =
112                         spanned(attr.span.lo, attr.span.hi,
113                             ast::attribute_ { style: ast::attr_outer,
114                                               value: attr.node.value,
115                                               is_sugared_doc: false });
116                     next_outer_attrs += ~[outer_attr];
117                     break;
118                 }
119               }
120               token::DOC_COMMENT(s) => {
121                 let attr = ::attr::mk_sugared_doc_attr(
122                     copy *self.id_to_str(s),
123                     self.span.lo,
124                     self.span.hi
125                 );
126                 self.bump();
127                 if attr.node.style == ast::attr_inner {
128                   inner_attrs += ~[attr];
129                 } else {
130                   next_outer_attrs += ~[attr];
131                   break;
132                 }
133               }
134               _ => break
135             }
136         }
137         (inner_attrs, next_outer_attrs)
138     }
139
140     // matches meta_item = IDENT
141     // | IDENT = lit
142     // | IDENT meta_seq
143     fn parse_meta_item(&self) -> @ast::meta_item {
144         let lo = self.span.lo;
145         let name = self.id_to_str(self.parse_ident());
146         match *self.token {
147             token::EQ => {
148                 self.bump();
149                 let lit = self.parse_lit();
150                 let hi = self.span.hi;
151                 @spanned(lo, hi, ast::meta_name_value(name, lit))
152             }
153             token::LPAREN => {
154                 let inner_items = self.parse_meta_seq();
155                 let hi = self.span.hi;
156                 @spanned(lo, hi, ast::meta_list(name, inner_items))
157             }
158             _ => {
159                 let hi = self.span.hi;
160                 @spanned(lo, hi, ast::meta_word(name))
161             }
162         }
163     }
164
165     // matches meta_seq = ( COMMASEP(meta_item) )
166     fn parse_meta_seq(&self) -> ~[@ast::meta_item] {
167         copy self.parse_seq(
168             &token::LPAREN,
169             &token::RPAREN,
170             seq_sep_trailing_disallowed(token::COMMA),
171             |p| p.parse_meta_item()
172         ).node
173     }
174
175     fn parse_optional_meta(&self) -> ~[@ast::meta_item] {
176         match *self.token {
177             token::LPAREN => self.parse_meta_seq(),
178             _ => ~[]
179         }
180     }
181 }
182
183 //
184 // Local Variables:
185 // mode: rust
186 // fill-column: 78;
187 // indent-tabs-mode: nil
188 // c-basic-offset: 4
189 // buffer-file-coding-system: utf-8-unix
190 // End:
191 //