www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Expose D Objects as DMDScript Objects

reply Kyle Furlong <kylefurlong gmail.com> writes:
How? :-)
Sep 16 2005
parent reply Carlos Santander <csantander619 gmail.com> writes:
Kyle Furlong escribió:
 How? :-)

I think this belongs to the DMDScript newsgroup. Anyway, this should give you an idea of what you need. I haven't tested in a while, but it might just work ;) /* Digital Mars DMDScript source code. * Copyright (c) 2000-2002 by Chromium Communications * D version Copyright (c) 2004-2005 by Digital Mars * All Rights Reserved * written by Walter Bright * www.digitalmars.com * Use at your own risk. There is no warranty, express or implied. * License for redistribution is by the GNU General Public License in gpl.txt. * * A binary, non-exclusive license for commercial use can be * purchased from www.digitalmars.com/dscript/buy.html. * * DMDScript is implemented in the D Programming Language, * www.digitalmars.com/d/ * * For a C++ implementation of DMDScript, including COM support, * see www.digitalmars.com/dscript/cpp.html. */ module testscript; import std.conv; import std.path; import std.file; import std.stdio; import dmdscript.script; enum { EXITCODE_INIT_ERROR = 1, EXITCODE_INVALID_ARGS = 2, EXITCODE_RUNTIME_ERROR = 3, } class C:Dobject { int _p; int _q; this(ThreadContext *tc) { super(tc.Dobject_prototype); Put("p",0,0); Put("1",0,0); } int opIndex(int idx) { if (idx==1) return _q; throw new Exception( format("[opIndex] index out of bounds: ",idx)); } void opIndexAssign(int v,int idx) { if (idx==1) { _q=v; Put("1",_q,0); } else throw new Exception(format("[opIndexAssign] index out of bounds: ",idx)); } void p(int newP) { _p=newP; Put("p",newP,0); } int p() { return _p; } Value* Put(d_string PropertyName, Value* value, uint attributes) { if (PropertyName=="p") { _p=cast(int)value.toNumber(); writefln("[0: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=cast(int)value.toNumber(); writefln("[0: c.q changed to ",_q,"]"); } return super.Put(PropertyName,value,attributes); } Value* Put(Identifier* key, Value* value, uint attributes) { if (key.toString=="p") { _p=cast(int)value.toNumber(); writefln("[1: c.p changed to ",_p,"]"); } else if (key.toString=="1") { _q=cast(int)value.toNumber(); writefln("[1: c.q changed to ",_q,"]"); } return super.Put(key,value,attributes); } Value* Put(d_string PropertyName, Dobject o, uint attributes) { if (PropertyName=="p") { _p=cast(int)o.value.toNumber(); writefln("[2: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=cast(int)o.value.toNumber(); writefln("[2: c.q changed to ",_q,"]"); } return super.Put(PropertyName,o,attributes); } Value* Put(d_string PropertyName, d_number n, uint attributes) { if (PropertyName=="p") { _p=cast(int)n; writefln("[3: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=cast(int)n; writefln("[3: c.q changed to ",_q,"]"); } return super.Put(PropertyName,n,attributes); } Value* Put(d_string PropertyName, d_string s, uint attributes) { if (PropertyName=="p") { _p=toInt(s); writefln("[4: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=toInt(s); writefln("[4: c.q changed to ",_q,"]"); } return super.Put(PropertyName,s,attributes); } Value* Put(d_uint32 index, Value* vindex, Value* value, uint attributes) { if (index==1) { _q=cast(int)value.toNumber(); writefln("[5: c.q changed to ",_q,"]"); } return super.Put(index,vindex,value,attributes); } Value* Put(d_uint32 index, Value* value, uint attributes) { if (index==1) { _q=cast(int)value.toNumber(); writefln("[5: c.q changed to ",_q,"]"); } return super.Put(index,value,attributes); } /* Value* Get(d_string PropertyName) { return Get(PropertyName, Value.calcHash(PropertyName)); } Value* Get(Identifier* id) { Value* v; //writefln("Dobject.Get(this = %x, '%s', hash = %x)", cast(uint)cast(void*)this, PropertyName, hash); //writef("\tinternal_prototype = %p\n", this.internal_prototype); //writef("\tDfunction.getPrototype() = %p\n", Dfunction.getPrototype()); v = proptable.get(&id.value, id.value.hash); //if (v) writef("found it %p\n", v.object); return v; } Value* Get(d_string PropertyName, uint hash) { Value* v; //writefln("Dobject.Get(this = %x, '%s', hash = %x)", cast(uint)cast(void*)this, PropertyName, hash); //writef("\tinternal_prototype = %p\n", this.internal_prototype); //writef("\tDfunction.getPrototype() = %p\n", Dfunction.getPrototype()); v = proptable.get(PropertyName, hash); //if (v) writef("found it %p\n", v.object); return v; } Value* Get(d_uint32 index) { Value* v; v = proptable.get(index); // if (!v) // v = &vundefined; return v; } Value* Get(d_uint32 index, Value* vindex) { return proptable.get(vindex, Value.calcHash(index)); } */ } C c; int main(char[][] args) { char [][] src; do { writef(">"); fflush(stdout); char * buf = new char[80]; gets(buf); char [] tmp = std.string.toString(buf); if (tmp.length>0 && tmp[0]=='#') { delete buf; break; } src ~= tmp.dup; } while (true) SrcFile f=new SrcFile(std.string.join(src,"\r\n")); f.compile(); ThreadContext *tc; tc = ThreadContext.getThreadContext(); assert(tc != null); c=new C(tc); c.p=4; c[1]=9; PutValue(f.program.callcontext,"c",&c.value); writefln("[c.p=",c.p,"]"); writefln("[c[1]=",c[1],"]"); f.execute(); writefln("[c.p=",c.p,"]"); writefln("[c[1]=",c[1],"]"); return EXIT_SUCCESS; } class SrcFile { char[] srcfile; char[][] includes; Program program; char[] buffer; this (char [] src) { buffer = /*"var c=new Object();c.p="~format(c.p)~" ;" ~*/ src.dup ~ ";"; } this(char[] srcfilename, char[][] includes) { /* DMDScript source files default to a '.ds' extension */ srcfile = std.path.defaultExt(srcfilename, "ds"); this.includes = includes; } void read() { /* Read the source file, prepend the include files, * and put it all in buffer[]. Allocate an extra byte * to buffer[] and terminate it with a 0x1A. * (If the 0x1A isn't at the end, the lexer will put * one there, forcing an extra copy to be made of the * source text.) */ //writef("read file '%s'\n",srcfile); // Read the includes[] files uint i; void[] buf; ulong len; len = std.file.getSize(srcfile); foreach (char[] filename; includes) { len += std.file.getSize(filename); } len++; // leave room for sentinal assert(len < uint.max); // Prefix the includes[] files buffer = new tchar[len]; foreach (char[] filename; includes) { buf = std.file.read(filename); buffer[i .. i + buf.length] = cast(char[])buf[]; i += buf.length; } buf = std.file.read(srcfile); buffer[i .. i + buf.length] = cast(char[])buf[]; i += buf.length; buffer[i] = 0x1A; // ending sentinal i++; assert(i == len); } void compile() { /* Create a DMDScript program, and compile our text buffer. */ program = new Program(); program.compile(srcfile, buffer, null); } void execute() { /* Execute the resulting program. */ program.execute(null); } } -- Carlos Santander Bernal
Sep 16 2005
parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Carlos Santander wrote:
 Kyle Furlong escribió:
 
 How? :-)

I think this belongs to the DMDScript newsgroup. Anyway, this should give you an idea of what you need. I haven't tested in a while, but it might just work ;) /* Digital Mars DMDScript source code. * Copyright (c) 2000-2002 by Chromium Communications * D version Copyright (c) 2004-2005 by Digital Mars * All Rights Reserved * written by Walter Bright * www.digitalmars.com * Use at your own risk. There is no warranty, express or implied. * License for redistribution is by the GNU General Public License in gpl.txt. * * A binary, non-exclusive license for commercial use can be * purchased from www.digitalmars.com/dscript/buy.html. * * DMDScript is implemented in the D Programming Language, * www.digitalmars.com/d/ * * For a C++ implementation of DMDScript, including COM support, * see www.digitalmars.com/dscript/cpp.html. */ module testscript; import std.conv; import std.path; import std.file; import std.stdio; import dmdscript.script; enum { EXITCODE_INIT_ERROR = 1, EXITCODE_INVALID_ARGS = 2, EXITCODE_RUNTIME_ERROR = 3, } class C:Dobject { int _p; int _q; this(ThreadContext *tc) { super(tc.Dobject_prototype); Put("p",0,0); Put("1",0,0); } int opIndex(int idx) { if (idx==1) return _q; throw new Exception( format("[opIndex] index out of bounds: ",idx)); } void opIndexAssign(int v,int idx) { if (idx==1) { _q=v; Put("1",_q,0); } else throw new Exception(format("[opIndexAssign] index out of bounds: ",idx)); } void p(int newP) { _p=newP; Put("p",newP,0); } int p() { return _p; } Value* Put(d_string PropertyName, Value* value, uint attributes) { if (PropertyName=="p") { _p=cast(int)value.toNumber(); writefln("[0: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=cast(int)value.toNumber(); writefln("[0: c.q changed to ",_q,"]"); } return super.Put(PropertyName,value,attributes); } Value* Put(Identifier* key, Value* value, uint attributes) { if (key.toString=="p") { _p=cast(int)value.toNumber(); writefln("[1: c.p changed to ",_p,"]"); } else if (key.toString=="1") { _q=cast(int)value.toNumber(); writefln("[1: c.q changed to ",_q,"]"); } return super.Put(key,value,attributes); } Value* Put(d_string PropertyName, Dobject o, uint attributes) { if (PropertyName=="p") { _p=cast(int)o.value.toNumber(); writefln("[2: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=cast(int)o.value.toNumber(); writefln("[2: c.q changed to ",_q,"]"); } return super.Put(PropertyName,o,attributes); } Value* Put(d_string PropertyName, d_number n, uint attributes) { if (PropertyName=="p") { _p=cast(int)n; writefln("[3: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=cast(int)n; writefln("[3: c.q changed to ",_q,"]"); } return super.Put(PropertyName,n,attributes); } Value* Put(d_string PropertyName, d_string s, uint attributes) { if (PropertyName=="p") { _p=toInt(s); writefln("[4: c.p changed to ",_p,"]"); } else if (PropertyName=="1") { _q=toInt(s); writefln("[4: c.q changed to ",_q,"]"); } return super.Put(PropertyName,s,attributes); } Value* Put(d_uint32 index, Value* vindex, Value* value, uint attributes) { if (index==1) { _q=cast(int)value.toNumber(); writefln("[5: c.q changed to ",_q,"]"); } return super.Put(index,vindex,value,attributes); } Value* Put(d_uint32 index, Value* value, uint attributes) { if (index==1) { _q=cast(int)value.toNumber(); writefln("[5: c.q changed to ",_q,"]"); } return super.Put(index,value,attributes); } /* Value* Get(d_string PropertyName) { return Get(PropertyName, Value.calcHash(PropertyName)); } Value* Get(Identifier* id) { Value* v; //writefln("Dobject.Get(this = %x, '%s', hash = %x)", cast(uint)cast(void*)this, PropertyName, hash); //writef("\tinternal_prototype = %p\n", this.internal_prototype); //writef("\tDfunction.getPrototype() = %p\n", Dfunction.getPrototype()); v = proptable.get(&id.value, id.value.hash); //if (v) writef("found it %p\n", v.object); return v; } Value* Get(d_string PropertyName, uint hash) { Value* v; //writefln("Dobject.Get(this = %x, '%s', hash = %x)", cast(uint)cast(void*)this, PropertyName, hash); //writef("\tinternal_prototype = %p\n", this.internal_prototype); //writef("\tDfunction.getPrototype() = %p\n", Dfunction.getPrototype()); v = proptable.get(PropertyName, hash); //if (v) writef("found it %p\n", v.object); return v; } Value* Get(d_uint32 index) { Value* v; v = proptable.get(index); // if (!v) // v = &vundefined; return v; } Value* Get(d_uint32 index, Value* vindex) { return proptable.get(vindex, Value.calcHash(index)); } */ } C c; int main(char[][] args) { char [][] src; do { writef(">"); fflush(stdout); char * buf = new char[80]; gets(buf); char [] tmp = std.string.toString(buf); if (tmp.length>0 && tmp[0]=='#') { delete buf; break; } src ~= tmp.dup; } while (true) SrcFile f=new SrcFile(std.string.join(src,"\r\n")); f.compile(); ThreadContext *tc; tc = ThreadContext.getThreadContext(); assert(tc != null); c=new C(tc); c.p=4; c[1]=9; PutValue(f.program.callcontext,"c",&c.value); writefln("[c.p=",c.p,"]"); writefln("[c[1]=",c[1],"]"); f.execute(); writefln("[c.p=",c.p,"]"); writefln("[c[1]=",c[1],"]"); return EXIT_SUCCESS; } class SrcFile { char[] srcfile; char[][] includes; Program program; char[] buffer; this (char [] src) { buffer = /*"var c=new Object();c.p="~format(c.p)~" ;" ~*/ src.dup ~ ";"; } this(char[] srcfilename, char[][] includes) { /* DMDScript source files default to a '.ds' extension */ srcfile = std.path.defaultExt(srcfilename, "ds"); this.includes = includes; } void read() { /* Read the source file, prepend the include files, * and put it all in buffer[]. Allocate an extra byte * to buffer[] and terminate it with a 0x1A. * (If the 0x1A isn't at the end, the lexer will put * one there, forcing an extra copy to be made of the * source text.) */ //writef("read file '%s'\n",srcfile); // Read the includes[] files uint i; void[] buf; ulong len; len = std.file.getSize(srcfile); foreach (char[] filename; includes) { len += std.file.getSize(filename); } len++; // leave room for sentinal assert(len < uint.max); // Prefix the includes[] files buffer = new tchar[len]; foreach (char[] filename; includes) { buf = std.file.read(filename); buffer[i .. i + buf.length] = cast(char[])buf[]; i += buf.length; } buf = std.file.read(srcfile); buffer[i .. i + buf.length] = cast(char[])buf[]; i += buf.length; buffer[i] = 0x1A; // ending sentinal i++; assert(i == len); } void compile() { /* Create a DMDScript program, and compile our text buffer. */ program = new Program(); program.compile(srcfile, buffer, null); } void execute() { /* Execute the resulting program. */ program.execute(null); } }

Okay, but I have a more complicated design requirement. The object cannot inherit from Dobject. The D object cannot know anything about DMDScript. Basically the scripting package is implemented as a plugin, with the main code only knowing about certain interfaces. An ideal solution of course would be to use reflection, but thats a ways away I guess.
Sep 16 2005
parent reply Carlos Santander <csantander619 gmail.com> writes:
Kyle Furlong escribió:
 
 Okay, but I have a more complicated design requirement. The object 
 cannot inherit from Dobject. The D object cannot know anything about 
 DMDScript. Basically the scripting package is implemented as a plugin, 
 with the main code only knowing about certain interfaces. An ideal 
 solution of course would be to use reflection, but thats a ways away I 
 guess.

Wrap your D object in a Dobject subclass. I did that when (in another sample) I changed a button's caption using DMDScript. The button knew nothing about DMDScript, of course. I don't know, there should be a way to get it done. -- Carlos Santander Bernal
Sep 16 2005
parent Kyle Furlong <kylefurlong gmail.com> writes:
Carlos Santander wrote:
 Kyle Furlong escribió:
 
 Okay, but I have a more complicated design requirement. The object 
 cannot inherit from Dobject. The D object cannot know anything about 
 DMDScript. Basically the scripting package is implemented as a plugin, 
 with the main code only knowing about certain interfaces. An ideal 
 solution of course would be to use reflection, but thats a ways away I 
 guess.

Wrap your D object in a Dobject subclass. I did that when (in another sample) I changed a button's caption using DMDScript. The button knew nothing about DMDScript, of course. I don't know, there should be a way to get it done.

What I meant was that the code which has the D object must be completely scripting language agnostic. So it could implement an IScriptable interface or such but that is about the extent of it. The design is for a game engine. So I am trying to implement a plugin system whereby any subsystem can be changed out for a different implementation. So you could use DirectX or OpenGL, or use Lua or DMDScript, all you would have to do is write a dll with certain requirements. The pertinent classes/interfaces are: <code> /**************************************** ScriptingEngine.d - ScriptingEngine Implementation Author: Kyle Furlong Date: Sept. 13, 2005 ****************************************/ module Dluge.Plugings.Scripting.ScriptingEngine; private { import Dluge.All; import Dluge.Plugins.Scripting.Script; import std.c.windows.windows; import std.stdio; import std.string; import dmdscript.program; import dmdscript.dglobal; } extern(C) { export IScriptingEngine Create() { return new ScriptingEngineImpl(); } } private class ScriptingEngineImpl : IScriptingEngine { public IScript Create(char[] source) { return new Script(source); } public bit Initialize() { writefln("Scripting Engine Initialize"); return true; } public bit Initialized() { return true; } private int i = 0; public void Frame() { //writefln(format(i++)); } public void Shutdown() { } } extern (C) { void gc_init(); void gc_term(); void _minit(); void _moduleCtor(); void _moduleUnitTests(); } extern (Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: gc_init(); // initialize GC _minit(); // initialize module list _moduleCtor(); // run module constructors _moduleUnitTests(); // run module unit tests break; case DLL_PROCESS_DETACH: gc_term(); // shut down GC break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: // Multiple threads not supported yet return false; } return true; } /**************************************** Script.d - IScript Implementation for DMDScript Author: Kyle Furlong Date: Sept. 15, 2005 ****************************************/ module Dluge.Plugins.Scripting.Script; private { import Dluge.All; import dmdscript.program; import std.date; } public class Script : IScript { private char[] name = ""; public char[] Name() { return name; } private char[] source = ""; public char[] Source() { return source; } private Program program; this(char[] source) { this.program = new Program(); this.source = source; this.name = std.string.toString(getUTCtime()); } bit Run(char[][] args) { try { program.execute(args); return true; } catch(ScriptException e) { return false; } } bit Compile() { try { program.compile(name, source, null); return true; } catch(ScriptException e) { return false; } } void AddObject(char[] name, *IScriptable* o) // This needs to be worked on { program.callcontext.global.Put(name, o, DontEnum); } void RemoveObject(char[] name) { program.callcontext.global.Delete(name); } } /**************************************** IScript.d - Script interface Author: Kyle Furlong Date: Sept. 12, 2005 ****************************************/ module Dluge.Scripting.IScript; private { import Dluge.Common; } public interface IScript { bit Run(char[][] args); bit Compile(); void AddObject(char[] name, Object o); void RemoveObject(char[] name); } /**************************************** ScriptingEngine.d - Scripting engine interface Author: Kyle Furlong Date: Sept. 12, 2005 ****************************************/ module Dluge.Scripting.ScriptingEngine; private { import Dluge.Plugin; import Dluge.Common; import Dluge.Scripting.IScript; } public static class ScriptingEngine { mixin PluginProxy!(IScriptingEngine); } public interface IScriptingEngine : IPlugin { IScript Create(char[] script); } </code> _______________________________________________________ Let me know if you have any insight.
Sep 16 2005