From d30dfc89bf1b673b2fdc0638766b930adaec228c Mon Sep 17 00:00:00 2001
From: nsfisis then がキーワードになっている。次のように使う:
if cond then
- puts "Y"
-else
- puts "N"
-end
+ if cond then
+ puts "Y"
+else
+ puts "N"
+end
+
このキーワードが現れうる場所はいくつかあり、if、unless、rescue、case 構文がそれに当たる。 上記のように、何か条件を書いた後 then を置き、式がそこで終了していることを示すマーカーとして機能する。
# Example:
-
-if x then
- a
-end
-
-unless x then
- a
-end
-
-begin
- a
-rescue then
- b
-end
-
-case x
-when p then
- a
-end
+ # Example:
+
+if x then
+ a
+end
+
+unless x then
+ a
+end
+
+begin
+ a
+rescue then
+ b
+end
+
+case x
+when p then
+ a
+end
+ then を書くことはない。なぜか。次のコードを実行してみるとわかる。
- if true puts 'Hello, World!' end
+ if true puts 'Hello, World!' end
+ 次のような構文エラーが出力される。
-20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
-if true puts 'Hello, World!' end
- ^~~~
-20:1: syntax error, unexpected `end', expecting end-of-input
-...f true puts 'Hello, World!' end
+ 20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
+if true puts 'Hello, World!' end
+ ^~~~
+20:1: syntax error, unexpected `end', expecting end-of-input
+...f true puts 'Hello, World!' end
+
二つ目のメッセージは無視して一つ目を読むと、then か ; か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。
@@ -141,8 +148,10 @@ if true puts 'Hello, World!' end
ポイントは改行が then (や ;) の代わりとなることである。true の後に改行を入れてみる。
if true
-puts 'Hello, World!' end
+ if true
+puts 'Hello, World!' end
+
無事 Hello, World! と出力されるようになった。
@@ -155,21 +164,27 @@ puts 'Hello, World!'
簡略版:
ここで、
ところで、if a b end
+
+ if a b endthen も ; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。この例は二通りに解釈できる。
+ # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
-if a then
-b
-end
+ # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
+if a then
+b
+end
+ # a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
-# その結果が truthy なら何もしない
-if a(b) then
-end
+ # a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
+# その結果が truthy なら何もしない
+if a(b) then
+endthen 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。 C系の if 後に来る (/) や、Python の :、Rust/Go/Swift などの { も同じ役割を持つ。
@@ -190,39 +205,43 @@ b
https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986
+ p_case_body : keyword_in
-{
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p->command_start = FALSE;
- $<ctxt>1 = p->ctxt;
- p->ctxt.in_kwarg = 1;
- $<tbl>$ = push_pvtbl(p);
-}
-{
- $<tbl>$ = push_pktbl(p);
-}
-p_top_expr then
-{
- pop_pktbl(p, $<tbl>3);
- pop_pvtbl(p, $<tbl>2);
- p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
-}
-compstmt
-p_cases
-{
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
-}
-;
+ p_case_body : keyword_in
+{
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>1 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+}
+{
+ $<tbl>$ = push_pktbl(p);
+}
+p_top_expr then
+{
+ pop_pktbl(p, $<tbl>3);
+ pop_pvtbl(p, $<tbl>2);
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+}
+compstmt
+p_cases
+{
+ /*%%%*/
+ $$ = NEW_IN($4, $7, $8, &@$);
+ /*% %*/
+ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
+}
+;
+ p_case_body : keyword_in p_top_expr then compstmt p_cases
-;
+ p_case_body : keyword_in p_top_expr then compstmt p_cases
+;keyword_in は文字通り in、p_top_expr はいわゆるパターン、then は then キーワードのことではなく、この記事で then 等と呼んでいるもの、つまり then キーワード、;、改行のいずれかである。
@@ -232,36 +251,40 @@ p_cases
これにより、case - when による従来の構文と同じように、then 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:
+ case x
-in 1 then a
-in 2 then b
-in 3 then c
-end
-
-case x
-in 1
- a
-in 2
- b
-in 3
- c
-end
-
-case x
-in 1; a
-in 2; b
-in 3; c
-end
+ case x
+in 1 then a
+in 2 then b
+in 3 then c
+end
+
+case x
+in 1
+ a
+in 2
+ b
+in 3
+ c
+end
+
+case x
+in 1; a
+in 2; b
+in 3; c
+endp_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。
+ case x
-in 0 then a
-in n if n < 0 then b
-in n then c
-end
+ case x
+in 0 then a
+in n if n < 0 then b
+in n then c
+end