1 module dpp.translation.variable; 2 3 import dpp.from; 4 5 string[] translateVariable(in from!"clang".Cursor cursor, 6 ref from!"dpp.runtime.context".Context context) 7 @safe 8 { 9 import dpp.translation.dlang: maybePragma; 10 import dpp.translation.translation: translateCursor = translate; 11 import dpp.translation.type: translateType = translate; 12 import dpp.translation.tokens: translateTokens; 13 import clang: Cursor, Type, Token; 14 import std.conv: text; 15 import std.typecons: No; 16 import std.algorithm: canFind, find, map; 17 import std.array: empty, popFront, join; 18 19 assert(cursor.kind == Cursor.Kind.VarDecl); 20 21 string[] ret; 22 23 const isAnonymous = cursor.type.spelling.canFind("(anonymous"); 24 // If the type is anonymous, then we need to define it before we declare 25 // ourselves of that type, unless that type is an enum. See #54. 26 if(isAnonymous && cursor.type.canonical.declaration.kind != Cursor.Kind.EnumDecl) { 27 ret ~= translateCursor(cursor.type.canonical.declaration, context); 28 } 29 30 // variables can be declared multiple times in C but only one in D 31 if(!cursor.isCanonical) return []; 32 33 // Don't bother if we don't have a definition anywhere - C allows this but D 34 // doesn't. See it.compile.projects.ASN1_ITEM or try #including <openssl/ssl.h>. 35 // There will be a problem with the global variables such as DHparams_it that 36 // have a struct with an unknown type unless one includes <openssl/asn1t.h> 37 // as well. In C, as long as one doesn't try to do anything with the variable, 38 // that's ok. In D, it's not. Essentially: 39 // struct Foo; 40 // extern Foo gFoo; 41 if(isRecordWithoutDefinition(cursor, context)) return []; 42 43 const spelling = context.rememberLinkable(cursor); 44 45 // global variable or static member of a struct/class? 46 const static_ = cursor.semanticParent.type.canonical.kind == Type.Kind.Record 47 ? "static " 48 : ""; 49 const constexpr = cursor.tokens.canFind(Token(Token.Kind.Keyword, "constexpr")); 50 51 if(constexpr) { 52 // e.g. enum foo = 42; 53 auto tokens = cursor.tokens; 54 tokens = tokens.find!(a => a.kind == Token.Kind.Punctuation && a.spelling == "="); 55 56 if(tokens.empty) 57 throw new Exception(text("Could not find assignment in ", cursor.tokens)); 58 59 tokens.popFront; 60 61 ret ~= text("enum ", spelling, " = ", translateTokens(tokens), ";"); 62 } else 63 ret ~= 64 maybePragma(cursor, context) ~ 65 text("extern __gshared ", static_, 66 translateType(cursor.type, context, No.translatingFunction), " ", spelling, ";") 67 ; 68 69 return ret; 70 } 71 72 73 private bool isRecordWithoutDefinition( 74 in from!"clang".Cursor cursor, 75 ref from!"dpp.runtime.context".Context context) 76 @safe 77 { 78 import clang: Type; 79 80 const canonicalType = cursor.type.canonical; 81 82 if(canonicalType.kind != Type.Kind.Record) 83 return false; 84 85 86 const declaration = canonicalType.declaration; 87 const definition = declaration.definition; 88 89 context.log("canonicalType: ", canonicalType); 90 context.log("declaration: ", declaration); 91 context.log("definition: ", definition); 92 93 return definition.isInvalid; 94 }