Skip to content

Instantly share code, notes, and snippets.

@bhelyer
Created March 8, 2010 12:56
Show Gist options
  • Save bhelyer/325136 to your computer and use it in GitHub Desktop.
Save bhelyer/325136 to your computer and use it in GitHub Desktop.
module dsext;
/*
Let's try adding a new object type to DMDScript.
I shall call my new object... Monkey!
It shall have a property called "furColor"
with the value "brown".
It shall have a property called "hungry"
with the value 'true'.
It shall also have a method called "eatBanana"
which sets "hungry" to 'false'... of course.
*/
import std.file;
import dmdscript.script;
import dmdscript.threadcontext;
import dmdscript.text;
/*
The constructor... as a class...
Interesting.
*/
class DS_Monkey_Ctor : Dfunction {
this(ThreadContext *tc) {
super(1, tc.Dfunction_prototype);
}
void* Construct(CallContext *cc, Value *ret, Value[] arglist) {
// construct a new Monkey! Muahahaha!
ret.putVobject(new DS_Monkey);
return null;
}
void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
{
return Construct(cc, ret, arglist);
}
}
/*
The 'prototype' object...
I'm still not 100% positive exactly what this thing's
existance is all about, but I see what to do with it...
*/
class DS_Monkey_Prototype : Dobject {
this(ThreadContext *tc) {
// set up the core object stuff, I guess
super(tc.Dobject_prototype);
// set up this class
Put(TEXT_constructor, tc.ctorTable["Monkey"], 0);
Put(TEXT_name, "Monkey", 0);
// stuff under here translates to a DMDScript object property
Put("furColor", "brown", 0);
Put("hungry", true, 0);
}
}
/*
Finally, the actual Monkey class!
Ooh ooh aah aah.
*/
class DS_Monkey : Dobject {
// Looks like this, and the init(), are how DMDScript learns about Monkey
static this() {
ThreadContext.initTable ~= &(DS_Monkey.init);
}
static void init(ThreadContext *tc) {
Dfunction ctor = new DS_Monkey_Ctor(tc);
Dobject proto = new DS_Monkey_Prototype(tc);
tc.ctorTable["Monkey"] = ctor;
tc.protoTable["Monkey"] = proto;
ctor.Put(TEXT_prototype, proto, 0);
// this stuff is funky, but its how we add methods, apparently
// I'm not sure why the first field has to be a pointer...
// Is that supposed to facilitate... renaming the function??
// Or...???
static char[] TEXT_eatBanana = "eatBanana";
static NativeFunctionData nfd[] = [
{ &TEXT_eatBanana, &DS_Monkey_eatBanana, 0 }
];
DnativeFunction.init(proto, nfd, 0);
}
// because... constructors are sorta important, y'know?
static Dfunction getConstructor() {
ThreadContext *tc = ThreadContext.getThreadContext();
return tc.ctorTable["Monkey"];
}
// still wish I knew exactly why we have this guy
static Dobject getPrototype() {
ThreadContext *tc = ThreadContext.getThreadContext();
return tc.protoTable["Monkey"];
}
// the /real/ Monkey ctor
this() {
this(DS_Monkey.getPrototype());
}
this(Dobject prototype) {
super(prototype);
classname = "Monkey";
}
}
/*
The Monkey.eatBanana method
Its odd that DMDScript object methods must be defined as functions...
But then again, that might facilitate loading from a DLL.
Can you say, plugin engine? I thought you could.
*/
void* DS_Monkey_eatBanana(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) {
othis.Put("hungry", false, 0);
return null;
}
/*
The main function is pretty simple...
In fact, I'm reasonably impressed by how simple.
*/
void main() {
char[] source = cast(char[]) read("dsext.ds");
Program script = Program.getProgram();
if (script is null) {
script = new Program;
}
// I guess I could've gotten the filename from the command line..
// but... its just an experiment, yeesh
script.compile("dsext.ds", source, null);
script.execute(null);
}
var helloStr = "Hello world! (from DMDScript!!!)";
print("\n", helloStr, "\n");
var monkey = new Monkey;
println(monkey);
println("monkey.furColor = \"", monkey.furColor, "\"");
println("monkey.hungry = ", monkey.hungry);
println("Calling monkey.eatBanana()");
monkey.eatBanana();
println("monkey.hungry = ", monkey.hungry);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment