summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Mielczarek <ted@mielczarek.org>2015-07-07 15:00:16 -0400
committerTed Mielczarek <ted@mielczarek.org>2015-07-07 15:00:16 -0400
commit9684646d7bb3ba8b64c927d09abbeb012e033afe (patch)
treeaa6b4c332a4ad152ab3e11fe9a957e53f9354766
parent1cd7d980509fa934ba11ba39b301ff5a8bb1ce4c (diff)
Add support for generating consts for integer constants. Fixes #145.
This patch adds a few things to enable this: * Cursor::extent * struct Token * TranslationUnit::tokens - clang's C API doesn't have a straightforward way to get the integer literal from a variable declaration, so I used clang_tokenize to get the literal token and parse it. * VarInfo::val - to store the value. Non-const variable declarations and non-integer constants are handled as they were previously.
-rw-r--r--src/clang.rs37
-rw-r--r--src/gen.rs82
-rw-r--r--src/parser.rs39
-rw-r--r--src/types.rs3
4 files changed, 127 insertions, 34 deletions
diff --git a/src/clang.rs b/src/clang.rs
index 3b1878f7..da4b9dae 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -39,6 +39,12 @@ impl Cursor {
}
}
+ pub fn extent(&self) -> CXSourceRange {
+ unsafe {
+ clang_getCursorExtent(self.x)
+ }
+ }
+
pub fn cur_type(&self) -> Type {
unsafe {
Type { x: clang_getCursorType(self.x) }
@@ -351,6 +357,12 @@ impl Index {
}
}
+// Token
+pub struct Token {
+ pub kind: CXTokenKind,
+ pub spelling: String,
+}
+
// TranslationUnit
pub struct TranslationUnit {
x: CXTranslationUnit
@@ -358,7 +370,7 @@ pub struct TranslationUnit {
impl TranslationUnit {
pub fn parse(ix: &Index, file: &str, cmd_args: &[String],
- unsaved: &[UnsavedFile], opts: usize) -> TranslationUnit {
+ unsaved: &[UnsavedFile], opts: ::libc::c_uint) -> TranslationUnit {
let _fname = CString::new(file.as_bytes()).unwrap();
let fname = _fname.as_ptr();
let _c_args: Vec<CString> = cmd_args.iter().map(|s| CString::new(s.as_bytes()).unwrap()).collect();
@@ -370,7 +382,7 @@ impl TranslationUnit {
c_args.len() as c_int,
c_unsaved.as_mut_ptr(),
c_unsaved.len() as c_uint,
- opts as c_uint)
+ opts)
};
TranslationUnit { x: tu }
}
@@ -412,6 +424,27 @@ impl TranslationUnit {
pub fn is_null(&self) -> bool {
self.x.is_null()
}
+
+ pub fn tokens(&self, cursor: &Cursor) -> Option<Vec<Token>> {
+ let range = cursor.extent();
+ let mut tokens = vec![];
+ unsafe {
+ let mut token_ptr = ::std::ptr::null_mut();
+ let mut num_tokens : c_uint = 0;
+ clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens);
+ if token_ptr.is_null() {
+ return None;
+ }
+ let token_array = ::std::slice::from_raw_parts(token_ptr, num_tokens as usize);
+ for &token in token_array.iter() {
+ let kind = clang_getTokenKind(token);
+ let spelling = String_ { x: clang_getTokenSpelling(self.x, token) }.to_string();
+ tokens.push(Token { kind: kind, spelling: spelling });
+ }
+ clang_disposeTokens(self.x, token_ptr, num_tokens);
+ }
+ return Some(tokens);
+ }
}
// Diagnostic
diff --git a/src/gen.rs b/src/gen.rs
index 548e557b..eed36477 100644
--- a/src/gen.rs
+++ b/src/gen.rs
@@ -151,7 +151,22 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) ->
match g {
GOther => {}
GFunc(_) => fs.push(g),
- GVar(_) => vs.push(g),
+ GVar(_) => {
+ let is_int_const = {
+ match g {
+ GVar(ref vi) => {
+ let v = vi.borrow();
+ v.is_const && v.val.is_some()
+ }
+ _ => unreachable!()
+ }
+ };
+ if is_int_const {
+ gs.push(g);
+ } else {
+ vs.push(g);
+ }
+ }
_ => gs.push(g)
}
}
@@ -198,6 +213,11 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec<Global>, span: Span) ->
let e = ei.borrow().clone();
defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.kind, e.items).into_iter())
},
+ GVar(vi) => {
+ let v = vi.borrow();
+ let ty = cty_to_rs(&mut ctx, &v.ty);
+ defs.push(const_to_rs(&mut ctx, v.name.clone(), v.val.unwrap(), ty));
+ },
_ => { }
}
}
@@ -643,6 +663,28 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec<Com
items
}
+fn const_to_rs(ctx: &mut GenCtx, name: String, val: i64, val_ty: ast::Ty) -> P<ast::Item> {
+ let int_lit = ast::LitInt(
+ val.abs() as u64,
+ ast::UnsuffixedIntLit(if val < 0 { ast::Minus } else { ast::Plus })
+ );
+
+ let cst = ast::ItemConst(
+ P(val_ty),
+ ctx.ext_cx.expr_lit(ctx.span, int_lit)
+ );
+
+ let id = first(rust_id(ctx, name.clone()));
+ P(ast::Item {
+ ident: ctx.ext_cx.ident_of(&id[..]),
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ node: cst,
+ vis: ast::Public,
+ span: ctx.span
+ })
+}
+
fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, items: Vec<EnumItem>) -> Vec<P<ast::Item>> {
let ty = TInt(kind, Layout::zero());
let ty_id = rust_type_id(ctx, name);
@@ -651,27 +693,7 @@ fn cenum_to_rs(ctx: &mut GenCtx, name: String, kind: IKind, items: Vec<EnumItem>
let mut def = ty_def;
for it in items.iter() {
- let int_lit = ast::LitInt(
- it.val.abs() as u64,
- ast::UnsuffixedIntLit(if it.val < 0 { ast::Minus } else { ast::Plus })
- );
-
- let cst = ast::ItemConst(
- P(val_ty.clone()),
- ctx.ext_cx.expr_lit(ctx.span, int_lit)
- );
-
- let id = first(rust_id(ctx, it.name.clone()));
- let val_def = P(ast::Item {
- ident: ctx.ext_cx.ident_of(&id[..]),
- attrs: Vec::new(),
- id: ast::DUMMY_NODE_ID,
- node: cst,
- vis: ast::Public,
- span: ctx.span
- });
-
- def.push(val_def);
+ def.push(const_to_rs(ctx, it.name.clone(), it.val, val_ty.clone()));
}
return def;
@@ -849,14 +871,16 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String,
attrs.push(mk_link_name_attr(ctx, name));
}
+ let val_ty = P(cty_to_rs(ctx, ty));
+
return P(ast::ForeignItem {
- ident: ctx.ext_cx.ident_of(&rust_name[..]),
- attrs: attrs,
- node: ast::ForeignItemStatic(P(cty_to_rs(ctx, ty)), !is_const),
- id: ast::DUMMY_NODE_ID,
- span: ctx.span,
- vis: ast::Public,
- });
+ ident: ctx.ext_cx.ident_of(&rust_name[..]),
+ attrs: attrs,
+ node: ast::ForeignItemStatic(val_ty, !is_const),
+ id: ast::DUMMY_NODE_ID,
+ span: ctx.span,
+ vis: ast::Public,
+ });
}
fn cfuncty_to_rs(ctx: &mut GenCtx,
diff --git a/src/parser.rs b/src/parser.rs
index ee566124..b8e4e72a 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -451,8 +451,37 @@ fn visit_enum(cursor: &Cursor,
return CXChildVisit_Continue;
}
+fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option<i64> {
+ if cursor.kind() == CXCursor_IntegerLiteral {
+ return match unit.tokens(cursor) {
+ None => None,
+ Some(tokens) => {
+ if tokens.len() == 0 || tokens[0].kind != CXToken_Literal {
+ None
+ } else {
+ let ref s = tokens[0].spelling;
+ let parsed = {
+ //TODO: try to preserve hex literals?
+ if s.starts_with("0x") {
+ i64::from_str_radix(&s[2..], 16)
+ } else {
+ s.parse()
+ }
+ };
+ match parsed {
+ Ok(i) => Some(i),
+ Err(_) => None,
+ }
+ }
+ }
+ }
+ }
+ return None;
+}
+
fn visit_top<'r>(cursor: &Cursor,
- ctx: &mut ClangParserCtx) -> Enum_CXVisitorResult {
+ ctx: &mut ClangParserCtx,
+ unit: &TranslationUnit) -> Enum_CXVisitorResult {
if !match_pattern(ctx, cursor) {
return CXChildVisit_Continue;
}
@@ -509,6 +538,10 @@ fn visit_top<'r>(cursor: &Cursor,
let mut vi = vi.borrow_mut();
vi.ty = ty.clone();
vi.is_const = cursor.cur_type().is_const();
+ cursor.visit(|c, _: &Cursor| {
+ vi.val = visit_literal(c, unit);
+ CXChildVisit_Continue
+ });
ctx.globals.push(var);
return CXChildVisit_Continue;
@@ -586,11 +619,11 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result<Vec<Global>
cursor.visit(|cur, _: &Cursor| ast_dump(cur, 0));
}
- cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx));
+ cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit));
while !ctx.builtin_defs.is_empty() {
let c = ctx.builtin_defs.remove(0);
- visit_top(&c.definition(), &mut ctx);
+ visit_top(&c.definition(), &mut ctx, &unit);
}
unit.dispose();
diff --git a/src/types.rs b/src/types.rs
index 88b73e51..27cc0b03 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -281,6 +281,8 @@ impl fmt::Debug for TypeInfo {
pub struct VarInfo {
pub name: String,
pub ty: Type,
+ //TODO: support non-integer constants
+ pub val: Option<i64>,
pub is_const: bool
}
@@ -289,6 +291,7 @@ impl VarInfo {
VarInfo {
name: name,
ty: ty,
+ val: None,
is_const: false
}
}