Ace.js は、Webページに簡単に埋め込むことができるテキストエディタです。様々なプログラミング言語に対して、その記述をサポートする機能(シンタックスハイライトや自動インデントなど)が用意されており、Webページ上でのプログラミング用エディタの作成に適しています。
この記事の目的
Ace.js には、様々な言語をサポートする機能が既に用意されています。しかし、もちろんすべての言語に用意されてはおらず、サポートに含まれない言語も存在します。特に、研究目的で作られたプログラミング言語のような、マイナーな言語はサポートされていません。ただ、Ace には言語サポート機能を自作できる仕組みが用意されています。この記事では、R-WHILE というプログラミング言語に対して、シンタックスハイライト機能を作成します。
実装編
環境構築編では、R-WHILEのシンタックスハイライト機能の実装に必要な mode-rwhile.js
を作成するための環境を整えました。実装編では、rwhile_highlight_rules.js
にシンタックスハイライト規則を記述し、実際に ace テキストエディタ上で R-WHILE のプログラムが色付けされるようにします。
シンタックスハイライト機能を実装する
R-WHILE の構文規則
R-WHILE の構文規則は次のようになります。
Variables ∋ X, Y ::= X0 | X1 | ...
Expressions ∋ E, F ::= X | d | cons E F | hd E | tl E | =? E F
Patterns ∋ Q, R ::= X | d | cons Q R
Commands ∋ C, D ::= X ^= E | Q <= R | C; D
| if E then C else D fi F | from E do C loop D until F
Macro ∋ M ::= macro X ( X, ..., X ) C
Programs ∋ P ::= M* read X; C; write Y
Ace では、構文規則を厳密に定めることで、エラー表示など様々な恩恵を得ることができますが、この記事では、色付けのみ行います(すごく大変になるので)。ここで色付けするものは、macro
や cons
などのキーワードと、上の規則には載っていませんが、'name
で定義される変数です。
シンタックスハイライト規則を定義する
どのように色付けするのかが決まったので、実際に rwhile_highlight_rules.js
にシンタックスハイライト規則を記述します。rwhile_highlight_rules.js
は次のようになります。
...
var RwhileHighlightRules = function() {
// キーワード
var keyword = ("cons|hd|tl|if|fi|from|until|show|then|else|do|loop|read|write|macro");
// 組み込み定数
var builtinConstants = ("nil");
var keywordMapper = this.createKeywordMapper({
"keyword": keyword,
"constant.language": builtinConstants,
}, "identifier");
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
this.$rules = {
"start": [
{
token: "comment", // multi line comment
regex: "\\(\\*",
next: "comment"
}, {
token: keywordMapper, // String, Array, or Function: the CSS token to apply
regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b", // String or RegExp: the regexp to match
}, {
token: "keyword.operator",
regex: "\\^=|<=|=\\?"
}, {
token: "variable",
regex: /'(?!\s|\.|;|,|\))/,
next: "variable"
}
],
"variable": [
{
token: "variable",
regex: /[a-zA-Z0-9](?=\s|\.|;|,|\))/,
next: "start"
}, {
token: "variable",
regex: /^\s*/,
next: "start"
}, {
defaultToken: "variable"
}
],
"comment": [
{
token: "comment", // closing comment
regex: "\\*\\)",
next: "start"
}, {
defaultToken: "comment"
}
]
};
}
解説
- 初期状態が
start
で、そこから条件(regex)に従ってnext(variable
,comment
)に遷移するオートマトンです。 -
token
はCSSに関わります。例えばtoken:"comment"
の場合、HTMLは以下のようになります。
<span class="ace_support ace_comment"> 文字列 </span>
ace_comment
クラスに対応する色が読み込むテーマのCSSで定義されています。また、各テーマにおいてtextmateというテキストエディタの命名規則に従う限り、対応するカラーが定義されています。なので、Visual Studio CodeやAtomのシンタックスハイライト拡張機能を作るの記事を参考に、各状態のクラスを決めました。
結果
環境構築編の方法でmode-rwhile.js
を作成し、ace.js
で読み込むと、正しく色付けされていることがわかります。
補足
- R-WHILE シンタックスハイライト機能のソースコードはこちらから見られます。