HyperTalk

**HyperTalk**（ハイパートーク）はHyperCardに用いられるプログラミング言語。

## 概要
インタプリタ方式を採用するスクリプト言語で、その文法は英語に近く、初心者にもなじみやすい。

HyperCard開発チームのダン・ウィンクラーがデザインした。拡張性を考え、XCMD（外部コマンド）とXFCN（外部関数）という機構も用意され、プラグイン的に機能を追加可能である。

HyperCardがオブジェクト指向環境の為、それぞれのスクリプトは、HyperCardのスタック上のオブジェクトであるカードやボタン、フィールドなどのパーツ（オブジェクト）に付随する。

## 例
**簡単な例**

```applescript
on mouseUp
   Beep
   put sqrt(2+4) into card field "計算結果" 
 end mouseUp
```


この例は、このスクリプトが付加されているオブジェクト（パーツ）の上で、
マウスがクリックされたら、ビープ音を鳴らし、
2と4を加えた結果の平方根を、このオブジェクトが乗っているカードに存在する『計算結果』という名のフィールドに送る。
mouseUpとなっているのは、マウスクリックのチャタリングを防止するために、クリック後のアップを取り出している。

## 概念

* 一連の処理は、スタック、バックグラウンド、カード、ボタン、フィールドのプロパティである**スクリプト**に書かれる。
* 処理内容は、`on «命令名/メッセージ名»`〜`end «命令名/メッセージ名»` または `function «関数名»` 〜 `end «関数名»` に挟まれた行内に記述する。
** ボタンやフィールドからコールされた命令や関数は、「ボタン/フィールド」→「カード」→「バックグラウンド」→「スタック」→「HyperCard組み込み」のように局所から徐々に大域となるような経路で探索される。例えば、ボタンとスタックで同名で定義されている命令をボタンからコールした場合、ボタンで定義した方の命令で処理される。
** `on`～`end` 、`function`～`end` で挟まれていない内容は無視される。後述のキーワードが含まれる場合などでは、文法エラーになることもある。
* 処理を示す行は、必ず**命令**（`answer`、`go`、`put` 等）か**キーワード**（`if`、`repeat`、`do` 等）で始まる。
** 関数や、単なる数値や文字列で文を始めることはできない。この点、HyperTalkでは命令と関数には明確な区別が存在する。
** HyperTalkでいうキーワードは、同名の命令や変数を定義（オーバーライド）することができない予約語のこと。主に制御構造を示すキーワードを文頭に置くことができる。先述の`on`、`function`、`end` もキーワードに該当する。
** なお、先頭にインデントを示す空白を入れることは可能で、スクリプトエディタでは`if`や`repeat` の深さに応じて自動的にインデントが挿入される。

```applescript
on mouseUp
  answer "次のカードに進みますか？" with "はい" or "いいえ"
  if it = "はい" then
    go next
  end if
end mouseUp
```

* パラメータに対する計算処理（`sin`、`max`、`random`等）や、システムの状態等を取得する処理（`time`、`date`、`systemVersion` 等）を**関数**と呼ぶ。関数は `the «関数名» of «パラメータ»` または `«関数名»(«パラメータ»)` の形で呼び、命令や関数、キーワードのパラメータ内で使用することができる。
** 組み込み関数は両方の記法でコールできる。ただし、前者の方が非組み込み関数を参照しない分、高速である。
** 非組み込み関数は後者の記法でコールする必要がある。
* ボタンやフィールド、カード等のオブジェクトが持つ属性（`id`、`name`、`rectangle`、`location`、`highlight` 等）を**プロパティ**と呼ぶ。プロパティを設定する場合は`set`命令を用いる（変更不可のプロパティも存在する）。プロパティを参照する場合は `the «プロパティ名» of «オブジェクト名、オブジェクトID等»` の形で記述し、関数呼び出しに似ている。

```applescript
on mouseUp
  if the highlight of card button "時刻" = true then
    set the name of card button ID 1 to the time
  end if
  if the highlight of card button "日付" = true then
    set the name of card button ID 1 to date() -- 低速な関数のコール方法である
  end if
end mouseUp
```

* 値を内部に含むものを**コンテナ**と呼ぶ。変数、メッセージボックス、ボタン、フィールドなどがコンテナに該当する。`put` 命令によって値を設定することができ、命令や関数、キーワードのパラメータとして渡した場合は、コンテナ名として記載した部分が値で置き換えられる。
** コンテナで保持する値には型は存在しない（文字列型のみ）。算術計算に使用した場合は自動的に数値に変換され、ブール値は `true`、`false` の文字列で扱う。変換できない値の場合は実行時エラーが発生する。

```applescript
on mouseUp
  put card field "augend" into value1
  put card field "addend" into value2
  put value1 + value 2 into sum
  put sum into message box -- 「into message box」は省略しても機能する
  if sum < 0 then
    answer "結果がマイナスになりました。"
  end if 
end mouseUp
```

* 変数にはグローバル変数とローカル変数がある。グローバル変数として使用する前には `global` キーワードで宣言する必要がある。ローカル変数には宣言は必要ない。
** いずれも、値を代入するには `put` 命令の値の代入先として指定する。ただし `it` 変数は `answer` 命令や `get` 命令等の結果の格納先として暗黙的に使用される。
* 他、文法に関する細かい仕様
** 修飾子の多くには短縮形が用意されている。例えば `card` は `cd`、`background` は `bg`、 `button` は `btn`、 `field` は `fld` と短縮可能。
** 大文字と小文字は区別されない。`ID` は `id` 、 `on mouseUp` は `On MouseUp` と記述しても同じ動作をする。また、 `"hypercard" = "HyperCard"` の評価値は `true` である。
** 行の区切り文字は改行である。1つの処理を複数行で記述したい場合は、行末に `~`（チルダ）を記述する。
** `--` から改行までは、コメントとして扱われる。
** `char`、`item`、`word`、`line`のインデックス指定や、オブジェクト番号による`button`、`field`、`card`、`background` の指定には、インデックス番号を後置する記法と、序数詞を前置する記法がある。序数詞は`first`～`tenth`の他に、特殊なものとして`last`、`middle`、`any`が使用できる。

```applescript
-- インデックス番号を後置する記法
get char 1 of theString
go to card 2

-- 序数詞を前置する記法
get first char of theString
go to second card
```


## 他言語との比較
### C言語との比較
ここでは、初心者が初めて学ぶ言語として広く浸透しているC言語を例に比較する。

*C言語は文章の区切りとしてセミコロンを使い、比較的自由な表記が可能であるが、スクリプト言語であるHyperTalkは改行が文章の区切りとなるため、文章の途中で改行するとエラーになる。例えば「put "Hello, World!" into A」と表記すべきところを「put "Hello,（改行） World!" into A」と表記するとエラーになる。
*変数宣言や関数宣言が不要であり、また代入する値（整数、小数、文字列）を意識せずに変数に代入できる。
**例えば**A**という変数に「**10**」という整数が入っていたとしても、新たに宣言することなく「**0.5**」という小数や「**ten**」という文字列を入れることが出来る。
**ただし、文字（列）が入った変数に整数を加算する…といった動作はエラーとなり動かないため注意が必要である。尚、文字列と文字列、もしくは文字列と数値を繋げる記号は「&」である。
**また、数値間での型違い（整数、小数、符号付き・無し）が無いため、例えば、「0.5*4」「0.5+1.5」といった小数を元にした計算でも、結果が整数となる物は強制的に整数となり（小数点以下が無くなった状態で）代入される。一方、C言語では最も上位の型に変換され、最終的に代入する変数の型で決定される。このため、例えば「float型 = double型*int型」といった場合は最終的にfloat型に丸められた値が代入される（詳しくは型変換を参照）。
**変数の適用範囲もC言語とほぼ同じで、例えばある関数で使われた変数は呼び出した別の関数では適用されない。ただし、グローバル変数はこの限りではない。
*変数の代入・取り出しに関しては全て「put」命令を使うことになる。
**例えばC言語での「**A = B+C**」をHyperTalkで書くと「**put B+C into A**」となり、C言語とは順序が逆になる。
**また、「put」はinto以下を指定しなければ標準出力（**メッセージボックス**と呼ばれる小さい文字列表示用のウィンドウ）へ出力するほか、フィールド等へオブジェクトへの代入も可能（詳しくはHyperCardを参照）。
**ちなみに「=」はHyperTalk上では等号の意味を持ち、代入には使えない（C言語での「==」に相当）。
*記号を使った演算子の多くは、より直感的な表記や英単語で対応している。
**例えば、C言語における「%」「!」「&&」「||」は、HyperTalkでは「mod」「not」「and」「or」に対応する。
**ビット演算子、アドレス演算子等は一切存在しない。
*配列の概念が存在しないが、**文節**（word）、**行**（line）、**ある任意**（標準ではカンマ(,)であるがスクリプト内で変更可能）**の文字**（item）、**文字単位**（char）での区切りで代入・取り出しが標準で可能である。ただし、日本語に関する「word」の処理に関しては動作がアバウトであるため、カンマで区切って「item」を使い処理することが望ましい。
**これを使うことによって配列と同じような処理を行える。例えば、次の二つのコードはほぼ同様の処理をしている（便宜上「main()」や「on openstack」を省略する）。

**HyperTalk**

```applescript
put "10,20,30,40"&return&"100,200,300,400" into array -- 「&return&」は改行を意味する
 put item 2 of line 1 of array + item 2 of line 2 of array into A
 answer "A="&A -- 「A=220」とダイアログに表示
```


補足: より正確には、`&return&` は定数 `return` の内容（改行）と前後の文字列を `&` 演算子で連結することを意味する。

**C言語**

```c
int A,array[][]=;
A = array[0][1] + array[1][1];
printf("A=%d",A);
```


また、C言語よりも比較的自由に文字列処理が可能である。


```applescript
put "ABC,DEF,GHI"&return&"GHI,DEF,ABC" into array
 put item 2 of line 1 of array & item 2 of line 2 of array into A
 answer A -- 「DEFDEF」とダイアログに表示
```


*C言語はポインタを使ったメモリの動的割り当てやシフト演算といったハードウェアレベルでのアクセスが可能であるが、（スクリプト言語であることも関係しているが）HyperTalkはそういった処理は標準では不可能である。
**ただし、サウンド処理や画像処理などOSレベルにアクセスする処理については前述のXCMDやXFCNを使えば可能である。
*そのほか、繰り返しや条件分岐においてはC言語とほぼ同じ処理が可能である。
**例えば、繰り返しに関してはC言語での「**while(1){～}**」（無限ループ）は「**repeat ～ end repeat**」、「**for(i=1;i<=10;i++){～}**」は「**repeat with i = 1 to 10 ～ end repeat**」という風に、条件分岐は「**if(i==10){～}**」は「**if i=10 then ～ end if**」という風に記述すれば同様の処理が可能。

### Javaとの比較
次に、代表的なオブジェクト指向言語であるJavaを例に比較する。

*ボタン、フィールド、カード等はオブジェクト的な性質を持つ。
** プロパティ（属性）を持つ。プロパティに値を設定するには `set` 命令を使用する。
**マウスやキーボード等によるイベントを受け取る。先述の  `on mouseUp` ～  `end mouseUp` 内に処理内容を記述したスクリプトは、マウスが離されたイベントを受け取る例である。
*「クラス」「インスタンス」「継承」等の、多くのオブジェクト指向言語に存在する概念は、HyperTalkでは存在しない。
**「ボタン」をクラス、「カード上に作成したボタンのうち1つ」をインスタンス、「チェックボックス」や「ラジオボタン」をサブクラスと考えることはできるが、HyperTalkではそのような呼び方はしない。
** 「チェックボックス」「ラジオボタン」等のボタンの種類は、ボタンの `style` プロパティで判別する。
**独自のクラスを作成することはできない。クラスを宣言する構文そのものが存在しない。
* 文字列操作を行う機能は比較的充実しているが、Javaとは性質が異なる。
** 一致判定（`=`、`is`）、連結（`&`、`&&`）、含有判定（`contains`、`is in`）のための演算子が用意されている。
** 文字数取得（`length(《文字列》)`、`number of chars in 《文字列》`）、特定文字列の出現位置取得（`offset(《検索文字列》,《被検索文字列》)`）は関数を使用して行うことができる。
** 文字単位（`char`）や、区切り文字（`item`、`word`、`line`）を使用したインデックス指定により、文字列の一部の抽出、変更などの処理を比較的柔軟に行うことができる。
** 一方で、文字列置換や、正規表現を使用した文字列の含有判定などの機能は標準では用意されていない。

*ポインタ型が存在しないため、カード上、またはバックグラウンド上のボタンやフィールドを参照するには、オブジェクト名、オブジェクト番号、オブジェクトIDを利用することになる。

なお、HyperCardではボタンやフィールド等の配置はスタックの保存データから自動的にロードされるものであるため、オブジェクトの生成に関してはJavaとの単純な比較ができない。

**HyperTalk**

```applescript
put the highlight of card button "I Agreed" into agreed
  set the enabled of card button "OK" to agreed
```


**Java**

```java
// agreedCheckBox, okButton に値が入っているとする
  boolean agreed = agreedCheckBox.getState();
  okButton.setEnabled(agreed);
```


## 脚注