1 /**
2  * Copyright: Copyright (c) 2016 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
5  */
6 module dstep.Configuration;
7 
8 import clang.Util;
9 
10 import dstep.translator.Options;
11 
12 /**
13  *  Aggregation of global configuration options affecting the program
14  */
15 struct Configuration
16 {
17     /// app version string, generated by the build system
18     enum Version = import("VERSION");
19 
20     /// array of file names to translate to D
21     string[] inputFiles;
22 
23     /// expected programming language of input files
24     Language language;
25 
26     /// show dstep version
27     @("version", "Show dstep version.")
28     bool dstepVersion;
29 
30     /// show libclang version
31     @("clang-version", "Show libclang version.")
32     bool clangVersion;
33 
34     /// array of parameters needed to be forwarded to clang driver
35     string[] clangParams;
36 
37     /// output file name or folder (in case there are many input files)
38     string output;
39 
40     /// package name
41     @("package", "Use <package> as package name.")
42     string packageName;
43 
44     /// enable translation of comments
45     @("comments", "Translate comments [default].")
46     bool enableComments = true;
47 
48     /// use public imports for submodules
49     @("public-submodules", "Use public imports for submodules [default].")
50     bool publicSubmodules = false;
51 
52     // rename modules to D conforming form
53     @("normalize-modules", "Rename modules to D conforming form [default].")
54     bool normalizeModules = false;
55 
56     /// enable reduction of primitive type aliases
57     @("reduce-aliases", "Reduce primitive type aliases [default].")
58     bool reduceAliases = true;
59 
60     /// translate C preprocessor macros if possible
61     @("translate-macros", "Translate C preprocessor macros if possible [default].")
62     bool translateMacros = true;
63 
64     /// generate aliases for enum members in global scope
65     @("alias-enum-members", "Generate aliases for enum members in global scope [default].")
66     bool aliasEnumMembers = false;
67 
68     /// attempt to rename the enumeration members to D conforming form
69     @("rename-enum-members", "Attempt to rename the enumeration members to D conforming form. [default].")
70     bool renameEnumMembers = false;
71 
72     /// translate to wchar_t to core.stdc.stddef.wchar_t
73     @("portable-wchar_t", "Translate wchar_t as core.stdc.stddef.wchar_t [default].")
74     bool portableWCharT = true;
75 
76     /// translate functions with empty argument list as vararg
77     @("zero-param-is-vararg", "Translate functions with no arguments as variadic functions [default].")
78     bool zeroParamIsVararg = false;
79 
80     /// single line function headers
81     @("single-line-function-signatures", "Keep function signatures in a single line [default].")
82     bool singleLineFunctionSignatures = false;
83 
84     /// space after function name
85     @("space-after-function-name", "Put a space after a function name [default].")
86     bool spaceAfterFunctionName = true;
87 
88     /// do not translate bodies of following structs and unions
89     @("skip-definition", "Keep only the signature of <symbol>.")
90     string[] skipDefinitions;
91 
92     /// do not translate following symbols
93     @("skip", "Skip translation of <symbol>.")
94     string[] skipSymbols;
95 
96     /// print diagnostic informations
97     @("print-diagnostics", "Print diagnostic informations [default].")
98     bool printDiagnostics = true;
99 
100     /// action to take on symbol collision
101     @("collision-action", "Action to take when translated symbol collides with a preexisting symbol [default].")
102     CollisionAction collisionAction = CollisionAction.rename;
103 
104     /// add global attributes
105     @("global-attribute", "Add <attribute> as a global attribute.")
106     string[] globalAttributes;
107 
108     Options toOptions(string inputFile, string outputFile) const
109     {
110         Options options = toOptions();
111 
112         options.inputFile = inputFile.asAbsNormPath;
113         options.outputFile = outputFile.asAbsNormPath;
114 
115         return options;
116     }
117 
118     Options toOptions() const
119     {
120         import std.algorithm.iteration : map;
121         import std.array;
122 
123         Options options;
124         options.inputFiles = inputFiles.map!(path => path.asAbsNormPath).array;
125         options.language = language;
126         options.enableComments = enableComments;
127         options.packageName = packageName;
128         options.publicSubmodules = publicSubmodules;
129         options.normalizeModules = normalizeModules;
130         options.reduceAliases = reduceAliases;
131         options.translateMacros = translateMacros;
132         options.aliasEnumMembers = aliasEnumMembers;
133         options.renameEnumMembers = renameEnumMembers;
134         options.portableWCharT = portableWCharT;
135         options.zeroParamIsVararg = zeroParamIsVararg;
136         options.singleLineFunctionSignatures = singleLineFunctionSignatures;
137         options.spaceAfterFunctionName = spaceAfterFunctionName;
138         options.skipDefinitions = setFromList(skipDefinitions);
139         options.skipSymbols = setFromList(skipSymbols);
140         options.printDiagnostics = printDiagnostics;
141         options.collisionAction = collisionAction;
142         options.globalAttributes = globalAttributes;
143 
144         return options;
145     }
146 }
147 
148 template makeGetOptArgs(alias config)
149 {
150     import std.meta;
151 
152     template expand(alias spelling)
153     {
154         alias member = Alias!(__traits(getMember, config, spelling));
155 
156         static if (
157             __traits(compiles, &__traits(getMember, config, spelling)) &&
158             __traits(getAttributes, member).length == 2)
159         {
160             auto ptr() @property
161             {
162                 return &__traits(getMember, config, spelling);
163             }
164 
165             auto formatHelp(alias spelling)(string help)
166             {
167                 import std.algorithm;
168                 import std.format;
169                 import std..string;
170                 import std.range;
171 
172                 Configuration config;
173 
174                 string suffix;
175 
176                 static if (is(typeof(member) == bool) || is(typeof(member) == enum))
177                 {
178                     auto default_ = "[default]";
179 
180                     if (help.canFind(default_))
181                     {
182                         help = help.replace(
183                             default_,
184                             format("[default: %s]", __traits(getMember, config, spelling)));
185 
186                         static if (is(typeof(member) == bool))
187                         {
188                             suffix = "=true|false";
189                         }
190                         else
191                         {
192                             suffix = format(
193                                 "=%s",
194                                 join([ __traits(allMembers, typeof(member)) ], "|"));
195                         }
196                     }
197                 }
198                 else
199                 {
200                     auto beginning = findSplitBefore(help, "<");
201 
202                     if (!beginning[0].empty)
203                     {
204                         auto placeholder = findSplitAfter(beginning[1], ">");
205 
206                         if (!placeholder[0].empty)
207                             suffix = format(" %s", placeholder[0]);
208                     }
209                 }
210 
211                 return format("%s!%s", suffix, help);
212             }
213 
214             alias expand = AliasSeq!(
215                 __traits(getAttributes, __traits(getMember, config, spelling))[0],
216                 formatHelp!spelling(
217                     __traits(getAttributes, __traits(getMember, config, spelling))[1]),
218                 ptr);
219         }
220         else
221         {
222             alias expand = AliasSeq!();
223         }
224     }
225 
226     alias makeGetOptArgs = staticMap!(expand, __traits(allMembers, typeof(config)));
227 }
228