-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2790898
Showing
17 changed files
with
2,331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.dub | ||
docs.json | ||
__dummy.html | ||
docs/ | ||
/dangel | ||
libdangel.so | ||
dangel.dylib | ||
dangel.dll | ||
libdangel.a | ||
dangel.lib | ||
dangel-test-* | ||
*.exe | ||
*.o | ||
*.obj | ||
*.lst | ||
*.a | ||
*.so | ||
|
||
dub.selections.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# DAngel | ||
D bindings and wrapper for AngelScript with support for D strings. | ||
|
||
Do note this is still work in progress and there's currently issues with D calling conventions breaking with angelscript (will be working on patching angelscript to support D calling conventions) | ||
|
||
This library also depends on a patched C binding to angelscript that you will need to compile first, you can find that [here](https://github.com/KitsunebiGames/angelscriptc) | ||
|
||
# Why? | ||
Because I can, especially with the string support. | ||
I'm sorry in advance, there's some cursed GC stuff going on there and I'm not sure whether it will leak memory at some point. | ||
|
||
# Using the binding | ||
First compile AngelScript and the [patched c bindings](https://github.com/KitsunebiGames/angelscriptc) **AS DYNAMIC LIBRARIES** and install the libraries to your system's library path (or whatever the heck you do on Windows) | ||
|
||
Then put the libraries somewhere that the D linker will be able to find them, in my case that's `/usr/lib` and `/usr/include`. You may want to ship the libraries with your application. | ||
|
||
Once you have that sorted, just compile your application with dub and it _should_ link to the libraries, hopefully... | ||
|
||
# Using D strings | ||
To enable D string support register the D string subsystem in angelscript like this: | ||
```d | ||
import as.addons.str : registerDStrings; | ||
ScriptEngine engine = ScriptEngine.create(); | ||
engine.registerDStrings(); | ||
// Register all your other stuff and execute your scripts. | ||
``` | ||
|
||
# Registering D types | ||
Currently DAngel supports registering a few D types automatically, one being **integer** enums. To register a D integer enum do the following: | ||
```d | ||
enum MyEnum { | ||
Item1, | ||
Item2, | ||
Item3 = 42, | ||
} | ||
// After this call the enum will be available to your scripts. | ||
engine.registerEnum!MyEnum; | ||
``` | ||
|
||
There's experimental and buggy support for registering D structs in `as.addons.dwrap`. I don't recommend using it currently, though. | ||
|
||
# There's parts of the API missing! | ||
I know, there's also a lot of places where I haven't done any error handling yet that will just fail silently. It will be fixed with time. | ||
|
||
# My functions don't run correctly! | ||
I know, there's some incompatibility between AngelScript and the D ABI's calling conventions, changing the calling convention to the C calling convention via `extern(C)` and marking your function as `asCDECL` should work around it temporarily. | ||
|
||
I'll be working on making a patched version of AngelScript that supports the D calling convention unless the creator of AngelScript decides to add it themself. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
name "dangel" | ||
description "D AngelScript binding" | ||
authors "Luna Nielsen" | ||
copyright "Copyright © 2020, Luna Nielsen" | ||
license "BSD 2-Clause" | ||
libs "as_c" "angelscript" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
module as.addons.dwrap; | ||
import as.def; | ||
import as.engine; | ||
import core.memory; | ||
import core.stdc.stdlib : free; | ||
import std.traits; | ||
import std.format; | ||
import std.string; | ||
import std.stdio; | ||
|
||
private { | ||
extern(C) void constructClassOrStruct(T)(T* self) { | ||
import std.conv : emplace; | ||
emplace!T(self); | ||
} | ||
|
||
extern(C) void destructClassOrStruct(T)(T* self) { | ||
destroy(self); | ||
} | ||
|
||
extern(C) T structAssign(T)(ref T in_, ref T self) { | ||
writeln(self, " ", in_); | ||
self = in_; | ||
return self; | ||
} | ||
|
||
string toASType(string typeName) { | ||
switch(typeName) { | ||
|
||
case "string": | ||
case "int": | ||
case "float": | ||
case "double": return typeName; | ||
|
||
case "ubyte": return "byte"; | ||
case "ushort": return "uint16"; | ||
case "uint": return "uint"; | ||
case "ulong": return "uint64"; | ||
default: { | ||
while (typeName.endsWith("*")) { | ||
typeName.length--; | ||
} | ||
return typeName; | ||
} | ||
} | ||
} | ||
|
||
string buildArgList(alias T)() { | ||
string[] o; | ||
static foreach(param; Parameters!T) { | ||
o ~= toASType(param.stringof); | ||
} | ||
return o.length == 0 ? "" : o.join(", "); | ||
} | ||
} | ||
|
||
void registerDStruct(T, string namespace = "")(ScriptEngine engine) if (is(T == struct)) { | ||
mixin("import ", moduleName!T, ";"); | ||
|
||
static if (namespace.length != 0) { | ||
string prevNamespace = engine.getDefaultNamespace(); | ||
scope(exit) engine.setDefaultNamespace(prevNamespace); | ||
|
||
// Set up namespace | ||
engine.setDefaultNamespace(namespace); | ||
} | ||
|
||
engine.registerObjectType(T.stringof, T.sizeof, asEObjTypeFlags.asOBJ_VALUE | asEObjTypeFlags.asOBJ_APP_CLASS_CDAK); | ||
engine.registerObjectBehaviour( | ||
T.stringof, | ||
asEBehaviours.asBEHAVE_CONSTRUCT, | ||
"void f()", | ||
cast(asFUNCTION_t)&constructClassOrStruct!T, | ||
DCallConvClass, | ||
null | ||
); | ||
|
||
engine.registerObjectBehaviour( | ||
T.stringof, | ||
asEBehaviours.asBEHAVE_DESTRUCT, | ||
"void f()", | ||
cast(asFUNCTION_t)&destructClassOrStruct!T, | ||
DCallConvClass, | ||
null | ||
); | ||
engine.registerObjectMethod( | ||
T.stringof, | ||
"%s &opAssign(const %s &in)".format(T.stringof, T.stringof), | ||
&structAssign!T, | ||
DCallConvClassR | ||
); | ||
|
||
|
||
static foreach(member; __traits(allMembers, T)) { | ||
{ | ||
alias mInstance = mixin(T.stringof, ".", member); | ||
enum visibility = __traits(getProtection, mInstance); | ||
static if (visibility == "public" || visibility == "static") { | ||
static if (is(typeof(mInstance) == function)) { | ||
{ | ||
string retType = (ReturnType!mInstance).stringof; | ||
|
||
engine.registerObjectMethod(T.stringof, "%s %s(%s)".format(toASType(retType), member, buildArgList!mInstance()), cast(asFUNCTION_t)&mInstance, DCallConvClassR, null); | ||
} | ||
} else static if(!is(typeof(mInstance) == struct) && !is(typeof(mInstance) == class)) { | ||
engine.registerObjectProperty(T.stringof, "%s %s".format(toASType(typeof(mInstance).stringof), member), mInstance.offsetof); | ||
} else static if(is(typeof(mInstance) == struct)) { | ||
// TODO: Auto register structs if needed | ||
} | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
module as.addons.str; | ||
import as.def; | ||
import as.engine; | ||
import core.memory; | ||
import std.stdio; | ||
|
||
private extern(C) { | ||
|
||
/** | ||
A proto string | ||
*/ | ||
union protostring { | ||
struct pstr_impl { | ||
size_t len; | ||
const(char)* data; | ||
} | ||
|
||
this(size_t length, const(char)* data) { | ||
proto = pstr_impl(length, data); | ||
GC.addRoot(&this); | ||
GC.setAttr(&this, GC.BlkAttr.NO_MOVE); | ||
} | ||
|
||
this(string str) { | ||
this.str = str.idup; | ||
GC.addRoot(&this); | ||
GC.setAttr(&this, GC.BlkAttr.NO_MOVE); | ||
} | ||
|
||
void release() { | ||
GC.removeRoot(&this); | ||
} | ||
|
||
size_t length() { | ||
return proto.len; | ||
} | ||
|
||
void setText(string text) { | ||
GC.removeRoot(cast(void*)str); | ||
str = text.idup; | ||
GC.addRoot(cast(void*)str); | ||
} | ||
|
||
pstr_impl proto; | ||
string str; | ||
} | ||
|
||
/** | ||
The cache of constant values | ||
*/ | ||
int[protostring*] constantCache; | ||
|
||
// FACTORY | ||
void* getStringConstant(const(char)* data, asUINT length) { | ||
protostring* text = new protostring(cast(string)data[0..length]); | ||
|
||
// Handle adding references to strings | ||
if (text !in constantCache) constantCache[text] = 1; | ||
else constantCache[text]++; | ||
|
||
return cast(void*)text; | ||
} | ||
|
||
int releaseStringConstant(const(void)* str) { | ||
if (str is null) return asERetCodes.asERROR; | ||
|
||
auto text = cast(protostring*)str; | ||
|
||
// Handle releasing strings | ||
if (text !in constantCache) return asERetCodes.asERROR; | ||
else if (--constantCache[text] <= 0) constantCache.remove(text); | ||
|
||
return asERetCodes.asSUCCESS; | ||
} | ||
|
||
int getRawStringData(const(void)* istr, char* data, asUINT* length) { | ||
if (istr is null) return asERetCodes.asERROR; | ||
|
||
protostring* proto = cast(protostring*)istr; | ||
|
||
// If the length is not null set the length | ||
if (length !is null) | ||
*length = cast(uint)proto.length; | ||
|
||
// If the data pointer is not null fill the data buffer | ||
if (data !is null) | ||
data[0..proto.length] = proto.str[0..proto.length]; | ||
|
||
// We're done | ||
return asERetCodes.asSUCCESS; | ||
} | ||
|
||
void strConstructor(protostring* self) { | ||
self = new protostring; | ||
|
||
GC.addRoot(self); | ||
GC.setAttr(self, GC.BlkAttr.NO_MOVE); | ||
} | ||
|
||
void strDestructor(protostring* self) { | ||
GC.removeRoot(self); | ||
GC.clrAttr(self, GC.BlkAttr.FINALIZE | GC.BlkAttr.NO_MOVE); | ||
} | ||
|
||
protostring* strOpAssign(ref string in_, protostring* self) { | ||
self.setText(in_); | ||
return self; | ||
} | ||
|
||
protostring* strOpAddAssign(ref string in_, protostring* self) { | ||
self.setText(self.str~in_); | ||
return self; | ||
} | ||
|
||
protostring* strOpAdd(protostring* lhs, ref string rhs) { | ||
return new protostring(lhs.str~rhs); | ||
} | ||
|
||
uint strLength(protostring* self) { | ||
return cast(uint)self.length; | ||
} | ||
|
||
bool strEmpty(protostring* self) { | ||
return self.length == 0; | ||
} | ||
|
||
void strResize(uint size, protostring* self) { | ||
string newString = self.str.idup; | ||
newString.length = size; | ||
self.setText(newString); | ||
} | ||
|
||
protostring* strSubstr(uint start, uint length, protostring* self) { | ||
|
||
// TODO: Slice via code points? | ||
return new protostring(self.str[start..start+length]); | ||
} | ||
} | ||
|
||
/** | ||
Makes a copy of a string on the heap and gets a pointer to it | ||
*/ | ||
string* toAS(string text) { | ||
protostring* proto = new protostring(text.idup); | ||
return &proto.str; | ||
} | ||
|
||
/** | ||
Registers D UTF-8 strings | ||
*/ | ||
void registerDStrings(ScriptEngine engine) { | ||
engine.registerObjectType("string", string.sizeof, asEObjTypeFlags.asOBJ_VALUE | asEObjTypeFlags.asOBJ_APP_CLASS_CDAK); | ||
engine.registerStringFactory("string", &getStringConstant, &releaseStringConstant, &getRawStringData); | ||
engine.registerObjectBehaviour("string", asEBehaviours.asBEHAVE_CONSTRUCT, "void f()", &strConstructor, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
engine.registerObjectBehaviour("string", asEBehaviours.asBEHAVE_DESTRUCT, "void f()", &strDestructor, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
|
||
engine.registerObjectMethod("string", "string &opAssign(const string &in)", &strOpAssign, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
engine.registerObjectMethod("string", "string &opAddAssign(const string &in)", &strOpAddAssign, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
engine.registerObjectMethod("string", "string &opAdd(const string &in)", &strOpAdd, asECallConvTypes.asCALL_CDECL_OBJFIRST); | ||
|
||
engine.registerObjectMethod("string", "uint length() const", &strLength, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
engine.registerObjectMethod("string", "bool isEmpty() const", &strEmpty, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
engine.registerObjectMethod("string", "void resize(uint size) const", &strResize, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
engine.registerObjectMethod("string", "string &substr(uint start, uint length)", &strSubstr, asECallConvTypes.asCALL_CDECL_OBJLAST); | ||
} |
Oops, something went wrong.