1 module janet.func; 2 3 import janet.c; 4 5 import janet.d; 6 7 /** 8 A wrapper around call_janet using D-like varargs. 9 */ 10 Janet callJanet(T...)(JanetFunction* fun,T args) 11 { 12 Janet[T.length] wrappedArgs; 13 static foreach(i,v;args) 14 { 15 wrappedArgs[i]=janetWrap(v); 16 } 17 return janet_call(fun,T.length,cast(const(Janet*))(wrappedArgs)); 18 } 19 /** 20 Wraps around a function, allowing it to be called in Janet. 21 */ 22 template makeJanetCFunc(alias func) 23 { 24 import std.traits : Parameters,ReturnType,isNestedFunction; 25 import std.typecons : Tuple; 26 extern(C) static Janet ourJanetFunc (int argc, Janet* argv) 27 { 28 Tuple!(Parameters!func) args; 29 alias funcParams = Parameters!func; 30 static foreach(i;0..args.length) 31 { 32 args[i] = getFromJanet!(funcParams[i])(argv[i]); 33 } 34 return janetWrap!(ReturnType!func)(func(args.expand)); 35 } 36 JanetCFunction makeJanetCFunc() 37 { 38 return &ourJanetFunc; 39 } 40 } 41 /** 42 The same, but requires a delegate or function pointer be put in as an argument. 43 This is due to many class methods requiring context pointers. 44 This is mostly only useful for class registering. 45 */ 46 template makeJanetCFunc(alias func,T,Args...) 47 { 48 import std.traits : Parameters,ReturnType,isNestedFunction; 49 import std.typecons : Tuple; 50 static T delegate(Args) dg; 51 static T function(Args) fp; 52 JanetCFunction makeJanetCFunc(T delegate(Args) argDg) 53 { 54 dg = argDg; 55 return &ourJanetFunc; 56 } 57 JanetCFunction makeJanetCFunc(T function(Args) argFp) // templates are so wonderful. 58 { 59 fp = argFp; 60 return &ourJanetFunc; 61 } 62 extern(C) static Janet ourJanetFunc (int argc, Janet* argv) 63 { 64 Tuple!(Parameters!func) args; 65 alias funcParams = Parameters!func; 66 static foreach(i;0..args.length) 67 { 68 args[i] = getFromJanet!(funcParams[i])(argv[i]); 69 } 70 if(dg) 71 { 72 return janetWrap!(ReturnType!func)(dg(args.expand)); 73 } 74 else 75 { 76 return janetWrap!(ReturnType!func)(fp(args.expand)); 77 } 78 } 79 } 80 81 /** 82 Makes a function globally available with Janet. 83 */ 84 void registerFunctionWithJanet(alias func,string documentation = "")() 85 { 86 import std.string : toStringz; 87 JanetReg[2] reg; 88 reg[0].name = cast(const(char)*)toStringz(__traits(identifier,func)); 89 reg[0].cfun = makeJanetCFunc!func; 90 reg[0].documentation = cast(const(char)*)toStringz(documentation); 91 janet_cfuns(coreEnv,"",®[0]); 92 } 93 94 version(unittest) 95 { 96 int foo(int x) 97 { 98 return x+1; 99 } 100 int bar(int y) 101 { 102 return y+2; 103 } 104 } 105 106 unittest 107 { 108 import std.file; 109 import std.parallelism : task; 110 auto fileTask = task!read("./source/tests/dtests/function.janet"); 111 fileTask.executeInNewThread(); 112 initJanet(); 113 scope(exit) janet_deinit(); 114 import std.stdio : writeln; 115 writeln("Performing CFunction register test."); 116 registerFunctionWithJanet!foo(); 117 registerFunctionWithJanet!bar(); 118 Janet* j; 119 const ubyte[] file = cast(const(ubyte[]))(fileTask.spinForce); 120 const(ubyte)* realFile = cast(const(ubyte)*)file; 121 int realFileLength = cast(int)(file.length); 122 assert(janet_dobytes(coreEnv,realFile,realFileLength, 123 cast(const(char)*)("./source/tests/dtests/function.janet"),j)==0,"CFunction register test errored!"); 124 writeln("Success."); 125 }