# 字句構造

ソースファイルは**トークン**（識別子、キーワード、リテラル、ラベル、記号）に分割されます。空白とコメントはトークンを区切るだけで、それ以外の意味はありません。`.kis` と `.kix` は同じ字句解析器を使い、`.kix` ファイルの[フォーム](./forms.md)も同じトークンで組み立てられます。

## ソーステキスト {#source-text}

- ソースファイルは UTF-8 です。UTF-8 として正しくないファイルは読み込めず、ファイルを読み込めないモジュールは見つからないものとして報告されます（[`E1002`](../../diagnostics/modules.md#e1002)）。
- バイトオーダーマーク（U+FEFF）は使えません。予期しない文字として扱われます。
- 行末は LF または CRLF です。どちらも空白です。

## 空白 {#whitespace}

空白となる文字は、スペース（U+0020）、タブ（U+0009）、ラインフィード（U+000A）、垂直タブ（U+000B）、フォームフィード（U+000C）、キャリッジリターン（U+000D）、ネクストライン（U+0085）、左から右へのマーク（U+200E）、右から左へのマーク（U+200F）、行区切り（U+2028）、段落区切り（U+2029）です。これは Unicode の `Pattern_White_Space` で、Rust と同じ集合です。全角スペース U+3000 などそれ以外の Unicode の空白は空白ではなく、文字列リテラルの外ではエラーになります。

## コメント {#comments}

| 形 | 意味 |
| -- | ---- |
| `// …` | 行コメント。行末まで |
| `/* … */` | ブロックコメント。入れ子にでき、`/* a /* b */ c */` は 1 つのコメントです |
| `/// …` | 後に続くアイテムのドキュメントコメント。エディタのホバーに表示されます |
| `//! …` | 慣習として、ファイル先頭でそのモジュールを説明します |

コメントは任意の 2 つのトークンの間に置けます。フォームの中でも同じです。ドキュメントコメントはちょうど 3 つのスラッシュで始まる行コメントで、`////` は普通のコメントです。`//!` と `/** … */` はツールにとって特別な意味を持ちません。閉じる `*/` のないブロックコメントはエラーです。

```kis
//! The characters of the game.

/// Hanako's entity on the screen.
pub const HANAKO: EntityId = EntityId(216); /* ids below 1000 are reserved /* by us */ */
```

## 識別子 {#identifiers}

識別子は Unicode の文字クラス `XID_Start` の文字か `_` で始まり、`XID_Continue` の文字が 0 個以上続きます。ASCII 以外の識別子も使えます。

```kis
const 花子: EntityId = EntityId(216);
```

- `_` 単独は識別子ではありません。パターンのワイルドカードであり、型のプレースホルダです。
- 識別子は[厳格キーワード](#strict-keywords)であってはなりません。生識別子（`r#match`）はありません。
- 識別子は書かれたとおりに比較されます。コンパイラは Unicode の正規化をしません。

## キーワード {#keywords}

### 厳格キーワード {#strict-keywords}

次の語は常にキーワードで、名前には使えません。

```text
as        break     const     continue  crate     else      enum      false
fn        for       if        impl      in        let       loop      match
mod       mut       pub       return    self      Self      static    struct
super     trait     true      type      use       while
```

このうち 2 つは限られた用途にしかありません。

- `as` はインポートの別名（`use a::b as c;`）に使います。キャスト演算子としても構文解析はされますが、常にエラーです（[`E2019`](../../diagnostics/types.md#e2019)）。[変換](./numbers.md#conversions)を参照してください。
- `trait` はトレイトを宣言しますが、それができるのは標準ライブラリだけです（[`E1012`](../../diagnostics/modules.md#e1012)）。

### 文脈キーワード {#contextual-keywords}

次の語は特定の位置でだけキーワードになり、それ以外では普通の識別子です。

| 語 | キーワードになる位置 | 例 |
| -- | -------------------- | -- |
| `pushdown` | `fn`（関数または関数ポインタ型）の直前、または `Fn(` の直前 | `pushdown fn visit()`、`pushdown Fn(Map)` |
| `scene` | 型の中の `fn` の直前 | `scene fn() -> Answer` |
| `Fn` | 型の中の `(` の直前 | `Fn(u32) -> bool` |

### キーワードではない Rust のキーワード {#rust-keywords-that-are-not-keywords}

`async`、`await`、`dyn`、`extern`、`move`、`ref`、`unsafe`、`where`、`yield` と Rust の予約語（`abstract`、`box`、`macro` など）は、Kagari では普通の識別子です。これらに対応する機能はありません。[Rust との違い](./rust-differences.md)を参照してください。

## リテラル {#literals}

| リテラル | 例 | 型 |
| -------- | -- | -- |
| 整数 | `0`、`1_000`、`0xFF`、`0o17`、`0b1010`、`5u8`、`0x1Fi64` | 整数型。[整数リテラル](./numbers.md#integer-literals)を参照 |
| 十進数 | `0.5`、`1.0`、`12.25`、`1_000.000_1` | `Decimal` |
| 文字列 | `"Mio"`、`"line\nbreak"`、`"\u{3042}"` | `Text` |
| 真偽値 | `true`、`false` | `bool` |

文字リテラル、バイトリテラル、バイト文字列、生文字列、浮動小数点リテラルはありません。

### 整数リテラル {#integer-literals}

整数リテラルは次の要素からなります。

1. 省略可能な基数接頭辞。`0x`（16 進）、`0o`（8 進）、`0b`（2 進）で、小文字で書きます。
2. その基数の数字。区切りとして `_` をどこにでも置けます。数字は 1 つ以上必要です。
3. 型を固定する省略可能な接尾辞。`u8`、`u16`、`u32`、`u64`、`u128`、`usize`、`i8`、`i16`、`i32`、`i64`、`i128`、`isize` のいずれかです。

16 進リテラルでは、接尾辞は 16 進数字でも `_` でもない最初の文字から始まります。それ以外では、10 進数字でも `_` でもない最初の文字から始まります。数字のないリテラル、基数の範囲外の数字（`0b102`）、上記以外の接尾辞はエラーです。値は 128 ビットに収まらなければなりません。

接尾辞は貪欲に読まれるため、`1e5` は不正な接尾辞 `e5` の付いた整数 `1` になり、`0X1F` は不正な接尾辞 `X1F` の付いた `0` になります。マイナス記号はリテラルの一部ではありません。`-128i8` は `128i8` に演算子 `-` を適用したもので、符号を反転した値が型に収まるのでコンパイラは受け付けます。

### 十進数リテラル {#decimal-literals}

十進数リテラルは、数字、`.`、再び数字からなります。それぞれの部分の最初の数字の後には区切りの `_` を置けます。どちらの部分にも数字が必要で、`1.` や `.5` は十進数リテラルではありません。指数も接尾辞もありません。十進数リテラルの型は [`Decimal`](./numbers.md#decimal) です。

次の 2 つは十進数リテラルに見えますが、そうではありません。

- `.` の直後の数はタプルのインデックスに分割されます。`pair.0.1` は `pair` のフィールド `0` のフィールド `1` です。
- `..` の直後の数は分割されません。`0..1.5` は `1.5` までの範囲です。

### 文字列リテラル {#string-literals}

文字列リテラルは二重引用符で囲んだテキストです。複数行にまたがってもよく、その改行は値の一部になります。バックスラッシュはエスケープを始めます。

| エスケープ | 文字 |
| ---------- | ---- |
| `\n` | ラインフィード |
| `\r` | キャリッジリターン |
| `\t` | タブ |
| `\\` | バックスラッシュ |
| `\"` | 二重引用符 |
| `\0` | U+0000 |
| `\u{…}` | 1〜6 桁の 16 進数で表す Unicode スカラー値。桁の間を `_` で区切れます |

それ以外のエスケープ（`\'` や `\x41` など）はエラーで、Unicode スカラー値でない `\u{…}`（サロゲートや U+10FFFF を超える値）もエラーです。行末のバックスラッシュによる行継続はありません。閉じる引用符のない文字列はエラーです。

文字列リテラルの型は、プログラムの定数テキストである `Text` です（[Text と String](./types.md#text-and-string) を参照）。

```kis
const GREETING: Text = "\"Good morning,\" she said.\n\u{2026}";
```

### 真偽値リテラル {#boolean-literals}

`true` と `false` はキーワードで、`bool` の 2 つの値です。

## ラベル {#labels}

**ラベル**は `'` の直後に識別子が続くもので、`'outer` のように書きます。ラベルはループに名前を付け、`break` と `continue` の行き先になります（[制御フローとループ](./control-flow.md)を参照）。Kagari にはライフタイムがないので、`'` の用途はこれだけです。

```kis
'outer: for row in 0..3 {
    for col in 0..3 {
        if col == row { continue 'outer; }
    }
}
```

## 記号 {#punctuation}

字句解析器は 1 文字ずつのトークンを出します。文法がより長い演算子を必要とする所では、構文解析器が**隣接した**文字（間に何もないもの）をつなぎます。そのため `Vec<Vec<u8>>` の `>>` は 2 つのジェネリクス引数リストを閉じ、`a >> 2` はシフトになり、空白を挟んだ `- >` は `->` ではありません。

| トークン | 用途 |
| -------- | ---- |
| `(` `)` | グループ化、タプル、呼び出し、引数リスト、タプル構造体 |
| `[` `]` | 配列、インデックス、配列型、属性、`t![…]` |
| `{` `}` | ブロック、構造体リテラル、アイテムリスト、`use` のグループ、`t![…]` の `{expr}` |
| `<` `>` | ジェネリクス。小なり、大なり |
| `,` `;` `:` | 区切り。`:` は型や境界の前 |
| `.` | フィールドアクセス、メソッド呼び出し、タプルのインデックス |
| `=` | 代入、初期化子、フォームの属性（`who = …`） |
| `!` | 論理否定とビット否定。フォーム（`s!(…)`）とテキスト効果（`!["…"](…)`） |
| `+` `-` `*` `/` `%` | 算術。`-` は符号反転、`*` は参照外しとグロブインポート、`+` は境界の連結 |
| `&` | 参照（`&x`、`&mut x`、`&T`）。ビット積 |
| `\|` | クロージャ（`\|x\| x + 1`）。ビット和、パターンの選択肢、ルビの読み |
| `^` | ビット排他的論理和 |
| `#` | 属性（`#[scene]`） |
| `?` | `Option` と `Result` に対する `?` 演算子 |
| `::` | パスの区切り、ターボフィッシュ（`f::<u8>()`） |
| `->` | 戻り値型 |
| `=>` | match のアーム、選択肢のアーム |
| `==` `!=` `<=` `>=` | 比較 |
| `&&` `\|\|` | 論理積、論理和 |
| `<<` `>>` | シフト |
| `+=` `-=` `*=` `/=` `%=` `^=` `&=` `\|=` `<<=` `>>=` | 複合代入 |
| `..` `..=` | 範囲、残余パターン |

次の文字はトークンではなく、コメントと文字列の外ではエラーです。`@`、`$`、`~`、`` ` ``、`\`、およびラベルを始めない `'`。`...` もトークンではありません。

## `.kix` ファイルのフォーム {#forms-in-kix-files}

`.kix` ファイルに固有のトークンはありません。**フォーム**は、識別子、`!`、開き括弧 `(`・`[`・`{` からなります。`s!(…)`、`t![…]`、`choice!{…}`、`button!{…}` がその例です。`t![…]` の中では、文字列リテラル、ルビ `["漢字"]("かん" | "じ")`、テキスト効果 `!["…"](effect)`、埋め込み `{expr}` をカンマなしで並べます。`.kis` ファイルの中のフォームはエラーです。フォームとその構文は[フォーム](./forms.md)で説明します。

## 字句エラー {#lexical-errors}

字句エラーはすべて [`E0001`](../../diagnostics/syntax.md#e0001) として報告されます。予期しない文字、閉じていないブロックコメントや文字列、未知のエスケープ、不正な `\u{…}`、不正な整数リテラルです。ファイルの残りも読み続けるので、後続のエラーも報告されることがあります。
