]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/parse/attr.rs
Merge tag 'debian/0.7-0_exp1'
[rustc.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.push(self.parse_attribute(ast::attr_outer));
46 }
47 token::DOC_COMMENT(s) => {
48 let attr = ::attr::mk_sugared_doc_attr(
49 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.push(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, is_sugared_doc: false }); }
81
82 // Parse attributes that appear after the opening of an item, each
83 // terminated by a semicolon. In addition to a vector of inner attributes,
84 // this function also returns a vector that may contain the first outer
85 // attribute of the next item (since we can't know whether the attribute
86 // is an inner attribute of the containing item or an outer attribute of
87 // the first contained item until we see the semi).
88
89 // matches inner_attrs* outer_attr?
90 // you can make the 'next' field an Option, but the result is going to be
91 // more useful as a vector.
92 fn parse_inner_attrs_and_next(&self) ->
93 (~[ast::attribute], ~[ast::attribute]) {
94 let mut inner_attrs: ~[ast::attribute] = ~[];
95 let mut next_outer_attrs: ~[ast::attribute] = ~[];
96 loop {
97 match *self.token {
98 token::POUND => {
99 if self.look_ahead(1u) != token::LBRACKET {
100 // This is an extension
101 break;
102 }
103 let attr = self.parse_attribute(ast::attr_inner);
104 if *self.token == token::SEMI {
105 self.bump();
106 inner_attrs.push(attr);
107 } else {
108 // It's not really an inner attribute
109 let outer_attr =
110 spanned(attr.span.lo, attr.span.hi,
111 ast::attribute_ { style: ast::attr_outer,
112 value: attr.node.value,
113 is_sugared_doc: false });
114 next_outer_attrs.push(outer_attr);
115 break;
116 }
117 }
118 token::DOC_COMMENT(s) => {
119 let attr = ::attr::mk_sugared_doc_attr(
120 self.id_to_str(s),
121 self.span.lo,
122 self.span.hi
123 );
124 self.bump();
125 if attr.node.style == ast::attr_inner {
126 inner_attrs.push(attr);
127 } else {
128 next_outer_attrs.push(attr);
129 break;
130 }
131 }
132 _ => break
133 }
134 }
135 (inner_attrs, next_outer_attrs)
136 }
137
138 // matches meta_item = IDENT
139 // | IDENT = lit
140 // | IDENT meta_seq
141 fn parse_meta_item(&self) -> @ast::meta_item {
142 let lo = self.span.lo;
143 let name = self.id_to_str(self.parse_ident());
144 match *self.token {
145 token::EQ => {
146 self.bump();
147 let lit = self.parse_lit();
148 let hi = self.span.hi;
149 @spanned(lo, hi, ast::meta_name_value(name, lit))
150 }
151 token::LPAREN => {
152 let inner_items = self.parse_meta_seq();
153 let hi = self.span.hi;
154 @spanned(lo, hi, ast::meta_list(name, inner_items))
155 }
156 _ => {
157 let hi = self.last_span.hi;
158 @spanned(lo, hi, ast::meta_word(name))
159 }
160 }
161 }
162
163 // matches meta_seq = ( COMMASEP(meta_item) )
164 fn parse_meta_seq(&self) -> ~[@ast::meta_item] {
165 copy self.parse_seq(
166 &token::LPAREN,
167 &token::RPAREN,
168 seq_sep_trailing_disallowed(token::COMMA),
169 |p| p.parse_meta_item()
170 ).node
171 }
172
173 fn parse_optional_meta(&self) -> ~[@ast::meta_item] {
174 match *self.token {
175 token::LPAREN => self.parse_meta_seq(),
176 _ => ~[]
177 }
178 }
179 }