www.digitalmars.com               DMDScript   C & C++
Last update Wed May 12 17:42:20 2010

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

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.
Once the function is created, it needs to be added to the global object.
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.

Adding a New Object Type

Native ECMAScript object types are named Function, Date, Number, Math, String, Array, Regexp, etc. Adding a new object type involves using one of the existing types, deriving from it, giving the derived object a unique name, and registering it.