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): Integer; overload; function Run(Args: TJValueList): Integer; overload; function Run: 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: TStringList3.イベントコンパイル済バイナリを使用する。 property CompiledBinary: Boolean
標準出力 property OnStdout: TStringEvent4.実行例標準エラー property OnStderr: TStringEvent
標準入力 property OnStdin: TReadStringEvent
デバッグ出力 property OnDebugout: TStringEvent
スクリプト実行時にオブジェクトが作成されたとき呼ばれます。 property OnNewObject: TNewObjectEvent
実行開始 property OnRun: TNotifyEvent
実行終了 property OnDone: TNotifyEvent
スクリプトの文(statement)を一つ実行するたびに呼ばれます。スクリプトの中断などに使用します。 property OnStep: TStepEvent
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;
5.条件定義 {$DEFINE }
DMonkeyの言語仕様について簡単に解説します。
※0.2.0からfor..in文が変更になりました
Array,Strings,HtmlParserの扱いが変更になっています。
例(1) 0.1.7まで
a = ['a','b','c','d'];//配列
for(i in a) //iにはインデックスが入る
println(a[i]);
例(2) 0.2.0から
a = ['a','b','c','d'];//配列
for(v in a) //vには要素が直接入る
println(v);
※0.2.1からfor..in文が変更になりました
例(1) 0.2.1から
a = ['a','b','c','d'];//配列
for(i in a) //iにはインデックスが入る
println(a[i]);
例(2) 条件定義
@set @VERSION7 = true //条件定義
a = ['a','b','c','d'];//配列
for(v in a) //vには要素が直接入る
println(v);
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);
}
}
a = new Hoge;
println(a.getProperties());
a.f1('hello');
a.f2();
a.f3();
for(i in a.ccc)
println(i);
例(2)
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);
}
println('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)
println(a);
else {
println('exit');
exit();
}
例(7)
s = ""; // 文字列を連結します。 s += scriptEngine() + " Version "; s += scriptEngineMajorVersion() + "."; s += scriptEngineMinorVersion() + "."; s += scriptEngineBuildVersion(); println(s);
例(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);
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(c[0][i]);
a.clear();
println(c[0].length);
例(2)
a = [5,4,3,2,1,0]; //配列生成
for(i in a)
println(a[i]);
例(1)
a = 100; println(a.toString(16));println(0x41.toChar());
例(1)
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++)
println(s[i]);
例(4)
pass = prompt('パスワードを入力してください','');
//saltは最初の二文字
salt = pass;
/*chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTQVWXYZ';
salt = chars[Math.floor(Math.random() * chars.length)] +
chars[Math.floor(Math.random() * chars.length)];
*/;
//暗号化
alert(c = pass.crypt(salt));
a = prompt('確認のパスワードを入力してください','');
if(a){
//暗号化された文字をsaltに使う
if(c == a.crypt(c))
alert('正解です');
else
alert('違います');
}
例(1)
re = new RegExp(';');
a = '100;200;300;400';
b = re.split(a);
for(i in b)
println(b[i]);
例(2)
re = new RegExp('a+','g');
a = 'akgatranavayakhahjajatdaa';
b = re.exec(a);
for(i in b)
println(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();//すべて読む
println(s);
f.seek(0); //最初に戻る
s = f.readln(); //1行読む
println(s);
}
catch(e){
println(e);
}
finally{
f.close();
}
例(3)
f = new File('c:\program files\irvine\irvine.exe');
println(f.extractName());
println(f.extractPath());
println(f.extractDir());
println(f.extractDrive());
println(f.extractExt());
println(f.changeExt('.jpg'));
例(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('.');
例(4)
d = new Directory('c:\program files\irvine');
println(d.includePathDelimiter());
println(d.excludePathDelimiter());
例(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)
reg = new RegIni('\software\wildforce\irvine');
println(reg.readSections().text);
if(reg.sectionExists('path'))
println(reg.read('path','Application',''));
例(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); println(c); d = b64.decodeHeader(c); println(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)
a = new HtmlParser;
a.parse('<a href="http://host/">abc</a>');
println(a.length);
println(a.html);
println(a.text);
for(i=0; i<a.length;i++){
println(a[i]);
}
for(i in a){
for(ii in a[i]){
println(ii + ': ' + a[i][ii]);
}
}
例(1)
ftp = new FTP; ftp.debug = true; ftp.host = '127.0.0.1'; ftp.userid = 'test'; ftp.password = 'test';ftp.connect(); //ftp.login('test','test'); try{ ftp.passiveMode = true; list = ftp.list(); for(i in list) println(list[i]);
println(ftp.printWorkDir()); println(ftp.currentDir);
ftp.makeDir('test'); ftp.changeDir('test'); println(ftp.printWorkDir()); ftp.type('I'); ftp.upload('test.txt','test.txt'); ftp.rename('test.txt','t.txt'); ftp.delete('t.txt'); ftp.changeDir('..'); ftp.removeDir('test');
ff = ftp.findFiles(ftp.currentDir,'*.txt',true); println(ff.text); if(ff.count > 0) ftp.download(ff[0],ff[0]);
list = ftp.nlist(); for(i in list) println(list[i]); } finally{ ftp.disconnect(); //ftp.quit(); }
例(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 StringBuffer(256);
dcall.register('advapi32','GetUserName','i=s4','f=s','r=b');
println(dcall.GetUserName(s,s.length));
s.delete(s.toString().indexOf(0.toChar()));
println(s);
println(s.length);
例(3)
dcall = new DynaCall;
dcall.register('kernel32','GetTickCount','f=s','r=l');
println(dcall.GetTickCount());
1.メソッドに足し算、プロパティにアプリケーションファイル名と日付オブジェクトを持つオブジェクトを作成します。
interface uses ecma_type,ecma_object;type //TJObjectを継承します TTestObject = class(TJObject) private FCells: array[0..10] of array[0..10] of String; FDate: TJDateObject; function GetApplicationFilename: String; //メソッドは TJMethod型である必要があります function DoAdd(Param: TJValueList): TJValue; function DoCells(Param: TJValueList): TJValue; protected procedure Notification(AObject: TJNotify); override; public constructor Create(AEngine: TJBaseEngine; Param: TJValueList; RegisteringFactory: Boolean = True); override; destructor Destroy; override; published //propertyはpublishedに設定します property applicationFilename: String read GetApplicationFilename; property date: TJDateObject read FDate; end;
implementation
{ TTestObject }
constructor TTestObject.Create(AEngine: TJBaseEngine; Param: TJValueList; RegisteringFactory: Boolean); begin inherited; //objectの名前を設定します RegistName('Test'); //メソッドを登録します RegistMethod('add',DoAdd); RegistMethod('Cells',DoCells);
//Date Objectを作成します //※RegisteringFactoryはFalseにしてFactoryに登録しない FDate := TJDateObject.Create(AEngine,nil,False); {または、登録する場合には終了通知を受ける FDate := TJDateObject.Create(AEngine); FDate.FreeNotification(Self); } //参照カウントを増やす FDate.IncRef; end;
procedure TTestObject.Notification(AObject: TJNotify); //終了通知を受ける begin inherited; {終了通知を受けた場合はFDateをnilにする if AObject = FDate then FDate := nil; } end;
destructor TTestObject.Destroy; begin //参照カウントを減らす(解放はしない) FDate.DecRef; {終了通知を受けた場合はFDateがnilになっている可能性がある if Assigned(FDate) then FDate.DecRef; } inherited; end;
function TTestObject.DoAdd(Param: TJValueList): TJValue; var v: TJValue; i,ret: Integer; begin //全ての引数を加算する ret := 0; if IsParam1(Param) then 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.DoCells(Param: TJValueList): TJValue; var row,col: Integer; v: TJValue; begin EmptyValue(Result); //引数をチェック if IsParam2(Param) then begin v := Param[0]; row := AsInteger(@v); v := Param[1]; col := AsInteger(@v); //もう一つあればセットする if IsParam3(Param) then begin //setter Result := Param[2]; FCells[row][col] := AsString(@Result); end else begin //getter //s := Format('%s(%d,%d) = %s',['Cells',row,col,FCells[row][col]]); Result := BuildString(FCells[row][col]); end; end; 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);