4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ace.js のシンタックスハイライターを自作する(実装編)

Last updated at Posted at 2021-03-13

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 では、構文規則を厳密に定めることで、エラー表示など様々な恩恵を得ることができますが、この記事では、色付けのみ行います(すごく大変になるので)。ここで色付けするものは、macrocons などのキーワードと、上の規則には載っていませんが、'name で定義される変数です。

シンタックスハイライト規則を定義する

どのように色付けするのかが決まったので、実際に rwhile_highlight_rules.js にシンタックスハイライト規則を記述します。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 シンタックスハイライト機能のソースコードはこちらから見られます。

参考サイト

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?