]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/asm.rs
mk: The beta channel produces things called 'beta'
[rust.git] / src / libsyntax / ext / asm.rs
1 // Copyright 2012-2013 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 /*
12  * Inline assembly support.
13  */
14 use self::State::*;
15
16 use ast;
17 use codemap;
18 use codemap::Span;
19 use ext::base;
20 use ext::base::*;
21 use parse::token::InternedString;
22 use parse::token;
23 use ptr::P;
24
25 enum State {
26     Asm,
27     Outputs,
28     Inputs,
29     Clobbers,
30     Options,
31     StateNone
32 }
33
34 impl State {
35     fn next(&self) -> State {
36         match *self {
37             Asm       => Outputs,
38             Outputs   => Inputs,
39             Inputs    => Clobbers,
40             Clobbers  => Options,
41             Options   => StateNone,
42             StateNone => StateNone
43         }
44     }
45 }
46
47 static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
48
49 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
50                        -> Box<base::MacResult+'cx> {
51     let mut p = cx.new_parser_from_tts(tts);
52     let mut asm = InternedString::new("");
53     let mut asm_str_style = None;
54     let mut outputs = Vec::new();
55     let mut inputs = Vec::new();
56     let mut clobs = Vec::new();
57     let mut volatile = false;
58     let mut alignstack = false;
59     let mut dialect = ast::AsmAtt;
60
61     let mut state = Asm;
62
63     'statement: loop {
64         match state {
65             Asm => {
66                 let (s, style) = match expr_to_string(cx, p.parse_expr(),
67                                                    "inline assembly must be a string literal") {
68                     Some((s, st)) => (s, st),
69                     // let compilation continue
70                     None => return DummyResult::expr(sp),
71                 };
72                 asm = s;
73                 asm_str_style = Some(style);
74             }
75             Outputs => {
76                 while p.token != token::Eof &&
77                       p.token != token::Colon &&
78                       p.token != token::ModSep {
79
80                     if outputs.len() != 0 {
81                         p.eat(&token::Comma);
82                     }
83
84                     let (constraint, _str_style) = p.parse_str();
85
86                     let span = p.last_span;
87
88                     p.expect(&token::OpenDelim(token::Paren));
89                     let out = p.parse_expr();
90                     p.expect(&token::CloseDelim(token::Paren));
91
92                     // Expands a read+write operand into two operands.
93                     //
94                     // Use '+' modifier when you want the same expression
95                     // to be both an input and an output at the same time.
96                     // It's the opposite of '=&' which means that the memory
97                     // cannot be shared with any other operand (usually when
98                     // a register is clobbered early.)
99                     let output = match constraint.get().slice_shift_char() {
100                         Some(('=', _)) => None,
101                         Some(('+', operand)) => {
102                             Some(token::intern_and_get_ident(&format!(
103                                         "={}", operand)[]))
104                         }
105                         _ => {
106                             cx.span_err(span, "output operand constraint lacks '=' or '+'");
107                             None
108                         }
109                     };
110
111                     let is_rw = output.is_some();
112                     outputs.push((output.unwrap_or(constraint), out, is_rw));
113                 }
114             }
115             Inputs => {
116                 while p.token != token::Eof &&
117                       p.token != token::Colon &&
118                       p.token != token::ModSep {
119
120                     if inputs.len() != 0 {
121                         p.eat(&token::Comma);
122                     }
123
124                     let (constraint, _str_style) = p.parse_str();
125
126                     if constraint.get().starts_with("=") {
127                         cx.span_err(p.last_span, "input operand constraint contains '='");
128                     } else if constraint.get().starts_with("+") {
129                         cx.span_err(p.last_span, "input operand constraint contains '+'");
130                     }
131
132                     p.expect(&token::OpenDelim(token::Paren));
133                     let input = p.parse_expr();
134                     p.expect(&token::CloseDelim(token::Paren));
135
136                     inputs.push((constraint, input));
137                 }
138             }
139             Clobbers => {
140                 while p.token != token::Eof &&
141                       p.token != token::Colon &&
142                       p.token != token::ModSep {
143
144                     if clobs.len() != 0 {
145                         p.eat(&token::Comma);
146                     }
147
148                     let (s, _str_style) = p.parse_str();
149
150                     if OPTIONS.iter().any(|&opt| s == opt) {
151                         cx.span_warn(p.last_span, "expected a clobber, found an option");
152                     }
153                     clobs.push(s);
154                 }
155             }
156             Options => {
157                 let (option, _str_style) = p.parse_str();
158
159                 if option == "volatile" {
160                     // Indicates that the inline assembly has side effects
161                     // and must not be optimized out along with its outputs.
162                     volatile = true;
163                 } else if option == "alignstack" {
164                     alignstack = true;
165                 } else if option == "intel" {
166                     dialect = ast::AsmIntel;
167                 } else {
168                     cx.span_warn(p.last_span, "unrecognized option");
169                 }
170
171                 if p.token == token::Comma {
172                     p.eat(&token::Comma);
173                 }
174             }
175             StateNone => ()
176         }
177
178         loop {
179             // MOD_SEP is a double colon '::' without space in between.
180             // When encountered, the state must be advanced twice.
181             match (&p.token, state.next(), state.next().next()) {
182                 (&token::Colon, StateNone, _)   |
183                 (&token::ModSep, _, StateNone) => {
184                     p.bump();
185                     break 'statement;
186                 }
187                 (&token::Colon, st, _)   |
188                 (&token::ModSep, _, st) => {
189                     p.bump();
190                     state = st;
191                 }
192                 (&token::Eof, _, _) => break 'statement,
193                 _ => break
194             }
195         }
196     }
197
198     let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
199         call_site: sp,
200         callee: codemap::NameAndSpan {
201             name: "asm".to_string(),
202             format: codemap::MacroBang,
203             span: None,
204         },
205     });
206
207     MacExpr::new(P(ast::Expr {
208         id: ast::DUMMY_NODE_ID,
209         node: ast::ExprInlineAsm(ast::InlineAsm {
210             asm: token::intern_and_get_ident(asm.get()),
211             asm_str_style: asm_str_style.unwrap(),
212             outputs: outputs,
213             inputs: inputs,
214             clobbers: clobs,
215             volatile: volatile,
216             alignstack: alignstack,
217             dialect: dialect,
218             expn_id: expn_id,
219         }),
220         span: sp
221     }))
222 }