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; 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 57 ret ~= 58 maybePragma(cursor, context) ~ 59 text("extern __gshared ", static_, 60 translateType(cursor.type, context, No.translatingFunction), " ", spelling, ";"); 61 } 62 63 return ret; 64 } 65 66 67 private string[] translateConstexpr(in string spelling, 68 in from!"clang".Cursor cursor, 69 ref from!"dpp.runtime.context".Context context) 70 @safe 71 { 72 import dpp.translation.tokens: translateTokens; 73 import dpp.translation.exception: UntranslatableException; 74 import dpp.translation.type: translate; 75 import clang: Cursor, Token; 76 import std.algorithm: find, canFind; 77 import std.conv: text; 78 import std.array: empty, popFront; 79 import std.typecons: No; 80 81 auto tokens = cursor.tokens; 82 tokens = tokens.find!(a => a.kind == Token.Kind.Punctuation && a.spelling == "="); 83 84 const init = () { 85 // see contract.constexpr.variable.init.braces 86 if(cursor.children.canFind!(c => c.kind == Cursor.Kind.InitListExpr)) 87 return " = " ~ translate(cursor.type, context, No.translatingFunction) ~ ".init"; 88 89 if(!tokens.empty) { 90 tokens.popFront; 91 return " = " ~ translateTokens(tokens); 92 } 93 94 throw new UntranslatableException( 95 text("Could not find assignment in ", cursor.tokens, 96 "\ncursor: ", cursor, "\n@ ", cursor.sourceRange)); 97 }(); 98 99 return [ text("enum ", spelling, init, ";") ]; 100 } 101 102 private bool isRecordWithoutDefinition( 103 in from!"clang".Cursor cursor, 104 ref from!"dpp.runtime.context".Context context) 105 @safe 106 { 107 import clang: Cursor, Type; 108 109 const canonicalType = cursor.type.canonical; 110 111 if(canonicalType.kind != Type.Kind.Record) 112 return false; 113 114 const declaration = canonicalType.declaration; 115 const definition = declaration.definition; 116 const specializedTemplate = declaration.specializedCursorTemplate; 117 118 context.log("canonicalType: ", canonicalType); 119 context.log("declaration: ", declaration); 120 context.log("definition: ", definition); 121 context.log("specialised cursor template: ", specializedTemplate); 122 123 return 124 definition.isInvalid && 125 // See #97 126 specializedTemplate.kind != Cursor.Kind.ClassTemplate 127 ; 128 }