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 in(cursor.kind == from!"clang".Cursor.Kind.VarDecl) 9 do 10 { 11 import dpp.translation.exception: UntranslatableException; 12 import dpp.translation.dlang: maybePragma; 13 import dpp.translation.translation: translateCursor = translate; 14 import dpp.translation.type: translateType = translate; 15 import dpp.translation.tokens: translateTokens; 16 import clang: Cursor, Type, Token; 17 import std.conv: text; 18 import std.typecons: No; 19 import std.algorithm: canFind, find, map; 20 import std.array: empty, popFront, join, replace; 21 22 string[] ret; 23 24 const isAnonymous = cursor.type.spelling.canFind("(anonymous"); 25 // If the type is anonymous, then we need to define it before we declare 26 // ourselves of that type, unless that type is an enum. See #54. 27 if(isAnonymous && cursor.type.canonical.declaration.kind != Cursor.Kind.EnumDecl) { 28 ret ~= translateCursor(cursor.type.canonical.declaration, context); 29 } 30 31 // variables can be declared multiple times in C but only one in D 32 if(!cursor.isCanonical) return []; 33 34 // Don't bother if we don't have a definition anywhere - C allows this but D 35 // doesn't. See it.compile.projects.ASN1_ITEM or try #including <openssl/ssl.h>. 36 // There will be a problem with the global variables such as DHparams_it that 37 // have a struct with an unknown type unless one includes <openssl/asn1t.h> 38 // as well. In C, as long as one doesn't try to do anything with the variable, 39 // that's ok. In D, it's not. Essentially: 40 // struct Foo; 41 // extern Foo gFoo; 42 if(isRecordWithoutDefinition(cursor, context)) return []; 43 44 const spelling = context.rememberLinkable(cursor); 45 46 // global variable or static member of a struct/class? 47 const static_ = cursor.semanticParent.type.canonical.kind == Type.Kind.Record 48 ? "static " 49 : ""; 50 // e.g. enum foo = 42; 51 const constexpr = cursor.tokens.canFind(Token(Token.Kind.Keyword, "constexpr")); 52 53 if(constexpr) 54 ret ~= translateConstexpr(spelling, cursor, context); 55 else { 56 const maybeTypeSpelling = translateType(cursor.type, context, No.translatingFunction); 57 // In C it is possible to have an extern void variable 58 const typeSpelling = cursor.type.kind == Type.Kind.Void 59 ? maybeTypeSpelling.replace("void", "void*") 60 : maybeTypeSpelling; 61 ret ~= 62 maybePragma(cursor, context) ~ 63 text("extern __gshared ", static_, typeSpelling, " ", spelling, ";"); 64 } 65 66 return ret; 67 } 68 69 70 private string[] translateConstexpr(in string spelling, 71 in from!"clang".Cursor cursor, 72 ref from!"dpp.runtime.context".Context context) 73 @safe 74 { 75 import dpp.translation.tokens: translateTokens; 76 import dpp.translation.exception: UntranslatableException; 77 import dpp.translation.type: translate; 78 import clang: Cursor, Token; 79 import std.algorithm: find, canFind; 80 import std.conv: text; 81 import std.array: empty, popFront; 82 import std.typecons: No; 83 84 auto tokens = cursor.tokens; 85 tokens = tokens.find!(a => a.kind == Token.Kind.Punctuation && a.spelling == "="); 86 87 const init = () { 88 // see contract.constexpr.variable.init.braces 89 if(cursor.children.canFind!(c => c.kind == Cursor.Kind.InitListExpr)) 90 return " = " ~ translate(cursor.type, context, No.translatingFunction) ~ ".init"; 91 92 if(!tokens.empty) { 93 tokens.popFront; 94 return " = " ~ translateTokens(tokens); 95 } 96 97 throw new UntranslatableException( 98 text("Could not find assignment in ", cursor.tokens, 99 "\ncursor: ", cursor, "\n@ ", cursor.sourceRange)); 100 }(); 101 102 return [ text("enum ", spelling, init, ";") ]; 103 } 104 105 private bool isRecordWithoutDefinition( 106 in from!"clang".Cursor cursor, 107 ref from!"dpp.runtime.context".Context context) 108 @safe 109 { 110 import clang: Cursor, Type; 111 112 const canonicalType = cursor.type.canonical; 113 114 if(canonicalType.kind != Type.Kind.Record) 115 return false; 116 117 const declaration = canonicalType.declaration; 118 const definition = declaration.definition; 119 const specializedTemplate = declaration.specializedCursorTemplate; 120 121 context.log("canonicalType: ", canonicalType); 122 context.log("declaration: ", declaration); 123 context.log("definition: ", definition); 124 context.log("specialised cursor template: ", specializedTemplate); 125 126 return 127 definition.isInvalid && 128 // See #97 129 specializedTemplate.kind != Cursor.Kind.ClassTemplate 130 ; 131 }