こんにちは。筆者はHTMLでプログラムを書けるプログラミング言語、その名も「The HTML Programming Language (THPL)」を作りました。なので、明らかにHTMLはプログラミング言語です。以下では、THPLについて説明します。
最初のプログラム
HTMLプログラミング言語では、Hello, world!プログラムは次のように書くことができます。HTMLプログラムを実行するには、HTMLファイルをブラウザで開きます。そうするだけでHTMLプログラムが実行され、出力が表示されます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>My First HTML Program</title>
<script src="https://unpkg.com/the-html-programming-language@0.1.0/browser.min.js"></script>
</head>
<body>
<p><output>Hello, world!</output></p>
</body>
</html>
順に説明していきましょう。<body>
までの以下の部分はおまじないです。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>My First HTML Program</title>
<script src="https://unpkg.com/the-html-programming-language@0.1.0/browser.min.js"></script>
</head>
<body>
ただし、<title></title>
の間の部分は好きに書くことができ、プログラムのタイトルを表します。分かりやすい名前を付けてあげましょう。また、script
という部分にある@0.1.0
というのはTHPLのバージョンを表します。プログラミング言語自体のバージョンを常に明示的に指定してあげることで、互換性などの問題が生じにくくなっています。
また、プログラムの最後の2行についてもおまじないです。ここの文言は常に固定です。
</body>
</html>
よって、このプログラムの本体は以下の1行となります。
<p><output>Hello, world!</output></p>
ここに書かれているのはP文であり、これは<p>式</p>
という構文を持ちます。意味は、中の式を実行することです。JavaScriptなどと同様にHTMLでは文は結果を持たず式は結果を持ちます。P文では、中の式を実行した結果は使われません。JavaScriptでいうところの 式;
に相当する文ですね。
P文の中にあるのはOUTPUT式であり、これは<output>式</output>
という構文を持ちます。意味は、中の式を評価し、その結果を出力します。OUTPUT式の結果は中の結果そのままです。上の例ではHello, world!
という文字列を出力しています。御察しの通り、Hello, world!
というプレーンテキストもHTMLでは式として扱われます。要するに文字列リテラルです。
変数を定義する
HTML言語では変数を使うことができます。変数を定義するにはDL文を用います。DL文は次のような構文を持ちます。
<dl>
<dt>変数名1</dt>
<dd>式1</dd>
<dt>変数名2</dt>
<dd>式2</dd>
<!-- ... -->
</dl>
このように、DL文の中では<dt>
と<dd>
という構文がペアになって現れます。dt
で示された名前の変数が作られ、その中身はdd
に書かれた式の評価結果となります。
また、変数の中身を得るためには<var>変数名</var>
という構文のVAR式を用います。
例(以下の例ではおまじない部分は省略します):
<dl>
<dt>str1</dt>
<dd>Hello</dd>
<dt>str2</dt>
<dd>world</dd>
</dl>
<p>
<output><var>str1</var>, <var>str2</var>!</output>
</p>
関数を定義する
HTMLではSECTION文を用いて関数を宣言できます。構文は<section title="関数名">関数本体</section>
です。また、関数呼び出しにはABBR式を用います。こちらは<abbr title="関数名">引数</abbr>
という構文です。引数を複数渡す場合は<br>
で区切ります。
<section title="say">
<p>
<output><slot name="0"></slot>, <slot name="1"></slot>!</output>
</p>
</section>
<p>
<abbr title="say">Hello<br />world</abbr>
</p>
この例ではsay
関数にHello
とworld
という2つの関数を渡しています。関数内では、受け取った引数はSLOT式を用いて参照することができます。最初の引数が0
、次の引数が1
……という名前を指定します。また、最初の引数は<slot></slot>
というようにname
構文を省略することができます。
また、関数名というのは実は変数名として解釈されます。上のプログラムでは、SECTION文は実際にはtitle
という名前の変数を作りその中に関数オブジェクトを格納します。ABBR式では、title
構文で関数を呼び出す方式のほかに、ABBR式の内部で、VARで取得した関数オブジェクトを指定する方法もあります。この場合、関数オブジェクトは引数よりも前に書かれ、関数オブジェクトと引数の間はやはり<br>
で区切られます。つまり、上のプログラムの関数呼び出し部分は次のように書くことも可能です。
<abbr>
<var>say</var><br />Hello<br />world
</abbr>
なお、関数の戻り値は関数内でP文の代わりにFOOTER文を実行することで指定できます。FOOTER文の中に書かれた式が実行され、その結果が関数の返り値となります。
算術演算
HTMLでは算術演算も可能ですが、あまり得意ではなくやや複雑なプログラムを書く必要があります。HTMLには算術演算用の演算子のようなものはなく、各演算が関数として提供されています。それらの関数はmath名前空間から取得する必要があります。math名前空間にアクセスするには、次のようなmath式を用います。次の例は、加算を表すplus
関数をmath名前空間から取得する例です。
<math><plus /></math>
このような関数は上述のABBR式を用いて呼び出すことができます。
<p>
<output>1 + 2 + 3 = <abbr>
<math><plus /></math><br>
1<br>2<br>3
</abbr></output>
</p>
<!-- 1 + 2 + 3 = 6 と表示される -->
HTMLの値には文字列と数値がありますが、算術演算の結果は数値です。一方で、HTMLプログラムに書かれた1
, 2
, 3
といったプレーンテキストは文字列として扱われます。これらが算術演算の関数に渡される際は自動的に数値に変換されます。明示的に数値に変換したい場合は、文字列から数値への変換を表すMETER式を用いて次のようにできます。
<p>
<output>1 + 2 + 3 = <abbr>
<math><plus /></math><br>
<meter>1</meter><br><meter>2</meter><br><meter>3</meter>
</abbr></output>
</p>
条件分岐
HTMLでの条件分岐はRUBY式として提供されています。RUBY式はやや特殊な構文を持ち、JavaScriptで言うところのswitch
に似た挙動をします。RUBY式は次のような構文を持ちます。
式
<ruby>
条件式1
<rt>分岐式1</rt>
条件式2
<rt>分岐式2</rt>
<!-- ... -->
条件式n
<rt>分岐式n</rt>
<rt>else分岐 (任意)</rt>
</ruby>
このように、RUBY式は条件分岐の対象となる式に後置することで形成されます。ここではまず式
が評価され、次に条件式1
が評価されて両者が一致するかどうか確かめられます。一致した場合、分岐式1
が評価され、その結果がRUBY式の結果となります。一致しなかった場合、次に条件式2
が評価され、式
の結果と条件式2
の結果が一致すれば分岐式2
が評価され……のように進行します。
RUBY式には、一番最後に条件式を伴わない<rt>
構文を書くことができ、これはelse分岐です。これまでのどの条件にもマッチしなかった場合にこの分岐が実行されます。else分岐が無いRUBY文でどの条件にもマッチしなかった場合は、結果はnullとなります。
例えば、与えられた数値が偶数なら"even"
を、奇数なら"odd"
を返すodd_even
関数は次のように定義できるでしょう。
<section title="odd_even">
<footer>
<abbr>
<math><rem /></math><br />
<slot></slot><br />
2
</abbr>
<ruby>
<meter>0</meter>
<rt>even</rt>
<meter>1</meter>
<rt>odd</rt>
</ruby>
</footer>
</section>
<p>
<output>15 is <abbr title="odd_even">15</abbr>.<wbr /></output>
</p>
<p>
<output>-2 is <abbr title="odd_even">-2</abbr>.<wbr /></output>
</p>
ここでのポイントは、RUBY式の条件分岐に先ほど紹介したMETER式が使われている点です。RUBY式の条件分岐の対象となっているのはその前のABBR式ですが、ここではmath名前空間から取り出したrem関数を実行しているので、その結果は数値です。RUBY式では文字列と数値の間の暗黙の変換は行われないため、このように条件として数値を与えないとマッチしてくれません。HTML初心者が引っかかりがちな罠の一つですので気をつけましょう。
ちなみに、この例では密かに<wbr />
という構文のWBR式が登場しています。これは改行文字を表す式です。
実践編: FizzBuzz
HTMLの言語機能は以上です。実践編として、FizzBuzzを書いてみました。HTMLの力試しをしたい方は自力で書いてみましょう。
ヒントとしては、ループの言語機能がありませんので、再帰関数を用いることになります。
以下がHTML言語によるFizzBuzzの実装です。1から100までループします。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>FizzBuzz</title>
<script src="https://unpkg.com/the-html-programming-language@0.1.0/browser.min.js"></script>
</head>
<body>
<section title="fizzbuzz">
<dl>
<dt>rem3</dt>
<dd>
<abbr>
<math><rem /></math><br />
<slot></slot><br />3
</abbr>
</dd>
<dt>rem5</dt>
<dd>
<abbr>
<math><rem /></math><br />
<slot></slot><br />5
</abbr>
</dd>
<dt>text</dt>
<dd>
<abbr>
<math><eq /></math><br /><var>rem3</var><br /><meter>0</meter></abbr
><abbr>
<math><eq /></math><br /><var>rem5</var><br /><meter>0</meter></abbr
><ruby>
<span>00</span>
<rt><slot></slot></rt>
<span>10</span>
<rt>Fizz</rt>
<span>01</span>
<rt>Buzz</rt>
<span>11</span>
<rt>FizzBuzz</rt>
</ruby>
</dd>
</dl>
<p>
<output><var>text</var><wbr /></output>
</p>
<footer>
<slot></slot>
<ruby>
<meter>100</meter>
<rt><span></span></rt>
<rt
><abbr title="fizzbuzz">
<abbr
><math><plus /></math><br /><slot></slot><br />1</abbr
>
</abbr></rt
>
</ruby>
</footer>
</section>
<p>
<abbr title="fizzbuzz"><meter>1</meter></abbr>
</p>
</body>
</html>
おおよそこれまで解説した知識で読み解くことができますが、一つだけ新たな要素としてSPAN式が登場しています。これは基本的には括弧( )
のようなもので、中の式を評価してそのまま返すだけの式です。ただ、HTML言語では特徴的な使われ方をされることがあります。
まず、<span></span>
のような空のSPAN式が許可されています。これは空文字列を返す式となります。式を書くべき所に何も書かないのは構文エラーとなるので、何もしたくないが式を書く必要がある場合に重宝されます。
また、よく見ると以下の箇所でRUBY式の条件式としてSPAN式で囲まれた文字列が使用されています。
<ruby>
<span>00</span>
<rt>...</rt>
</ruby>
これはHTMLパーサーの特徴的な挙動によるものです。HTMLパーサーは空白文字だけからなるプレーンテキストを無視しますが、次のようにSPANが無いと、RUBY文の条件式が"(改行) 00(改行) "
のような文字列であると認識され、本来"00"
にマッチさせたいところマッチしなくなってしまいます。
<ruby>
00
<rt>...</rt>
</ruby>
SPAN式を使うことで<ruby>
と<span>
の間のテキストが文字列の一部ではなく無視するべき空白であるとパーサーに認識されます。SPAN式はこのような用途で使うこともできます。
まとめ
皆さんもHTMLで楽しいプログラミングライフを!
HTML言語への機能追加提案やプルリクエストなども歓迎です。
Q&A
Q. HTML中に <script>
があるので、HTMLがプログラミング言語というわけではないのでは?
A. それはおまじないって書いてあるじゃないですか。
メタ的な話をすると、これは「ブラウザで文書を開くと自動的にHTMLプログラムが実行される」というギミックのためだけに書かれるおまじないであり、HTMLがプログラミング言語であることの本質ではありません。実際、リポジトリにあるテスト用のHTMLコードたちを見ると、<script>
が無くてもHTMLプログラムの実行に支障がないことが分かります。
Q. TypeScriptでインタプリタが実装されているならHTMLがプログラミング言語というのは嘘では?
A. Rubyのインタプリタは主にC言語で実装されています。
Q. これはHTMLの文法を使った別の言語であり、HTMLがプログラミング言語というわけではないのでは?
A. たしかに。