]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/asm.rs
babf0f13874169d9d9a1a5c850cd489dcf2ad27f
[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
15 use ast;
16 use codemap::Span;
17 use ext::base;
18 use ext::base::*;
19 use parse;
20 use parse::token::InternedString;
21 use parse::token;
22
23 enum State {
24     Asm,
25     Outputs,
26     Inputs,
27     Clobbers,
28     Options
29 }
30
31 fn next_state(s: State) -> Option<State> {
32     match s {
33         Asm      => Some(Outputs),
34         Outputs  => Some(Inputs),
35         Inputs   => Some(Clobbers),
36         Clobbers => Some(Options),
37         Options  => None
38     }
39 }
40
41 pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
42                -> base::MacResult {
43     let mut p = parse::new_parser_from_tts(cx.parse_sess(),
44                                            cx.cfg(),
45                                            tts.to_owned());
46
47     let mut asm = InternedString::new("");
48     let mut asm_str_style = None;
49     let mut outputs = ~[];
50     let mut inputs = ~[];
51     let mut cons = ~"";
52     let mut volatile = false;
53     let mut alignstack = false;
54     let mut dialect = ast::AsmAtt;
55
56     let mut state = Asm;
57
58     // Not using labeled break to get us through one round of bootstrapping.
59     let mut continue_ = true;
60     while continue_ {
61         match state {
62             Asm => {
63                 let (s, style) = match expr_to_str(cx, p.parse_expr(),
64                                                    "inline assembly must be a string literal.") {
65                     Some((s, st)) => (s, st),
66                     // let compilation continue
67                     None => return MacResult::dummy_expr(),
68                 };
69                 asm = s;
70                 asm_str_style = Some(style);
71             }
72             Outputs => {
73                 while p.token != token::EOF &&
74                       p.token != token::COLON &&
75                       p.token != token::MOD_SEP {
76
77                     if outputs.len() != 0 {
78                         p.eat(&token::COMMA);
79                     }
80
81                     let (constraint, _str_style) = p.parse_str();
82
83                     if constraint.starts_with("+") {
84                         cx.span_unimpl(p.last_span,
85                                        "'+' (read+write) output operand constraint modifier");
86                     } else if !constraint.starts_with("=") {
87                         cx.span_err(p.last_span, "output operand constraint lacks '='");
88                     }
89
90                     p.expect(&token::LPAREN);
91                     let out = p.parse_expr();
92                     p.expect(&token::RPAREN);
93
94                     outputs.push((constraint, out));
95                 }
96             }
97             Inputs => {
98                 while p.token != token::EOF &&
99                       p.token != token::COLON &&
100                       p.token != token::MOD_SEP {
101
102                     if inputs.len() != 0 {
103                         p.eat(&token::COMMA);
104                     }
105
106                     let (constraint, _str_style) = p.parse_str();
107
108                     if constraint.starts_with("=") {
109                         cx.span_err(p.last_span, "input operand constraint contains '='");
110                     } else if constraint.starts_with("+") {
111                         cx.span_err(p.last_span, "input operand constraint contains '+'");
112                     }
113
114                     p.expect(&token::LPAREN);
115                     let input = p.parse_expr();
116                     p.expect(&token::RPAREN);
117
118                     inputs.push((constraint, input));
119                 }
120             }
121             Clobbers => {
122                 let mut clobs = ~[];
123                 while p.token != token::EOF &&
124                       p.token != token::COLON &&
125                       p.token != token::MOD_SEP {
126
127                     if clobs.len() != 0 {
128                         p.eat(&token::COMMA);
129                     }
130
131                     let (s, _str_style) = p.parse_str();
132                     let clob = format!("~\\{{}\\}", s);
133                     clobs.push(clob);
134                 }
135
136                 cons = clobs.connect(",");
137             }
138             Options => {
139                 let (option, _str_style) = p.parse_str();
140
141                 if "volatile" == option {
142                     volatile = true;
143                 } else if "alignstack" == option {
144                     alignstack = true;
145                 } else if "intel" == option {
146                     dialect = ast::AsmIntel;
147                 }
148
149                 if p.token == token::COMMA {
150                     p.eat(&token::COMMA);
151                 }
152             }
153         }
154
155         while p.token == token::COLON   ||
156               p.token == token::MOD_SEP ||
157               p.token == token::EOF {
158             state = if p.token == token::COLON {
159                 p.bump();
160                 match next_state(state) {
161                     Some(x) => x,
162                     None    => {
163                         continue_ = false;
164                         break
165                     }
166                 }
167             } else if p.token == token::MOD_SEP {
168                 p.bump();
169                 let s = match next_state(state) {
170                     Some(x) => x,
171                     None    => {
172                         continue_ = false;
173                         break
174                     }
175                 };
176                 match next_state(s) {
177                     Some(x) => x,
178                     None    => {
179                         continue_ = false;
180                         break
181                     }
182                 }
183             } else if p.token == token::EOF {
184                 continue_ = false;
185                 break;
186             } else {
187                state
188             };
189         }
190     }
191
192     MRExpr(@ast::Expr {
193         id: ast::DUMMY_NODE_ID,
194         node: ast::ExprInlineAsm(ast::InlineAsm {
195             asm: asm.get().to_managed(),
196             asm_str_style: asm_str_style.unwrap(),
197             clobbers: cons.to_managed(),
198             inputs: inputs,
199             outputs: outputs,
200             volatile: volatile,
201             alignstack: alignstack,
202             dialect: dialect
203         }),
204         span: sp
205     })
206 }