Skip to content

Commit 1a3f8ee

Browse files
committed
Create support for auto converting includes to imports.
Added command line options --import-filter A regular expression. All includes matching this will be converted to imports. Only the basename part of the file name is used to generate the import. --import-prefix A prefix to give the imports. The import will have the form "<prefix><basename>"
1 parent 5b4ad3a commit 1a3f8ee

File tree

3 files changed

+83
-6
lines changed

3 files changed

+83
-6
lines changed

README.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Alternatively compile libclang yourself:
8181
## Limitations/Known issues
8282

8383
* Doesn't translate preprocessor macros of any kind
84-
* Doesn't translate `#include` to `import`. A few standard C headers are translated
84+
* Only very simplistic translation of `#include` to `import`. A few standard C headers are translated
8585
* Doesn't translate C++ at all
8686
* Umbrella headers. Some headers just serve to include other headers. If these other headers contain some form of protection, like `#error`, to be included directly this can cause problems for DStep
8787
* Some headers are designed to always be included together with other header files. These headers may very well use symbols from other header files without including them itself. Since DStep is designed to convert header files one-by-one this doesn't work. There are two workarounds for this:

dstep/driver/Application.d

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import clang.Util;
2525

2626
import dstep.core.Exceptions;
2727
import dstep.translator.Translator;
28+
import dstep.translator.IncludeHandler;
2829

2930
class Application : DStack.Application
3031
{
@@ -70,6 +71,14 @@ class Application : DStack.Application
7071
.on(&handleLanguage);
7172

7273
arguments("objective-c", "Treat source input file as Objective-C input.");
74+
75+
arguments('f',"import-filter", "A regex to filter includes that will be auto converted.")
76+
.params(1)
77+
.defaults(".*");
78+
79+
arguments('p',"import-prefix", "A prefix to add to any custom generated import")
80+
.params(1)
81+
.defaults("");
7382
}
7483

7584
private:
@@ -123,6 +132,12 @@ private:
123132
// FIXME: Cannot use type inference here, probably a bug. Results in segfault.
124133
if (arguments.rawArgs.any!((string e) => e == "-ObjC"))
125134
handleObjectiveC();
135+
136+
if (arguments["import-prefix"].hasValue)
137+
handleAutoImportPrefix(arguments["import-prefix"].value);
138+
139+
if (arguments["import-filter"].hasValue)
140+
handleAutoImportFilter(arguments["import-filter"].value);
126141
}
127142

128143
void handleObjectiveC ()
@@ -160,6 +175,16 @@ private:
160175
argsToRestore ~= language;
161176
}
162177

178+
void handleAutoImportPrefix (string prefix)
179+
{
180+
includeHandler.setAutoImportPrefix(prefix);
181+
}
182+
183+
void handleAutoImportFilter(string filter)
184+
{
185+
includeHandler.setAutoImportFilter(filter);
186+
}
187+
163188
@property string[] remainingArgs ()
164189
{
165190
return arguments.rawArgs[1 .. $] ~ argsToRestore;
@@ -205,6 +230,8 @@ private:
205230
println(" -ObjC, --objective-c Treat source input file as Objective-C input.");
206231
println(" -x, --language <language> Treat subsequent input files as having type <language>.");
207232
println(" -h, --help Show this message and exit.");
233+
println(" -f, --import-filter A regex to filter includes that will be auto converted to imports.");
234+
println(" -p, --import-prefix A prefix to add to any import generated from an include.");
208235
println();
209236
println("All options that Clang accepts can be used as well.");
210237
println();

dstep/translator/IncludeHandler.d

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
module dstep.translator.IncludeHandler;
88

99
import Path = std.path;
10+
import std.regex;
11+
import std.range;
12+
import std.array;
13+
import std.conv;
1014

1115
import mambo.core._;
1216

@@ -26,6 +30,16 @@ class IncludeHandler
2630
{
2731
private string[] rawIncludes;
2832
private string[] imports;
33+
34+
// True if includes should be converted to imports.
35+
private bool convertIncludes = false;
36+
37+
// Includes matching this will be converted to imports.
38+
private Regex!char convertableIncludePattern = regex(".*");
39+
40+
// Prefix for auto generated imports.
41+
private string importPrefix = "";
42+
2943
static string[string] knownIncludes;
3044

3145
static this ()
@@ -109,21 +123,43 @@ class IncludeHandler
109123
imports ~= "core.stdc.config";
110124
}
111125

126+
/// Makes includes that match regex filter be converted to import with prefix.
127+
void setAutoImportPrefix (string prefix)
128+
{
129+
this.convertIncludes = true;
130+
this.importPrefix = prefix;
131+
}
132+
133+
/// Makes includes that match regex filter be converted to import with prefix.
134+
void setAutoImportFilter (string filter)
135+
{
136+
this.convertIncludes = true;
137+
this.convertableIncludePattern = regex(filter);
138+
}
139+
112140
string[] toImports ()
113141
{
114-
auto r = rawIncludes.map!((e) {
142+
auto r = mambo.core.Array.map!((e) {
115143
if (auto i = isKnownInclude(e))
116144
return toImport(i);
117-
145+
else if( this.convertIncludes && isConvertableInclude(e) )
146+
return toImport(autoConvertInclude(e));
118147
else
119148
return "";
120-
});
149+
})(rawIncludes);
121150

122-
auto imps = imports.map!(e => toImport(e));
151+
auto imps = mambo.core.Array.map!(e => toImport(e))(imports);
123152

124153
return r.append(imps).filter!(e => e.any).unique.toArray;
125154
}
126155

156+
/// Returns the base name (last component without extension) of a file path.
157+
static string baseName (string path)
158+
{
159+
string last_component = text(retro(Path.pathSplitter(path)).front);
160+
return Path.stripExtension( last_component );
161+
}
162+
127163
private:
128164

129165
string toImport (string str)
@@ -140,4 +176,18 @@ private:
140176

141177
return null;
142178
}
143-
}
179+
180+
/// Checks if the given include file name should be converted to an import declaration.
181+
bool isConvertableInclude (string include)
182+
{
183+
// Do not try to convert empty strings, no matter what the pattern says.
184+
return include != "" && cast(bool)(matchFirst(include, convertableIncludePattern));
185+
}
186+
187+
188+
/// Generates an importable module name from an include file name.
189+
string autoConvertInclude(string include)
190+
{
191+
return this.importPrefix ~ baseName(include);
192+
}
193+
}

0 commit comments

Comments
 (0)