[前][次][番号順一覧][スレッド一覧]

ruby-changes:58207

From: Jeremy <ko1@a...>
Date: Fri, 11 Oct 2019 06:10:52 +0900 (JST)
Subject: [ruby-changes:58207] 29c1e9a0d4 (master): Document the difference between expressions and statements [ci skip]

https://git.ruby-lang.org/ruby.git/commit/?id=29c1e9a0d4

From 29c1e9a0d4c855781853f0ad41b0125f42cf504d Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Thu, 10 Oct 2019 11:25:54 -0700
Subject: Document the difference between expressions and statements [ci skip]

In the grammar, all expressions are statements, but not all
statements are expressions.  Some parts of the grammar accept
expressions and not other types of statements, which causes
similar looking code to parse differently due to operator
precedence.

Mostly from Dan0042 (Daniel DeLorme).

Fixes [Bug #16092]

diff --git a/doc/keywords.rdoc b/doc/keywords.rdoc
index 98bbd5e..b2f72da 100644
--- a/doc/keywords.rdoc
+++ b/doc/keywords.rdoc
@@ -76,7 +76,7 @@ for:: https://github.com/ruby/ruby/blob/trunk/doc/keywords.rdoc#L76
   expressions}[rdoc-ref:syntax/control_expressions.rdoc]
 
 if::
-  Used for +if+ and modifier +if+ expressions.  See {control
+  Used for +if+ and modifier +if+ statements.  See {control
   expressions}[rdoc-ref:syntax/control_expressions.rdoc]
 
 in::
@@ -137,7 +137,7 @@ undef:: https://github.com/ruby/ruby/blob/trunk/doc/keywords.rdoc#L137
   See {modules and classes}[rdoc-ref:syntax/modules_and_classes.rdoc]
 
 unless::
-  Used for +unless+ and modifier +unless+ expressions.  See {control
+  Used for +unless+ and modifier +unless+ statements.  See {control
   expressions}[rdoc-ref:syntax/control_expressions.rdoc]
 
 until::
diff --git a/doc/syntax/control_expressions.rdoc b/doc/syntax/control_expressions.rdoc
index 65f7b43..f7e6d54 100644
--- a/doc/syntax/control_expressions.rdoc
+++ b/doc/syntax/control_expressions.rdoc
@@ -144,7 +144,7 @@ expression. https://github.com/ruby/ruby/blob/trunk/doc/syntax/control_expressions.rdoc#L144
 == Modifier +if+ and +unless+
 
 +if+ and +unless+ can also be used to modify an expression.  When used as a
-modifier the left-hand side is the "then" expression and the right-hand side
+modifier the left-hand side is the "then" statement and the right-hand side
 is the "test" expression:
 
   a = 0
@@ -164,7 +164,7 @@ This will print 1. https://github.com/ruby/ruby/blob/trunk/doc/syntax/control_expressions.rdoc#L164
 This will print 0.
 
 While the modifier and standard versions have both a "test" expression and a
-"then" expression, they are not exact transformations of each other due to
+"then" statement, they are not exact transformations of each other due to
 parse order.  Here is an example that shows the difference:
 
   p a if a = 0.zero?
@@ -439,6 +439,64 @@ longer true, now you will receive a SyntaxError when you use +retry+ outside https://github.com/ruby/ruby/blob/trunk/doc/syntax/control_expressions.rdoc#L439
 of a +rescue+ block.  See {Exceptions}[rdoc-ref:syntax/exceptions.rdoc]
 for proper usage of +retry+.
 
+== Modifier Statements
+
+Ruby's grammar differentiates between statements and expressions.  All
+expressions are statements (an expression is a type of statement), but
+not all statements are expressions.  Some parts of the grammar accept
+expressions and not other types of statements, which causes code that
+looks similar to be parsed differently.
+
+For example, when not used as a modifier, +if+, +else+, +while+, +until+,
+and +begin+ are expressions (and also statements).  However, when
+used as a modifier, +if+, +else+, +while+, +until+ and +rescue+
+are statements but not expressions.
+
+  if true; 1 end # expression (and therefore statement)
+  1 if true      # statement (not expression)
+
+Statements that are not expressions cannot be used in contexts where an
+expression is expected, such as method arguments.
+
+  puts( 1 if true )      #=> SyntaxError
+
+You can wrap a statement in parentheses to create an expression.
+
+  puts((1 if true))      #=> 1
+
+If you put a space between the method name and opening parenthesis, you
+do not need two sets of parentheses.
+
+  puts (1 if true)       #=> 1, because of optional parentheses for method
+
+This is because this is parsed similar to a method call without
+parentheses.  It is equivalent to the following code, without the creation
+of a local variable:
+
+  x = (1 if true)
+  p x
+
+In a modifier statement, the left-hand side must be a statement and the
+right-hand side must be an expression.
+
+So in <code>a if b rescue c</code>, because <code>b rescue c</code> is a
+statement that is not an expression, and therefore is not allowed as the
+right-hand side of the +if+ modifier statement, the code is necessarily
+parsed as <code>(a if b) rescue c</code>.
+
+This interacts with operator precedence in such a way that:
+
+  stmt if v = expr rescue x
+  stmt if v = expr unless x
+
+are parsed as:
+
+  stmt if v = (expr rescue x)
+  (stmt if v = expr) unless x
+
+This is because modifier +rescue+ has higher precedence than <code>=</code>,
+and modifier +if+ has lower precedence than <code>=</code>.
+
 == Flip-Flop
 
 The flip-flop is a rarely seen conditional expression.  It's primary use is
diff --git a/doc/syntax/precedence.rdoc b/doc/syntax/precedence.rdoc
index 515626c..f64691a 100644
--- a/doc/syntax/precedence.rdoc
+++ b/doc/syntax/precedence.rdoc
@@ -49,10 +49,14 @@ Unary <code>+</code> and unary <code>-</code> are for <code>+1</code>, https://github.com/ruby/ruby/blob/trunk/doc/syntax/precedence.rdoc#L49
 <code>-1</code> or <code>-(a + b)</code>.
 
 Modifier-if, modifier-unless, etc. are for the modifier versions of those
-keywords.  For example, this is a modifier-unless expression:
+keywords.  For example, this is a modifier-unless statement:
 
   a += 1 unless a.zero?
 
+Note that <code>(a if b rescue c)</code> is parsed as <code>((a if b) rescue
+c)</code> due to reasons not related to precedence. See {modifier
+statements}[control_expressions_rdoc.html#label-Modifier+Statements].
+
 <code>{ ... }</code> blocks have priority below all listed operations, but
 <code>do ... end</code> blocks have lower priority.
 
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]