DMonkeyは Delphiで作られた
アプリケーションへの組込みを目的としたインタプリタ・スクリプトエンジンです。
言語仕様は
ECMAScript(JavaScript)
のサブセットになっています。
DMonkeyの使用・配布・改変についての制限はありません。
コンポーネントのインストールから DMonkey.pasをインストールします。
1.メソッド
スクリプトをコンパイルします。 function Compile(SourceCode: String): Boolean; function CompileFile(AFilename: String): Boolean;2.プロパティスクリプトを実行します。 function Run(Args: array of const; ARoot: PJStatement = nil): Integer; overload; function Run(Args: TJValueList; ARoot: PJStatement = nil): Integer; overload; function Run(ARoot: PJStatement = nil): Integer; overload;
関数を呼び出します。 function CallFunction(Symbol: String; Param: array of const; var RetValue: TJValue): Boolean; overload; function CallFunction(Symbol: String; Param: TJValueList; var RetValue: TJValue): Boolean; overload;
クリアします。 procedure Clear;
スクリプトを中止します。 procedure Abort;
実行中かどうか。 function IsRunning: Boolean;
拡張組込みオブジェクトをインポートします。 procedure ImportObject(ObjectName: String; ObjectClass: TJObjectClass);
import宣言での検索パス。 property LibraryPath: TStringList read GetLibraryPath;3.イベントガベージコレクトを使用する。ガベージコレクトを使用しなくても終了時にはすべてのオブジェクトを解放します。 property GarbageCollection: Boolean read GetGarbageCollection write SetGarbageCollection;
標準出力 property OnStdout: TStringEvent read FOnStdout write FOnStdout;4.実行例標準エラー property OnStderr: TStringEvent read FOnStderr write FOnStderr;
デバッグ出力 property OnDebugout: TStringEvent read FOnDebugout write FOnDebugout;
スクリプト実行時にオブジェクトが作成されたとき呼ばれます。 property OnNewObject: TNewObjectEvent read FOnNewObject write FOnNewObject;
実行開始 property OnRun: TNotifyEvent read FOnRun write FOnRun;
実行終了 property OnDone: TNotifyEvent read FOnDone write FOnDone;
スクリプトの文(statement)を一つ実行するたびに呼ばれます。スクリプトの中断などに使用します。 property OnStep: TStepEvent read FOnStep write FOnStep;
begin //実行 if DMonkey1.Compile('println("hello,world");') then DMonkey1.Run; end;var retval: TJValue; begin //関数呼び出し if DMonkey1.Compile('function f(a){ println(a);}') then begin //実行する必要があります DMonkey1.Run; //呼び出し DMonkey1.CallFunction('f',['hello'],retval); end; end;
DMonkeyの言語仕様について簡単に解説します。
class Foo{ //指定しない場合は Objectを継承 aaa = 10; function f1(a){ Global.println(a + ',world'); //Globalが必要になります } } class Bar extends Foo{ bbb = 20; function f2(){ Global.println(this.aaa); } } class Hoge extends Bar{ ccc = new Array(5,6,7,8,9,10); function f3(){ Global.println(this.bbb); } }例(2)a = new Hoge; print(a.getProperties()); a.f1('hello'); a.f2(); a.f3(); for(i in a.ccc) println(i + '=' + a.ccc[i]);
class IE { ie = new ActiveXObject('InternetExplorer.Application'); win32 = new Win32; function IE(){ //コンストラクタを指定すると作成時に呼ばれます。 if(arguments.length > 0) this.ie.Visible = arguments[0]; else this.ie.Visible = true; } function goGoogle(){ this.ie.Navigate('http://www.google.com/intl/ja/'); } function go(url){ this.ie.Navigate(url); while(this.ie.Busy) this.win32.processMessages(); //待機 } function quit(){ this.ie.Quit(); } } ie = new IE(true); //ie.goGoogle(); for(;;){ a = prompt('URLを指定してください'); if(a) ie.go(a); else{ ie.quit(); exit(); } }
println(a); //未定義の値を参照したため例外が起きます。 println('hello'); //ここは実行されません例(2) catch文は例外が起きた場合にのみ実行します。
try{ println(a); //例外が起きるとcatch文へ移動します。 } catch(e){ println('error: ' + e); }例(3) finally文を使うと例外に関係なく常に実行します。
try{ println(a); //例外が起きるとcatch文へ移動します。 } finally{ println('hello'); } catch(e){ println('error: ' + e); }
print('hello,'); a = 'world';例(2) 名前空間なしでインポートします。
import hello.*; println(a);
例(3) 名前空間ありでインポートします。
import hello; println(hello.a); println(a); //現在の名前空間に a が存在しない場合
例(4) 名前空間ありでインポートします。
import hello; a = 10; println(hello.a); println(a); //現在の名前空間に a が存在する場合
例(1)
a = new Object; a['hello'] = 'world'; println(a['hello']); println(a.hello); println(a.hasKey('hello'));例(2)
obj = {hello : 'world', foo : 10}; //object生成 println(obj.hello); println(obj.foo);例(3)
obj = {hello : 'world', foo : 10}; //object生成 sl = new Strings; sl.text = obj.getKeys(); for(i in sl) println(sl[i]);例(4)
function _inc(){ return this.counter += 1; } function _dec(){ return this.counter -= 1; } //擬似的なオブジェクト定義 a = {counter: 0, inc: _inc, dec: _dec }; b = {counter: 0, inc: _inc, dec: _dec };for(i = 0; i < 10; i++) a.inc();
for(i = 0; i < 10; i++) b.dec();
println(a.counter); println(b.counter);
例(1)
a = 'あいうえお'; b = escape(a); println(b); println(unescape(b));例(2)
ret = eval('return 10*10;'); println(ret);例(3)
a = 10; if (! isNaN(a)) println('number');例(4)
a = '0.9'; b = 0.1; println(a + b); println(parseFloat(a) + b);例(5)
a = '0xa'; //10 b = 1; println(a + b); println(parseInt(a) + b);例(6)
alert('hello'); if(confirm('prompt?')) a = prompt('prompt',''); else a = textArea('textArea','');if(a) print(a); else { print('exit'); exit(); }
例(1)
a = new Array; a.add(1); a.add(2); a.add(3); println(a.toString()); println(a.reverse().toString()); for(i = a.length - 1; i >= 0; i--) a.delete(i);例(2)for(i = 0;i < 10;i++) a.add(i);
function f(a,b){ return b - a;} println(a.toString()); a.sort(f); println(a.toString());
c = new Array(a); for(i in c[0]) println(i + ': ' + c[0][i]);
a.clear(); print(c[0].length);
a = [5,4,3,2,1,0]; //配列生成 for(i in a) println(a[i]);
a = 100; println(a.toString(16));
a = true; b = new Boolean(true); println(a.toString()); //true println(b); //true
例(1)
a = 'あいうえお'; b = a.toEUC(); c = a.toJIS(); println(b); println(c); println(b.fromEUCtoSJIS()); println(c.fromJIStoSJIS());
例(2)
s = new String('あいうえお'); println(s.toString());
例(3)
s = 'abcdefghijklmn'; for(i = 0; i < s.length; i++) print(s[i]);
例(1)
re = new RegExp(';'); a = '100;200;300;400'; b = re.split(a); for(i in b) print(b[i]);例(2)
re = new RegExp('a+','g'); a = 'akgatranavayakhahjajatdaa'; b = re.exec(a); for(i in b) print(b[i]);
例(1)
f = new File('temp.txt'); try{ f.open('w'); //書き込みモードで開く f.writeln('hello,'); f.write('world'); } catch(e){ println(e); } finally{ f.close(); }
例(2)
f = new File('temp.txt'); try{ f.open('r'); //読み込みモードで開く s = f.read();//すべて読む print(s); f.seek(0); //最初に戻る s = f.readln(); //1行読む println(s); } catch(e){ println(e); } finally{ f.close(); }
例(1)
d = new Directory('.\temp'); if(! d.exists()) d.make();
例(2)
d = new Directory('.\temp'); if(d.exists()) d.remove();
例(3)
function checkpath(dirname){ if(dirname.lastIndexOf('\') == (dirname.length - 1)) return dirname; else return dirname + '\'; } function checkdot(dirname){ return ((dirname != '.') && (dirname != '..')); } function search(dirname){ dirname = checkpath(dirname); println(dirname); d = new Directory(dirname); n = d.findFirstFile(); //ファイル検索 try{ if(n){ println("\t" + n); for(;;){ n = d.findNextFile(); if(n) println("\t" + n); else break; } } } finally{ d.findClose(); } n = d.findFirstDir(); //フォルダ検索 try{ if(n){ if (checkdot(n)) search(dirname + n); //再帰検索 for(;;){ n = d.findNextDir(); if(n){ if (checkdot(n)) search(dirname + n);//再帰検索 } else break; } } } finally{ d.findClose(); } }search('.');
例(1)
sl = new Strings; sl.add('aaa'); sl.add('bbb'); sl.insert(0,'ccc'); sl.insert(1,'ddd'); println(sl.text); println(sl.commaText); sl.saveToFile('temp.txt');
例(2)
sl = new Strings; sl.loadFromFile('temp.txt'); for(i in sl) println(sl[i]);sl.clear();
例(1)
ini = new Ini('iria.ini'); secs = ini.readSections(); for(i in secs){ println(secs[i]); keys = ini.readSection(secs[i]); for(j in keys){ println(' ' + keys[j] + '=' + ini.read(secs[i],keys[j],'')); } }
例(1)
crc = new CRC; crc.calc('あいうえお'); println(crc.CRC16.toString(16).substr(4,4)); println(crc.CRC32.toString(16));
例(1)
b64 = new Base64; a = 'あいうえお'; b = b64.encode(a); println(b); println(b64.decode(b));
例(2)
b64 = new Base64; a = 'あいうえお'; c = b64.encodeHeader(a); print(c); d = b64.decodeHeader(c); print(d);
例(1)
d = new Dialog; println(d.openFile('load')); println(d.saveFile('save')); println(d.openFolder()); s = d.openFiles(); for(i in s) println(s[i]);
例(1)
mutex = new Mutex('sakura'); if (mutex.existed) println('えんいー');
例(1)
u = new URL('http://127.0.0.1/dir/index.html?qqq'); println(u.url); println(u.protocol); println(u.host); println(u.path); println(u.dir); println(u.filename); println(u.query);
例(1)
u = new URL('http://127.0.0.1/index.html'); http = new HTTP; println(http.get(u.url)); http.getFile(u.url,u.filename);
例(2)
http = new HTTP; http.requestHeader['User-Agent'] = 'dmonkey'; http.requestHeader['Referer'] = 'referer'; http.requestHeader['Cookie'] = 'name=value'; try{ http.request('GET','http://127.0.0.1/'); http.response(); if(http.responseHeader.code == 200){ while(true){ s = http.readln(); if(s) println(s); else break; } } } finally{ http.disconnect(); }
例(1)
s = new TCPSocket; s.host = '127.0.0.1'; s.port = 9801; try{ s.connect(); s.writeln('SEND SSTP/1.1'); s.writeln('Sender: DMonkey'); s.writeln('Script: \h\s0えんいー。\e'); s.writeln('Charset: Shift_JIS'); s.writeln(''); } finally{ s.disconnect(); }
例(1)
p = new POP3; p.host = '127.0.0.1'; p.port = 110; p.userid = 'test'; p.password = 'test'; try{ p.connect(); for(i = 1;i <= p.length; i++){ //メール番号は1から p.getMail(i); println(p.mail.header); println(p.mail.body); } } finally{ p.disconnect(); }
例(1)
s = new SMTP; s.host = '127.0.0.1'; s.port = 25; s.mail['To'] = 'gaogao@moemoe.gr.jp'; s.mail['From'] = 'gaogao@moemoe.gr.jp'; s.mail['Subject'] = 'DMonkey SMTP'; s.mail.message = 'テスト'; try{ s.connect(); s.sendMail(); println('OK'); } finally{ s.disconnect(); }
例(1)
ie = new ActiveXObject('InternetExplorer.Application'); ie.Visible = true; ie.Navigate('http://gaogao.moemoe.gr.jp');例(2)
iria = new ActiveXObject('Iria.IriaApi'); iria.Download('http://127.0.0.1/',1);例(3) JScriptドキュメントから
function ShowDriveInfo1(drvPath){ s = ''; fso = new ActiveXObject("Scripting.FileSystemObject"); drv = fso.GetDrive(fso.GetDriveName(drvPath)); s += "ドライブ " + drvPath.toUpperCase()+ " - "; s += drv.VolumeName + "\n"; s += "合計サイズ: " + drv.TotalSize / 1024; s += " KB" + "\n"; s += "空き領域: " + drv.FreeSpace / 1024; s += " KB" + "\n"; println(s); }ShowDriveInfo1('c:\');
例(1)
dcall = new DynaCall; /* DynaCall.register() 第1引数 DLLの名前 第2引数 関数の名前 第3引数~第5引数 この3つは任意の順番で並べる事ができる i=[flag]* 引数を指定する(参照を指定することはできるが現在のところ値は変化しない) c char(1バイト) 1 char参照(4バイト) t short(2バイト) 2 short参照(4バイト) l long(4バイト) 4 long参照(4バイト) i int64(8バイト) 8 int64参照(4バイト) p ポインタ(4バイト) h ハンドル(4バイト) u unsigned int(4バイト) b boolean(4バイト) s 文字列(4バイト) w ワイド文字列(4バイト) f 4バイト実数(4バイト) d 8バイト実数(8バイト) a IDispatch(4バイト) k IUnknown(4バイト)f=[flag]* 呼び出し規約を指定する m Microsoft互換 b Borland互換 s stdcall呼び出し(標準) c cdecl呼び出し 4 戻り値が4バイト実数 8 戻り値が8バイト実数
r=[flag] 戻り値を指定する 引数のフラグと同じ */ dcall.register('user32.dll','MessageBox','i=hssu','f=s','r=l');
//登録した関数はそのまま呼び出すことができます print(dcall.MessageBox(applicationHandle,'これはDynaCallで呼び出しています。','DynaCall',1));
例(2)
dcall = new DynaCall; s = new String; s.length = 255; dcall.register('advapi32','GetUserName','i=s4','f=s','r=b'); print(dcall.GetUserName(s,s.length)); print(s);
例(3)
dcall = new DynaCall; dcall.register('kernel32','GetTickCount','f=s','r=l'); print(dcall.GetTickCount());
1.メソッドに足し算、プロパティにアプリケーションファイル名と日付オブジェクトを持つオブジェクトを作成します。
interface uses ecma_type,ecma_object;type //TJObjectを継承します TTestObject = class(TJObject) private FDate: TJDateObject; function GetApplicationFilename: String; //メソッドは TJMethod型である必要があります function DoAdd(Param: TJValueList): TJValue; public constructor Create(AFactory: TJObjectFactory; Param: TJValueList); override; destructor Destroy; override; published //propertyはpublishedに設定します property applicationFilename: String read GetApplicationFilename; property date: TJDateObject read FDate; end;
implementation
{ TTestObject }
constructor TTestObject.Create(AFactory: TJObjectFactory; Param: TJValueList); begin inherited; //objectの名前を設定します RegistName('Test'); //メソッドを登録します RegistMethod('add',DoAdd); //Date Objectを作成します FDate := AFactory.NewObject('Date',nil) as TJDateObject; //参照カウントを増やす FDate.IncRefCount; end;
destructor TTestObject.Destroy; begin //参照カウントを減らす FDate.DecRefCount; inherited; end;
function TTestObject.DoAdd(Param: TJValueList): TJValue; var v: TJValue; i,ret: Integer; begin //全ての引数を加算する ret := 0; for i := 0 to Param.Count - 1 do begin v := Param[i]; //TJValueを整数に変換して加算 Inc(ret,AsInteger(@v)); end; //整数をTJValueに変換する Result := BuildInteger(ret); end;
function TTestObject.GetApplicationFilename: String; begin //普通に文字列を返すとTJValueに変換されます Result := ParamStr(0); end;
2.TDMonkey.ImportObjectメソッドで登録します。
DMonkey1.ImportObject('Test',TTestObject);
3.実行
a = new Test; println(a.add(1,2,3,4,5)); println(a.applicationFilename); println(a.date);