On Tuesday, 29 May 2018 at 20:53:14 UTC, DigitalDesigns wrote:
On Tuesday, 29 May 2018 at 20:26:52 UTC, arturg wrote:
On Tuesday, 29 May 2018 at 19:06:24 UTC, DigitalDesigns wrote:
On Monday, 28 May 2018 at 22:15:40 UTC, arturg wrote:
this might help you,
https://dpaste.dzfl.pl/2cf844a11e3f
you can use them to generate the functions as strings.
Thanks,
So, the problem I'm having is that I cannot use the generated
interface for the abstract class because the abstract class
needs the interface defined. I need to be able to forward
define the interface then extend it.
D doesn't like this
main.d(10): Error: interface `main.B` base `A` is forward
referenced
interface A;
mixin(Generate!(B,A));
interface B : A
{
}
abstract class C : B
{
}
would it work if you define the interface but mixin the
members?
interface A
{
mixin(InterfaceFromClass!C);
}
Yes, I made a post about it but it didn't get through or I
forgot to send ;/
Doing it this way solves the original problems but creates a
new problem in that any class that inherits from an abstract
class that implements A doesn't work.
interface A
{
mixin(InterfaceFromClass!C);
}
abstract class B : A
{
A foo() { return this; }
int bar() { return 3; }
}
class C : B
{
// compiler says foo, bar not implemented
}
so, instead
interface A
{
mixin(InterfaceFromClass!C);
}
abstract class B
{
A foo() { return this; } // requires cast
int bar() { return 3; }
}
class C : B, A
{
}
works but requires casting this in B which happens to work in
C. So It is a fessible solution but I'm not sure why the
compiler things the first case doesn't implement the methods
when it clearly does. I think it looks at A and doesn't compute
the mixin first when parsing C because if I put the output of
the mixin directly it works. Probably a bug...
This method, which imports the source code and extracts the
members works but is very fragile and requires using -J:
// Directly copies the data to the interface with a few hacks to
fix the bug from the original, it excepts a well formatted input
template InterfaceFromClass(alias T)
{
string InterfaceFromClass(string file = __FILE_FULL_PATH__)()
{
string res;
import std.path, std.string, std.algorithm;
enum data = import(file.baseName);
enum mc = "abstract class "~T.stringof~" : ";
enum im = `@("InterfaceMembers")`;
int level = 0;
auto baseIndentLevel = -1;
int funcIndentLevel = -1;
foreach(v; data.splitLines)
{
string l = v;
auto indentLevel = l.length - l.stripLeft().length;
auto ll = l.strip();
if (ll.length == 0) continue;
//res ~= to!string(l.length) ~"\n" ~ l[0..min(mc.length,
l.length)] ~ "\n";
if (level == 0 && ll.length >= mc.length &&
ll[0..min(mc.length, ll.length)] == mc) { baseIndentLevel =
indentLevel; level = 1; continue; } // Finds "abstract class <T>
: "
if (level == 1 && ll.length >= im.length &&
ll[0..min(im.length, ll.length)] == im) { level = 2; continue;
} // Finds "@("InterfaceMembers))" near by
if (level >= 2 && l == "}") break;
if (level == 2 && ll.length > 1)
{
if (funcIndentLevel < 0) funcIndentLevel =
indentLevel;
if (funcIndentLevel < indentLevel) continue;
// A simple function definition(ends with a
');')
if (!ll.canFind("=") && l.length > 2 && l[$-2..$] == ");") {
res ~= l ~ "\n"; continue; }
// ignore fields(assumes it has no {, } but
ends with a ';')
if (!ll.canFind("{") && l[$-1] == ';' && ll[$-2..$] != "};")
continue;
// ignore functions with inline blocks
if (ll.canFind(") {")) { l = l[0..$ - ll.find(") {").length]
~ ")"; }
// must get function signature only(ignore
body)
res ~= l ~ ((ll[$] != ';') ? ";" : "") ~ "\n";
}
}
return res;
}
}
Why the original code is being broke by using D's traits to build
the functions properly is beyond me. I'm pretty sure it is a bug
given the example I gave earlier.