Haxeの式

C言語の伝統に則った言語には文 statement と式 expression の区別があり、`+`や`,`、`&&`といった演算子は式を作り、`if`や`for`や`return`、`;`といったキーワードは文を作ります。一方、Haxeには構文上、文と式の区別がが存在せず、Rubyのように、C言語では文だったような構文もすべて式です。

多くの式は型と値を持ちますが、Void型の式や、単独で型や値といった意味を持たない式もあります。そのような意味を持たない式もマクロで使うことができます。

# イカしたエクスプレッション紹介

`enum haxe.macro.ExprDef`のメンバーを紹介します。

## 定数式 `EConst`

リテラルや識別子。以下の種類があります。

- 整数 `CInt`
- 浮動小数点数 `CFloat`
- 文字列 `CString`
- 識別子 `CIdent`
- 正規表現 `CRegexp`

## 添字アクセス式 `EArray`

`e1[e2]`の形をした、添字アクセスの式。

## 単項演算子式 `EUnop`

`op e`または`e op`の形をした式。`op`には次の種類があります。

- `OpIncrement` `++`
- `OpDecrement` `--`
- `OpNot` `!`
- `OpNeg` `-`
- `OpNegBits` `~`

## 二項演算子式 `EBinop`

`e1 op e2`の形をした式。`op`には以下の種類があります。

- `OpAdd` `+`
- `OpMult` `*`
- `OpDiv` `/`
- `OpSub` `-`
- `OpAssign` `=`
- `OpEq` `==`
- `OpNotEq` `!=`
- `OpGt` `>`
- `OpGte` `>=`
- `OpLt` `<`
- `OpLte` `<=`
- `OpAnd` `&`
- `OpOr` `|`
- `OpXor` `^`
- `OpBoolAnd` `&&`
- `OpBoolOr` `||`
- `OpShl` `<<`
- `OpShr` `>>`
- `OpUShr` `>>>`
- `OpMod` `%`
- `OpInterval` `...`
- `OpArrow` `=>`
- `OpAssignOp(op:Binop)` `+=` `-=` `/=` `*=` `<<=` `>>=` `>>>=` `|=` `&=` `^=` `%=`

## フィールドアクセス式 `EField`

`e.field`の形をした式。

## 括弧式 `EParenthesis`

`(e)` の形をした式。

## オブジェクト宣言式 `EObjectDecl`

`{field: expr, ...}`の形をした、匿名構造体を宣言する式。

## 配列宣言式 `EArrayDecl`

`[e, ...]`の形をした、配列を宣言する式。連想配列や内包記法も内部表現はこの式になります。

## 呼出し式 `ECall`

`e1(e2, ...)`の形をした、関数呼出しの式。

## `new`式 `ENew`

`new T(e, ...)`の形をした式。

## `var`式 `EVar`

`var x = e, ...`の形をした、変数を宣言する式。値は`Void`。

## `function`式 `EFunction`

`function f<T>(arg, ...) e`の形をした、関数を宣言する式。

## ブロック式 `EBlock`

`{e; ...}`の形をした式。ブロック式中一番最後の式の値が、ブロック式全体の値となります。

## `for`式 `EFor`

`for (e1) e2`の形をした式。値は`Void`。内包記法にも使われます。

## `in`式 `EIn`

`e1 in e2`の形をした式。基本的にfor式の中で使われます。

## `if`式 `EIf`

`if (e1) e2 else e3`の形をした式。`else`節がある場合、`e1`の値に応じて、`e2`または`e3`の値が`if`式全体の値となります。

## `while`式 `EWhile`

`while (e1) e2`または`do e1 while(e2)`の形をした式。値は`Void`。

## `switch`式 `ESwitch`

`switch e1 {case e2, ... if (e3): e4; ...}`の形をした式。`e1`の値に応じて、各ケースいずれかが`switch`式全体の値となる。マクロ以外では`e1`の部分を括弧で括られた`(e)`か配列の`[e, ...]`の形のどちらかにしなければなりません。

## `try`式 `ETry`

`try e1 catch (x: T) e2 ...`の形をした式。`e1`または例外を捕捉した`catch`節の値を返します。

## `return`式 `EReturn`

`return e`の形をした式。`Dynamic`型として扱われます。

## `break`式 `EBreak`, `continue`式 `EContinue`

`break`と`continue`も式。`return`式同様`Dynamic`型として扱われます。

## `untyped`式 `EUntyped`

`untyped e`の形をした式。`e`の型を無視した型が付きます。

## `throw`式 `EThrow`

`throw e`の形をした式。例外を投げます。

## `cast`式 `ECast`

`cast e`または`cast(e, T)`の形をした式。型キャストを行います

## 三項演算子式 `ETernary`

`e1 ? e2 : e3`の形をした式。これの代わりに`if`式があるので必要ありません。

## 型検査式 `ECheckType`

`e : T`の形をした式。`e`の型が`T`であることをコンパイル時に検査する。マクロ以外では全体を括弧で括って`(e : T)`の形で使わなければなりません。

## メタデータ式 `EMeta`

`@m(p, ...) e`や`@:m(p, ...) e`, `$m{e}`の形をした式。マクロなどで使います。

## `macro`式

抽象構文木に`macro`式は存在しません。これはシンタックスシュガーで、`macro`を使った表現は、内部で他の式を使った表現に置き換わります。

# 意味を持たない式

例えば`in`式は単独では意味を持たず、普通は`for`式と組み合わせて使う必要があります。しかし、マクロに与える式の場合には、抽象構文木を書き換えてしまうわけで、式が意味を持たないことは問題となりません。意味を持たない式を使っている具体例として、[hxparseのパーサー](https://github.com/Simn/hxparse/wiki/Writing-a-Parser)の`switch stream`を使った記法が挙げられます。

# 曖昧な式

空のオブジェクト宣言式と空のブロック式はどちらも`{}`という表現で、区別が付きません。構文解析の段階では空のブロック式としてパースしておき、その後の処理で文脈を見て空のオブジェクト宣言か空のブロックかを判断しているようです。気をつけておかないと、マクロを書くときに引っかかりそうですね。

# ASTを簡単に調べる方法

ihxを使うと簡単に抽象構文木を調べられます。

```
% haxelib run ihx
haxe interactive shell v0.3.4
type "help" for help
>> macro [for (x in a) if (p(x)) f(x)] 
haxe.macro.Expr : { expr => EArrayDecl([{ expr => EFor({ expr => EIn({ expr => EConst(CIdent(x)), pos => { file => /tmp/IhxProgram_8249.hx, max => 235, min => 234 } },{ expr => EConst(CIdent(a)), pos => { file => /tmp/IhxProgram_8249.hx, max => 240, min => 239 } }), pos => { file => /tmp/IhxProgram_8249.hx, max => 240, min => 234 } },{ expr => EIf({ expr => ECall({ expr => EConst(CIdent(p)), pos => { file => /tmp/IhxProgram_8249.hx, max => 247, min => 246 } },[{ expr => EConst(CIdent(x)), pos => { file => /tmp/IhxProgram_8249.hx, max => 249, min => 248 } }]), pos => { file => /tmp/IhxProgram_8249.hx, max => 250, min => 246 } },{ expr => ECall({ expr => EConst(CIdent(f)), pos => { file => /tmp/IhxProgram_8249.hx, max => 253, min => 252 } },[{ expr => EConst(CIdent(x)), pos => { file => /tmp/IhxProgram_8249.hx, max => 255, min => 254 } }]), pos => { file => /tmp/IhxProgram_8249.hx, max => 256, min => 252 } },null), pos => { file => /tmp/IhxProgram_8249.hx, max => 256, min => 242 } }), pos => { file => /tmp/IhxProgram_8249.hx, max => 256, min => 229 } }]), pos => { file => /tmp/IhxProgram_8249.hx, max => 257, min => 228 } }
```

よきマクロ生活をお過ごしください。