Skip to content

Instantly share code, notes, and snippets.

@lomereiter
Created April 24, 2012 07:28
Show Gist options
  • Save lomereiter/2477467 to your computer and use it in GitHub Desktop.
Save lomereiter/2477467 to your computer and use it in GitHub Desktop.
d compile-time binding generation
module cinterface;
import std.traits;
import std.string;
import std.conv;
import std.range;
import std.typetuple;
import std.algorithm;
import std.ascii;
// http://stackoverflow.com/questions/5630137/for-and-foreach-statements-in-d
template Iota(size_t a, size_t b)
{
static if (a < b) {
alias TypeTuple!(a, Iota!(a + 1, b)) Iota;
} else {
alias TypeTuple!() Iota;
}
}
string fromCamelCase(string s) {
char res[];
for (size_t i = 0; i < s.length; i++) {
auto c = s[i];
if (isUpper(c)) {
if (res.length > 0 &&
(!isUpper(s[i-1]) ||
(i+1 < s.length && isLower(s[i+1]))))
{
res ~= '_';
}
res ~= toLower(c);
} else {
res ~= c;
}
}
return res.idup;
}
template makeCWrappers(T) {
static if(is(typeof(moduleName!T))) {
mixin("import " ~ moduleName!T ~ ";");
} else {
mixin("import " ~
fullyQualifiedName!(T)[0..fullyQualifiedName!(T).countUntil('.')] ~
";"); // FIXME
}
string[] makeCWrappers() {
// TODO: check for __ctor and __dtor and process them separately
// in case any of these is not found, generate default T_new and T_destroy
// TODO: add conversions string <-> const char* (and other useful ones)
string[] methods;
foreach(m; __traits(allMembers, T)) {
enum method = fullyQualifiedName!(T) ~ "." ~ m;
enum underscore_m = fromCamelCase(m);
static if(is(ReturnType!(mixin(method)))) {
alias ReturnType!(mixin(method)) RetType;
alias ParameterTypeTuple!(mixin(method)) ParamTypes;
char[] params;
params ~= T.stringof.dup ~ "* p";
// other parameters will be tmp0, tmp1, ...
foreach (i; Iota!(0, ParamTypes.length)) {
params ~= ", " ~ ParamTypes[i].stringof ~ " tmp".dup ~ to!string(i);
}
// generate return expression
char[] ret_expr;
ret_expr ~= "p." ~ m.dup ~ "(";
if (ParamTypes.length > 0) {
ret_expr ~= "tmp0".dup;
foreach (i; Iota!(1, ParamTypes.length)) {
ret_expr ~= ", tmp" ~ to!string(i);
}
}
ret_expr ~= ")".dup;
methods ~= "extern (C) " ~ RetType.stringof ~ ' ' ~
toLower(T.stringof) ~ '_' ~ underscore_m ~
"(" ~ params.idup ~ ")" ~
"{ " ~ (RetType.stringof != "void" ? "return " : "") ~
ret_expr.idup ~ "; }";
}
}
return methods;
}
}
template makeCInterface(T) {
string makeCInterface() {
char[] result;
foreach (decl; makeCWrappers!T) {
result ~= decl.dup ~ "\n";
}
return result.idup;
}
}
module foo;
import std.stdio;
public struct Foo {
public double foo(string boo, Foo foo) {
return boo.length * foo.moo();
}
public int moo() {
return 42;
}
public void bar(string name) {
writeln("hello, " ~ name ~ "!");
}
}
import cinterface;
// dmd foo.d cinterface.d -shared -offoo.so
// nm -D foo.so | grep foo will show generated functions :-)
mixin(makeCInterface!Foo);
void main() {
writeln(makeCInterface!File);
writeln(makeCInterface!Foo);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment