diff --git a/dev/build-examples b/dev/build-examples new file mode 100755 index 0000000..b575381 --- /dev/null +++ b/dev/build-examples @@ -0,0 +1,8 @@ +#!/bin/bash + +for example in acceptnovisitors adventure matrix next rolex synopsis whytheunderscore; do + touch examples/$example/source/app.d + dub build openmethods:$example +done + +du -hc examples/*/openmethods_* diff --git a/dev/run-everything b/dev/run-everything index 3ed72bc..d35f1ff 100755 --- a/dev/run-everything +++ b/dev/run-everything @@ -34,7 +34,8 @@ do do if [ -d $dir/$target ]; then - echo $target + echo "========================================================================" + echo "Running $target" if [ "$target" = 'dl' ]; then if [[ "$DC" == 'dmd' ]]; @@ -70,7 +71,8 @@ do if [[ $target == *'.d' ]] then - echo $target + echo "========================================================================" + echo "Running $target" if [[ "$DC" == 'gdc' ]] && grep --quiet -P $DC_EXCLUSIONS $dir/$target; then diff --git a/dub.json b/dub.json index 3ef06b6..f523a2a 100644 --- a/dub.json +++ b/dub.json @@ -27,9 +27,6 @@ }, "configurations": [ { - "dependencies": { - "fluent-asserts": "~>0.13.3" - }, "dflags": [ "-mixin=mixins.txt" ], @@ -38,9 +35,6 @@ } ], "copyright": "Copyright © 2017, Jean-Louis Leroy", - "dependencies": { - "bolts": "~>1.7.0" - }, "description": "fast, open multi-methods for D", "importPaths": [ "source/" @@ -63,4 +57,4 @@ ], "targetType": "library", "version": "1.3.0+commit.2.gaa32b61" -} \ No newline at end of file +} diff --git a/examples/dl/run b/examples/dl/run index 176f1df..8917e84 100755 --- a/examples/dl/run +++ b/examples/dl/run @@ -5,17 +5,17 @@ rm -f *.o *.di *.so DC=dmd -BOLT_VERSION=1.7.0 -dub fetch bolts@$BOLT_VERSION -BOLT_SOURCE=~/.dub/packages/bolts-$BOLT_VERSION/bolts/source +# BOLT_VERSION=1.7.0 +# dub fetch bolts@$BOLT_VERSION +# BOLT_SOURCE=~/.dub/packages/bolts-$BOLT_VERSION/bolts/source DFLAGS="-g -I../../source -I$BOLT_SOURCE $DFLAGS" SOFLAGS="-L-fPIC -shared" $DC $DFLAGS $SOFLAGS -i -c ../../source/openmethods.d -$DC $DFLAGS $SOFLAGS -i -c ../../source/bolts/reflection/*.d -$DC $DFLAGS $SOFLAGS openmethods.o meta*.o -oflibopenmethods.so +$DC $DFLAGS $SOFLAGS -i -c ../../source/bolts/experimental/*.d +$DC $DFLAGS $SOFLAGS *.o -oflibopenmethods.so $DC $DFLAGS $SOFLAGS -c animals.d $DC $DFLAGS $SOFLAGS animals.o -oflibanimals.so diff --git a/examples/matrix/source/matrix.d b/examples/matrix/source/matrix.d index f1af8f8..a28d2e0 100644 --- a/examples/matrix/source/matrix.d +++ b/examples/matrix/source/matrix.d @@ -9,5 +9,5 @@ interface Matrix } Matrix plus(virtual!Matrix, virtual!Matrix); -Matrix times(double, virtual!Matrix); Matrix times(virtual!Matrix, double); +Matrix times(double, virtual!Matrix); diff --git a/source/bolts/experimental/refraction.d b/source/bolts/experimental/refraction.d new file mode 100644 index 0000000..87a5e71 --- /dev/null +++ b/source/bolts/experimental/refraction.d @@ -0,0 +1,575 @@ +/++ + It is sometimes necessary to create a function which is an exact copy of + another function. Or sometimes it is necessary to introduce a few + variations, while carrying all the other aspects. Because of function + attributes, parameter storage classes and user-defined attributes, this + requires building a string mixin. In addition, the mixed-in code must refer + only to local names, if it is to work across module boundaires. + + This module facilitates the creation of such mixins. + + Copyright: Copyright Jean-Louis Leroy 2017-2020 + + License: $(LINK2 http://boost.org/LICENSE_1_0.txt, Boost License 1.0). + + Authors: Jean-Louis Leroy ++/ + +module bolts.experimental.refraction; + +import std.array; +import std.format; +import std.meta; +import std.algorithm.iteration : map; +import std.range : iota; +import std.traits; + +template ParameterAttribute(alias F, int i, int j) +{ + static if (is(typeof(F) P == __parameters)) { + alias ParameterAttribute = Alias!(__traits(getAttributes, P[i..i+1])[j]); + } +} + +/** + Return a Function object that captures all the aspects of Fun, using the + value of localSymbol to represent the return and parameter types, and the + UDAs. + + Params: + fun = a function + localSymbol = a string mixin that represents fun in the caller's context + +*/ + +Function refract(alias fun, string localSymbol)() + if (is(typeof(fun) == function)) +{ + Function model = { + name: __traits(identifier, fun), + localSymbol: localSymbol, + returnType: "std.traits.ReturnType!("~localSymbol~")", + parameters: refractParameterList!(fun, localSymbol), + udas: __traits(getAttributes, fun) + .length.iota.map!( + formatIndex!("@(__traits(getAttributes, %s)[%%d])".format(localSymbol))).array, + attributes: functionAttributes!(fun), + static_: __traits(isStaticFunction, fun) && isAggregate!(__traits(parent, fun)), + body_: ";", + }; + + return model; +} + +/// +unittest +{ + pure @nogc int answer(lazy string question); + alias F = answer; // typically F is a template argument + static assert( + refract!(F, "F").mixture == + "pure @nogc @system std.traits.ReturnType!(F) answer(lazy std.traits.Parameters!(F)[0] _0);"); +} + +/// +unittest +{ + import std.format; + import std.traits; + + interface GrandTour + { + pure int foo() immutable; + @nogc @trusted nothrow ref int foo(out real, return ref int, lazy int) const; + @safe shared scope void bar(scope Object); + } + + class Mock(Interface) : Interface + { + static foreach (member; __traits(allMembers, Interface)) { + static foreach (fun; __traits(getOverloads, Interface, member)) { + mixin({ + enum Model = refract!(fun, "fun"); + if (is(ReturnType!fun == void)) { + return Model.setBody("{}").mixture; + } else if (Model.attributes & FunctionAttribute.ref_) { + return Model.setBody(q{{ + static %s rv; + return rv; + }}.format(Model.returnType)).mixture; + } else { + return Model.setBody(q{{ + return %s.init; + }}.format(Model.returnType)).mixture; + } + }()); + } + } + } + + GrandTour mock = new Mock!GrandTour; + real x; + int i, l; + mock.foo(x, i, l++) = 1; + assert(mock.foo(x, i, l++) == 1); + assert(l == 0); +} + +private enum isAggregate(T...) = + is(T[0] == struct) || is(T[0] == union) || is(T[0] == class) + || is(T[0] == interface); + +/** + A struct capturing all the properties of a function. +*/ + +struct Function +{ + + /** + A string that evaluates to a function symbol. + */ + + string localSymbol; + + /** + Function name. Initial value: `__traits(identifier, fun)`. + */ + + string name; + + /** + Set the function name. + */ + + Function setName(string value) + { + name = value; + return this; + } + + /// + unittest + { + pure @nogc int answer(); + mixin(refract!(answer, "answer").setName("ultimateAnswer").mixture); + static assert( + __traits(getAttributes, ultimateAnswer) == + __traits(getAttributes, answer)); + } + + /** + Return type. Initial value: `std.traits.ReturnType!fun`. + */ + + string returnType; + + /** + Set the return type. + */ + + Function setReturnType(string value) + { + returnType = value; + return this; + } + + /// + unittest + { + pure int answer(); + mixin( + refract!(answer, "answer").setName("realAnswer") + .setReturnType("real") + .mixture); + static assert(is(typeof(realAnswer()) == real)); + } + + /** + Function parameters. Initial value: from the refracted function. + */ + + Parameter[] parameters; + + /** + Set the parameter list. + */ + + Function setParameters(Parameter[] value) + { + parameters = value; + return this; + } + + /// + unittest + { + int answer(); + mixin( + refract!(answer, "answer").setName("answerQuestion") + .setParameters([ Parameter().setName("question").setType("string")]) + .mixture); + int control(string); + static assert(is(Parameters!answerQuestion == Parameters!control)); + } + + /** + Function body. Initial value: `;`. + */ + + string body_; + + /** + Set the function body. + */ + + Function setBody(string value) + { + body_ = value; + return this; + } + + /// + unittest + { + pure int answer(); + mixin( + refract!(answer, "answer").setName("theAnswer") + .setBody("{ return 42; }") + .mixture); + static assert(theAnswer() == 42); + } + + /** + Function attributes. + Initial value: `__traits(getAttributes, fun)`. + */ + + ulong attributes; + + /** + Set `attributes`. Return `this`. + */ + + Function setAttributes(uint value) + { + attributes = value; + return this; + } + + /// + unittest + { + nothrow int answer(); + enum model = refract!(answer, "answer"); + with (FunctionAttribute) + { + mixin( + model + .setName("pureAnswer") + .setAttributes(model.attributes | pure_) + .mixture); + static assert(functionAttributes!pureAnswer & pure_); + static assert(functionAttributes!pureAnswer & nothrow_); + } + } + + /** + If `true`, prefix generated function with `static`. Initial value: `true` + if the refracted function is a static *member* function. + */ + + bool static_; + + /** + Set the `static_` attribute. Return `this`. + */ + + Function setStatic(bool value) + { + static_ = value; + return this; + } + + /// + unittest + { + struct Question + { + static int answer() { return 42; } + } + mixin( + refract!(Question.answer, "Question.answer") + .setStatic(false) + .setBody("{ return Question.answer; }") + .mixture); + static assert(answer() == 42); + } + + /** + User defined attributes. + Initial value: + `bolts.experimental.refraction.ParameterAttribute!(fun, parameterIndex..., attributeIndex...)`. + */ + + string[] udas; + + /** + Set the `udas` attribute. Return `this`. + */ + + Function setUdas(string[] value) + { + udas = value; + return this; + } + + /// + unittest + { + import std.typecons : tuple; + @(666) int answer(); + + mixin( + refract!(answer, "answer") + .setName("answerIs42") + .setUdas(["@(42)"]) + .mixture); + static assert(__traits(getAttributes, answerIs42).length == 1); + static assert(__traits(getAttributes, answerIs42)[0] == 42); + } + + /** + Return a string representing the entire function definition or declaration. + */ + + string mixture() + { + return join( + udas ~ + attributeMixtureArray() ~ + [ + returnType, + name ~ "(" ~ parameterListMixtureArray.join(", ") ~ ")", + ], " ") ~ + body_; + } + + const string[] parameterListMixtureArray() + { + return map!(p => p.mixture)(parameters).array; + } + + /** + Return the argument list as an array of strings. + */ + + const const(string)[] argumentMixtureArray() + { + return parameters.map!(p => p.name).array; + } + + /// + unittest + { + int add(int a, int b); + static assert(refract!(add, "add").argumentMixtureArray == [ "_0", "_1" ]); + } + + /** + Return the argument list as a string. + */ + + const string argumentMixture() + { + return argumentMixtureArray.join(", "); + } + + /// + unittest + { + int add(int a, int b); + static assert(refract!(add, "add").argumentMixture == "_0, _1"); + } + + /** + Return the attribute list as an array of strings. + */ + + const string[] attributeMixtureArray() + { + with (FunctionAttribute) + { + return [] + ~ (static_ ? ["static"] : []) + ~ (attributes & pure_ ? ["pure"] : []) + ~ (attributes & nothrow_ ? ["nothrow"] : []) + ~ (attributes & property ? ["@property"] : []) + ~ (attributes & trusted ? ["@trusted"] : []) + ~ (attributes & safe ? ["@safe"] : []) + ~ (attributes & nogc ? ["@nogc"] : []) + ~ (attributes & system ? ["@system"] : []) + ~ (attributes & const_ ? ["const"] : []) + ~ (attributes & immutable_ ? ["immutable"] : []) + ~ (attributes & inout_ ? ["inout"] : []) + ~ (attributes & shared_ ? ["shared"] : []) + ~ (attributes & return_ ? ["return"] : []) + ~ (attributes & scope_ ? ["scope"] : []) + ~ (attributes & ref_ ? ["ref"] : []) + ; + } + } + + /// + unittest + { + nothrow pure int answer(); + enum model = refract!(answer, "answer"); + static assert( + model.attributeMixtureArray == ["pure", "nothrow", "@system"]); + } + + /** + Return the attribute list as a string. + */ + + const string attributeMixture() + { + return attributeMixtureArray.join(" "); + } + + /// + unittest + { + nothrow pure int answer(); + enum model = refract!(answer, "answer"); + static assert(model.attributeMixture == "pure nothrow @system"); + } +} + +/** + A struct capturing all the properties of a function parameter. +*/ + +struct Parameter +{ + /** + Parameter name. Initial value: `_i`, where `i` is the position of the + parameter. + */ + + string name; + + /** + Set the parameter name. + */ + + Parameter setName(string value) + { + name = value; + return this; + } + + /** + Parameter type. Initial value: `std.traits.Parameter!fun[i]`, where `fun` + is the refracted function and `i` is the position of the parameter. + */ + + string type; + + /** + Set the parameter type. + */ + + Parameter setType(string value) + { + type = value; + return this; + } + + /** + Parameter storage classes. Initial value: + `[__traits(getParameterStorageClasses, fun, i)]`, where where `fun` is the + refracted function and `i` is the position of the parameter. + */ + + string[] storage; + + /** + Set the parameter storage classes. + */ + + Parameter setStorage(string[] value) + { + storage = value; + return this; + } + + /** + Parameter UDAs. Initial value: + `[@(bolts.experimental.refraction.ParameterAttribute!(fun,i, j...))]`, where + where `fun` is the refracted function, `i` is the position of the + parameter, and `j...` are the positions of the UDAs. + */ + + string[] udas; + + /** + Set the parameter udas. + */ + + Parameter setUdas(string[] value) + { + udas = value; + return this; + } + + /** + Return a string representing the parameter. + */ + + const string mixture() + { + return join(udas ~ storage ~ [ type, name ], " "); + } +} + +Parameter refractParameter(alias Fun, string mixture, uint index)() +{ + static if (is(typeof(Fun) parameters == __parameters)) { + alias parameter = parameters[index .. index + 1]; + static if (__traits(compiles, __traits(getAttributes, parameter))) { + enum udaFormat = "@(bolts.experimental.refraction.ParameterAttribute!(%s, %d, %%d))".format( + mixture, index); + enum udas = __traits(getAttributes, parameter).length.iota.map!( + formatIndex!udaFormat).array; + } else { + enum udas = []; + } + + Parameter p = + { + name: "_%d".format(index), + type: `std.traits.Parameters!(%s)[%d]`.format(mixture, index), + storage: [__traits(getParameterStorageClasses, Fun, index)], + udas: udas, + }; + } + return p; +} + +private Parameter[] refractParameterList(alias Fun, string mixture)() +{ + Parameter[] result; + static if (is(typeof(Fun) parameters == __parameters)) { + static foreach (i; 0 .. parameters.length) { + result ~= refractParameter!(Fun, mixture, i); + } + } + return result; +} + +private string formatIndex(string f)(ulong i) +{ + return format!f(i); +} diff --git a/source/bolts/reflection/metaaggregate.d b/source/bolts/reflection/metaaggregate.d deleted file mode 100644 index 57d9195..0000000 --- a/source/bolts/reflection/metaaggregate.d +++ /dev/null @@ -1,70 +0,0 @@ -module bolts.reflection.metaaggregate; - -import bolts.reflection.metafunction; - -static mixin template ModuleAggregateCommonCode() -{ - import std.meta : staticMap, AliasSeq; - import bolts.reflection.metafunction; - - alias functions = staticMap!(collectMembers, __traits(allMembers, origin)); - - private alias collectMembers(string name) = collectOverloads!( - name, 0, __traits(getOverloads, origin, name)); - - private alias collectOverloads(string name, int index, Fun...) = - AliasSeq!( - Function!(Fun[0], source, name, index), - collectOverloads!(name, index + 1, Fun[1..$])); - - private alias collectOverloads(string name, int index) = AliasSeq!(); -} - -template Aggregate(alias Aggregate_, string Source = __traits(identifier, Aggregate_)) -{ - alias origin = Aggregate_; - alias source = Source; - mixin ModuleAggregateCommonCode; -} - -unittest -{ - import std.format; - import bolts.reflection.metafunction; - import std.traits; // needed by expansion or Function.returnType - - interface TheFullMonty - { - pure int foo() immutable; - @nogc @trusted nothrow ref int foo(out real, return ref int, lazy int) const; - @safe shared scope void foo(scope Object); - } - - template Mocker(alias F) - { - static if (is(F.returnType.origin == void)) { - enum Mocker = F.setBody!("").mixture; - } else static if (F.isRef) { - enum Mocker = F.setBody!(q{ - static %s rv; - return rv; - }.format(F.returnType.mixture)).mixture; - } else { - enum Mocker = F.setBody!(q{ - return %s.init; - }.format(F.returnType.mixture)).mixture; - } - } - - class Mock(Interface) : Interface - { - mixin(staticMap!(Mocker, Aggregate!Interface.functions)); - } - - TheFullMonty mock = new Mock!TheFullMonty; - real x; - int i, l; - mock.foo(x, i, l++) = 1; - assert(mock.foo(x, i, l++) == 1); - assert(l == 0); -} diff --git a/source/bolts/reflection/metafunction.d b/source/bolts/reflection/metafunction.d deleted file mode 100644 index c587d12..0000000 --- a/source/bolts/reflection/metafunction.d +++ /dev/null @@ -1,708 +0,0 @@ -/** - Meta-object that captures all the properties of a function -*/ - -module bolts.reflection.metafunction; - -import bolts.reflection.metatype; -import bolts.reflection.metauda; - -import bolts.meta : AliasPack; -import bolts.traits : isSame; - -import std.array : join; -import std.format : format; -import std.meta : Alias, AliasSeq, aliasSeqOf, ApplyLeft, staticMap, anySatisfy; -import std.range : iota; -import std.traits; -import std.typecons : tuple; - -version(unittest) import fluent.asserts; - -private enum ExtendedFunctionAttribute : ulong -{ - firstExtended = 1UL << 32, - static_ = firstExtended << 0, -} - -private struct String(string value) -{ - enum mixture = value; - enum mixtureArray = [ value ]; -} - -template ParameterAttribute(alias F, int i, int j) -{ - static if (is(typeof(F) P == __parameters)) { - alias ParameterAttribute = Alias!(__traits(getAttributes, P[i..i+1])[j]); - } -} - -unittest -{ - struct foo; - - struct bar - { - this(string name) { this.name = name; } - string name; - } - - void f(@foo @bar int, @foo @bar("xyz") @foo @("baz") @(42) real); - - static assert(isSame!(ParameterAttribute!(f, 0, 0), foo)); - static assert(isSame!(ParameterAttribute!(f, 0, 1), bar)); - static assert(isSame!(ParameterAttribute!(f, 1, 0), foo)); - static assert(isSame!(ParameterAttribute!(f, 1, 1), bar("xyz"))); - static assert(isSame!(ParameterAttribute!(f, 1, 2), foo)); - static assert(isSame!(ParameterAttribute!(f, 1, 3), "baz")); - static assert(isSame!(ParameterAttribute!(f, 1, 4), 42)); -} - -enum subMixture(alias Meta) = Meta.mixture; -enum subMixtureArray(alias Meta) = Meta.mixtureArray; - -private template withDefaults(alias Values, Defaults...) -{ - static if (Values.length != 0) { - alias withDefaults = AliasSeq!( - Values.Unpack[0], - withDefaults!( - AliasPack!(Values.Unpack[1..$]), - Defaults[1..$])); - } else static if (Defaults.length != 0) { - alias withDefaults = AliasSeq!( - Defaults[0], - withDefaults!( - Values, - Defaults[1..$])); - } else { - alias withDefaults = AliasSeq!(); - } -} - -private template aliasSeqReplace(int position, T...) - if (T.length > 1) -{ - alias Seq = AliasSeq!(T[1..$]); - static if (position == Seq.length) { - alias aliasSeqReplace = AliasSeq!(Seq[0..$-1], T[0]); - } else static if (position == 0) { - alias aliasSeqReplace = AliasSeq!(T[0], Seq[1..$]); - } else { - alias aliasSeqReplace = AliasSeq!(Seq[0..position], T[0], Seq[position+1..$]); - } -} - -unittest -{ - static assert( - is(aliasSeqReplace!(0, int, char, real, void) - == AliasSeq!(int, real, void))); - static assert( - is(aliasSeqReplace!(1, int, char, real, void) - == AliasSeq!(char, int, void))); - static assert( - is(aliasSeqReplace!(2, int, char, real, void) - == AliasSeq!(char, real, int))); - - static assert( - is(aliasSeqReplace!(0, int, char, real) - == AliasSeq!(int, real))); - static assert( - is(aliasSeqReplace!(1, int, char, real) - == AliasSeq!(char, int))); - - static assert(is(aliasSeqReplace!(0, int, char) == AliasSeq!(int))); -} - -alias PDV = ParameterDefaults; - -private enum Property { - origin, - attributes, - returnType, - name, - index, - parameterList, - udaList, - body_, -} - -private alias PropertyDefaults = AliasSeq!( - void, - 0, - Type!void, - "", - 0, - ParameterList!(), - UDAList!(), - [], -); - -/** - Meta-class Function - - */ - -template Function(Props...) -{ - alias Properties = withDefaults!(AliasPack!(Props), PropertyDefaults); - - import std.ascii : toUpper; - - static foreach (i, property; __traits(allMembers, Property)) { - mixin("alias ", property, " = Alias!(Properties[Property.", property, "]);"); - mixin(q{ - alias set%s%s(NewValue...) = Function!( - aliasSeqReplace!(Property.%s, NewValue, Properties)); - }.format(property[0].toUpper, property[1..$], property)); - } - - /** - setBody - */ - - alias setBody(string newBody) = setBody_!([ "{", newBody, "}" ]); - - - // -------------------------------------------------------------------------- - // function attributes - - alias FA = FunctionAttribute; - alias XA = ExtendedFunctionAttribute; - - enum attributeMixtureArray = [] - ~ (attributes & XA.static_ ? ["static"] : []) - ~ (attributes & FA.pure_ ? ["pure"] : []) - ~ (attributes & FA.nothrow_ ? ["nothrow"] : []) - ~ (attributes & FA.property ? ["@property"] : []) - ~ (attributes & FA.trusted ? ["@trusted"] : []) - ~ (attributes & FA.safe ? ["@safe"] : []) - ~ (attributes & FA.nogc ? ["@nogc"] : []) - ~ (attributes & FA.system ? ["@system"] : []) - ~ (attributes & FA.const_ ? ["const"] : []) - ~ (attributes & FA.immutable_ ? ["immutable"] : []) - ~ (attributes & FA.inout_ ? ["inout"] : []) - ~ (attributes & FA.shared_ ? ["shared"] : []) - ~ (attributes & FA.return_ ? ["return"] : []) - ~ (attributes & FA.scope_ ? ["scope"] : []) - ~ (attributes & FA.ref_ ? ["ref"] : []) - ; - - enum attributeMixture = attributeMixtureArray.join(" "); - - static foreach ( - acc; - AliasSeq!( - tuple("Static", XA.static_), - tuple("Const", FA.const_), - tuple("Immutable", FA.immutable_), - tuple("Pure", FA.pure_), - tuple("Nothrow", FA.nothrow_), - tuple("Trusted", FA.trusted), - tuple("Safe", FA.safe), - tuple("Nogc", FA.nogc), - tuple("System", FA.system), - tuple("Ref", FA.ref_))) { - mixin(q{ - enum is%s = (attributes & acc[1]) != 0; - alias set%s(bool Set) = void; - alias set%s(bool Set : true) = Function!( - aliasSeqReplace!(Property.attributes, attributes | acc[1], Properties)); - alias set%s(bool Set : false) = Function!( - aliasSeqReplace!(Property.attributes, attributes & ~acc[1], Properties)); - }.format(acc[0], acc[0], acc[0], acc[0])); - } - - enum mutabilityAttributeArray = cast(string[]) [] - ~ (isConst ? [ "const" ] : []) - ~ (isImmutable ? [ "immutable" ] : []); - - enum mutabilityAttribute = mutabilityAttributeArray.join(""); - - // -------------------------------------------------------------------------- - // UDAs - - alias udas = udaList.Unpack; - - enum udaMixtureArray = cast(string[]) [ staticMap!(subMixture, udas) ]; - - enum udaMixture = udaMixtureArray.join(" "); - - enum isSameUDA(alias UDA, alias Meta) = isSame!(UDA, Meta.origin); - - enum hasUDA(UDA...) = anySatisfy!(ApplyLeft!(isSameUDA, UDA[0]), udas); - - // -------------------------------------------------------------------------- - // parameters - - alias parameters = parameterList.Unpack; - - enum arity = parameters.length; - - alias setParameters(NewParameters...) = Function!( - aliasSeqReplace!(Property.parameterList, ParameterList!(NewParameters), Properties)); - - alias insertParameter(int Position, NewParameter...) = setParameters!( - parameters[0..Position], NewParameter, parameters[Position..$]); - - alias appendParameter(NewParameter...) = insertParameter!(arity, NewParameter); - - enum argumentMixtureAt(int i) = parameters[i].argumentMixture; - - enum argumentMixtureArray = cast(string[]) [ - staticMap!( - argumentMixtureAt, aliasSeqOf!(parameters.length.iota)) - ]; - - enum argumentMixture = argumentMixtureArray.join(", "); - - enum parameterMixtureArray = - cast(string[]) [staticMap!(subMixture, parameters) ]; - - enum parameterMixture = parameterMixtureArray.join(", "); - - enum declarationMixtureArray = udaMixtureArray ~ attributeMixtureArray - ~ returnType.mixtureArray ~ [ "%s(%s)".format(name, parameterMixture) ]; - - enum declarationMixture = declarationMixtureArray.join(" "); - - enum mixtureArray = declarationMixtureArray ~ body_; - - enum mixture = mixtureArray.join(" "); - - enum pointerMixture = - Function!(Properties).setName!("function").declarationMixture; -} - -/// Examining a function -unittest -{ - struct small; - pure int add(@small int a, @small int b) { return a + b; } - static assert(Function!add.isPure); - static assert(Function!add.isNothrow); - static assert(Function!add.isNogc); - static assert(Function!add.parameters.length == 2); - static assert(is(Function!add.parameters[0].type.origin == int)); - static assert(Function!add.parameters[0].UDAs.length == 1); - static assert(is(Function!add.parameters[0].UDAs[0].origin == small)); -} - -/// Generating a function -unittest -{ - pure int f() { return 42; } - - template plus1(alias F) - { - alias NewFunction = Function!(f, "F").setName!"plus1".setBody!("return F() + 1;"); - static assert( - NewFunction.mixture == - "pure nothrow @safe @nogc std.traits.ReturnType!(F) plus1() { return F() + 1; }"); - mixin(NewFunction.mixture); - } - Assert.equal(plus1!f, 43); -} - -template makeUDAs(string Source, int Position, UDAs...) -{ - static if (UDAs.length == 0) { - alias makeUDAs = AliasSeq!(); - } else { - alias makeUDAs = AliasSeq!( - UDA!( - UDAs[0], - "__traits(getAttributes, %s)[%d]".format(Source, Position) - ), - makeUDAs!(Source, Position + 1, UDAs[1..$])); - } -} - -alias Function(alias Fun, string Source = __traits(identifier, Fun), int Index = 0) = - Function!( - Fun, - functionAttributes!Fun | - (__traits(isStaticFunction, Fun) ? ExtendedFunctionAttribute.static_ : 0), - Type!(ReturnType!Fun, "std.traits.ReturnType!(%s)".format(Source)), - __traits(identifier, Fun), - Index, - reflectParameterList!(Fun, Source), - UDAList!(makeUDAs!(Source, 0, __traits(getAttributes, Fun)))); - -/// Create a Function meta-object from function Fun, -alias Function(alias Fun, string Aggregate, string Member, int Index) = - Function!( - Fun, - `__traits(getOverloads, %s, "%s")[%d]`.format(Aggregate, Member, Index), - Index); - -unittest -{ - void foo(); - Assert.equal( - Function!foo.mixture, - "@system std.traits.ReturnType!(foo) foo()"); - Assert.equal( - Function!foo.pointerMixture, - "@system std.traits.ReturnType!(foo) function()"); -} - -// returnType, setReturnType -unittest -{ - void foo(); - Assert.equal( - Function!foo.returnType.mixture, - "std.traits.ReturnType!(foo)"); - Assert.equal( - Function!foo.setReturnType!(Type!int).returnType.mixture, - "int"); - Assert.equal( - __traits(compiles, Function!foo.setReturnType!int), - false); -} - -unittest -{ - @safe ref int foo(lazy int i, char c) - { - static int x; - return x; - } - - alias Foo = Function!(foo); - Assert.equal(Foo.parameters[0].typeMixture, "std.traits.Parameters!(foo)[0]"); - Assert.equal(Foo.attributeMixture, "nothrow @safe @nogc ref"); - Assert.equal( - Foo.mixture, - "nothrow @safe @nogc ref std.traits.ReturnType!(foo) foo(lazy std.traits.Parameters!(foo)[0] a0, std.traits.Parameters!(foo)[1] a1)"); - - Assert.equal( - (Foo.setName!("bar")).mixture, - "nothrow @safe @nogc ref std.traits.ReturnType!(foo) bar(lazy std.traits.Parameters!(foo)[0] a0, std.traits.Parameters!(foo)[1] a1)"); - - static assert(Foo.isSafe); - static assert(Foo.isRef); - static assert(!Foo.isPure); - Assert.equal((Foo.setSafe!false).attributeMixture, "nothrow @nogc ref"); - Assert.equal((Foo.setPure!true).attributeMixture, "pure nothrow @safe @nogc ref"); - - struct S - { - const void foo() {} - immutable void bar() {} - static @nogc pure @safe void baz(); - } - - static assert(Function!(S.foo, "foo").isConst); - static assert(Function!(S.bar, "foo").isImmutable); - Assert.equal( - Function!(S.foo, "foo").mixture, - "@system const std.traits.ReturnType!(foo) foo()"); - static assert(Function!(S.baz, "baz").isStatic); - static assert(Function!(S.baz, "baz").isNogc); - static assert(Function!(S.baz, "baz").isPure); - static assert(Function!(S.baz, "baz").isSafe); - Assert.equal( - Function!(S.baz, "baz").mixture, - "static pure @safe @nogc std.traits.ReturnType!(baz) baz()"); -} - -unittest -{ - void foo(); - alias F1 = Function!foo.setParameters!(Parameter!([], Type!int, "j")); - Assert.equal( - F1.mixture, - "@system std.traits.ReturnType!(foo) foo(int j)"); - alias F2 = F1.insertParameter!(0, Parameter!([], Type!int, "i")); - Assert.equal( - F2.mixture, - "@system std.traits.ReturnType!(foo) foo(int i, int j)"); - alias F3 = F2.appendParameter!(Parameter!([], Type!int, "k")); - Assert.equal( - "@system std.traits.ReturnType!(foo) foo(int i, int j, int k)", - F3.mixture); -} - -// ============================================================================ -// Parameter - -mixin template mixtureFromArray() -{ - enum mixture = mixtureArray.join(" "); -} - -template ParameterDefaultValue(alias Value, string Mixture) -{ - alias origin = Value; - - static if (is(Value == void)) { - enum mixtureArray = cast(string[]) []; - } else { - enum mixtureArray = [ "=", Mixture ]; - } - - mixin mixtureFromArray; -} - -template Parameter( - alias UDAList, string[] StorageClasses, alias Type_, string Name = "", - alias DefaultValue = ParameterDefaultValue!(void, "")) -{ - alias udaList = UDAList; - alias UDAs = udaList.Unpack; - enum storageClasses = StorageClasses; - enum name = Name; - alias type = Type_; - alias defaultValue = DefaultValue; - alias setType(alias newType) = Parameter!( - udaList, StorageClasses, newType, Name, defaultValue); - - enum storageClassArray = StorageClasses; - enum storageClassMixture = storageClassArray.join(" "); - - enum typeMixture = type.mixture; - enum typeMixtureArray = type.mixtureArray; - import std.traits : Select; - enum argumentMixtureArray = Select!(name == "", [], [ name ]); - enum argumentMixture = Name; - - enum mixture = join( - udaList.mixtureArray - ~ storageClassArray - ~ typeMixtureArray - ~ argumentMixtureArray - ~ defaultValue.mixtureArray - , " "); - - enum mixtureArray = [ mixture ]; - - static foreach ( - sc; [ - "In", "Out", "Ref", "Lazy", "Const", "Immutable", "Shared", "Inout", - "Scope" ]) { - import std.algorithm: canFind; - import std.string : toLower; - mixin(q{enum is%s = StorageClasses.canFind("%s"); }.format(sc, sc.toLower)); - } - - alias setStorageClasses(string[] newStorageClasses) = - Parameter!(udaList, newStorageClasses, type, name, defaultValue); -} - -alias Parameter(alias Type, string Name = "") = Parameter!([], Type, Name); - -alias Parameter(string[] StorageClasses, alias Type, string Name = "") = - Parameter!(UDAList!(), StorageClasses, Type, Name); - -template ParameterList(T...) -{ - alias Unpack = T; - enum mixture = mixtureArray.join(" "); - enum mixtureArray = cast(string[]) [ staticMap!(subMixture, T) ]; -} - -template UDAList(T...) -{ - alias Unpack = T; - enum mixtureArray = cast(string[]) [ staticMap!(subMixture, T) ]; - enum mixture = mixtureArray.join(" "); -} - -template reflectParameterList(alias fun, string mixture) -{ - // disabled because of bug in ParameterDefaults (20744) - // static if (is(typeof(ParameterDefaults!fun))) { - // alias defaultValues = ParameterDefaults!fun; - // } else { - // alias Void(int _) = void; - // alias defaultValues = staticMap!(Void, aliasSeqOf!(Parameters!fun.length.iota)); - // } - - static if (is(typeof(fun) parameters == __parameters)) { - alias reflectParameterList = ParameterList!(reflectParameter!0); - - template reflectParameter(int parameterIndex) - { - static if (parameterIndex == parameters.length) { - alias reflectParameter = AliasSeq!(); - } else { - alias parameter = parameters[parameterIndex .. parameterIndex + 1]; - - alias reflectParameter = AliasSeq!( - Parameter!( - UDAList!(reflectUDAs!0), - [ __traits(getParameterStorageClasses, fun, parameterIndex) ], - Type!( - parameters[parameterIndex], - "std.traits.Parameters!(%s)[%d]".format(mixture, parameterIndex)), - "a%d".format(parameterIndex), - // ParameterDefaultValue!( - // defaultValues[parameterIndex], - // "bolts.reflection.metafunction.PDV!(%s)[%d]".format( - // mixture, parameterIndex)) - ), - reflectParameter!(parameterIndex + 1)); - - template reflectUDAs(int udaIndex) - { - static if (__traits(compiles, __traits(getAttributes, parameter))) { - static if (udaIndex < __traits(getAttributes, parameter).length) { - alias value = Alias!(__traits(getAttributes, parameter)[udaIndex]); - alias reflectUDAs = AliasSeq!( - UDA!( - value, - "bolts.reflection.metafunction.ParameterAttribute!(%s, %d, %d)".format( - mixture, parameterIndex, udaIndex)), - reflectUDAs!(udaIndex + 1)); - } else { - alias reflectUDAs = AliasSeq!(); - } - } else { - alias reflectUDAs = AliasSeq!(); - } - } - } - } - } -} - -unittest -{ - struct attr - { - this(string name) { this.name = name; } - string name; - } - - void f(int, @attr int, lazy char, @attr("foo") @(42) out real); - - alias PL = reflectParameterList!(f, "F").Unpack; - - Assert.equal(PL.length, 4); - Assert.equal(PL[0].mixture, "std.traits.Parameters!(F)[0] a0"); - - Assert.equal(PL[0].storageClasses.length, 0); - Assert.equal(PL[0].UDAs.length, 0); - - Assert.equal(PL[1].storageClasses.length, 0); - Assert.equal(PL[1].UDAs.length, 1); - Assert.equal(PL[1].UDAs[0].origin.stringof, "attr"); - Assert.equal(PL[1].UDAs[0].mixture, "@(bolts.reflection.metafunction.ParameterAttribute!(F, 1, 0))"); - - Assert.equal(PL[2].storageClasses.length, 1); - Assert.equal(PL[2].storageClasses[0], "lazy"); - Assert.equal(PL[2].UDAs.length, 0); - - Assert.equal(PL[3].storageClasses.length, 1); - Assert.equal(PL[3].storageClasses[0], "out"); - Assert.equal(PL[3].UDAs.length, 2); - Assert.equal(PL[3].UDAs[0].origin.name, "foo"); - Assert.equal(PL[3].UDAs[1].origin, 42); - - // Assert.equal( - // reflectParameterList!(f, "F").mixture, - // ""); -} - -unittest -{ - void f(in Object, out Object, ref Object, lazy Object, const Object, immutable Object, - // 0 1 2 3 4 5 - shared Object, inout Object, scope Object); - // 6 7 8 - alias P(int Position) = Parameter!( - [__traits(getParameterStorageClasses, f, Position)], - Type!Object, - ""); - //static assert(P!0.isIn); - static assert(P!1.isOut); - static assert(P!2.isRef); - static assert(P!3.isLazy); - // for the following the storage class has already become part of the type? - //static assert(P!4.isConst); - //static assert(P!5.isImmutable); - //static assert(P!6.isShared); - //static assert(P!7.isInout); - static assert(P!8.isScope); - - Assert.equal(P!1.mixture, "out Object"); - Assert.equal(P!1.setStorageClasses!([]).mixture, "Object"); -} - -unittest -{ - alias P = Parameter!(["lazy"], Type!(int), "a"); - Assert.equal(P.typeMixture, "int"); - Assert.equal(P.argumentMixture, "a"); - Assert.equal(P.storageClassMixture, "lazy"); - Assert.equal(P.mixture, "lazy int a"); - - Assert.equal(Parameter!(Type!(int, "T"), "a").typeMixture, "T"); -} - -unittest -{ - // building a function from scratch - alias F = Function!() - .setName!"foo" - .setReturnType!(Type!int) - .setParameters!( - Parameter!(Type!int), - Parameter!(Type!string)); - Assert.equal(F.mixture, "int foo(int, string)"); -} - -// ============================================================================ -// UDAs - -unittest -{ - struct foo; - @foo @("bar") void f(); - alias F = Function!f; - Assert.equal(F.udas.length, 2); - Assert.equal(F.udas[0].mixture, "@(__traits(getAttributes, f)[0])"); - Assert.equal(is(F.udas[0].origin == foo), true); - Assert.equal(F.udas[1].origin, "bar"); - Assert.equal(F.hasUDA!foo, true); - Assert.equal(F.hasUDA!"bar", true); - Assert.equal(F.hasUDA!"baz", false); - Assert.equal( - F.udaMixture, - `@(__traits(getAttributes, f)[0]) @(__traits(getAttributes, f)[1])`); - mixin(F.setName!"g".mixture, ";"); - Assert.equal( - __traits(getAttributes, f).stringof, - __traits(getAttributes, g).stringof); - Assert.equal( - Function!f.pointerMixture, - `@(__traits(getAttributes, f)[0]) @(__traits(getAttributes, f)[1]) @system std.traits.ReturnType!(f) function()`); -} - -unittest -{ - struct foo - { - this(string name) { this.name = name; } - string name; - } - - void f(int, @foo @foo("xyz") @("baz") @(42) real); - alias F = Function!f; - Assert.equal(F.parameters[0].UDAs.length, 0); - Assert.equal(F.parameters[1].UDAs.length, 4); -} - -// default parameter values -// unittest -// { -// int increment(int i, int by = 1); -// Assert.equal(Function!(increment, "F").parameters[1].defaultValue.origin, 1); -// Assert.equal( -// Function!(increment, "F").parameters[1].mixture, -// "std.traits.Parameters!(F)[1] a1 = bolts.reflection.metafunction.PDV!(F)[1]"); -// } diff --git a/source/bolts/reflection/metamodule.d b/source/bolts/reflection/metamodule.d deleted file mode 100644 index 979cd89..0000000 --- a/source/bolts/reflection/metamodule.d +++ /dev/null @@ -1,25 +0,0 @@ -module bolts.reflection.metamodule; - -template Module(alias Module, string Source = __traits(identifier, Module)) -{ - alias origin = Module; - enum source = Source; - static import bolts.reflection.metaaggregate; - mixin bolts.reflection.metaaggregate.ModuleAggregateCommonCode; -} - -version(unittest) -{ - import fluent.asserts; - - void fun1(); - void fun1(int); - int fun2(); - int a; -} - -unittest -{ - alias M = Module!(bolts.reflection.metamodule); - Assert.equal(M.functions.length, 3); -} diff --git a/source/bolts/reflection/metatype.d b/source/bolts/reflection/metatype.d deleted file mode 100644 index be6b983..0000000 --- a/source/bolts/reflection/metatype.d +++ /dev/null @@ -1,49 +0,0 @@ -module bolts.reflection.metatype; - -import std.traits; -import std.format; - -private mixin template makeAccessor(string Attribute, string Trait = Attribute ~ "Of") -{ - mixin(q{enum is%s = is(%s!origin == origin);}.format(Attribute, Trait)); -} - -template Type(alias Origin, string Source = Origin.stringof) -{ - alias origin = Origin; - enum mixtureArray = [ Source ]; - enum mixture = Source; - alias setMixture(string value) = Type!(origin, value); - mixin makeAccessor!("Const"); - mixin makeAccessor!("Immutable"); - enum isMutable = !isConst && !isImmutable; - mixin makeAccessor!("Shared"); - mixin makeAccessor!("Inout"); -} - -unittest -{ - import fluent.asserts; - static assert(is(Type!int.origin == int)); - static assert(Type!int.mixture == "int"); - static assert(Type!(int, "T").mixture == "T"); - - static assert(!Type!int.isConst); - static assert(Type!(const(int)).isConst); - - static assert(!Type!int.isImmutable); - static assert(Type!(immutable(int)).isImmutable); - - static assert(Type!int.isMutable); - static assert(!Type!(const(int)).isMutable); - static assert(!Type!(immutable(int)).isMutable); - - static assert(!Type!int.isShared); - static assert(Type!(shared(int)).isShared); - - static assert(!Type!int.isShared); - static assert(Type!(shared(int)).isShared); - - static assert(!Type!int.isInout); - static assert(Type!(inout(int)).isInout); -} diff --git a/source/bolts/reflection/metauda.d b/source/bolts/reflection/metauda.d deleted file mode 100644 index 0e5b4f1..0000000 --- a/source/bolts/reflection/metauda.d +++ /dev/null @@ -1,15 +0,0 @@ -module bolts.reflection.metauda; - -private import std.format : format; -private import std.meta : AliasSeq; - -template UDA(T...) -{ - static if (is(T[0])) { - alias origin = T[0]; - } else { - enum origin = T[0]; - } - enum source = T[1]; - enum mixture = "@(%s)".format(source); -} diff --git a/source/openmethods.d b/source/openmethods.d index 5a4a070..2da5323 100644 --- a/source/openmethods.d +++ b/source/openmethods.d @@ -93,7 +93,8 @@ import std.meta; import std.range; import std.traits; -import bolts.meta; +import rf = bolts.experimental.refraction; +static import bolts.experimental.refraction; // ============================================================================ // Public stuff @@ -291,6 +292,7 @@ auto registerMethods(string moduleName = __MODULE__) { return q{ static import openmethods; + static import bolts.experimental.refraction; mixin(openmethods.registrationMixture!(%s, "%s")); }.format(moduleName, moduleName); } @@ -324,7 +326,7 @@ mixin template registerClasses(Classes...) { /++ Update the runtime dispatch tables. Must be called after dynamically - loading or unloading a shared lubrary. + loading or unloading a shared library. +/ Runtime.Metrics updateMethods() @@ -450,23 +452,7 @@ private alias UnqualType(T : covariant!U, U) = U; private template Format(alias F, A...) { - static if (isInstanceOf!(AliasPack, A[0])) { - static assert(A.length == 1); - enum Format = format!F(A[0].Unpack); - } else { - enum Format = format!F(A); - } -} - -unittest -{ - alias F1 = ApplyLeft!(Format, "a%s"); - static assert(F1!1 == "a1"); - static assert(F1!(AliasPack!(1)) == "a1"); - static assert(staticMap!(F1, 1, 2, 3) == AliasSeq!("a1", "a2", "a3")); - alias F2 = ApplyLeft!(Format, "%s a%s"); - static assert(F2!("int", 1) == "int a1"); - static assert(F2!(AliasPack!("int", 1)) == "int a1"); + enum Format = format!F(A); } // ============================================================================ @@ -477,7 +463,18 @@ struct MethodTag { } enum MptrInDeallocator = "deallocator"; enum MptrViaHash = "hash"; -struct Method(alias module_, string name, uint index) +auto makeCallParams(rf.Parameter[] parameters) +{ + return parameters.length.iota.map!( + i => parameters[i].setType("CallParams[%d]".format(i))).array; +} + +auto removeStorageClasses(rf.Parameter[] parameters) +{ + return parameters.map!(p => p.setStorage([])).array; +} + +struct Method(alias module_, string name, int index) { alias Module = module_; enum Name = name; @@ -493,20 +490,12 @@ struct Method(alias module_, string name, uint index) // ========================================================================== // Meta-programming - import bolts.reflection.metafunction; - import bolts.reflection.metatype; + enum Original = rf.refract!(Declaration, "Declaration"); - alias Original = Function!(Declaration, "Declaration"); - - alias updateParameter(int i) = Original.parameters[i].setType!( - Original.parameters[i].type.setMixture!("CallParams[%d]".format(i))); - - alias Editor = Function!(Declaration, "Declaration") - .setReturnType!(Type!(ReturnType, "ReturnType")) // not really needed but helps debugging - .setParameters!( - staticMap!( - updateParameter, - aliasSeqOf!(Original.arity.iota))); + enum Editor = Original + .setStatic(true) + .setReturnType("ReturnType") // not really needed but helps debugging + .setParameters(makeCallParams(Original.parameters)); static if (hasUDA!(Declaration, mptr)) { static assert(getUDAs!(Declaration, mptr).length == 1, "only one @mptr allowed"); @@ -520,31 +509,31 @@ struct Method(alias module_, string name, uint index) isVirtualPosition, aliasSeqOf!(QualParams.length.iota)); enum virtualArgListCode = [ - staticMap!(ApplyLeft!(Format, "a%s"), virtualPositions) + staticMap!(ApplyLeft!(Format, "_%d"), virtualPositions) ].join(", "); static template castArgCode(QualParam, size_t i) { static if (IsVirtual!QualParam) { static if (is(UnqualType!QualParam == interface)) { - enum castArgCode = "cast(SpecParams[%s]) a%s".format(i, i); + enum castArgCode = "cast(SpecParams[%s]) _%d".format(i, i); } else { - enum castArgCode = "cast(SpecParams[%s]) cast(void*) a%s".format(i, i); + enum castArgCode = "cast(SpecParams[%s]) cast(void*) _%d".format(i, i); } } else static if (IsCovariant!QualParam) { static if (is(UnqualType!QualParam == class)) { debug { - enum castArgCode = "cast(SpecParams[%s]) a%s".format(i, i); + enum castArgCode = "cast(SpecParams[%s]) _%d".format(i, i); } else { - enum castArgCode = "cast(SpecParams[%s]) cast(void*) a%s".format(i, i); + enum castArgCode = "cast(SpecParams[%s]) cast(void*) _%d".format(i, i); } } else { static assert(is(UnqualType!QualParam == interface), "covariant argument must be a class or an interface"); - enum castArgCode = "cast(SpecParams[%s]) a%s".format(i, i); + enum castArgCode = "cast(SpecParams[%s]) _%d".format(i, i); } } else { - enum castArgCode = "a%s".format(i); + enum castArgCode = "_%d".format(i); } } @@ -556,35 +545,35 @@ struct Method(alias module_, string name, uint index) return casts.join(", "); }(); - alias Wrapper(alias Spec) = Editor - .setName!"wrapper" - .setBody!("return Spec(%s);".format(castArgListCode!Spec)); + enum Wrapper(alias Spec) = Editor + .setName("wrapper") + .setBody("{ return Spec(%s); }".format(castArgListCode!Spec)); mixin( "alias Spec = ", - Editor.setUdaList!(UDAList!()).pointerMixture, + Editor.setUdas([]).setName("function").mixture, ";"); // dispatcher - alias Dispatcher = + enum Dispatcher = Editor - .setName!"dispatcher" - .setBody!("return resolve(%s)(%s);".format( - virtualArgListCode, Editor.argumentMixture)); + .setName("dispatcher") + .setBody( + "{ return resolve(%s)(%s); }".format( + virtualArgListCode, Editor.argumentMixture)); mixin(Dispatcher.mixture); // discriminator note that we do *not* carry parameter storage classes // because we use CallParams[i].init to form an argument list when "calling" // the discriminator to locate the method. - alias removeStorageClasses(alias P) = P.setStorageClasses!([]); mixin( Editor - .setReturnType!(Type!(TheMethod, "TheMethod")) - .setName!"discriminator" - .setParameters!( - Parameter!([], Type!(openmethods.MethodTag), ""), - staticMap!(removeStorageClasses, Editor.parameters)) - .mixture, ";"); + .setReturnType("TheMethod") + .setName("discriminator") + .setParameters( + [ rf.Parameter().setType("openmethods.MethodTag") ] + ~ removeStorageClasses(Editor.parameters)) + .mixture); enum aliases = q{ alias %s = openmethods.Method!(%s, "%s", %d).dispatcher; @@ -811,13 +800,16 @@ unittest string registrationMixture(alias MODULE, alias moduleName)() { import std.array; - import bolts.reflection.metamodule; string[] mixture; - foreach (m; Module!MODULE.functions) { - static if (hasVirtualParameters!(m.origin)) { - mixture ~= openmethods.Method!(MODULE, m.name, m.index).aliases; + foreach (m; __traits(allMembers, MODULE)) { + static if (is(typeof(__traits(getOverloads, MODULE, m)))) { + foreach (i, o; __traits(getOverloads, MODULE, m)) { + static if (hasVirtualParameters!(o)) { + mixture ~= openmethods.Method!(MODULE, m, i).aliases; + } + } } } @@ -830,26 +822,33 @@ string registrationMixture(alias MODULE, alias moduleName)() return join(mixture, "\n"); } -mixin template registrar(alias M, alias ModuleName) +mixin template registrar(alias MODULE, alias ModuleName) { import openmethods; import std.traits; - import bolts.reflection.metamodule; void registerMethods() { - foreach (fun; Module!M.functions) { - static if (hasVirtualParameters!(fun.origin)) { - openmethods.Method!(M, fun.name, fun.index).register; + foreach (m; __traits(allMembers, MODULE)) { + static if (is(typeof(__traits(getOverloads, MODULE, m)))) { + foreach (i, o; __traits(getOverloads, MODULE, m)) { + static if (hasVirtualParameters!(o)) { + openmethods.Method!(MODULE, m, i).register; + } + } } } } void unregisterMethods() { - foreach (fun; Module!M.functions) { - static if (hasVirtualParameters!(fun.origin)) { - openmethods.Method!(M, fun.name, fun.index).unregister; + foreach (m; __traits(allMembers, MODULE)) { + static if (is(typeof(__traits(getOverloads, MODULE, m)))) { + foreach (i, o; __traits(getOverloads, MODULE, m)) { + static if (hasVirtualParameters!(o)) { + openmethods.Method!(MODULE, m, i).unregister; + } + } } } } @@ -868,30 +867,38 @@ mixin template registrar(alias M, alias ModuleName) } void registerSpecs() { - foreach (fun; Module!M.functions) { - static if (hasUDA!(fun.origin, method)) { - static assert( - isNamedSpec!(fun.origin) || fun.name[0] == '_', - fun.name ~ ": method name must begin with an underscore, " - ~ "or be set in @method()"); - static assert( - !hasVirtualParameters!(fun.origin), - fun.name ~ ": virtual! must not be used in method definitions"); - alias Method = typeof( - mixin(specId!(fun.name, fun.origin))( - openmethods.MethodTag.init, Parameters!(fun.origin).init)); - Method.specRegistrar!(fun.origin).register; + foreach (m; __traits(allMembers, MODULE)) { + static if (is(typeof(__traits(getOverloads, MODULE, m)))) { + foreach (i, o; __traits(getOverloads, MODULE, m)) { + static if (hasUDA!(o, method)) { + static assert( + isNamedSpec!(o) || m[0] == '_', + m ~ ": method name must begin with an underscore, " + ~ "or be set in @method()"); + static assert( + !hasVirtualParameters!(o), + m ~ ": virtual! must not be used in method definitions"); + alias Method = typeof( + mixin(specId!(m, o))( + openmethods.MethodTag.init, Parameters!(o).init)); + Method.specRegistrar!(o).register; + } + } } } } void unregisterSpecs() { - foreach (fun; Module!M.functions) { - static if (hasUDA!(fun.origin, method)) { - alias Method = typeof( - mixin(specId!(fun.name, fun.origin))( - openmethods.MethodTag.init, Parameters!(fun.origin).init)); - Method.specRegistrar!(fun.origin).unregister; + foreach (m; __traits(allMembers, MODULE)) { + static if (is(typeof(__traits(getOverloads, MODULE, m)))) { + foreach (i, o; __traits(getOverloads, MODULE, m)) { + static if (hasUDA!(o, method)) { + alias Method = typeof( + mixin(specId!(m, o))( + openmethods.MethodTag.init, Parameters!(o).init)); + Method.specRegistrar!(o).unregister; + } + } } } } diff --git a/tests/dub.json b/tests/dub.json index 0a73fc7..52fd8e9 100644 --- a/tests/dub.json +++ b/tests/dub.json @@ -26,9 +26,6 @@ { "name": "unittest", "dflags": ["-mixin=mixins.txt"], - "dependencies": { - "fluent-asserts": "~>0.13.3", - } }, ] } diff --git a/tests/source/defaultparametervalues.d b/tests/source/defaultparametervalues.d index 6a58089..e2539d7 100644 --- a/tests/source/defaultparametervalues.d +++ b/tests/source/defaultparametervalues.d @@ -4,7 +4,6 @@ import openmethods; mixin(registerMethods); import std.array, std.range; -import fluent.asserts; class Animal {} class Cat : Animal {} @@ -18,7 +17,7 @@ string kick(virtual!Animal, int times = 1); unittest { - Assert.equal(kick(new Cat), "meow!"); - Assert.equal(kick(new Cat, 3), "meow! meow! meow!"); + assert(kick(new Cat) == "meow!"); + assert(kick(new Cat, 3) == "meow! meow! meow!"); } } diff --git a/tests/source/udas.d b/tests/source/udas.d index fbb12cd..563e552 100644 --- a/tests/source/udas.d +++ b/tests/source/udas.d @@ -4,7 +4,6 @@ import openmethods; mixin(registerMethods); import std.traits; -import fluent.asserts; class Animal {} @@ -21,11 +20,11 @@ void pet(@beast("pet") virtual!Animal, @(42) int times) {} unittest { - Assert.equal( - getSymbolsByUDA!(udatest, nasty).stringof, + assert( + getSymbolsByUDA!(udatest, nasty).stringof == "tuple(kick, dispatcher, discriminator)"); - Assert.equal( - Parameters!(Method!(udatest, "pet", 0).dispatcher).stringof, + assert( + Parameters!(Method!(udatest, "pet", 0).dispatcher).stringof == `(@(beast("pet")) Animal, @(42) int)`); }