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     bool delegate(ref const(Cursor)) isWantedCursorForTypedefs;
53 
54     string toString() const
55     {
56         import std.format : format;
57 
58         return format(
59             "Options(outputFile = %s, language = %s, enableComments = %s, " ~
60             "reduceAliases = %s, portableWCharT = %s)",
61             outputFile,
62             language,
63             enableComments,
64             reduceAliases,
65             portableWCharT);
66     }
67 }
68 
69 string fullModuleName(string packageName, string path, bool normalize = true)
70 {
71     import std.algorithm;
72     import std.path : baseName, stripExtension;
73     import std.range;
74     import std.uni;
75     import std.utf;
76 
77     dchar replace(dchar c)
78     {
79         if (c == '_' || c.isWhite)
80             return '_';
81         else if (c.isPunctuation)
82             return '.';
83         else
84             return c;
85     }
86 
87     bool discard(dchar c)
88     {
89         return c.isAlphaNum || c == '_' || c == '.';
90     }
91 
92     bool equivalent(dchar a, dchar b)
93     {
94         return (a == '.' || a == '_') && (b == '.' || b == '_');
95     }
96 
97     auto moduleBaseName = stripExtension(baseName(path));
98     auto moduleName = moduleBaseName.map!replace.filter!discard.uniq!equivalent;
99 
100 
101     if (normalize)
102     {
103         auto segments = moduleName.split!(x => x == '.');
104         auto normalized = segments.map!(x => x.toUTF8.toSnakeCase).join('.');
105         return only(packageName, normalized).join('.');
106     }
107     else
108     {
109         return only(packageName, moduleName.toUTF8).join('.');
110     }
111 }
112 
113 unittest
114 {
115     assert(fullModuleName("pkg", "foo") == "pkg.foo");
116     assert(fullModuleName("pkg", "Foo") == "pkg.foo");
117     assert(fullModuleName("pkg", "Foo.ext") == "pkg.foo");
118 
119     assert(fullModuleName("pkg", "Foo-bar.ext") == "pkg.foo.bar");
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 
125     assert(fullModuleName("pkg", "Foo__bar.ext") == "pkg.foo_bar");
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 
130     assert(fullModuleName("pkg", "FooBarBaz.ext") == "pkg.foo_bar_baz");
131     assert(fullModuleName("pkg", "FooBar.BazQux.ext") == "pkg.foo_bar.baz_qux");
132 
133     assert(fullModuleName("pkg", "FooBarBaz.ext", false) == "pkg.FooBarBaz");
134     assert(fullModuleName("pkg", "FooBar.BazQux.ext", false) == "pkg.FooBar.BazQux");
135 }