/ 最近 .rdf 追記 設定 本棚

log[javascript: 2008-02-04]



20080204()

[SHJS][javascript] sh_main.jsの高速化

SHJSのブラウザでの実行時間を削るには sh_main.js(SHJSのメイスクリ)を速くするか正規表現を効率的なものにする方法がある(>遅い正規表現(20080116p01))

正規表現に関してできることは限られるうえ知識も少ない(『詳説 正規表現 第三版待ち)ので可能な限り文字クラスや文字集合といわれるものを使うように気を付けただけにとどまる(sh_ruby.js, sh_javascript.js)

メイスクリトの sh_main.jsに対してできることは多いこの日記の現在?の最新ページ(2008112日から7)を表示してsh_highlightDocument()前後での経過時間を表示したところこのようになった

Firefox2IE7(64-bit)IE7(32-bit)Opera9.25
sh_main.js (0.4.2)935ms1050ms1270ms1260±150ms
改変版600ms680ms865ms1200±150ms
削減率36%35%32%5%

ハイラト対象が少なくて数ミリ秒で処理が終わるような場合はオーバーヘドのために改変版の方が 1-2ミリ秒遅くなるがそれよりもスクリトがブラウザをロックする時間が長くなるような場合にこそ速度改善が必要なので OK

代償としてファイルサイズが sh_main.js10.5KiBから 12.7KiB+2.2KiBjsmin圧縮後の sh_main.min.js6.22KiBから 7.82KiB+1.60KiBApacheによる gzip圧縮やブラウザのキッシュに期待します。

 () Operaについて

普段は全く Operaを使わないし詳しくもないむしろ Operaではキーボドを使ったブラウジングもままならないそんな人間が Firefox+Firebugを頼りに sh_main.jsの修正を行ったので Operaの速度が改善しないのは仕方のない部分がある(IEは改善したが)(あんだけいじータルで変わらない方がすごいどこが足を引っぱっているのだろう)リテラル文字列と Stringオブジトの差が他のブラウザより大きいらしいがそれが原因?

EfficientJavaScript - Dev.Opera - 効率的な JavaScript (www.hyuki.com)

Operaでの JavaScriptの実行時間が他のブラウザに比べて長いのははっきりした理由があってOperaはスクリトが全力疾走中であってもユーザーの操作に対する反応を後回しにしたりしないこれは偉いーザーを待たせない代わりにスクリトが遅れるのは当然の代償で仕方がない

スクリトでなく再描画が律速してるから改善しないということ?

 (かんせいしたへびのえにあしをかきくわえるこういとまでは言わない) この日記で使用中のファイルへのリンク

(常に最新版だが一時的にバグが混入していることがあるか)

 追記@日:sh_main.jsをちっと修正

すぐ上のリンク先はすでに変更が反映されている

これら二つの記事を参考に escapeHTML()を変更した測定に使ったページでは 9000回ちかく呼び出されるメソドなので影響はバカにならないといっても 600msったのが 590msを切るようになったというレベルむしろ下請けfunctionを隠蔽できたことの方が嬉しい

escapeHTML()自体sh_builderのインターフェイスではないので外部から呼び出せないようにすべきかもしれないがfunctionをかぶせるたびに呼び出しのオーバーヘドが増える気がしてそうはしていない

 追記@今日

SHJSpatternStackオブジトは外部と完全に独立して動作するのにsh_highlightString()が呼ばれるたびに無名クラスとそのイスタスを作成するような方法がとられているトラクタと prototypeを書こう(sh_highlightString()HTML文書内の <pre class="sh_XXX">の数だけしか呼ばれないから影響は小さい件のページでは 58)

sh_highlightString()からしか使われないのにスタックの可視範囲が広がるのが気になるならっき覚えた無名functionで二つをくるんでしまえば良い

var sh_highlightString = (function(){
  var Stack = function(){
    this.stack_ = [];
  };
  Stack.prototype.getLength = function(){/* ... */};
  // ……
  return function(){
    var patternStack = new Stack();
    /* sh_highlightStringの中身がつづく…… */
  };
})();

まあ速度が改善するわけではないので書き直さないんだけど

 追記@2008-02-25

innerHTMLtextContentinnerTextの使用は堕落だという気もするが冗長な上に呼び出しを重ねることで遅くなる DOMメソドがいけない


20080116() PythonかわいいよPython

[SHJS][SakuraEditor][javascript] SHJSSakuraEditor用のハイラトルールファイル

SHJSjavascript定義ファイル(lang/sh_javascript.js)の元になったファイル(javascript.lang)の中身がこれ

include "java.lang"

subst keyword = "abstract|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|final|finally|for|function|goto|if|implements|in|instanceof|interface|native|new|null|private|protected|prototype|public|return|static|super|switch|synchronized|throw|throws|this|transient|true|try|typeof|var|volatile|while|with"

javaて……ーワドにしても使ったことのないものがいっぱい

あまりにあんまりなんで一から書いた(sh_javascript.js, sh_javascript.min.js) 参照したのは JScript5.5HTMLHelpなので JScript.NETECMAScript4には対応していない古典的な JavaScript

ついでに同じものを SakuraEditorにも(javascript_keywords.zip)


20080115()

[javascript] ラベル付きブロックと break - JScript

オブジトリテラルの存在も JScript5.5HTMLHelpでの扱いが一行しかなかった*ために気付くのが遅れたがこれはその上をいく古典的な javascriptで何年ぶりの新発見しかもこれもちゃんと書いてあった(但し一行)

block:
{
  break block;
}

ープにラベルを付けてトしたループから外側のループを continueしたり breakしたりできるのは知っていた(が忘れていた)ラベル付きブロックと breakのこの使い方は全く知らなかった

labelのスコープはローカル変数と同じみたいでfunctionをまたいで goto代わりには使えなかった

 余談

 function(){ alert(1) }();
 void function(){ alert(2) }();
 (function(){ alert(3) })();

alertが表示されるのは 23二行目ので初めて voidの使い途を見つけたと思ったのだったが三番目の書き方もあるらしくまたそれが一般的っぽいまあなんとなくわかるあれでし

 余談の追記@2008-02-25

1行目の functionだけ functionExpressionではなく functionDeclarationだと解釈されて続く () は関数呼び出しのかっこではなく式をグルーピングするかっこになるのだと(functionDeclarationでは関数名を省略できないのだから(省略できる)functionExpressionだと解釈してくれても良さそうなものだ)

そういう理由なのでこんなのもあり

+function(){ alert(4) }();
(function(){ alert(5) }());

* JScript>ーザーズ ガ>JScriptの基本>JScriptドの記述

 JScript>ランゲージ リファレ>ステトメ>break ステトメ

 ローカル変数なら自分より外側のものが見えるラベルは見えないのでそれより厳しい


20080105()

[SHJS][javascript]SHJS Ruby定義ファイル(sh_ruby.js) 私的改訂版 まとめ(2008-01-17 最終更)

ァイルはこちら20080101p01

あいだにコメトを挟みながら一連の DIFF差分(sh_ruby.js.diff)を見ていく

 っこ(?:)を省略して減量

--- sh_ruby.js.original	Fri Aug  3 12:16:32 2007
+++ sh_ruby.js	Sat Jan 19 01:35:32 2008
@@ -2,123 +2,427 @@
   this.sh_languages = {};
 }
 sh_languages['ruby'] = [
   [
     {
-      'regex': /\b(?:require)\b/g,
-      'style': 'sh_preproc'
+      regex: /\brequire\b/g,
+      style: 'sh_preproc'
     },

 #から後ろはすべてコメトなんていう強力すぎるルールは後ろに移動して優先度を下げる

-    {
-      'next': 1,
-      'regex': /#/g,
-      'style': 'sh_comment'

 必ず最初に実行される処理(BEGIN)最後に実行される処理(ENDat_exit)スクリトを終了する(exit)など無視できない働きを持ったメソドをハイラ

+    { // part of Kernel methods.
+      regex: /\b(?:exit!?|(?:abort|at_exit|BEGIN|callcc|END|eval|exec|fork|load|spawn|syscall|system|trap|warn)\b)/g,
+      style: 'sh_preproc'
     },

 \bの後ろの +-は絶対にマッチしないので前に出してマッチするように

 数値リテラルの定義が cpp,java,pascal,perl,php,prolog,python,sh,sql,tclと共通だったので Ruby専用に(先頭末尾や連続するアンダースコアやが許容されているがべつに Rubyインタープリタじゃないので気にしな)

     {
-      'regex': /\b[+-]?(?:(?:0x[A-Fa-f0-9]+)|(?:(?:[\d]*\.)?[\d]+(?:[eE][+-]?[\d]+)?))u?(?:(?:int(?:8|16|32|64))|L)?\b/g,
-      'style': 'sh_number'
+      regex: /[+-]?\b(?:0(?:x[A-Fa-f0-9_]+|d[\d_]+|b[01_]+|o?[0-7_]+)|(?:0\.)?[\d_]+(?:[Ee][+-]?[\d_]+)?)\b/g,
+      style: 'sh_number'
     },

 javascriptのオブジトリテラルのプロパ名部分は引用符を省ける(ので省く)

     {
-      'next': 2,
-      'regex': /"/g,
-      'style': 'sh_string'
+      next: 2,
+      regex: /"/g,
+      style: 'sh_string'
     },
     {
-      'next': 3,
-      'regex': /'/g,
-      'style': 'sh_string'
+      next: 3,
+      regex: /'/g,
+      style: 'sh_string'
     },

 <<メソドや <<HEREDOCUMENTに誤ってマッチしないようにHTMLタグっぽいものだけをハイラ(そもそもなんで <hoge>を文字列としてハイラトするのかは GNU Source-highlightのみぞ知る)

     {
-      'next': 4,
-      'regex': /</g,
-      'style': 'sh_string'
+      next: 4,
+      regex: /<(?=[\w\/])/g,
+      style: 'sh_string'
     },

 /regexp/i 型の正規表現リテラルの条件を厳しくして URLに誤ってマッチしないようにまたオプション部分もマッチに含めるように

     {
-      'regex': /\/[^\n]*\//g,
-      'style': 'sh_regexp'
+      regex: /\/(?:\\.|[^\n\\\/])*\/[eimnosux]*(?![A-Za-z])/g,
+      style: 'sh_regexp'
     },

 別途定義したので不完全な %r{regexp}の定義は削除

     {
-      'regex': /(%r)(\{(?:\\\}|#\{[A-Za-z0-9]+\}|[^}])*\})/g,
-      'style': ['sh_symbol', 'sh_regexp']

 定義と処理の流れに関わるキーワドやメソドを選択除外したものはすべて定数や無視できないメソドとして別に定義した

+      regex: /(?:\b(?:alias|attr(?:_reader|_writer|_accessor)?|begin|break|case|do|else|elsif|end|ensure|for|if|in|include|lambda|loop|next|proc|raise|redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield|and|not|or|def|class|module|catch|fail|throw)\b|&&|\|\|)/g,
+      style: 'sh_keyword'
     },
     {
-      'regex': /\b(?:alias|begin|BEGIN|break|case|defined|do|else|elsif|end|END|ensure|for|if|in|include|loop|next|raise|redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield|false|nil|self|true|__FILE__|__LINE__|and|not|or|def|class|module|catch|fail|load|throw)\b/g,
-      'style': 'sh_keyword'

 不要なグループ化(?:)とエスケープ(\=)を削除

+      next: 5,
+      regex: /^=begin/g,
+      style: 'sh_comment'
     },
     {
-      'next': 5,
-      'regex': /(?:^\=begin)/g,
-      'style': 'sh_comment'

 グローバル変数は別に定義したのでここではイスタス変数とクラス変数のみを扱うことに

+      regex: /@@?[A-Za-z_][A-Za-z0-9_]*/g,
+      style: 'sh_type'
     },
-    {
-      'regex': /(?:\$[#]?|@@|@)(?:[A-Za-z0-9_]+|'|\"|\/)/g,
-      'style': 'sh_type'

 グローバル変数専用のルールを追加

+    { // global variables
+      regex: /\$(?:[_&~`'\+\?!@=\/\\,;\.<>\*\$:"]|-?[A-Za-z0-9_]+\b)/g,
+      style: 'sh_type'
+    },

 各種かっこ(<[{}]>)を使った正規表現コマ文字列配列文字列シンボルリテラルのルールを追加(後ろの方に関連する追加部分あ)

+    { // %r(regexp)
+      next: 6,
+      regex: /%r(?=[\(<\[\{])/g,
+      style: 'sh_regexp'
+    },
+    { // %x(command), %w(array)
+      next: 11,
+      regex: /%[xWw](?=[\(<\[\{])/g,
+      style: 'sh_normal'
+    },
+    { // %(string), %s(symbol)
+      next: 16,
+      regex: /%[Qqs]?(?=[\(<\[\{])/g,
+      style: 'sh_string'
+    },

 っこ以外の記号を使った正規表現コマ文字列配列文字列シンボルリテラルのルールを追加

+    { // %r!regexp!i
+      regex: /%r([ -'*-\/:;=?@\\^_`|~])(?:\\.|.)*?\1[eimnosux](?![A-Za-z])/g,
+      style: 'sh_regexp'
+    },
+    { // %x!command!, %w!array!
+      regex: /%[xWw]?([ -'*-\/:;=?@\\^_`|~])(?:\\.|.)*?\1/g,
+      style: 'sh_string'
+    },
+    { // %!string!, %s!symbol!
+      regex: /%[Qqs]?([ -'*-\/:;=?@\\^_`|~])(?:\\.|.)*?\1/g,
+      style: 'sh_string'
+    },

 シンボルリテラルのルールを追加(コロンにクーテーションマークが続くタイプのシンボル(:"symbol")は現状でもコロンがsh_symbolその後ろがsh_stringとして認識されるので対応する必要がな)

+    { // Symbol
+      regex: /(:)((?:@@?|\$|[A-Za-z_])\w+\b[!\?]?)/g,
+      style: ['sh_symbol', 'sh_string']
+    },
+    { // Symbol
+      regex: /(:)(\+|~|\*\*?|-|\/|%|<=>|<<?|>>?|^|===?|=~|!~|&|\|)(?=[^\w\d]|$)/g,
+      style: ['sh_symbol', 'sh_string']
+    },

 定数のルールを追加

+    { // Constants
+      regex: /\b[A-Z]\w+\b/g,
+      style: 'sh_function'
+    },
+    { // Constants
+      regex: /\b(?:self|nil(?!\?)|true|false|__FILE__|__LINE__)\b/g,
+      style: 'sh_function'
+    },

 大文字や数字で始まって ?!で終わるメソドはないので(ないよね?)そのように正規表現を変更

+    { // don't highlight ? and ! as symbols if they are part of a method call
+      regex: /\b[a-z_]\w*[!\?]/g,
+      style: 'sh_normal'
     },
     {
-      'regex': /[A-Za-z0-9]+(?:\?|!)/g,
-      'style': 'sh_normal'

 ::hogeSymbolと誤認しないように先に ::sh_symbolにしてしまう

 プロパ名部分の引用符を省略

+      regex: /~|!|%|\^|\*|\(|\)|-|\+|=|\[|\]|\\|::?|;|,|\.|\/|\?|&|<|>|\|/g,
+      style: 'sh_symbol'
     },
     {
-      'regex': /~|!|%|\^|\*|\(|\)|-|\+|=|\[|\]|\\|:|;|,|\.|\/|\?|&|<|>|\|/g,
-      'style': 'sh_symbol'
+      regex: /(#)(\{)/g,
+      style: ['sh_symbol', 'sh_cbracket']
     },
     {
-      'regex': /(#)(\{)/g,
-      'style': ['sh_symbol', 'sh_cbracket']
+      regex: /\{|\}/g,
+      style: 'sh_cbracket'
     },
     {
-      'regex': /\{|\}/g,
-      'style': 'sh_cbracket'

 #一行コメト ルールを前の方から最後のここまで移動

+      next: 1,
+      regex: /#/g,
+      style: 'sh_comment'
     }
   ],

 プロパ名部分の引用符を省略

 グループ化(?:)の代わりに文字クラス( [] )を使用して字数削減

 'exit'するときの 'style'指定はなくてもかまわないので削除

 不要なグループ化とエスケープを削除(?:\=end)

   [
     {
-      'exit': true,
-      'regex': /$/g
+      exit: true,
+      regex: /$/g
     }
   ],
   [
     {
-      'exit': true,
-      'regex': /$/g
+      exit: true,
+      regex: /$/g
     },
     {
-      'regex': /\\(?:\\|")/g
+      regex: /\\[\\"]/g
     },
     {
-      'exit': true,
-      'regex': /"/g,
-      'style': 'sh_string'
+      exit: true,
+      regex: /"/g
     }
   ],
   [
     {
-      'exit': true,
-      'regex': /$/g
+      exit: true,
+      regex: /$/g
     },
     {
-      'regex': /\\(?:\\|')/g
+      regex: /\\[\\']/g
     },
     {
-      'exit': true,
-      'regex': /'/g,
-      'style': 'sh_string'
+      exit: true,
+      regex: /'/g
     }
   ],
   [
     {
-      'exit': true,
-      'regex': /$/g
+      exit: true,
+      regex: /$/g
     },
     {
-      'exit': true,
-      'regex': />/g,
-      'style': 'sh_string'
+      exit: true,
+      regex: />/g
     }
   ],
   [
     {
-      'exit': true,
-      'regex': /^(?:\=end)/g,
-      'style': 'sh_comment'
+      exit: true,
+      regex: /^=end/g
     }
+  ],

 各種かっこ(<[{}]>)を使ったリテラルのルール(後半部)

+  [ // state 6-10: %r(regexp)
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 7,
+      regex: /\(/g,
+      style: 'sh_regexp'
+    },
+    {
+      next: 8,
+      regex: /</g,
+      style: 'sh_regexp'
+    },
+    {
+      next: 9,
+      regex: /\[/g,
+      style: 'sh_regexp'
+    },
+    {
+      next: 10,
+      regex: /\{/g,
+      style: 'sh_regexp'
+    },
+    {
+      exit: true,
+      regex: /[)>\]}][eimnosux]*/g,
+      style: 'sh_regexp'
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 6,
+      regex: /(?=\()/g
+    },
+    {
+      exit: true,
+      regex: /(?=\))/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 6,
+      regex: /(?=<)/g
+    },
+    {
+      exit: true,
+      regex: /(?=>)/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 6,
+      regex: /(?=\[)/g
+    },
+    {
+      exit: true,
+      regex: /(?=])/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 6,
+      regex: /(?={)/g
+    },
+    {
+      exit: true,
+      regex: /(?=})/g
+    }
+  ],
+  [ // state 11-15: %x(command)
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 12,
+      regex: /\(/g,
+      style: 'sh_normal'
+    },
+    {
+      next: 13,
+      regex: /</g,
+      style: 'sh_normal'
+    },
+    {
+      next: 14,
+      regex: /\[/g,
+      style: 'sh_normal'
+    },
+    {
+      next: 15,
+      regex: /\{/g,
+      style: 'sh_normal'
+    },
+    {
+      exit: true,
+      regex: /[)>\]}]/g,
+      style: 'sh_normal'
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 11,
+      regex: /(?=\()/g
+    },
+    {
+      exit: true,
+      regex: /(?=\))/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 11,
+      regex: /(?=<)/g
+    },
+    {
+      exit: true,
+      regex: /(?=>)/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 11,
+      regex: /(?=\[)/g
+    },
+    {
+      exit: true,
+      regex: /(?=])/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 11,
+      regex: /(?={)/g
+    },
+    {
+      exit: true,
+      regex: /(?=})/g
+    }
+  ],
+  [ // state 16-20: %Q(string)
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 17,
+      regex: /\(/g,
+      style: 'sh_string'
+    },
+    {
+      next: 18,
+      regex: /</g,
+      style: 'sh_string'
+    },
+    {
+      next: 19,
+      regex: /\[/g,
+      style: 'sh_string'
+    },
+    {
+      next: 20,
+      regex: /\{/g,
+      style: 'sh_string'
+    },
+    {
+      exit: true,
+      regex: /[)>\]}]/g,
+      style: 'sh_string'
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 16,
+      regex: /(?=\()/g
+    },
+    {
+      exit: true,
+      regex: /(?=\))/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 16,
+      regex: /(?=<)/g
+    },
+    {
+      exit: true,
+      regex: /(?=>)/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 16,
+      regex: /(?=\[)/g
+    },
+    {
+      exit: true,
+      regex: /(?=])/g
+    }
+  ],
+  [
+    {
+      exit: true,
+      regex: /$/g
+    },
+    {
+      next: 16,
+      regex: /(?={)/g
+    },
+    {
+      exit: true,
+      regex: /(?=})/g
+    }
   ]
 ];

20080103()

[SHJS][javascript] jsmin.js

SHJSのスクリトは全て機能が同じでファイルサイズが違う hoge.jshoge.min.jsの二種類が収録されている言語ごとに定義ファイルが分かれているのもおそらく転送量を抑えるためで個々の jsァイルのほとんどが数キロバトに収まっている

*.min.jsァイルは JSMINというツールで空白を詰めることで作られているJSMINのオリジナルは DOS実行ファイルだけどC#JavaJavaScriptPerlPHPPythonOCAMLRubyの実装もあるjavascriptを圧縮するのなら javascriptを使いたいよねということで javascriptージョンの jsmin.jsをダウンロドしてきた

jsmin.jsの中には jsmin()という関数が一つだけあるこれに javascriptのソースを渡すとコンパトになったソースが返ってくるのだけどどうやって実行しようjsmin.jsと同じ場所にあった test.htmlをブラウザで表示してテキトエリアにソースを貼り付けて実行するのもありだが sh_ruby.jsをちょこちょこいじってる身としては毎回となると面倒くさい

というわけで J(ava)Scriptexec_jsmin.jsというのを書いたjsmin.jsと同じ場所に置いたこのファイルに *.jsァイルドロップすると *.min.jsというファイルを作成する

var fso = new ActiveXObject("Scripting.FileSystemObject");

function ReadFile(path)
{
	var ts = fso.OpenTextFile(path, 1, false);
	var text = ts.ReadAll();
	ts.Close();
	return text;
}

function WriteFile(path, text)
{
	var ts = fso.CreateTextFile(path, true, false);
	ts.Write(text);
	ts.Close();
}

eval(ReadFile(fso.BuildPath(fso.GetParentFolderName(WScript.ScriptFullName), "jsmin.js")));

var args = WScript.Arguments;
for(var i = 0; i < args.Length; ++i)
{
	var path = args(i);
	if(fso.FileExists(path)) {
		var path_min = fso.BuildPath(fso.GetParentFolderName(path), fso.GetBaseName(path)) + '.min.js';
		WriteFile(path_min, jsmin(ReadFile(path)));
	} else {
		WScript.Echo("FileNotExist:"+path);
	}
}

最初から最後まで J(ava)Scriptで完結して満足です。

[SHJS][javascript]まだまだいじってます。>SHJS | \bを正しく使用 & わずかに減量

ァイルはこちら。20080101p01

頭の方から変更点を見ていく

 #includeに相当するもの (sh_preproc)

-      'regex': /\b(?:require)\b/g,
+      'regex': /\brequire\b/g,

require一つだけだからかっこで囲む必要はない

 使用頻度は低いけど無視できないメソドたち (sh_preprocを流)

-      'regex': /\b(?:defined\?|Array|Floar|Integer|String|abort|callcc|exec|exit!?|fork|proc|lambda|set_trace_func|spawn|syscall|system|trace_var|trap|untrace_var|warn)\b/g,
+      'regex': /\b(?:defined\?|exit!?|(?:abort|callcc|exec|fork|set_trace_func|spawn|syscall|system|trace_var|trap|untrace_var|warn)\b)/g,

ArrayFloar(Floatのスペルミスでした)IntegerStringを取り除いて定数のルールが適用されるようにsh_preprocではなく sh_functionになる

lambdaprocも取り除いてsh_keywordに含めることにした

\bdefined??exit!!の直前にマッチし?の後や !の後にはマッチしないので正しくマッチするように修正

 シンボル (sh_string)

-    { // Symbol
-      'regex': /:(?:(?:@@|@|\$)?\w+[\?!]?|\+=?|!=?|~|\*\*=?|-=?|\*=?|\/=?|%=?|<<=?|>>=?|&=?|\|=?|^=?|>=?|<=?|<=>|===?|=~|!~|&&=?|\|\|=?|\.\.|\.\.\.|=)(?=\s|$)/g,
-      'style': 'sh_string'
-    },
+    { // Symbol
+      'regex': /(:)((?:@@|@|\$)?\w+\b[!\?]?)/g,
+      'style': ['sh_symbol', 'sh_string']
+    },
+    { // Symbol
+      'regex': /(:)(\+|~|\*\*|-|\*|\/|%|<<?|>>?|^|<=>|===?|=~|!~|&|\|)(?=[^\w\d]|$)/g,
+      'style': ['sh_symbol', 'sh_string']
+    },

あまりにルールが乖離してるので Symbolのルールを分割加えて不正な Symbolリテラルをルールから除外(代入複合代入:&&:||:...)

リテラルの先頭の :sh_stringから sh_symbolにしたのは

:"hoge"
:hoge

の整合性をとるため

 正規表現リテラル (/regexp/ish_regexp)

-      'regex': /\/[^\n]*\//g,
+      'regex': /\/(?:\\.|[^\n\\\/])*\/[eimnosux]*(?!\w)/g,

正規表現リテラルのオプション部分もマッチに含めるようにあと条件を厳しくしたので URLに誤マッチすることが減るはず。

 制御構造と定義に関わるキーワドやメソ(sh_keyword)

-      'regex': /(?:\b(?:alias|begin|BEGIN|at_exit|break|case|do|else|elsif|end|END|ensure|for|if|in|include|loop|next|raise|redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield|and|not|or|def|class|module|catch|fail|load|throw)\b|&&|\|\|)/g,
+      'regex': /(?:\b(?:alias|begin|BEGIN|at_exit|break|case|do|else|elsif|end|END|ensure|for|if|in|include|lambda|loop|next|proc|raise|redo|rescue|retry|return|super|then|undef|unless|until|when|while|yield|and|not|or|def|class|module|catch|fail|load|throw)\b|&&|\|\|)/g,

lambdaprocsh_preprocから sh_keywordへ持ってきたどちらもメソドになりうる重要な要素だと思うから

 定数 (sh_function)

-      'regex': /\b[A-Z]\w+[!\?]?(?=\b|$)/g,
+      'regex': /\b[A-Z]\w+\b[!\?]?/g,

\bを正しく使用最後の [!\?]?は不要でした試してみたらエラーになった

-      'regex': /\b(?:false|nil(?!\?)|true|self|__FILE__|__LINE__)(?=\b|$)/g,
+      'regex': /\b(?:false|nil(?!\?)|true|self|__FILE__|__LINE__)\b/g,

 よくわからないもの (sh_normal)

-      'regex': /[a-z0-9_]+(?:\?|!)/g,
+      'regex': /\b[a-z0-9_]+[!\?]?/g,

末尾が ?!のメソドだけを拾い上げたかったのだろうか?ローカル変数っぽいものにもマッチするようにしたけどどのみち色はつかないので害はない因みに文字配列リテラル( %w(one two three) )も適切なクラスが見つからなかったので sh_normalにしている

 文字列リテラルとタグとコメ(=begin=end)

-      'style': 'sh_string'
-      'style': 'sh_string'
-      'style': 'sh_string'
-      'style': 'sh_commend'

'string'"string"<tagname>=begin=endの終了条件部分から styleを取り除くなくても出力は変わらないそれにしても HTMLタグっぽいものにマッチするルールがあるのはなぜだろうWeb用言語だと思われてるのかな?(<stdio><stdlib> のたぐいの可能性もある)不都合はないので消さないけど


20080102()

[SHJS][tDiary][javascript] SHJSRubyールを %[]に対応

20080101p01からの続き正式な sh_ruby.js (私的改訂版)はそちらから

機能は同じ(はず)なのになぜか全く様子の違う二つのスクリトができてしまったこんな感じ

 Ruby%記法対応 (stateっぱい版)

    { // %r(regexp)
      'next': 6,
      'regex': /%r(?=[\(<\[\{])/g,
      'style': 'sh_regexp'
    },
    { // %x(command), %w(array)
      'next': 11,
      'regex': /%[xWw](?=[\(<\[\{])/g,
      'style': 'sh_normal'
    },
    { // %(string), %s(symbol)
      'next': 16,
      'regex': /%[Qqs]?(?=[\(<\[\{])/g,
      'style': 'sh_string'
    },
  [ // state 6-10: %r(regexp)
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 7,
      'regex': /\(/g,
      'style': 'sh_regexp'
    },
    {
      'next': 8,
      'regex': /</g,
      'style': 'sh_regexp'
    },
    {
      'next': 9,
      'regex': /\[/g,
      'style': 'sh_regexp'
    },
    {
      'next': 10,
      'regex': /\{/g,
      'style': 'sh_regexp'
    },
    {
      'exit': true,
      'regex': /[)>\]}]/g,
      'style': 'sh_regexp'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 6,
      'regex': /(?=\()/g,
    },
    {
      'exit': true,
      'regex': /(?=\))/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 6,
      'regex': /(?=<)/g,
    },
    {
      'exit': true,
      'regex': /(?=>)/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 6,
      'regex': /(?=\[)/g,
    },
    {
      'exit': true,
      'regex': /(?=])/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 6,
      'regex': /(?={)/g,
    },
    {
      'exit': true,
      'regex': /(?=})/g,
    }
  ],
  [ // state 11-15: %x(command)
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 12,
      'regex': /\(/g,
      'style': 'sh_normal'
    },
    {
      'next': 13,
      'regex': /</g,
      'style': 'sh_normal'
    },
    {
      'next': 14,
      'regex': /\[/g,
      'style': 'sh_normal'
    },
    {
      'next': 15,
      'regex': /\{/g,
      'style': 'sh_normal'
    },
    {
      'exit': true,
      'regex': /[)>\]}]/g,
      'style': 'sh_normal'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 11,
      'regex': /(?=\()/g,
    },
    {
      'exit': true,
      'regex': /(?=\))/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 11,
      'regex': /(?=<)/g,
    },
    {
      'exit': true,
      'regex': /(?=>)/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 11,
      'regex': /(?=\[)/g,
    },
    {
      'exit': true,
      'regex': /(?=])/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 11,
      'regex': /(?={)/g,
    },
    {
      'exit': true,
      'regex': /(?=})/g,
    }
  ],
  [ // state 16-20: %Q(string)
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 17,
      'regex': /\(/g,
      'style': 'sh_string'
    },
    {
      'next': 18,
      'regex': /</g,
      'style': 'sh_string'
    },
    {
      'next': 19,
      'regex': /\[/g,
      'style': 'sh_string'
    },
    {
      'next': 20,
      'regex': /\{/g,
      'style': 'sh_string'
    },
    {
      'exit': true,
      'regex': /[)>\]}]/g,
      'style': 'sh_string'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 16,
      'regex': /(?=\()/g,
    },
    {
      'exit': true,
      'regex': /(?=\))/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 16,
      'regex': /(?=<)/g,
    },
    {
      'exit': true,
      'regex': /(?=>)/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 16,
      'regex': /(?=\[)/g,
    },
    {
      'exit': true,
      'regex': /(?=])/g,
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    {
      'next': 16,
      'regex': /(?={)/g,
    },
    {
      'exit': true,
      'regex': /(?=})/g,
    }
  ]

 Ruby%記法対応 (ありえない正規表現版)

    { // %r(regexp)
      'next': 6,
      'regex': /%r(?=[\(<\[\{])/g,
      'style': 'sh_regexp'
    },
    { // %x(command), %w(array)
      'next': 8,
      'regex': /%[xWw](?=[\(<\[\{])/g,
      'style': 'sh_normal'
    },
    { // %(string), %s(symbol)
      'next': 10,
      'regex': /%[Qqs]?(?=[\(<\[\{])/g,
      'style': 'sh_string'
    },
  [
    {
      'exit': true,
      'regex': /$/g
    },
    { // from 7. next sibling exists.
      'next' : 7,
      'regex': /(?:\)[^\(\)]*(?=\()|>[^<>]*(?=<)|][^\[\]]*(?=\[)|}[^\{}]*(?={))/g,
      'style': 'sh_regexp'
    },
    { // from 7. no next sibling.
      'exit' : true,
      'regex': /(?:\)[^\)]*\)|>[^>]*>|][^\]]*]|}[^}]*})/g,
    },
    { // from 0. no nesting parenthesis.
      'exit' : true,
      'regex': /(?:\([^\()]*\)|<[^<>]*>|\[[^\[\]]*]|\{[^\{}]*})/g,
    },
    { // from 0. nesting parenthesis.
      'next' : 7,
      'regex': /(?:\([^\()]*(?=\()|<[^<>]*(?=<)|\[[^\[\]]*(?=\[)|\{[^\{}]*(?=\{))/g,
      'style': 'sh_regexp'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    { // from 7. next sibling exists.
      'next': 7,
      'regex': /(?:\)[^\(\)]*(?=\()|>[^<>]*(?=<)|][^\[\]]*(?=\[)|}[^\{}]*(?={))/g,
      'style': 'sh_regexp'
    },
    { // from 7. no next sibling.
      'exit': true,
      'regex': /(?:\)[^\)]*(?=\))|>[^>]*(?=>)|][^\]]*(?=])|}[^}]*(?=}))/g,
    },
    { // from 6. no nesting parenthesis.
      'exit' : true,
      'regex': /(?:\([^\()]*(?=\))|<[^<>]*(?=>)|\[[^\[\]]*(?=])|\{[^\{}]*(?=}))/g,
    },
    { // from 6. nesting parenthesis.
      'next': 7,
      'regex': /(?:\([^\()]*(?=\()|<[^<>]*(?=<)|\[[^\[\]]*(?=\[)|\{[^\{}]*(?=\{))/g,
      'style': 'sh_regexp'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    { // from 9. next sibling exists.
      'next' : 9,
      'regex': /(?:\)[^\(\)]*(?=\()|>[^<>]*(?=<)|][^\[\]]*(?=\[)|}[^\{}]*(?={))/g,
      'style': 'sh_normal'
    },
    { // from 9. no next sibling.
      'exit' : true,
      'regex': /(?:\)[^\)]*\)|>[^>]*>|][^\]]*]|}[^}]*})/g,
    },
    { // from 0. no nesting parenthesis.
      'exit' : true,
      'regex': /(?:\([^\()]*\)|<[^<>]*>|\[[^\[\]]*]|\{[^\{}]*})/g,
    },
    { // from 0. nesting parenthesis.
      'next' : 9,
      'regex': /(?:\([^\()]*(?=\()|<[^<>]*(?=<)|\[[^\[\]]*(?=\[)|\{[^\{}]*(?=\{))/g,
      'style': 'sh_normal'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    { // from 9. next sibling exists.
      'next': 9,
      'regex': /(?:\)[^\(\)]*(?=\()|>[^<>]*(?=<)|][^\[\]]*(?=\[)|}[^\{}]*(?={))/g,
      'style': 'sh_normal'
    },
    { // from 9. no next sibling.
      'exit': true,
      'regex': /(?:\)[^\)]*(?=\))|>[^>]*(?=>)|][^\]]*(?=])|}[^}]*(?=}))/g,
    },
    { // from 8. no nesting parenthesis.
      'exit' : true,
      'regex': /(?:\([^\()]*(?=\))|<[^<>]*(?=>)|\[[^\[\]]*(?=])|\{[^\{}]*(?=}))/g,
    },
    { // from 8. nesting parenthesis.
      'next': 9,
      'regex': /(?:\([^\()]*(?=\()|<[^<>]*(?=<)|\[[^\[\]]*(?=\[)|\{[^\{}]*(?=\{))/g,
      'style': 'sh_normal'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    { // from 11. next sibling exists.
      'next' : 11,
      'regex': /(?:\)[^\(\)]*(?=\()|>[^<>]*(?=<)|][^\[\]]*(?=\[)|}[^\{}]*(?={))/g,
      'style': 'sh_string'
    },
    { // from 11. no next sibling.
      'exit' : true,
      'regex': /(?:\)[^\)]*\)|>[^>]*>|][^\]]*]|}[^}]*})/g,
    },
    { // from 0. no nesting parenthesis.
      'exit' : true,
      'regex': /(?:\([^\()]*\)|<[^<>]*>|\[[^\[\]]*]|\{[^\{}]*})/g,
    },
    { // from 0. nesting parenthesis.
      'next' : 11,
      'regex': /(?:\([^\()]*(?=\()|<[^<>]*(?=<)|\[[^\[\]]*(?=\[)|\{[^\{}]*(?=\{))/g,
      'style': 'sh_string'
    }
  ],
  [
    {
      'exit': true,
      'regex': /$/g
    },
    { // from 11. next sibling exists.
      'next': 11,
      'regex': /(?:\)[^\(\)]*(?=\()|>[^<>]*(?=<)|][^\[\]]*(?=\[)|}[^\{}]*(?={))/g,
      'style': 'sh_string'
    },
    { // from 11. no next sibling.
      'exit': true,
      'regex': /(?:\)[^\)]*(?=\))|>[^>]*(?=>)|][^\]]*(?=])|}[^}]*(?=}))/g,
    },
    { // from 10. no nesting parenthesis.
      'exit' : true,
      'regex': /(?:\([^\()]*(?=\))|<[^<>]*(?=>)|\[[^\[\]]*(?=])|\{[^\{}]*(?=}))/g,
    },
    { // from 10. nesting parenthesis.
      'next': 11,
      'regex': /(?:\([^\()]*(?=\()|<[^<>]*(?=<)|\[[^\[\]]*(?=\[)|\{[^\{}]*(?=\{))/g,
      'style': 'sh_string'
    }
  ]

stateっぱい版の方が素性がいいのは一目瞭然ですね(;^_^A アセアセ… 書くのにかかった時間は数分の一から十分の一だし読み返して理解できるのもそっちだし

ありえない正規表現の方は SHJSのエンジン部分(sh_main.js)を全く利用していないところに複雑さの原因がありそう括弧の種類ごとに一つの stateが必要でなおかつそれが×3(=12)という stateっぱい版の見通しに後込みしてこっちの泥沼にはまりこんでいった感じ

尚どちらも似てるけどちっとだけ違うコドがほとんどの部分を占めている例えば stateっぱい版の state7-10state12-15state17-20の相違点は

      'next': 6, // state7-10
      'next': 11, // state12-15
      'next': 16, // state17-20

の部分だここを

      'next': 'caller'

と書ければ共通化できるのに……またstate6state11state16の違いは

      'style': 'sh_regexp' // state6
      'style': 'sh_normal' // state11
      'style': 'sh_string' // state16

の部分だけここを

      'style': 'inherit'

と書ければ共通化できるのに……

それなら追加部分のサイズが今のほぼ 1/3になったものを