|
1 | 1 | //! Intermediate representation of variables.
|
2 | 2 |
|
| 3 | +use cexpr; |
3 | 4 | use clang;
|
4 | 5 | use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
|
| 6 | +use std::num::Wrapping; |
5 | 7 | use super::context::BindgenContext;
|
6 | 8 | use super::function::cursor_mangling;
|
7 | 9 | use super::int::IntKind;
|
@@ -73,43 +75,66 @@ impl ClangSubItemParser for Var {
|
73 | 75 | ctx: &mut BindgenContext)
|
74 | 76 | -> Result<ParseResult<Self>, ParseError> {
|
75 | 77 | use clangll::*;
|
| 78 | + use cexpr::expr::EvalResult; |
76 | 79 | match cursor.kind() {
|
77 | 80 | CXCursor_MacroDefinition => {
|
78 |
| - let value = parse_int_literal_tokens(&cursor, |
79 |
| - ctx.translation_unit()); |
| 81 | + let value = parse_macro(ctx, &cursor, ctx.translation_unit()); |
80 | 82 |
|
81 |
| - let value = match value { |
| 83 | + let (id, value) = match value { |
82 | 84 | Some(v) => v,
|
83 | 85 | None => return Err(ParseError::Continue),
|
84 | 86 | };
|
85 | 87 |
|
86 |
| - let name = cursor.spelling(); |
87 |
| - if name.is_empty() { |
88 |
| - warn!("Empty macro name?"); |
89 |
| - return Err(ParseError::Continue); |
90 |
| - } |
| 88 | + assert!(!id.is_empty(), "Empty macro name?"); |
91 | 89 |
|
92 |
| - if ctx.parsed_macro(&name) { |
| 90 | + if ctx.parsed_macro(&id) { |
| 91 | + let name = String::from_utf8(id).unwrap(); |
93 | 92 | warn!("Duplicated macro definition: {}", name);
|
94 | 93 | return Err(ParseError::Continue);
|
95 | 94 | }
|
96 |
| - ctx.note_parsed_macro(name.clone()); |
97 |
| - |
98 |
| - let ty = if value < 0 { |
99 |
| - Item::builtin_type(TypeKind::Int(IntKind::Int), true, ctx) |
100 |
| - } else if value.abs() > u32::max_value() as i64 { |
101 |
| - Item::builtin_type(TypeKind::Int(IntKind::ULongLong), |
102 |
| - true, |
103 |
| - ctx) |
104 |
| - } else { |
105 |
| - Item::builtin_type(TypeKind::Int(IntKind::UInt), true, ctx) |
| 95 | + |
| 96 | + // NB: It's important to "note" the macro even if the result is |
| 97 | + // not an integer, otherwise we might loose other kind of |
| 98 | + // derived macros. |
| 99 | + ctx.note_parsed_macro(id.clone(), value.clone()); |
| 100 | + |
| 101 | + // NOTE: Unwrapping, here and above, is safe, because the |
| 102 | + // identifier of a token comes straight from clang, and we |
| 103 | + // enforce utf8 there, so we should have already panicked at |
| 104 | + // this point. |
| 105 | + let name = String::from_utf8(id).unwrap(); |
| 106 | + let (int_kind, val) = match value { |
| 107 | + // TODO(emilio): Handle the non-invalid ones! |
| 108 | + EvalResult::Float(..) | |
| 109 | + EvalResult::Char(..) | |
| 110 | + EvalResult::Str(..) | |
| 111 | + EvalResult::Invalid => return Err(ParseError::Continue), |
| 112 | + |
| 113 | + EvalResult::Int(Wrapping(value)) => { |
| 114 | + // FIXME(emilio): We might be able to do better, an int |
| 115 | + // can be too small for large negative values I guess. |
| 116 | + // |
| 117 | + // The easiest thing may be just using i64 for |
| 118 | + // everything. |
| 119 | + let kind = if value < 0 { |
| 120 | + if value < i32::min_value() as i64 { |
| 121 | + IntKind::LongLong |
| 122 | + } else { |
| 123 | + IntKind::Int |
| 124 | + } |
| 125 | + } else if value > u32::max_value() as i64 { |
| 126 | + IntKind::ULongLong |
| 127 | + } else { |
| 128 | + IntKind::UInt |
| 129 | + }; |
| 130 | + |
| 131 | + (kind, value) |
| 132 | + } |
106 | 133 | };
|
107 | 134 |
|
108 |
| - Ok(ParseResult::New(Var::new(name, |
109 |
| - None, |
110 |
| - ty, |
111 |
| - Some(value), |
112 |
| - true), |
| 135 | + let ty = Item::builtin_type(TypeKind::Int(int_kind), true, ctx); |
| 136 | + |
| 137 | + Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), |
113 | 138 | Some(cursor)))
|
114 | 139 | }
|
115 | 140 | CXCursor_VarDecl => {
|
@@ -153,49 +178,43 @@ impl ClangSubItemParser for Var {
|
153 | 178 | }
|
154 | 179 | }
|
155 | 180 |
|
156 |
| -/// Try and parse the immediately found tokens from an unit (if any) to integers |
| 181 | +/// Try and parse a macro using all the macros parsed until now. |
| 182 | +fn parse_macro(ctx: &BindgenContext, |
| 183 | + cursor: &clang::Cursor, |
| 184 | + unit: &clang::TranslationUnit) |
| 185 | + -> Option<(Vec<u8>, cexpr::expr::EvalResult)> { |
| 186 | + use cexpr::{expr, nom}; |
| 187 | + |
| 188 | + let cexpr_tokens = match unit.cexpr_tokens(cursor) { |
| 189 | + None => return None, |
| 190 | + Some(tokens) => tokens, |
| 191 | + }; |
| 192 | + |
| 193 | + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); |
| 194 | + let result = parser.macro_definition(&cexpr_tokens); |
| 195 | + |
| 196 | + match result { |
| 197 | + nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), |
| 198 | + _ => None, |
| 199 | + } |
| 200 | +} |
| 201 | + |
157 | 202 | fn parse_int_literal_tokens(cursor: &clang::Cursor,
|
158 | 203 | unit: &clang::TranslationUnit)
|
159 | 204 | -> Option<i64> {
|
160 |
| - use clangll::{CXToken_Literal, CXToken_Punctuation}; |
| 205 | + use cexpr::{expr, nom}; |
| 206 | + use cexpr::expr::EvalResult; |
161 | 207 |
|
162 |
| - let tokens = match unit.tokens(cursor) { |
| 208 | + let cexpr_tokens = match unit.cexpr_tokens(cursor) { |
163 | 209 | None => return None,
|
164 | 210 | Some(tokens) => tokens,
|
165 | 211 | };
|
166 | 212 |
|
167 |
| - let mut literal = None; |
168 |
| - let mut negate = false; |
169 |
| - for token in tokens.into_iter() { |
170 |
| - match token.kind { |
171 |
| - CXToken_Punctuation if token.spelling == "-" => { |
172 |
| - negate = !negate; |
173 |
| - } |
174 |
| - CXToken_Literal => { |
175 |
| - literal = Some(token.spelling); |
176 |
| - break; |
177 |
| - } |
178 |
| - _ => { |
179 |
| - // Reset values if we found anything else |
180 |
| - negate = false; |
181 |
| - literal = None; |
182 |
| - } |
183 |
| - } |
| 213 | + // TODO(emilio): We can try to parse other kinds of literals. |
| 214 | + match expr::expr(&cexpr_tokens) { |
| 215 | + nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), |
| 216 | + _ => None, |
184 | 217 | }
|
185 |
| - |
186 |
| - literal.and_then(|lit| { |
187 |
| - if lit.starts_with("0x") { |
188 |
| - // TODO: try to preserve hex literals? |
189 |
| - i64::from_str_radix(&lit[2..], 16).ok() |
190 |
| - } else if lit == "0" { |
191 |
| - Some(0) |
192 |
| - } else if lit.starts_with("0") { |
193 |
| - i64::from_str_radix(&lit[1..], 8).ok() |
194 |
| - } else { |
195 |
| - lit.parse().ok() |
196 |
| - } |
197 |
| - }) |
198 |
| - .map(|lit| if negate { -lit } else { lit }) |
199 | 218 | }
|
200 | 219 |
|
201 | 220 | fn get_integer_literal_from_cursor(cursor: &clang::Cursor,
|
|
0 commit comments