Extending DMDScript
Simply linking in DMDScript to a D application will provide a full script interpreter that can read and write to the console, but to integrate it in it will need to be extended so that scripts can access the D application's data structures, and so that the D application can add functionality to the scripting language.For example, for a text editor that is script enabled, from the script one should be able to access and modify the document text.
The two basic ways to extend DMDScript are:
- Adding a global function.
- Adding a new object type.
Adding a Global Function
Global functions all follow the same form:void* Dglobal_name(
Dobject pthis,
CallContext* cc,
Dobject othis,
Value* ret,
Value[] arglist)
{
...
}
Where:
- Dglobal_name
- By convention, the name of these functions starts with "D"
followed by the name of the object type it will be installed in
(in this case "global") followed by "_" and followed by a
descriptive name for the function.
- Dobject pthis
- Script functions are actually objects whose call method
is the function. pthis is that object.
It will normally be a reference to a DnativeFunction instance.
- CallContext* cc
- Provides a reference to global state information in the
CallContext struct.
- Dobject othis
- The script object that called this function.
- Value* ret
- What the script language will see as the return value for the
function. If there is no return value, this should be set to
undefined like this:
ret.putVundefined(); // result is "undefined"
- Value[] arglist
- All script functions have variable length argument lists.
This comes through as arglist.
The expected number of arguments is given as the .length
property of the function, but this imposes no requirement on how
many arguments are actually passed or processed.
Arguments needed but not supplied should normally be interpreted
as if undefined were passed.
- Return value
- The return value is null upon successful completion.
Upon unsuccessful completion, a pointer to a Value is returned,
and the contents of the Value are an instance of an Error.
For example, here's an error return for a RuntimeError:
ret.putVundefined(); // result is "undefined" ErrInfo errinfo; // load up this with info about the error Dobject o = new runtimeerror.D0(&errinfo); Value* v = new Value; v.putVobject(o); return v;
A better design would likely be to have error returns throw a D exception; but the design of DMDScript is old enough to need to work with C++ compilers that didn't do exception handling right, hence using the return value instead.
static char[] TEXT_name = "name"; static NativeFunctionData nfd[] = [ // Function properties { &TEXT_name, // name of the function &Dglobal_name, // address of the function 1 // length property for function }, ]; DnativeFunction.init(cc.global, // the global object nfd, DontEnum);Look through the source of dmdscript.dglobal, there are many examples of how to do things.