1 module orelang.operator.DllOperator; 2 import orelang.operator.IOperator, orelang.Engine, orelang.Value; 3 import orelang.Util; 4 import core.sys.posix.dlfcn; 5 import std..string, std.stdio, std.format, std.conv; 6 7 version (WithFFI) { 8 enum D_TYPE { 9 VOID, 10 UBYTE, 11 BYTE, 12 USHORT, 13 SHORT, 14 UINT, 15 INT, 16 ULONG, 17 LONG, 18 FLOAT, 19 DOUBLE, 20 POINTER, 21 STRING, 22 } 23 24 D_TYPE string_to_dtype(string s) { 25 final switch (s) with (D_TYPE) { 26 case "void": 27 return VOID; 28 case "ubyte": 29 return UBYTE; 30 case "byte": 31 return BYTE; 32 case "ushort": 33 return USHORT; 34 case "short": 35 return SHORT; 36 case "uint": 37 return UINT; 38 case "int": 39 return INT; 40 case "ulong": 41 return ULONG; 42 case "long": 43 return LONG; 44 case "float": 45 return FLOAT; 46 case "double": 47 return DOUBLE; 48 case "pointer": 49 return POINTER; 50 case "string": 51 return STRING; 52 } 53 } 54 55 ffi_type* d_type_to_ffi_type(D_TYPE type) { 56 return [&ffi_type_void, &ffi_type_uint8, &ffi_type_sint8, 57 &ffi_type_uint16, &ffi_type_sint16, &ffi_type_uint32, 58 &ffi_type_sint32, &ffi_type_uint64, &ffi_type_sint64, &ffi_type_float, 59 &ffi_type_double, &ffi_type_pointer, &ffi_type_pointer][type]; 60 } 61 62 ffi_type*[] d_types_to_ffi_types(D_TYPE[] types) { 63 ffi_type*[] ret; 64 foreach (type; types) { 65 ret ~= d_type_to_ffi_type(type); 66 } 67 return ret; 68 } 69 70 struct Func { 71 string name; 72 void* ptr; 73 D_TYPE[] arg_types; 74 D_TYPE r_type; 75 ffi_cif cif; 76 } 77 78 Func newFunc(void* lh, string name, D_TYPE[] arg_types, D_TYPE r_type) { 79 import std..string; 80 81 void* ptr = dlsym(lh, name.toStringz); 82 char* error = dlerror(); 83 84 if (error) { 85 throw new Error("dlsym error: %s\n".format(error)); 86 } 87 88 ffi_cif cif; 89 ffi_status status; 90 91 auto _arg_types = d_types_to_ffi_types(arg_types); 92 auto _r_type = d_type_to_ffi_type(r_type); 93 94 if ((status = ffi_prep_cif(&cif, ffi_abi.FFI_DEFAULT_ABI, 95 arg_types.length.to!uint, _r_type, cast(ffi_type**)_arg_types)) != ffi_status.FFI_OK) { 96 throw new Error("ERROR : %d".format(status)); 97 } 98 99 return Func(name, ptr, arg_types, r_type, cif); 100 } 101 102 bool checkCastable(T)(void* ptr) { 103 return (cast(T*)ptr) !is null; 104 } 105 106 Value invokeFunc(Func func, void*[] args) { 107 foreach (i, type; func.arg_types) { 108 final switch (type) with (D_TYPE) { 109 case VOID: 110 break; 111 case UBYTE: 112 if (!checkCastable!(ubyte)(args[i])) { 113 throw new Error("Invalid argument<type error>"); 114 } 115 break; 116 case BYTE: 117 if (!checkCastable!(byte)(args[i])) { 118 throw new Error("Invalid argument<type error>"); 119 } 120 break; 121 case USHORT: 122 if (!checkCastable!(ushort)(args[i])) { 123 throw new Error("Invalid argument<type error>"); 124 } 125 break; 126 case SHORT: 127 if (!checkCastable!(short)(args[i])) { 128 throw new Error("Invalid argument<type error>"); 129 } 130 break; 131 case UINT: 132 if (!checkCastable!(uint)(args[i])) { 133 throw new Error("Invalid argument<type error>"); 134 } 135 break; 136 case INT: 137 if (!checkCastable!(int)(args[i])) { 138 throw new Error("Invalid argument<type error>"); 139 } 140 break; 141 case ULONG: 142 if (!checkCastable!(ulong)(args[i])) { 143 throw new Error("Invalid argument<type error>"); 144 } 145 break; 146 case LONG: 147 if (!checkCastable!(long)(args[i])) { 148 throw new Error("Invalid argument<type error>"); 149 } 150 break; 151 case FLOAT: 152 if (!checkCastable!(float)(args[i])) { 153 throw new Error("Invalid argument<type error>"); 154 } 155 break; 156 case DOUBLE: 157 if (!checkCastable!(double)(args[i])) { 158 throw new Error("Invalid argument<type error>"); 159 } 160 break; 161 case POINTER: 162 if (!checkCastable!(void)(args[i])) { 163 throw new Error("Invalid argument<type error>"); 164 } 165 break; 166 case STRING: 167 if (!checkCastable!(char)(args[i])) { 168 throw new Error("Invalid argument<type error>"); 169 } 170 break; 171 } 172 } 173 174 ffi_arg result; 175 176 ffi_call(&func.cif, func.ptr, &result, cast(void**)args); 177 178 final switch (func.r_type) with (D_TYPE) { 179 case VOID: 180 return new Value; 181 case UBYTE: 182 auto v = cast(ubyte)result; 183 return new Value(v); 184 case BYTE: 185 auto v = cast(byte)result; 186 return new Value(v); 187 case USHORT: 188 auto v = cast(ushort)result; 189 return new Value(v); 190 case SHORT: 191 auto v = cast(short)result; 192 return new Value(v); 193 case UINT: 194 auto v = cast(uint)result; 195 return new Value(v); 196 case INT: 197 auto v = cast(int)result; 198 return new Value(v); 199 case ULONG: 200 auto v = cast(ulong)result; 201 return new Value(v); 202 case LONG: 203 auto v = cast(long)result; 204 return new Value(v); 205 case FLOAT: 206 auto v = cast(float)result; 207 return new Value(v); 208 case DOUBLE: 209 auto v = cast(double)result; 210 return new Value(v); 211 case POINTER: 212 void* ptr = cast(void*)result; 213 return new Value(ptr); 214 case STRING: 215 auto v = cast(char*)result; 216 return new Value(cast(string)v.fromStringz); 217 } 218 } 219 220 class DllOperator : IOperator { 221 /** 222 * call 223 */ 224 void*[] lhs; 225 226 ~this() { 227 foreach (lh; lhs) { 228 dlclose(lh); 229 } 230 } 231 232 void* open_dll(string dll_path) { 233 void* lh = dlopen(dll_path.toStringz, RTLD_LAZY); 234 if (!lh) { 235 throw new Error("dlopen error: %s\n".format(dlerror())); 236 } 237 lhs ~= lh; 238 return lh; 239 } 240 241 public Value call(Engine engine, Value[] args) { 242 struct Func_Info { 243 string name; 244 D_TYPE r_type; 245 D_TYPE[] arg_types; 246 } 247 248 string dll_path; 249 Func_Info[] func_infos; 250 251 foreach (arg; args) { 252 if (arg.type == ValueType.Array) { 253 Value[] array = arg.getArray; 254 if (array[0].type != ValueType.SymbolValue) { 255 throw new Error("<1>Invalid Syntax"); 256 } 257 if (array[0].getSymbolValue.value == "dll-path") { 258 if (array[1].type != ValueType.String) { 259 throw new Error("<2>Invalid Syntax"); 260 } 261 dll_path = array[1].getString; 262 } else if (array[0].getSymbolValue.value == "dll-functions") { 263 if (array[1].type != ValueType.Array) { 264 throw new Error("<3>Invalid Syntax"); 265 } 266 Value[] funcs = array[1 .. $]; 267 268 foreach (func; funcs) { 269 if (func.type != ValueType.Array) { 270 throw new Error("<4>Invalid Syntax"); 271 } 272 Value[] info = func.getArray; 273 if (info.length != 3) { 274 throw new Error("<5>Invalid Syntax"); 275 } 276 if (info[0].type != ValueType.String 277 || info[1].type != ValueType.SymbolValue || info[2].type != ValueType.Array) { 278 throw new Error("<6>Invalid Syntax"); 279 } 280 string name = info[0].getString; 281 D_TYPE r_type = info[1].getSymbolValue.value.string_to_dtype; 282 D_TYPE[] arg_types; 283 284 foreach (Value type; info[2].getArray) { 285 if (type.type != ValueType.SymbolValue) { 286 throw new Error("<7>Invalid Syntax"); 287 } 288 arg_types ~= type.getSymbolValue.value.string_to_dtype; 289 } 290 291 func_infos ~= Func_Info(name, r_type, arg_types); 292 } 293 } 294 } else { 295 throw new Error("<dll_op call>Invalid argument"); 296 } 297 } 298 299 if (dll_path.length == 0 || func_infos.length == 0) { 300 throw new Error("Invalid Syntax"); 301 } 302 303 void* lh = open_dll(dll_path); 304 305 foreach (func_info; func_infos) { 306 IOperator new_op = new class() IOperator { 307 Func func; 308 309 this() { 310 func = newFunc(lh, func_info.name, func_info.arg_types, func_info.r_type); 311 } 312 313 ~this() { 314 dlclose(lh); 315 } 316 317 public Value call(Engine engine, Value[] args) { 318 void*[] f_args; 319 foreach (i, arg_type; func.arg_types) { 320 Value eargs = engine.eval(args[i]); 321 322 final switch (arg_type) with (D_TYPE) { 323 case VOID: 324 break; 325 case UBYTE: 326 if (eargs.type != ValueType.Numeric) { 327 throw new Error("<ubyte>Invalid Argument"); 328 } 329 auto arg = eargs.getNumeric.to!(ubyte); 330 auto ptr = &arg; 331 f_args ~= ptr; 332 break; 333 case BYTE: 334 if (eargs.type != ValueType.Numeric) { 335 throw new Error("<byte>Invalid Argument"); 336 } 337 auto arg = eargs.getNumeric.to!(byte); 338 auto ptr = &arg; 339 f_args ~= ptr; 340 break; 341 case USHORT: 342 if (eargs.type != ValueType.Numeric) { 343 throw new Error("<ushort>Invalid Argument"); 344 } 345 auto arg = eargs.getNumeric.to!(ushort); 346 auto ptr = &arg; 347 f_args ~= ptr; 348 break; 349 case SHORT: 350 if (eargs.type != ValueType.Numeric) { 351 throw new Error("<short>Invalid Argument"); 352 } 353 auto arg = eargs.getNumeric.to!(short); 354 auto ptr = &arg; 355 f_args ~= ptr; 356 break; 357 case UINT: 358 if (eargs.type != ValueType.Numeric) { 359 throw new Error("<uint>Invalid Argument"); 360 } 361 auto arg = eargs.getNumeric.to!(uint); 362 auto ptr = &arg; 363 f_args ~= ptr; 364 break; 365 case INT: 366 if (eargs.type != ValueType.Numeric) { 367 throw new Error("<int>Invalid Argument"); 368 } 369 auto arg = eargs.getNumeric.to!(int); 370 auto ptr = &arg; 371 f_args ~= ptr; 372 break; 373 case ULONG: 374 if (eargs.type != ValueType.Numeric) { 375 throw new Error("<ulong>Invalid Argument"); 376 } 377 auto arg = eargs.getNumeric.to!(ulong); 378 auto ptr = &arg; 379 f_args ~= ptr; 380 break; 381 case LONG: 382 if (eargs.type != ValueType.Numeric) { 383 throw new Error("<long>Invalid Argument"); 384 } 385 auto arg = eargs.getNumeric.to!(long); 386 auto ptr = &arg; 387 f_args ~= ptr; 388 break; 389 case FLOAT: 390 if (eargs.type != ValueType.Numeric) { 391 throw new Error("<float>Invalid Argument"); 392 } 393 auto arg = eargs.getNumeric.to!(float); 394 auto ptr = &arg; 395 f_args ~= ptr; 396 break; 397 case DOUBLE: 398 if (eargs.type != ValueType.Numeric) { 399 throw new Error("<double>Invalid Argument"); 400 } 401 auto arg = eargs.getNumeric.to!(double); 402 auto ptr = &arg; 403 f_args ~= ptr; 404 break; 405 case POINTER: 406 if (eargs.type != ValueType.RAWPointer) { 407 throw new Error("<ptr>Invalid Argument"); 408 } 409 auto arg = eargs.getRAWPointer; 410 void* ptr = &arg; 411 f_args ~= ptr; 412 break; 413 case STRING: 414 if (eargs.type != ValueType.String) { 415 throw new Error("<string>Invalid Argument"); 416 } 417 auto arg = eargs.getString.toStringz; 418 auto ptr = &arg; 419 f_args ~= ptr; 420 break; 421 } 422 } 423 424 return invokeFunc(func, f_args); 425 } 426 }; 427 428 engine.defineVariable(func_info.name, new Value(new_op)); 429 } 430 431 return new Value(true); 432 } 433 } 434 }