はじめに

DMonkeyは Delphiで作られた アプリケーションへの組込みを目的としたインタプリタ・スクリプトエンジンです。
言語仕様は ECMAScript(JavaScript) のサブセットになっています。



ライセンス

DMonkeyの使用・配布・改変についての制限はありません。



インストール

コンポーネントのインストールから DMonkey.pasをインストールします。



使用法

1.メソッド

スクリプトをコンパイルします。
function Compile(SourceCode: String): Boolean;
function CompileFile(AFilename: String): Boolean;

スクリプトを実行します。 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);

2.プロパティ
import宣言での検索パス。
property LibraryPath: TStringList read GetLibraryPath;

ガベージコレクトを使用する。ガベージコレクトを使用しなくても終了時にはすべてのオブジェクトを解放します。 property GarbageCollection: Boolean read GetGarbageCollection write SetGarbageCollection;

3.イベント
標準出力
property OnStdout: TStringEvent read FOnStdout write FOnStdout;

標準エラー 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;

4.実行例
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の言語仕様について簡単に解説します。


式については JavaScriptとほぼ同じです。
変数を使用する場合にあらかじめ宣言しておく必要はなく、 最初に代入された時点で宣言とみなします。
未定義の変数を使用した場合には例外が発生します。
文字列は ' で囲むとエスケープ文字を展開しません。


文は以下が使用できます。
if..else, while, do..while, for, for..in, continue, break, return, try, throw, catch, finally, with,


宣言

宣言は以下が使用できます。
function, var, class, import


オブジェクト

オブジェクトは以下が使用できます。(個別については後述)
Object, Global, Array, String, RegExp, Number,Boolean, Math, Strings, File, Directory,TCPSocket, HTTP, HTTPS,Cookie,Response,Mail, SMTP, POP3, URL, CRC, Dialog, Mutex, Win32, Base64,Ini,ActiveXObject,Keyboard,Mouse,Clipboard,Dynacall


クラス定義

既存のオブジェクトを継承して新しいオブジェクトを作ることができます。

例(1)
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; print(a.getProperties()); a.f1('hello'); a.f2(); a.f3(); for(i in a.ccc) println(i + '=' + a.ccc[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();
    }    
  }


例外

未定義の値を参照したりエラーの場合などには、 例外が発生してスクリプトは終了します。 例外後も継続して実行する場合には try..catchを使用します。

例(1)
  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);
  }


インポート

他のスクリプトファイルをインポートすることができます。

例(1) hello.jsのファイル名で保存します。
  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 が存在する場合



組込みオブジェクト

DMonkeyでは組込みオブジェクトによって機能を拡張していきます。


Object

すべての基本となるオブジェクト。ハッシュテーブルの機能を持ちます。

例(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);


Global

カレントオブジェクト。スクリプトは Globalオブジェクト内で実行されます。
グローバルオブジェクト Globalがスクリプトに最初から存在します。

例(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(); }


Array

配列オブジェクト。存在しない要素の値をgetしようとすると例外が発生します

例(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(i + ': ' + c[0][i]);

a.clear(); print(c[0].length);

例(2)
  a = [5,4,3,2,1,0]; //配列生成
  for(i in a)
    println(a[i]);


Number

数値オブジェクト。
グローバルオブジェクト Numberがスクリプトに最初から存在します。


例(1)
  a = 100;
  println(a.toString(16));


Boolean

真偽オブジェクト。


例(1)
  a = true;
  b = new Boolean(true);
  println(a.toString());  //true
  println(b);             //true


String

文字列オブジェクト。
グローバルオブジェクト Stringがスクリプトに最初から存在します。
配列として各文字を得ることが出来ます。

例(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]);


RegExp

正規表現オブジェクト。
グローバルオブジェクト RegExpがスクリプトに最初から存在します。


例(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]);


Math

数学オブジェクト。
グローバルオブジェクト Mathがスクリプトに最初から存在します。


Date

日付オブジェクト。
グローバルオブジェクト Dateがスクリプトに最初から存在します。
月は 1 ~ 12になります。


File

ファイルオブジェクト。ファイルはバイナリモードで開きます
テキストモードは後述するStringsオブジェクトを使用します。

例(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();
  }


Directory

ディレクトリオブジェクト。

例(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('.');


Strings

文字列リストオブジェクト。TStringListのラッパーです。

例(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();


Win32

Win32オブジェクト。Win32APIなど。


Ini

Iniオブジェクト。Iniファイルを処理します。TIniFileのラッパーです。

例(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],''));
    }
  }


CRC

CRCオブジェクト。

例(1)

  crc = new CRC;
  crc.calc('あいうえお');
  println(crc.CRC16.toString(16).substr(4,4));
  println(crc.CRC32.toString(16));


Base64

Base64オブジェクト。Base64エンコード、デコードを行います。

例(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);


Dialog

Dialogオブジェクト。

例(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]);


Mutex

同期オブジェクト。スレッド、プロセスを越えて同期をとります。

例(1)

  mutex = new Mutex('sakura');
  if (mutex.existed)
    println('えんいー');


URL

URL情報オブジェクト。

例(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);


Cookie

HTTPのCookieオブジェクト。Responseオブジェクトの一部として使われます。


Response

HTTPのResponseオブジェクト。HTTPとHTTPSの一部として使われます。


HTTP

HTTPオブジェクト。

例(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();
  }


HTTPS

HTTPSオブジェクト。HTTPと互換なので省略。


TCPSocket

TCP Socketオブジェクト。

例(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();
  }


Mail

Mailデータオブジェクト。STMPとPOP3で使用します。


POP3

POP3オブジェクト。メールの受信に使用します。

例(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();
  }


SMTP

SMTPオブジェクト。メール送信に使用します。

例(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();
  }


ActiveXObject

ActiveXオートメーションオブジェクト。

例(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:\');


Keyboard

キーボード状態オブジェクト。


Mouse

マウス状態オブジェクト。


Clipboard

クリップボードオブジェクト。


DynaCall

DLL呼び出しオブジェクト。

例(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);


Delphi Component: DMonkey
Version: 0.1.1
Last Modified: 2002/03/21
Author: Wolfy
http://http://hp.vector.co.jp/authors/VA024591/
http://gaogao.moemoe.gr.jp/