練炭ブログ

萌え壁紙、Irvine、DMonkey、Proxomitron などの情報を扱ってます。

DMonkey: シフト演算子

コメントなし»

DMonkey のシフト演算子は JavaScript と異なります。

JavaScript DMonkey
<< 演算 符号なし左シフト
結果 -2147483648~2147483647
>> 演算 符号あり右シフト 符号なし右シフト
結果 -2147483648~2147483647 -2147483648~2147483647
>>> 演算 符号なし右シフト 符号なし右シフト
結果 0~4294967295 -2147483648~2147483647

見にくい表で申し訳ない。

今回は、シフトの際の符号の有無と演算結果を符号ありとなしのどちらとして解釈するかだけしか調べていません。それ以外で違うところもあるかも知れません。

DMonkey: ビット演算における小数の扱い

コメントなし»

JavaScript でビット演算のオペランドに小数を指定した場合、小数部を 0 方向に切り捨てて(round towards zero)、32ビットの整数に変換してから演算されます。

DMonkey では小数部を最近接偶数への丸め(round half to even)で整数化するため、演算結果が異なります。

alert (+1.5 | 0);   //  2 ※JavaSciprt では  1
alert (0 | -1.5);   // -2 ※JavaSciprt では -1

DMonkey: number.toExponential()

コメントなし»

number.toExponential ([digits])

Number オブジェクトのメソッド。
数を10進指数表記の文字列に変換します。

digits は小数部分の桁数を 1~17 で指定します(省略時は 1)。

丸めの方法は四捨五入で、負数は絶対値として丸めます(round half away from zero)。

JavaScript では digits を省略すると数を表現するのに必要な桁数として処理されますが、DMonkey では単に 1 が指定されたものとして動作します。

DMonkey: number.toFixed() / number.toPrecision()

コメントなし»

number.toFixed ([digits])

Number オブジェクトのメソッド。
数を10進固定小数点表記の文字列に変換します。

digits は小数部分の桁数を 0~18 で指定します(省略時は 0)。負数を指定すると整数部分を丸め、小数部分は18桁の '0' で埋められます。

丸めの方法は四捨五入で、負数は絶対値として丸めます(round half away from zero)。

数が 1e15 以上の場合は、digits の指定にかかわらず .toString() の結果と同じ文字列が返されます(多分)。

なお、alert (-1.25.toFixed (1)); で 0 と表示されるのは、number.toFixed の動作ではなく、

-1.25.toFixed (1)
= -(1.25.toFixed (1))
= -('1.3')
= -'1.3'

となり、-'1.3' は 0 になるという DMonkey の型変換の挙動の影響です(parseInt と同じ感じ)。

number.toPrecision ([digits])

JavaScript の number.toPrecision() は、有効数字を digits で指定した桁数に変更して文字列化するメソッドですが、DMonkey においてはそれとは異なり .toFixed() と同じ動作として実装されているようです。混乱防止のため、DMonkey においては .toPrecision() は一切使わない方がよいでしょう。

DMonkey: Math.round()

コメントなし»

JavaScript と DMonkey における Math.round() の動作の違い。

JavaScript …… round half up

  • 小数部分が 0.5 より大きければ、次に大きい整数。
  • 小数部分が 0.5 なら、次に大きい整数(↑と同じ)。
  • 小数部分が 0.5 より小さければ、次に小さい整数。

DMonkey …… round half to even

  • 小数部分が 0.5 より大きければ、次に大きい整数。
  • 小数部分が 0.5 なら、最近接偶数への丸め
  • 小数部分が 0.5 より小さければ、次に小さい整数。
function r (n) {
  alert ('Math.round (' + n + ') == ' + Math.round (n));
}

r (-2.5);   // -2
r (-1.5);   // -2
r (-0.5);   // 0
r (+0.5);   // 0
r (+1.5);   // 2
r (+2.5);   // 2

関連: DMonkey: Global.parseInt()

Global.parseInt() に number 型を渡した時も同じ丸め方になります。これらの挙動は Delphi の System.Round() を規定の丸めモード(rmNearest)で呼び出しているためと思われます。

DMonkey: iconv.dll による文字列変換

コメントなし»

KaoriYa さんが配布している Vim に同梱されている iconv.dll を使って、Irvine のスクリプトで UTF-8 文字列を Shift_JIS に変換するテスト。

function iconvUtf8ToSjis (text) {
	var Dorothy = { path: 'C:\bin\Irvine\Dorothy2\' };

	var dll = Dorothy.path + 'bin\iconv.dll';

	var d = new DynaCall ();
	d.register (dll, 'libiconv_open',	'i=ss',		'r=l');
	d.register (dll, 'libiconv_close',	'i=l',		'r=l');
	d.register (dll, 'libiconv',		'i=lssss',	'r=l');

	var n;

	var iconv = d.libiconv_open ('Shift_JIS//IGNORE', 'UTF-8');
	// alert ('libiconv_open: ' + iconv);

	var insb = new StringBuffer (text);
	var inbufp = new Struct ('inbuf:s');
	inbufp.inbuf = insb;

	var inbytesleftp = new Struct ('inbytesleft:l');
	inbytesleftp.inbytesleft = new Number (insb.length);

	var outsb = new StringBuffer (100);
	var outbufp = new Struct ('outbuf:s');
	outbufp.outbuf = outsb;

	var outbytesleftp = new Struct ('outbytesleft:l');
	outbytesleftp.outbytesleft = new Number (outsb.length);

	n = d.libiconv (iconv, inbufp, inbytesleftp, outbufp, outbytesleftp);
	// alert (n + "\n\n" + outbytesleftp.outbytesleft + "\n\n" + outsb.text);

	n = d.libiconv_close (iconv);
	// alert ('libiconv_close: ' + n);

	return outsb.text;
}

var t = String.fromCharCode (0x61, 0xF0, 0xA0, 0xAE, 0xB7, 0x7a);
alert (iconvUtf8ToSjis (t));

てきとうに書いたのでバッファの扱いとか間違っているかもしれません。Irvine の動作自体がおかしくなる恐れもあるので、このコードは実行しないで下さい。

変換できない文字を米印※とかゲタ〓のような任意の文字に変換できればよかったんですが、変換自体をエラーにするか文字を無視するかしか選べないようです。

DMonkey: オブジェクト.$数字 の直後に演算子を書くとエラー

コメントなし»
var o = { $1: 2 };
alert (o.$1+3);   // SyntaxError: Line(2) => Text( 3 )

オブジェクト.$数字 という形式の参照の直後に、スペースを置かずに +*
演算子を書くと SyntaxError になります。-/ は問題ありません。

上の例では alert (o.$1 +3) のようにスペースを入れると問題なく動作します。

RegExp.$1~$9 でもエラーになります。

DMonkey: Enumerator オブジェクトの使い方

コメントなし»

Enumerator オブジェクトの使い方がようやく分かりました。JScript と同じです。

var fso = new ActiveXObject ('Scripting.FileSystemObject');
var folder = fso.GetFolder ('R:\');

var list = [ ];

var en = new Enumerator (folder.Files);
for (; !en.atEnd (); en.moveNext ()) {
list.push (en.item ().Name);
}

alert (list.join ("\n"));

ただ、OnHttpRequest からは ActiveX が使えませんし、ファイルシステム関係は DMonkey が独自に組み込みオブジェクトを持っているので、Irvine から使う場面というのは思い浮かびません。

DMonkey: URL オブジェクト

コメントなし»

DMonkey の new URL() で確保されるオブジェクトの挙動について。

url への書き込み
→ protocol username password hostname port path dir filename query に反映されます。

url からの読み込み
→ その時点の protocol username password hostname port path の値から URL が計算されて返されます。dir、filename、query の値は無視されます。

host への書き込み
→ hostname と、ポート番号があれば port に反映されます。

host からの読み込み
→ hostname と port の値から計算されて返されます。

protocol username password hostname port path directory filename query への書き込み
→ そのプロパティのみに反映されます。

上記プロパティからの読み込み
→ そのプロパティの値が返されます。

.toString()
→ 初期化時の URL または url プロパティへ書き込んだ URL が返されます。

上記に該当しない変化は起きません。

例えば、path を書き換えた後に filename を読み込んでも古い値のままです。
url の値を url へ書き込めば各プロパティにも反映されます。

var u = new URL ('http://example.com/aaa');
alert (u.filename);   // aaa

u.path = '/zzz';
alert (u.filename);   // aaa

u.url = u.url;
alert (u.filename);   // zzz

こういったプロパティごとの挙動の違いや、フラグメント識別子(#~)に対応していないところが使いづらく、ラッパーオブジェクトかあるいは完全に自前で処理するオブジェクトを作りたくなります。

ただ DMonkey では「プロパティを読み書きするとメソッドが呼ばれる」形での getter/setter が定義出来ないので、使いづらいのは解決できそうにないかなー。

DMonkey: StringBuffer における NUL 文字の検索

コメントなし»

StringBuffer.indexOf において、String.fromCharCode (0) で NUL 文字を検索することが出来ます。

var sb = new StringBuffer ('abc');
sb [1] = 0;

var s = String.fromCharCode (0);
alert (sb.indexOf (s));   // 1

// これらの方法では検索できない
alert (sb.indexOf (0));   // -1
alert (sb.indexOf (""));   // -1
alert (sb.indexOf ("\x00"));   // -1

NUL の後ろに文字が続いていても考慮されます。

var sb = new StringBuffer ('a*b*c');
sb [1] = sb [3] = 0;

var s = String.fromCharCode (0) + 'c';
alert (sb.indexOf (s));   // 3

ちなみに StringBuffer を文字列で初期化した場合、データ末尾に NUL 文字は付きません。また length を増やした場合は 0 で埋められます。

var sb = new StringBuffer ('abc');
var s = String.fromCharCode (0);

alert (sb.indexOf (s));   // -1
++sb.length;
alert (sb.indexOf (s));   // 3