1 module contract.macro_; 2 3 4 import contract; 5 6 7 @Tags("contract") 8 @("macro after enum") 9 @safe unittest { 10 11 import clang: TranslationUnitFlags; 12 import std.algorithm: countUntil; 13 14 const tu = parse( 15 C( 16 ` 17 enum TheEnum { BAR = 42 }; 18 #define BAR 42 19 ` 20 ), 21 TranslationUnitFlags.DetailedPreprocessingRecord, 22 ); 23 24 tu.children.length.shouldBeGreaterThan(2); 25 26 const enumIndex = tu.children.countUntil!(a => a.kind == Cursor.Kind.EnumDecl && a.spelling == "TheEnum"); 27 const macroIndex = tu.children.countUntil!(a => a.kind == Cursor.Kind.MacroDefinition && a.spelling == "BAR"); 28 29 // for unfathomable reasons, clang puts all the macros at the top 30 // completely disregarding the order they appear in the code 31 enumIndex.shouldBeGreaterThan(macroIndex); 32 } 33 34 35 @Tags("contract") 36 @("tokens") 37 @safe unittest { 38 import dpp.translation.macro_: isBuiltinMacro; 39 import clang: TranslationUnitFlags, Token; 40 import std.algorithm: filter; 41 import std.array: array; 42 43 const tu = parse( 44 C( 45 ` 46 #define INT 42 47 #define DOUBLE 33.3 48 #define OCTAL 00177 49 #define STRING "foobar" 50 ` 51 ), 52 TranslationUnitFlags.DetailedPreprocessingRecord, 53 ); 54 55 auto childrenRange = tu.children.filter!(a => !isBuiltinMacro(a)); 56 const children = () @trusted { return childrenRange.array; }(); 57 children.length.should == 4; 58 59 const int_ = children[0]; 60 int_.tokens.should == [ 61 Token(Token.Kind.Identifier, "INT"), 62 Token(Token.Kind.Literal, "42"), 63 ]; 64 65 const double_ = children[1]; 66 double_.tokens.should == [ 67 Token(Token.Kind.Identifier, "DOUBLE"), 68 Token(Token.Kind.Literal, "33.3"), 69 ]; 70 71 const octal = children[2]; 72 octal.tokens.should == [ 73 Token(Token.Kind.Identifier, "OCTAL"), 74 Token(Token.Kind.Literal, "00177"), 75 ]; 76 77 const string_ = children[3]; 78 string_.tokens.should == [ 79 Token(Token.Kind.Identifier, "STRING"), 80 Token(Token.Kind.Literal, `"foobar"`), 81 ]; 82 }