1 /**
2  * Copyright: Copyright (c) 2016 Wojciech Szęszoł. All rights reserved.
3  * Authors: Wojciech Szęszoł
4  * Version: Initial created: May 21, 2016
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dstep.translator.Options;
8 
9 import clang.Util;
10 
11 import dstep.translator.ConvertCase;
12 
13 enum Language
14 {
15     c,
16     objC
17 }
18 
19 enum CollisionAction
20 {
21     ignore,
22     rename,
23     abort
24 }
25 
26 struct Options
27 {
28     import clang.Cursor: Cursor;
29 
30     string[] inputFiles;
31     string inputFile;
32     string outputFile;
33     Language language = Language.c;
34     string packageName;
35     bool enableComments = true;
36     bool publicSubmodules = false;
37     bool normalizeModules = false;
38     bool keepUntranslatable = false;
39     bool reduceAliases = true;
40     bool translateMacros = true;
41     bool portableWCharT = true;
42     bool zeroParamIsVararg = false;
43     bool singleLineFunctionSignatures = false;
44     bool spaceAfterFunctionName = true;
45     bool aliasEnumMembers = false;
46     bool renameEnumMembers = false;
47     Set!string skipDefinitions;
48     Set!string skipSymbols;
49     bool printDiagnostics = true;
50     CollisionAction collisionAction = CollisionAction.rename;
51     const(string)[] globalAttributes;
52     const(string)[] globalImports;
53     bool delegate(ref const(Cursor)) isWantedCursorForTypedefs;
54 
55     string toString() const
56     {
57         import std.format : format;
58 
59         return format(
60             "Options(outputFile = %s, language = %s, enableComments = %s, " ~
61             "reduceAliases = %s, portableWCharT = %s)",
62             outputFile,
63             language,
64             enableComments,
65             reduceAliases,
66             portableWCharT);
67     }
68 }
69 
70 string fullModuleName(string packageName, string path, bool normalize = true)
71 {
72     import std.algorithm;
73     import std.path : baseName, stripExtension;
74     import std.range;
75     import std.uni;
76     import std.utf;
77 
78     dchar replace(dchar c)
79     {
80         if (c == '_' || c.isWhite)
81             return '_';
82         else if (c.isPunctuation)
83             return '.';
84         else
85             return c;
86     }
87 
88     bool discard(dchar c)
89     {
90         return c.isAlphaNum || c == '_' || c == '.';
91     }
92 
93     bool equivalent(dchar a, dchar b)
94     {
95         return (a == '.' || a == '_') && (b == '.' || b == '_');
96     }
97 
98     auto moduleBaseName = stripExtension(baseName(path));
99     auto moduleName = moduleBaseName.map!replace.filter!discard.uniq!equivalent;
100 
101 
102     if (normalize)
103     {
104         auto segments = moduleName.split!(x => x == '.');
105         auto normalized = segments.map!(x => x.toUTF8.toSnakeCase).join('.');
106         return only(packageName, normalized).join('.');
107     }
108     else
109     {
110         return only(packageName, moduleName.toUTF8).join('.');
111     }
112 }
113 
114 unittest
115 {
116     assert(fullModuleName("pkg", "foo") == "pkg.foo");
117     assert(fullModuleName("pkg", "Foo") == "pkg.foo");
118     assert(fullModuleName("pkg", "Foo.ext") == "pkg.foo");
119 
120     assert(fullModuleName("pkg", "Foo-bar.ext") == "pkg.foo.bar");
121     assert(fullModuleName("pkg", "Foo_bar.ext") == "pkg.foo_bar");
122     assert(fullModuleName("pkg", "Foo@bar.ext") == "pkg.foo.bar");
123     assert(fullModuleName("pkg", "Foo~bar.ext") == "pkg.foo.bar");
124     assert(fullModuleName("pkg", "Foo bar.ext") == "pkg.foo_bar");
125 
126     assert(fullModuleName("pkg", "Foo__bar.ext") == "pkg.foo_bar");
127     assert(fullModuleName("pkg", "Foo..bar.ext") == "pkg.foo.bar");
128     assert(fullModuleName("pkg", "Foo#$%#$%#bar.ext") == "pkg.foo.bar");
129     assert(fullModuleName("pkg", "Foo_#$%#$%#bar.ext") == "pkg.foo_bar");
130 
131     assert(fullModuleName("pkg", "FooBarBaz.ext") == "pkg.foo_bar_baz");
132     assert(fullModuleName("pkg", "FooBar.BazQux.ext") == "pkg.foo_bar.baz_qux");
133 
134     assert(fullModuleName("pkg", "FooBarBaz.ext", false) == "pkg.FooBarBaz");
135     assert(fullModuleName("pkg", "FooBar.BazQux.ext", false) == "pkg.FooBar.BazQux");
136 }