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")[1 .. $]; // strip the leading 'v'
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     /// add global imports
109     @("global-import", "Add <import> as a global import.")
110     string[] globalImports;
111 
112     Options toOptions(string inputFile, string outputFile) const
113     {
114         Options options = toOptions();
115 
116         options.inputFile = inputFile.asAbsNormPath;
117         options.outputFile = outputFile.asAbsNormPath;
118 
119         return options;
120     }
121 
122     Options toOptions() const
123     {
124         import std.algorithm.iteration : map;
125         import std.array;
126 
127         Options options;
128         options.inputFiles = inputFiles.map!(path => path.asAbsNormPath).array;
129         options.language = language;
130         options.enableComments = enableComments;
131         options.packageName = packageName;
132         options.publicSubmodules = publicSubmodules;
133         options.normalizeModules = normalizeModules;
134         options.reduceAliases = reduceAliases;
135         options.translateMacros = translateMacros;
136         options.aliasEnumMembers = aliasEnumMembers;
137         options.renameEnumMembers = renameEnumMembers;
138         options.portableWCharT = portableWCharT;
139         options.zeroParamIsVararg = zeroParamIsVararg;
140         options.singleLineFunctionSignatures = singleLineFunctionSignatures;
141         options.spaceAfterFunctionName = spaceAfterFunctionName;
142         options.skipDefinitions = setFromList(skipDefinitions);
143         options.skipSymbols = setFromList(skipSymbols);
144         options.printDiagnostics = printDiagnostics;
145         options.collisionAction = collisionAction;
146         options.globalAttributes = globalAttributes;
147         options.globalImports = globalImports;
148 
149         return options;
150     }
151 }
152 
153 template makeGetOptArgs(alias config)
154 {
155     import std.meta;
156 
157     template expand(alias spelling)
158     {
159         alias member = Alias!(__traits(getMember, config, spelling));
160 
161         static if (
162             __traits(compiles, &__traits(getMember, config, spelling)) &&
163             __traits(getAttributes, member).length == 2)
164         {
165             auto ptr() @property
166             {
167                 return &__traits(getMember, config, spelling);
168             }
169 
170             auto formatHelp(alias spelling)(string help)
171             {
172                 import std.algorithm;
173                 import std.format;
174                 import std..string;
175                 import std.range;
176 
177                 Configuration config;
178 
179                 string suffix;
180 
181                 static if (is(typeof(member) == bool) || is(typeof(member) == enum))
182                 {
183                     auto default_ = "[default]";
184 
185                     if (help.canFind(default_))
186                     {
187                         help = help.replace(
188                             default_,
189                             format("[default: %s]", __traits(getMember, config, spelling)));
190 
191                         static if (is(typeof(member) == bool))
192                         {
193                             suffix = "=true|false";
194                         }
195                         else
196                         {
197                             suffix = format(
198                                 "=%s",
199                                 join([ __traits(allMembers, typeof(member)) ], "|"));
200                         }
201                     }
202                 }
203                 else
204                 {
205                     auto beginning = findSplitBefore(help, "<");
206 
207                     if (!beginning[0].empty)
208                     {
209                         auto placeholder = findSplitAfter(beginning[1], ">");
210 
211                         if (!placeholder[0].empty)
212                             suffix = format(" %s", placeholder[0]);
213                     }
214                 }
215 
216                 return format("%s!%s", suffix, help);
217             }
218 
219             alias expand = AliasSeq!(
220                 __traits(getAttributes, __traits(getMember, config, spelling))[0],
221                 formatHelp!spelling(
222                     __traits(getAttributes, __traits(getMember, config, spelling))[1]),
223                 ptr);
224         }
225         else
226         {
227             alias expand = AliasSeq!();
228         }
229     }
230 
231     alias makeGetOptArgs = staticMap!(expand, __traits(allMembers, typeof(config)));
232 }
233