From b41dc61be65459b56c10ea35f7c52a5c0e67c644 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 27 Apr 2016 17:08:25 -0700 Subject: [PATCH 01/46] Fix three typos involving backslash characters A backslash was somehow used where a tilde was expected in two places, and an extra backslash crept into an arithmetic expression. --- spec/10-expressions.md | 4 ++-- spec/22-grammar.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 4efa05c..e4088e1 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -65,7 +65,7 @@ the full expression `$list1[$i] = $list2[$i++]`, whether the value of `$i` on the left-hand side is the old or new `$i`, is unspecified. Similarly, in the full expression `$j = $i + $i++`, whether the value of `$i` is the old or new `$i`, is unspecified. Finally, in the full -expression `f() + g() \* h()`, the order in which the three functions are +expression `f() + g() * h()`, the order in which the three functions are called, is unspecified.) **Implementation Notes** @@ -1585,7 +1585,7 @@ $a = array(100, 200); $v = ++$a[1]; // new value of $ia[1] (201) is assigned unary-operator cast-expression unary-operator: one of - + - ! \ + + - ! ~ **Defined elsewhere** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index bc6e7b2..a8f51d3 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -718,7 +718,7 @@ octal-digit unary-operator cast-expression unary-operator: one of - + - ! \ + + - ! ~ error-control-expression: @ expression From 1169aae056d7247c2962409472fd3963f78f1580 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 28 Apr 2016 14:52:38 -0700 Subject: [PATCH 02/46] Add missing coalesce operator to grammar summary When the coalescing operator (??) was added to section 9, it was not added to the copy of the grammar in section 22. --- spec/22-grammar.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/22-grammar.md b/spec/22-grammar.md index a8f51d3..b2810d7 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -309,7 +309,7 @@ octal-digit operator-or-punctuator:: one of [ ] ( ) { } . -> ++ -- ** * + - ~ ! $ / % << >> < > <= >= == === != !== ^ | - & && || ? : ; = **= *= /= %= += -= .= <<= + & && || ? ?? : ; = **= *= /= %= += -= .= <<= >>= &= ^= |= , @ :: => ==> ?-> From c51025cec849d41d67836714b7579c8ec51f342b Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Fri, 29 Apr 2016 09:15:11 -0700 Subject: [PATCH 03/46] Fix lexical/syntactic grammar for namespace names The spec had namespace names and qualified names defined in the lexical grammar, but no way to get from "token" to "qualified name". The simplest solution is to make "\" a token and make the namespace name and qualified name be part of the syntactic grammar, not the lexical grammar. I note that this is how the Hack and PHP tokenizers actually work, so the spec is brought into line with the implementation. --- spec/05-types.md | 8 ++++---- spec/09-lexical-structure.md | 15 +-------------- spec/10-expressions.md | 10 +++++----- spec/16-classes.md | 2 +- spec/17-interfaces.md | 2 +- spec/18-traits.md | 2 +- spec/20-namespaces.md | 17 +++++++++++++++-- spec/22-grammar.md | 28 ++++++++++++++-------------- 8 files changed, 42 insertions(+), 42 deletions(-) diff --git a/spec/05-types.md b/spec/05-types.md index c318878..b10e083 100644 --- a/spec/05-types.md +++ b/spec/05-types.md @@ -91,7 +91,7 @@ for `null`, use [`is_null`](http://www.php.net/is_null). Useful library function * [*map-like-array-type-specifier*](05-types.md#array-types) * [*name*](09-lexical-structure.md#names) * [*nullable-type-specifier*](05-types.md#nullable-types) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*shape-type-specifier*](05-types.md#shape-types) * [*tuple-type-specifier*](05-types.md#tuple-types) * [*vector-like-array-type-specifier*](05-types.md#array-types) @@ -487,7 +487,7 @@ private ?(int, (string, float)) $prop = null; **Defined elsewhere** -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals) * [*type-specifier*](05-types.md#general) @@ -695,7 +695,7 @@ parameters. See [§§](14-generic-types-methods-and-functions.md#generic-types-m **Defined elsewhere** -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) **Constraints** @@ -737,7 +737,7 @@ class C2 { **Defined elsewhere** * [*name*](09-lexical-structure.md#names) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*type-constraint*](05-types.md#general) * [*type-specifier*](05-types.md#general) diff --git a/spec/09-lexical-structure.md b/spec/09-lexical-structure.md index dcc3a15..e692c59 100644 --- a/spec/09-lexical-structure.md +++ b/spec/09-lexical-structure.md @@ -232,19 +232,6 @@ There are several kinds of source tokens: variable-name:: $ name - namespace-name:: - name - namespace-name \ name - - namespace-name-as-a-prefix:: - \ - \opt namespace-name \ - namespace \ - namespace \ namespace-name \ - - qualified-name:: - namespace-name-as-a-prefixopt name - name:: name-nondigit name name-nondigit @@ -882,7 +869,7 @@ A *null-literal* has the null type. [ ] ( ) { } . -> ++ -- ** * + - ~ ! $ / % << >> < > <= >= == === != !== ^ | & && || ? ?? : ; = **= *= /= %= += -= .= <<= - >>= &= ^= |= , @ :: => ==> ?-> + >>= &= ^= |= , @ :: => ==> ?-> \ **Semantics** diff --git a/spec/10-expressions.md b/spec/10-expressions.md index e4088e1..c5f11c5 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -122,7 +122,7 @@ of supertypes such as `num`, `arraykey`, or `?int`. Refer to [§§](05-types.md# * [*expression*](10-expressions.md#yield-operator) * [*intrinsic*](10-expressions.md#general-2) * [*literal*](09-lexical-structure.md#general-2) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*shape-literal*](10-expressions.md#shape-literals) * [*tuple-literal*](10-expressions.md#tuple-literals) * [*variable-name*](09-lexical-structure.md#names) @@ -525,7 +525,7 @@ in *field-initializer* need not be compile-time constants. * [*expression*](10-expressions.md#yield-operator) * [*integer-literal*](09-lexical-structure.md#integer-literals) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals) **Constraints** @@ -801,7 +801,7 @@ $obj2 = clone $obj1; // creates a new Manager that is a deep copy **Defined elsewhere** * [*argument-expression-list*](10-expressions.md#function-call-operator) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*variable-name*](09-lexical-structure.md#names) **Constraints** @@ -1363,7 +1363,7 @@ $a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned **Defined elsewhere** * [*name*](09-lexical-structure.md#names) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*variable-name*](09-lexical-structure.md#names) **Constraints** @@ -1792,7 +1792,7 @@ Function `main` calls async function `f`, which in turn awaits on async function **Defined elsewhere** * [*expression*](10-expressions.md#yield-operator) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*unary-expression*](10-expressions.md#general-4) * [*variable-name*](09-lexical-structure.md#names) diff --git a/spec/16-classes.md b/spec/16-classes.md index f65633b..b5d8c84 100644 --- a/spec/16-classes.md +++ b/spec/16-classes.md @@ -75,7 +75,7 @@ object. As such, assignment of a handle does not copy the object itself. * [*class-member-declarations*](16-classes.md#class-members) * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*name*](09-lexical-structure.md#names) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*trait-use-clauses*](18-traits.md#trait-declarations) **Constraints** diff --git a/spec/17-interfaces.md b/spec/17-interfaces.md index 7149507..b4cfe65 100644 --- a/spec/17-interfaces.md +++ b/spec/17-interfaces.md @@ -34,7 +34,7 @@ inherits all members from its *base interface(s)*. * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*interface-member-declarations*](17-interfaces.md#interface-members) * [*name*](09-lexical-structure.md#names) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) **Constraints** diff --git a/spec/18-traits.md b/spec/18-traits.md index 18a22f5..2f22263 100644 --- a/spec/18-traits.md +++ b/spec/18-traits.md @@ -128,7 +128,7 @@ trait T4 { * [*destructor-declaration*](16-classes.md#destructors) * [*method-declaration*](16-classes.md#methods) * [*property-declaration*](16-classes.md#properties) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](20-namespaces.md#defining-namespaces) **Constraints** diff --git a/spec/20-namespaces.md b/spec/20-namespaces.md index ed981b9..a9175aa 100644 --- a/spec/20-namespaces.md +++ b/spec/20-namespaces.md @@ -53,12 +53,25 @@ with a backslash (`\`), as in `\Exception`, `\PHP_INT_MAX`, and `\is_null`. The namespace-definition: namespace namespace-name ; namespace namespace-nameopt compound-statement + + namespace-name: + name + namespace-name \ name + + namespace-name-as-a-prefix: + \ + \opt namespace-name \ + namespace \ + namespace \ namespace-name \ + + qualified-name: + namespace-name-as-a-prefixopt name **Defined elsewhere** * [*compound-statement*](11-statements.md#compound-statements) -* [*namespace-name*](09-lexical-structure.md#names) +* [*name*](09-lexical-structure.md#names) **Constraints** @@ -140,7 +153,7 @@ namespace NS3\Sub1; **Defined elsewhere** * [*name*](09-lexical-structure.md#names) -* [*qualified-name*](09-lexical-structure.md#names) +* [*qualified-name*](#defining-namespaces) **Constraints** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index b2810d7..01b2908 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -77,19 +77,6 @@ The grammar notation is described in [§§](09-lexical-structure.md#grammars). variable-name:: $ name - namespace-name:: - name - namespace-name \ name - - namespace-name-as-a-prefix:: - \ - \opt namespace-name \ - namespace \ - namespace \ namespace-name \ - - qualified-name:: - namespace-name-as-a-prefixopt name - name:: name-nondigit name name-nondigit @@ -310,7 +297,7 @@ octal-digit [ ] ( ) { } . -> ++ -- ** * + - ~ ! $ / % << >> < > <= >= == === != !== ^ | & && || ? ?? : ; = **= *= /= %= += -= .= <<= - >>= &= ^= |= , @ :: => ==> ?-> + >>= &= ^= |= , @ :: => ==> ?-> \ ##Syntactic Grammar @@ -1344,6 +1331,19 @@ octal-digit namespace-aliasing-clause: as name + + namespace-name: + name + namespace-name \ name + + namespace-name-as-a-prefix: + \ + \opt namespace-name \ + namespace \ + namespace \ namespace-name \ + + qualified-name: + namespace-name-as-a-prefixopt name ###Attributes From 2ca8b0e968da22838b4e2b109840cce9f211c4ec Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Fri, 29 Apr 2016 09:31:38 -0700 Subject: [PATCH 04/46] Add ellipses to lexical grammar The lexical grammar did not include the "..." token used in variadic formal parameter lists. --- spec/09-lexical-structure.md | 2 +- spec/22-grammar.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/09-lexical-structure.md b/spec/09-lexical-structure.md index e692c59..a47b1bf 100644 --- a/spec/09-lexical-structure.md +++ b/spec/09-lexical-structure.md @@ -869,7 +869,7 @@ A *null-literal* has the null type. [ ] ( ) { } . -> ++ -- ** * + - ~ ! $ / % << >> < > <= >= == === != !== ^ | & && || ? ?? : ; = **= *= /= %= += -= .= <<= - >>= &= ^= |= , @ :: => ==> ?-> \ + >>= &= ^= |= , @ :: => ==> ?-> \ ... **Semantics** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 01b2908..a5e34a8 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -297,7 +297,7 @@ octal-digit [ ] ( ) { } . -> ++ -- ** * + - ~ ! $ / % << >> < > <= >= == === != !== ^ | & && || ? ?? : ; = **= *= /= %= += -= .= <<= - >>= &= ^= |= , @ :: => ==> ?-> \ + >>= &= ^= |= , @ :: => ==> ?-> \ ... ##Syntactic Grammar From 11ca48dd3d11b3c28c74ba8ca4fdc0adc7a9a6f1 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Tue, 3 May 2016 09:56:39 -0700 Subject: [PATCH 05/46] Small PHP difference clarifications * Hack reserves keywords "parent" and "self"; this was not documented in the specification. (Interestingly, Hack does not reserve "null", "true", "false" or "this", which we might want to look into.) * The explanation of the ${ } interpolation in string literals had a link to a now-deleted section of the specification, which meant that the feature was not explained. Since this feature is very restricted compared to its equivalent in PHP -- the PHP version of it cannot even be *lexed* without direction from the parser! -- I've added some verbiage explaining the difference and giving examples. * The deleted feature mentioned in the point above is the Variable-Name creation operator, but does not give the syntax which has been removed. The ${$y} syntax is at present unsupported in Hack. The $$y syntax is supported incorrectly now; Alex has a diff outstanding to make it an error. --- spec/09-lexical-structure.md | 6 +++--- spec/22-grammar.md | 4 ++-- spec/23-differences-from-php.md | 10 ++++++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/spec/09-lexical-structure.md b/spec/09-lexical-structure.md index a47b1bf..7edd0f4 100644 --- a/spec/09-lexical-structure.md +++ b/spec/09-lexical-structure.md @@ -294,8 +294,8 @@ cannot be used as a name. keyword:: one of abstract arraykey as async await break case catch class classname clone const continue default do echo else elseif enum extends final finally for foreach function if implements - instanceof insteadof interface mixed namespace new newtype noreturn num private - protected public require require_once return shape static switch throw trait try + instanceof insteadof interface mixed namespace new newtype noreturn num parent private + protected public require require_once return self shape static switch throw trait try tuple type use while yield @@ -678,7 +678,7 @@ The variable substitution accepts the following syntax: * [*name*](#names) * [*variable-name*](#names) -*expression* works the same way as in [variable name creation operator](10-expressions.md#variable-name-creation-operator). +The `${ expression }` syntax is deprecated in Hack. The expression must be such that if the enclosing braces were removed and the `$` prepended, then the resulting expression would be a legal `string-variable`. For example, `"${y[123]}"` is legal because `$y[123]` is a legal `string-variable`. No whitespace or comments are allowed inside the braces. After the variable defined by the syntax above is evaluated, its value is converted to string according to the rules of [string conversion](08-conversions.md#converting-to-string-type) diff --git a/spec/22-grammar.md b/spec/22-grammar.md index a5e34a8..73aaac7 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -100,8 +100,8 @@ The grammar notation is described in [§§](09-lexical-structure.md#grammars). keyword:: one of abstract arraykey as async break case catch class classname clone const continue default do echo else elseif enum extends final finally for foreach function if implements - instanceof insteadof interface mixed namespace new newtype noreturn num private - protected public require require_once return shape static switch throw trait try + instanceof insteadof interface mixed namespace new newtype noreturn num parent private + protected public require require_once return self shape static switch throw trait try tuple type use while yield diff --git a/spec/23-differences-from-php.md b/spec/23-differences-from-php.md index 8cee85c..87a0bb1 100644 --- a/spec/23-differences-from-php.md +++ b/spec/23-differences-from-php.md @@ -42,7 +42,7 @@ Hack treats comments of the forms `// strict` and `// FALLTHROUGH` in a special In Hack, function and method names are case-sensitive. ###Keywords -The following PHP identifiers are keywords in Hack: `arraykey`, `async`, `enum`, `mixed`, `newtype`, `num`, `shape`, `tuple`, and `type`. +The following PHP identifiers are keywords in Hack: `arraykey`, `async`, `enum`, `mixed`, `newtype`, `num`, `parent`, `self`, `shape`, `tuple`, and `type`. ##Expressions @@ -105,7 +105,7 @@ Hack does not allow casts to `array`, `binary`, `boolean`, `double`, `integer`, ####Variable-Name Creation Operator -This operator is not supported. +PHP allows variables to reference each other by means of a "variable variable". There are two syntaxes in PHP; if `$y` is equal to the string `"x"` then `$$y` and `${$y}` are both aliases for `$x`. This operator is not supported. ###`instanceof` Operator The right-hand operand cannot be a string. @@ -135,6 +135,12 @@ This is not supported. ###Logical `AND`, `OR`, `XOR` Operators (Alternate Forms) The `and`, `xor`, and `or` alternate forms are not supported. +###String Literals + +PHP allows the syntax `"${ expression }"` in a double-quoted string literal, where the expression can be the name of a variable, or any expression which evaluates to a string naming a variable. In PHP the expression may include delimited comments, spaces, and so on. In Hack this syntax is both deprecated and more strict. In Hack the only expression that may appear inside the braces is an expression which would be a legal `string-variable` if the braces were removed. + +For example, `"${y[123]}"` would be legal in Hack because `$y[123]` is a legal `string-variable`. In contrast, `"${ 'x'}"` is legal PHP equivalent to "$x", but in Hack this is not legal because `$ 'x'` is not a legal `string-variable`. + ##Statements ###General From 26053d7b6bb66a705f75431858bf6d52ff5855c4 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 4 May 2016 09:54:26 -0700 Subject: [PATCH 06/46] Link to enum-declarations was wrong Link to enum-declarations was wrong --- spec/04-basic-concepts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/04-basic-concepts.md b/spec/04-basic-concepts.md index 97826be..2e55553 100644 --- a/spec/04-basic-concepts.md +++ b/spec/04-basic-concepts.md @@ -28,7 +28,7 @@ A Hack *program* consists of one or more source files, known formally as * [*alias-declaration*](05-types.md#type-aliases) * [*class-declaration*](16-classes.md#class-declarations) -* [*enum-declaration*](12-script-inclusion.md#the-require-directive) +* [*enum-declaration*](13-enums.md#enum-declarations) * [*function-definition*](15-functions.md#function-definitions) * [*inclusion-directive*](12-script-inclusion.md#general) * [*interface-declaration*](17-interfaces.md#interface-declarations) From f213234f9e7be57287e5a8ecbad49eb1bd44c87b Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 4 May 2016 10:17:20 -0700 Subject: [PATCH 07/46] Correct require-once-expression to require-once-directive Looks like a previous search-and-replace operation was incomplete. The require-once directive should be listed as a directive, not an expression. --- spec/12-script-inclusion.md | 4 ++-- spec/22-grammar.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/12-script-inclusion.md b/spec/12-script-inclusion.md index 3e85340..eb7863e 100644 --- a/spec/12-script-inclusion.md +++ b/spec/12-script-inclusion.md @@ -7,13 +7,13 @@
   inclusion-directive:
     require-multiple-directive
-    require-once-expression
+    require-once-directive
 
**Defined elsewhere** * [*require-multiple-directive*](12-script-inclusion.md#the-require-directive) -* [*require-once-expression*](12-script-inclusion.md#the-require_once-directive) +* [*require-once-directive*](12-script-inclusion.md#the-require_once-directive) **Semantics:** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 73aaac7..fae6f82 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1043,7 +1043,7 @@ octal-digit
   inclusion-directive:
     require-multiple-directive
-    require-once-expression
+    require-once-directive
 
   require-multiple-directive:
     require  (  include-filename  )  ;

From 251647860a73edda82eb7457b05a7115c3a0e558 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Wed, 4 May 2016 13:13:16 -0700
Subject: [PATCH 08/46] The ${} interpolation is invalid in strict Hack

The ${} interpolation is invalid in strict Hack, so I've removed it
from the specification entirely. (Except to be called out as
unsupported in section 23.)
---
 spec/09-lexical-structure.md    | 17 +----------------
 spec/23-differences-from-php.md |  4 +---
 2 files changed, 2 insertions(+), 19 deletions(-)

diff --git a/spec/09-lexical-structure.md b/spec/09-lexical-structure.md
index 36ae815..982d02d 100644
--- a/spec/09-lexical-structure.md
+++ b/spec/09-lexical-structure.md
@@ -655,7 +655,6 @@ The variable substitution accepts the following syntax:
 
     string-variable::
         variable-name   offset-or-propertyopt
-        ${   expression   }  
 
     offset-or-property::
         offset-in-string
@@ -678,8 +677,6 @@ The variable substitution accepts the following syntax:
 * [*name*](#names)
 * [*variable-name*](#names)
 
-The `${ expression }` syntax is deprecated in Hack. The expression must be such that if the enclosing braces were removed and the `$` prepended, then the resulting expression would be a legal `string-variable`. For example, `"${y[123]}"` is legal because `$y[123]` is a legal `string-variable`. No whitespace or comments are allowed inside the braces.
-
 After the variable defined by the syntax above is evaluated, its value is converted
 to string according to the rules of [string conversion](08-conversions.md#converting-to-string-type)
 and is substituted into the string in place of the variable substitution expression.
@@ -690,21 +687,9 @@ and [member selection operator](10-expressions.md#member-selection-operator) res
 The exception is that *name* inside *offset-in-string* is interpreted as a string literal even if it is not
 quoted.
 
-If the character sequence following the `$` does not parse as *name* and does not start with `{`, the `$` character
+If the character sequence following the `$` does not parse as *name* then the `$` character
 is instead interpreted verbatim and no variable substitution is performed.
 
-Variable substitution also provides limited support for the evaluation
-of expressions. This is done by enclosing an expression in a pair of
-matching braces (`{ ... }`). The opening brace must be followed immediately by
-a dollar (`$`) without any intervening white space, and that dollar must
-begin a variable name. If this is not the case, braces are treated
-verbatim. If the opening brace (`{`) is escaped it is not interpreted as a start of
-the embedded expression and instead is interpreted verbatim.
-
-The value of the expression is converted to string according to the rules of
-[string conversion](08-conversions.md#converting-to-string-type) and is substituted into the string
-in place of the substitution expression.
-
 A double-quoted string literal is a [c-constant](06-constants.md#general) if it does not
 contain any variable substitution.
 
diff --git a/spec/23-differences-from-php.md b/spec/23-differences-from-php.md
index 87a0bb1..e7837f6 100644
--- a/spec/23-differences-from-php.md
+++ b/spec/23-differences-from-php.md
@@ -137,9 +137,7 @@ The `and`, `xor`, and `or` alternate forms are not supported.
 
 ###String Literals
 
-PHP allows the syntax `"${ expression }"` in a double-quoted string literal, where the expression can be the name of a variable, or any expression which evaluates to a string naming a variable. In PHP the expression may include delimited comments, spaces, and so on. In Hack this syntax is both deprecated and more strict. In Hack the only expression that may appear inside the braces is an expression which would be a legal `string-variable` if the braces were removed. 
-
-For example, `"${y[123]}"` would be legal in Hack because `$y[123]` is a legal `string-variable`. In contrast, `"${ 'x'}"` is legal PHP equivalent to "$x", but in Hack this is not legal because `$ 'x'` is not a legal `string-variable`. 
+PHP allows the syntax `"${ expression }"` in a double-quoted string literal, where the expression can be the name of a variable, or any expression which evaluates to a string naming a variable. This is an invalid string interpolation syntax in Hack.
 
 ##Statements
 

From 438e33242f910eeebc4928ab3ffcc0ed28c5d765 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Wed, 4 May 2016 13:14:56 -0700
Subject: [PATCH 09/46] Fixed missing hyphens in return-type

Fixed missing hyphens in return-type
---
 spec/15-functions.md | 2 +-
 spec/22-grammar.md   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/spec/15-functions.md b/spec/15-functions.md
index 11299f6..4a234ad 100644
--- a/spec/15-functions.md
+++ b/spec/15-functions.md
@@ -41,7 +41,7 @@ A function is called via the [function-call operator `()`](10-expressions.md#fun
   default-argument-specifier:
     =  const-expression
 
-  return type:
+  return-type:
     type-specifier
     noreturn
 
diff --git a/spec/22-grammar.md b/spec/22-grammar.md index fae6f82..3c96834 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1134,7 +1134,7 @@ octal-digit default-argument-specifier: = const-expression - return type: + return-type: type-specifier
From d1141f476f93623cb9d58feb3d1e57950404d024 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 4 May 2016 15:27:09 -0700 Subject: [PATCH 10/46] Fix broken cross references Fix broken cross references --- spec/10-expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 2677098..102f311 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -2390,8 +2390,8 @@ function factorial(int $int): int **Defined elsewhere** -* [*expression*](#general-6) -* [*logical-OR-expression*](#logical-inclusive-or-operator-form-1) +* [*expression*](10-expressions.md#yield-operator) +* [*logical-inc-OR-expression*](#logical-inclusive-or-operator) **Semantics** From a7692f8cd217b6a84089ed555637748b13bf4fbf Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Fri, 1 Jul 2016 08:17:31 -0700 Subject: [PATCH 11/46] Namespaces contain declarations, not statements The grammar suggests that the "namespace foo { }" form contains a block of statements, but in fact it contains a block of declarations. I've also eliminated the problematic use of "scope" to mean "definition extent". We already define "scope" as the region of program text in which a given name is visible, so we should not use "scope" to mean the region of program text which belongs syntactically to a namespace definition. --- spec/20-namespaces.md | 18 +++++++++--------- spec/22-grammar.md | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/20-namespaces.md b/spec/20-namespaces.md index a9175aa..560a120 100644 --- a/spec/20-namespaces.md +++ b/spec/20-namespaces.md @@ -52,7 +52,7 @@ with a backslash (`\`), as in `\Exception`, `\PHP_INT_MAX`, and `\is_null`. The
   namespace-definition:
     namespace  namespace-name  ;
-    namespace  namespace-nameopt  compound-statement
+    namespace  namespace-nameopt  { declaration-listopt }
 
   namespace-name:
     name 
@@ -70,7 +70,7 @@ with a backslash (`\`), as in `\Exception`, `\PHP_INT_MAX`, and `\is_null`. The
 
 **Defined elsewhere**
 
-* [*compound-statement*](11-statements.md#compound-statements)
+* [*declaration-list*](04-basic-concepts.md)
 * [*name*](09-lexical-structure.md#names)
 
 **Constraints**
@@ -80,14 +80,14 @@ first occurrence of a *namespace-definition* in a script must be the
 first thing in that script.
 
 All occurrence of a *namespace-definition* in a script must have the
-*compound-statement* form or must not have that form; the two forms
+*declaration-list* form or must have the "semicolon" form; the two forms
 cannot be mixed.
 
 When a script contains source code that is not inside a namespace, and
 source code that is inside one or namespaces, the namespaced code must
-use the *compound-statement* form of *namespace-definition*.
+use the *declaration-list* form of *namespace-definition*.
 
-*compound-statement* must not contain a *namespace-definition*.
+The *declaration-list* must not contain a *namespace-definition*.
 
 **Semantics**
 
@@ -100,10 +100,10 @@ When the same namespace is defined in multiple scripts, and those
 scripts are combined into the same program, the namespace is considered
 the merger of its individual contributions.
 
-The scope of the non-*compound-statement* form of *namespace-definition*
-runs until the end of the script, or until the lexically next
-*namespace-definition*, whichever comes first. The scope of the
-*compound-statement* form is the *compound-statement*.
+In the "semicolon" form of *namespace-definition* the given 
+namespace extends until the end of the script, or until the lexically next
+*namespace-definition*, whichever comes first. In the *declaration-list*
+form the namespace extends from the opening brace to the closing brace.
 
 **Examples**
 
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 61f316d..115fafd 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -1326,7 +1326,7 @@ octal-digit
 
   namespace-definition:
     namespace  namespace-name  ;
-    namespace  namespace-nameopt  compound-statement
+    namespace  namespace-nameopt { declaration-listopt }
 
   namespace-use-declaration:
     use  namespace-use-clauses  ;

From 15339905cb3c3c89ede1d9d1032e6e7f07495b22 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Fri, 1 Jul 2016 13:34:18 -0700
Subject: [PATCH 12/46] Link to cast expressions is incorrect

Link to cast expressions is incorrect
---
 spec/10-expressions.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index 3cf2c4d..8d317b5 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -1530,7 +1530,7 @@ values and the result can be represented as an `int`, the result has type
 **Defined elsewhere**
 
 * [*await-expression*](10-expressions.md#await-operator)
-* [*cast-expression*](10-expressions.md#anonymous-function-creation)
+* [*cast-expression*](10-expressions.md#cast-operator)
 * [*error-control-expression*](10-expressions.md#error-control-operator)
 * [*postfix-expression*](10-expressions.md#general-3)
 * [*prefix-decrement-expression*](10-expressions.md#prefix-increment-and-decrement-operators)

From 473395b8daa059b2af2f2cb097d9153f986b0de1 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Tue, 5 Jul 2016 15:04:35 -0700
Subject: [PATCH 13/46] Fix inconsistency between ch 22 and ch 10

Chapter 10 lists two production for anonymous-function-return; chapter
22 only lists one.
---
 spec/22-grammar.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 115fafd..e249900 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -576,6 +576,7 @@ octal-digit
 
   anonymous-function-return:
     : type-specifier
+    : noreturn
 
   anonymous-function-use-clause:
     use  (  use-variable-name-list  )

From 18c45534b64763ed1cc77e09765e19878f50cc6b Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Thu, 7 Jul 2016 14:28:47 -0700
Subject: [PATCH 14/46] A better fix for anonymous function returns

We can re-use the return-type production in anonymous type returns.
---
 spec/10-expressions.md | 4 ++--
 spec/22-grammar.md     | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index 8d317b5..88230f2 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -587,8 +587,7 @@ shape('id' => null, 'url' => null, 'count' => 0)
   attribute-specificationopt  type-specifieropt variable-name  default-argument-specifieropt
 
 anonymous-function-return:
-  : type-specifier
-  : noreturn
+  : return-type
 
 anonymous-function-use-clause:
   use  (  use-variable-name-list  )
@@ -603,6 +602,7 @@ shape('id' => null, 'url' => null, 'count' => 0)
 * [*attribute-specification*](20-namespaces.md#name-lookup)
 * [*compound-statement*](11-statements.md#compound-statements)
 * [*default-argument-specifier*](15-functions.md#function-definitions)
+* [*return-type*](15-functions.md#function-definitions)
 * [*type-specifier*](05-types.md#general)
 * [*variable-name*](09-lexical-structure.md#names)
 
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index e249900..e5e70cb 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -575,8 +575,7 @@ octal-digit
     attribute-specificationopt  type-specifieropt variable-name  default-argument-specifieropt
 
   anonymous-function-return:
-    : type-specifier
-    : noreturn
+    : return-type
 
   anonymous-function-use-clause:
     use  (  use-variable-name-list  )
@@ -1146,6 +1145,7 @@ octal-digit
 
   return-type:
     type-specifier
+    noreturn
 
###Classes From 13fc4fd787b0c3ce4de24f56bfbc0b4be3ca2fe6 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Tue, 12 Jul 2016 15:03:20 -0700 Subject: [PATCH 15/46] Fix grammar for enum bodies The grammar implied that enumerated type bodies were of the form x = 1 ; y = 2 that is, semicolon separated; in fact the items are semicolon terminated: x = 1; y = 2; --- spec/13-enums.md | 6 +++--- spec/22-grammar.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/13-enums.md b/spec/13-enums.md index d83d44b..8cc1bb1 100644 --- a/spec/13-enums.md +++ b/spec/13-enums.md @@ -14,10 +14,10 @@ An *enumeration* consists of a set of zero or more named, constant values called : int : string enumerator-list: - enumerator - enumerator-list ; enumerator + enumerator + enumerator-list enumerator enumerator: - enumerator-constant = constant-expression + enumerator-constant = constant-expression ; enumerator-constant: name
diff --git a/spec/22-grammar.md b/spec/22-grammar.md index e5e70cb..bae92b2 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1078,10 +1078,10 @@ octal-digit enumerator-list: enumerator - enumerator-list ; enumerator + enumerator-list enumerator enumerator: - enumerator-constant = constant-expression + enumerator-constant = constant-expression ; enumerator-constant: name From a2789081c71199a5586f2db0f236ee2f2dcb9fcc Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 14 Jul 2016 11:28:08 -0700 Subject: [PATCH 16/46] Fix grammar for methods The specification stated that a method is a modifier followed by a function, but that's not right; that would imply that "public <> function bar()..." is legal. The <> needs to come before the public. I've fixed up the grammar to ensure that the attribute comes before the modifier. --- spec/15-functions.md | 6 ++++-- spec/16-classes.md | 5 +++-- spec/22-grammar.md | 9 ++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/spec/15-functions.md b/spec/15-functions.md index 4a234ad..6933c72 100644 --- a/spec/15-functions.md +++ b/spec/15-functions.md @@ -20,11 +20,13 @@ A function is called via the [function-call operator `()`](10-expressions.md#fun
   function-definition:
+    attribute-specificationopt   function-definition-no-attribute
+
+  function-definition-no-attribute:
     function-definition-header  compound-statement
 
   function-definition-header:
-    attribute-specificationopt  asyncopt  function name  generic-type-parameter-listopt  (  parameter-listopt  )
-      :  return-type
+    asyncopt  function name  generic-type-parameter-listopt  (  parameter-listopt  ) :  return-type
 
   parameter-list:
     ...
diff --git a/spec/16-classes.md b/spec/16-classes.md
index b5d8c84..3e78921 100644
--- a/spec/16-classes.md
+++ b/spec/16-classes.md
@@ -433,8 +433,9 @@ class Point {
 
 
   method-declaration:
-    method-modifiers  function-definition
-    method-modifiers  function-definition-header  ;
+p
+  attribute-specificationopt method-modifiers  function-definition-no-attribute
+  attribute-specificationopt method-modifiers  function-definition-header  ;
 
   method-modifiers:
     method-modifier
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index bae92b2..a198b0e 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -1123,10 +1123,13 @@ octal-digit
 
 
   function-definition:
+    attribute-specificationopt   function-definition-no-attribute
+
+  function-definition-no-attribute:
     function-definition-header  compound-statement
 
   function-definition-header:
-    attribute-specificationopt  asyncopt  function name  generic-type-parameter-listopt  (  parameter-listopt  ) :  return-type
+    asyncopt  function name  generic-type-parameter-listopt  (  parameter-listopt  ) :  return-type
 
   parameter-list:
     ...
@@ -1218,8 +1221,8 @@ octal-digit
     =  expression
 
   method-declaration:
-    method-modifiers  function-definition
-    method-modifiers  function-definition-header  ;
+    attribute-specificationopt method-modifiers  function-definition-no-attribute
+    attribute-specificationopt method-modifiers  function-definition-header  ;
 
   method-modifiers:
     method-modifier

From 3df0555e95c66101688a0ea037a96d7b68bbf457 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Thu, 14 Jul 2016 11:36:44 -0700
Subject: [PATCH 17/46] Fix omission in switch specification

The specification nowhere noted that the first statement inside the
block of a switch must be a case or default.
---
 spec/11-statements.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/spec/11-statements.md b/spec/11-statements.md
index 598d339..4a73f29 100644
--- a/spec/11-statements.md
+++ b/spec/11-statements.md
@@ -241,6 +241,9 @@ There must be at most one default label.
 
 Each label expression's type must be a subtype of the switch *expression* type.
 
+The compound statement may be empty; if it is not, then the first statement in 
+it must be a labeled statement.
+
 **Semantics**
 
 Based on the value of its *expression*, a `switch` statement transfers

From 47aacb2fab54f4f1e214c67faab5f2c6680b329c Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Mon, 18 Jul 2016 13:36:27 -0700
Subject: [PATCH 18/46] Missing semis in require clause

The require-extends-clause and require-implements-clause productions
were missing the required semicolons.
---
 spec/18-traits.md  | 4 ++--
 spec/22-grammar.md | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/spec/18-traits.md b/spec/18-traits.md
index 2f22263..1d7bcc0 100644
--- a/spec/18-traits.md
+++ b/spec/18-traits.md
@@ -117,9 +117,9 @@ trait T4 {
     destructor-declaration
 
   require-extends-clause:
-    require  extends  qualified-name
+    require  extends  qualified-name  ;
   require-implements-clause:
-    require  implements  qualified-name
+    require  implements  qualified-name  ;
 
**Defined elsewhere** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index a198b0e..88a7845 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1319,10 +1319,10 @@ octal-digit destructor-declaration require-extends-clause: - require extends qualified-name + require extends qualified-name ; require-implements-clause: - require implements qualified-name + require implements qualified-name ;
###Namespaces From 2c09ddfee2733de75d5216ee3a34b268aa0b7113 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 20 Jul 2016 16:51:32 -0700 Subject: [PATCH 19/46] Add optional void annotations to constructors and destructors Hack, oddly enough, allows ": void" annotations on constructors and destructors, but does not require them. The annotation must be exactly ": void"; it cannot be an alias for void, for example. --- spec/16-classes.md | 12 ++++++++++-- spec/22-grammar.md | 7 +++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/spec/16-classes.md b/spec/16-classes.md index 3e78921..1710a8e 100644 --- a/spec/16-classes.md +++ b/spec/16-classes.md @@ -500,7 +500,7 @@ examples of abstract methods and their subsequent definitions.
   constructor-declaration:
     attribute-specificationopt  constructor-modifiers  function  __construct  (
-      constructor-parameter-declaration-listopt  )  compound-statement
+      constructor-parameter-declaration-listopt  ) void-returnopt  compound-statement
   constructor-parameter-declaration-list:
     constructor-parameter-declaration
     constructor-parameter-declaration-list  ,  constructor-parameter-declaration
@@ -564,6 +564,8 @@ need have a constructor.
 
 When a *constructor-parameter-declaration* contains a *visibility-modifier*, a property called *variable-name* with visibility *visibility-modifier* is added to the current class. When that constructor is called, the value of the argument for that parameter is assigned to the added property. Note: This feature simply provides a programming shortcut by having the implementation declare and initialize such properties.
 
+A constructor does not require a return type annotation; if one is included, it must be void.
+
 **Examples**
 
 ```Hack
@@ -595,7 +597,11 @@ class MyRangeException extends Exception {
 
 
   destructor-declaration:
-    attribute-specificationopt  visibility-modifier  function  __destruct  ( )  compound-statement
+    attribute-specificationopt  visibility-modifier  function  __destruct  ( )  void-returnopt  compound-statement
+
+  void-return:
+    : void
+
 
**Defined elsewhere** @@ -633,6 +639,8 @@ searches for the nearest destructor in the class hierarchy. Not every level of the hierarchy need have a destructor. A `private` destructor inhibits destructor calls from derived classes. +A destructor does not require a return type annotation; if one is included, it must be void. + **Examples** See [§§](#constructors) for an example of a constructor and destructor. diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 88a7845..0e1ba4d 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1236,7 +1236,7 @@ octal-digit constructor-declaration: attribute-specificationopt constructor-modifiers function __construct ( - constructor-parameter-declaration-listopt ) compound-statement + constructor-parameter-declaration-listopt ) void-returnopt compound-statement constructor-parameter-declaration-list: constructor-parameter-declaration @@ -1255,7 +1255,10 @@ octal-digit final destructor-declaration: - attribute-specificationopt visibility-modifier function __destruct ( ) compound-statement + attribute-specificationopt visibility-modifier function __destruct ( ) void-returnopt compound-statement + + void-return: + : void type-constant-declaration: abstract-type-constant-declaration From ff13997d00b047d2565f384bc0e32d62c56394a6 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Fri, 22 Jul 2016 11:31:07 -0700 Subject: [PATCH 20/46] A parameter list may end in a comma In Hack it is legal for a non-empty parameter list to end with a comma. For example "function foo(int $x, int $y,) : void {}" --- spec/15-functions.md | 1 + spec/22-grammar.md | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/15-functions.md b/spec/15-functions.md index 6933c72..270b57f 100644 --- a/spec/15-functions.md +++ b/spec/15-functions.md @@ -31,6 +31,7 @@ A function is called via the [function-call operator `()`](10-expressions.md#fun parameter-list: ... parameter-declaration-list + parameter-declaration-list , parameter-declaration-list , ... parameter-declaration-list: diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 0e1ba4d..322ae2b 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1134,6 +1134,7 @@ octal-digit parameter-list: ... parameter-declaration-list + parameter-declaration-list , parameter-declaration-list , ... parameter-declaration-list: From 3ccd3058a5289f52ae3aac03de2e87ab9aa24039 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Mon, 25 Jul 2016 10:35:31 -0700 Subject: [PATCH 21/46] Fix parameter declaration in catch clause The text originally said that a catch clause parameter is a parameter list with exactly one element. But this is wrong; a parameter list with exactly one element can (1) have an optional attribute, (2) have an optional default value, and (3) have an optional trailing comma. None of those are legal in Hack. It is far simpler to say that a catch clause must have a type and a variable, end of story. --- spec/11-statements.md | 11 ++++++----- spec/22-grammar.md | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/11-statements.md b/spec/11-statements.md index 4a73f29..a555c2c 100644 --- a/spec/11-statements.md +++ b/spec/11-statements.md @@ -837,7 +837,7 @@ throw new MyException; catch-clauses   catch-clause catch-clause: - catch (  parameter-declaration-list ) compound-statement + catch (  type-specifier variable-name ) compound-statement finally-clause: finally compound-statement @@ -846,17 +846,18 @@ throw new MyException; **Defined elsewhere** * [*compound-statement*](#compound-statements) -* [*parameter-declaration-list*](15-functions.md#function-definitions) +* [*type-specifier*](05-types.md#general). +* [*variable-name*](09-lexical-structure.md#names) **Constraints** -In a *catch-clause*, *parameter-declaration-list* must contain only one -parameter, and its type must be [`\Exception`](19-exception-handling.md#class-exception) or a type derived from +In a *catch-clause* the type referred to by the *type-specifier* +must be [`\Exception`](19-exception-handling.md#class-exception) or a type derived from that class. **Semantics** -In a *catch-clause*, *identifier* designates an *exception variable* +In a *catch-clause*, the *variable-name* designates an *exception variable* passed in by value. This variable corresponds to a local variable with a scope that extends over the catch-block. During execution of the catch-block, the exception variable represents the exception currently diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 322ae2b..5b2404c 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1041,7 +1041,7 @@ octal-digit catch-clauses catch-clause catch-clause: - catch ( parameter-declaration-list ) compound-statement + catch ( type-specifier variable-name ) compound-statement finally-clause: finally compound-statement From 7d0d3b395c126a95d8f716d306ae9e56c392a235 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Mon, 25 Jul 2016 14:01:36 -0700 Subject: [PATCH 22/46] Fix anonymous function / lambda parameter declaration grammar The productions for anonymous function and lambda parameter declarations did not support either "..." or trailing comma syntaxes. I've fixed up the grammar to support both, as we do for named function / method parameter lists. --- spec/10-expressions.md | 14 ++++++++++---- spec/22-grammar.md | 8 +++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 88230f2..574abeb 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -577,7 +577,13 @@ shape('id' => null, 'url' => null, 'count' => 0)
 anonymous-function-creation-expression:
-  asyncopt  function  (  anonymous-function-parameter-declaration-listopt  )  anonymous-function-returnopt  anonymous-function-use-clauseopt  compound-statement
+  asyncopt  function  (  anonymous-function-parameter-listopt  )  anonymous-function-returnopt  anonymous-function-use-clauseopt  compound-statement
+
+anonymous-function-parameter-list:
+  ...
+  anonymous-function-parameter-declaration-list
+  anonymous-function-parameter-declaration-list  ,
+  anonymous-function-parameter-declaration-list  ,  ...
 
 anonymous-function-parameter-declaration-list:
   anonymous-function-parameter-declaration
@@ -2481,7 +2487,7 @@ function pipe_operator_example(array $arr): int {
 
 lambda-function-signature:
   variable-name
-  (  anonymous-function-parameter-declaration-listopt  )  anonymous-function-returnopt
+  (  anonymous-function-parameter-listopt  )  anonymous-function-returnopt
 
 anonymous-function-body:
   expression
@@ -2490,7 +2496,7 @@ function pipe_operator_example(array $arr): int {
 
 **Defined elsewhere**
 
-* [*anonymous-function-parameter-declaration-list*](10-expressions.md#anonymous-function-creation)
+* [*anonymous-function-parameter-list*](10-expressions.md#anonymous-function-creation)
 * [*anonymous-function-return*](10-expressions.md#anonymous-function-creation)
 * [*coalesce-expression*](10-expressions.md#coalesce-operator)
 * [*compound-statement*](11-statements.md#compound-statements)
@@ -2501,7 +2507,7 @@ function pipe_operator_example(array $arr): int {
 
 **Constraints**
 
-Each variable-name in an *anonymous-function-parameter-declaration-list* must be distinct.
+Each variable-name in an *anonymous-function-parameter-list* must be distinct.
 
 If any *anonymous-function-parameter-declaration* has a *default-argument-specifier*, then all subsequent *anonymous-function-parameter-declarations* in the same *anonymous-function-parameter-declaration-list* must also have a *default-argument-specifier*.
 
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 5b2404c..77b4151 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -565,8 +565,14 @@ octal-digit
     qualified-name  =>  expression
 
   anonymous-function-creation-expression:
-    asyncopt  function  (  anonymous-function-parameter-declaration-listopt  )  anonymous-function-returnopt  anonymous-function-use-clauseopt  compound-statement
+    asyncopt  function  (  anonymous-function-parameter-listopt  )  anonymous-function-returnopt  anonymous-function-use-clauseopt  compound-statement
 
+  anonymous-function-parameter-list:
+    ...
+    anonymous-function-parameter-declaration-list
+    anonymous-function-parameter-declaration-list  ,
+    anonymous-function-parameter-declaration-list  ,  ...
+  
   anonymous-function-parameter-declaration-list:
     anonymous-function-parameter-declaration
     anonymous-function-parameter-declaration-list  ,  anonymous-function-parameter-declaration

From 802d5501e16b947d6e381741809bce33373bd8d2 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Tue, 26 Jul 2016 13:18:02 -0700
Subject: [PATCH 23/46] Rename anonymous-function-body

The "anonymous-function-body" production is nowhere used in the
anonymous function production, but rather only in the lambda expression
production.  This seems bizarre and confusing. I've renamed
anonymous-function-body to the more understandable "lambda-body".
---
 spec/10-expressions.md | 8 ++++----
 spec/22-grammar.md     | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index 574abeb..348f904 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -692,7 +692,7 @@ function compute(array $values): void {
 
 **Constraints**
 
-*awaitable-creation-expression* must not be used as the *anonymous-function-body* in a [*lambda-expression*](10-expressions.md#lambda-expressions).
+*awaitable-creation-expression* must not be used as the *lambda-body* in a [*lambda-expression*](10-expressions.md#lambda-expressions).
 
 **Semantics**
 
@@ -2483,13 +2483,13 @@ function pipe_operator_example(array $arr): int {
 
 lambda-expression:
   piped-expression
-  asyncopt  lambda-function-signature  ==>  anonymous-function-body
+  asyncopt  lambda-function-signature  ==>  lambda-body
 
 lambda-function-signature:
   variable-name
   (  anonymous-function-parameter-listopt  )  anonymous-function-returnopt
 
-anonymous-function-body:
+lambda-body:
   expression
   compound-statement
 
@@ -2511,7 +2511,7 @@ Each variable-name in an *anonymous-function-parameter-list* must be distinct. If any *anonymous-function-parameter-declaration* has a *default-argument-specifier*, then all subsequent *anonymous-function-parameter-declarations* in the same *anonymous-function-parameter-declaration-list* must also have a *default-argument-specifier*. -If the *type-specifier* in *anonymous-function-return* is `void`, the *compound-statement* must not contain any [`return` statements](11-statements.md#the-return-statement) having an *expression*. Otherwise, if that *type-specifier* is not omitted, the *expression* in *anonymous-function-body*, or all `return` statements in *compound-statement* must contain an *expression* whose type is a subtype of the type indicated by the return type's *type-specifier*. +If the *type-specifier* in *anonymous-function-return* is `void`, the *compound-statement* must not contain any [`return` statements](11-statements.md#the-return-statement) having an *expression*. Otherwise, if that *type-specifier* is not omitted, the *expression* in *lambda-body*, or all `return` statements in *compound-statement* must contain an *expression* whose type is a subtype of the type indicated by the return type's *type-specifier*. If `async` is present, *return-type* must be a type that implements [`Awaitable`](17-interfaces.md#interface-awaitable). diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 77b4151..7d0acf0 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -843,13 +843,13 @@ octal-digit
 lambda-expression:
   piped-expression
-  asyncopt  lambda-function-signature  ==>  anonymous-function-body
+  asyncopt  lambda-function-signature  ==>  lambda-body
 
 lambda-function-signature:
   variable-name
   (  anonymous-function-parameter-declaration-listopt  )  anonymous-function-returnopt
 
-anonymous-function-body:
+lambda-body:
   expression
   compound-statement
 
From b451a6e99c64c31e74c7ad40bc2b6b8761f6a59b Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 27 Jul 2016 12:21:05 -0700 Subject: [PATCH 24/46] Fix generic type argument lists The spec had numerous typos where generic type parameter lists eg,"<+T, -U>" were specified when generic type argument lists eg "" were intended. --- spec/16-classes.md | 7 ++++--- spec/17-interfaces.md | 5 +++-- spec/18-traits.md | 5 +++-- spec/22-grammar.md | 14 +++++++------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/spec/16-classes.md b/spec/16-classes.md index 1710a8e..8071b79 100644 --- a/spec/16-classes.md +++ b/spec/16-classes.md @@ -62,17 +62,18 @@ object. As such, assignment of a handle does not copy the object itself. abstract final class-base-clause: - extends qualified-name generic-type-parameter-listopt + extends qualified-name generic-type-argument-listopt class-interface-clause: - implements qualified-name generic-type-parameter-listopt - class-interface-clause  , qualified-name generic-type-parameter-listopt + implements qualified-name generic-type-argument-listopt + class-interface-clause  , qualified-name generic-type-argument-listopt
**Defined elsewhere** * [*attribute-specification*](21-attributes.md#attribute-specification) * [*class-member-declarations*](16-classes.md#class-members) +* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*name*](09-lexical-structure.md#names) * [*qualified-name*](20-namespaces.md#defining-namespaces) diff --git a/spec/17-interfaces.md b/spec/17-interfaces.md index b4cfe65..b6a6743 100644 --- a/spec/17-interfaces.md +++ b/spec/17-interfaces.md @@ -24,14 +24,15 @@ inherits all members from its *base interface(s)*. interface-member-declarationsopt  } interface-base-clause: - extends qualified-name generic-type-parameter-listopt - interface-base-clause , qualified-name generic-type-parameter-listopt + extends qualified-name generic-type-argument-listopt + interface-base-clause , qualified-name generic-type-argument-listopt
**Defined elsewhere** * [*attribute-specification*](21-attributes.md#attribute-specification) * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) +* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*interface-member-declarations*](17-interfaces.md#interface-members) * [*name*](09-lexical-structure.md#names) * [*qualified-name*](20-namespaces.md#defining-namespaces) diff --git a/spec/18-traits.md b/spec/18-traits.md index 1d7bcc0..82576dd 100644 --- a/spec/18-traits.md +++ b/spec/18-traits.md @@ -55,14 +55,15 @@ that trait is used. use trait-name-list ; trait-name-list: - qualified-name generic-type-parameter-listopt - trait-name-list , qualified-name generic-type-parameter-listopt + qualified-name generic-type-argument-listopt + trait-name-list , qualified-name generic-type-argument-listopt
**Defined elsewhere** * [*attribute-specification*](21-attributes.md#attribute-specification) * [*class-interface-clause*](16-classes.md#class-declarations) +* [*generic-type-argument-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*name*](09-lexical-structure.md#names) * [*trait-member-declarations*](18-traits.md#trait-members) diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 7d0acf0..05f1c2a 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1171,11 +1171,11 @@ octal-digit abstract final class-base-clause: - extends qualified-name generic-type-parameter-listopt + extends qualified-name generic-type-argument-listopt class-interface-clause: - implements qualified-name generic-type-parameter-listopt - class-interface-clause , qualified-name generic-type-parameter-listopt + implements qualified-name generic-type-argument-listopt + class-interface-clause , qualified-name generic-type-argument-listopt class-member-declarations: class-member-declaration @@ -1284,8 +1284,8 @@ octal-digit interface-member-declarationsopt } interface-base-clause: - extends qualified-name generic-type-parameter-listopt - interface-base-clause , qualified-name generic-type-parameter-listopt + extends qualified-name generic-type-argument-listopt + interface-base-clause , qualified-name generic-type-argument-listopt interface-member-declarations: interface-member-declaration @@ -1313,8 +1313,8 @@ octal-digit use trait-name-list ; trait-name-list: - qualified-name generic-type-parameter-listopt - trait-name-list , qualified-name generic-type-parameter-listopt + qualified-name generic-type-argument-listopt + trait-name-list , qualified-name generic-type-argument-listopt trait-member-declarations: trait-member-declaration From 8cd7917acd9f6fac36f4f1e43e3afa527502142a Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 27 Jul 2016 15:49:58 -0700 Subject: [PATCH 25/46] Argument lists may end in a comma Argument lists, like parameter lists, may end in a trailing comma if there is at least one item. --- spec/10-expressions.md | 5 ++++- spec/15-functions.md | 3 +-- spec/22-grammar.md | 10 ++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 348f904..07d4e4f 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -1169,8 +1169,11 @@ echo "\$p1[0] = " . $p1[0] . "\n"; // outputs '$p1[0] = 55' postfix-expression  (  argument-expression-listopt  ) argument-expression-list: + argument-expressions ,opt + + argument-expressions: expression - argument-expression-listexpression + argument-expressionsexpression **Defined elsewhere** diff --git a/spec/15-functions.md b/spec/15-functions.md index 270b57f..a77e461 100644 --- a/spec/15-functions.md +++ b/spec/15-functions.md @@ -30,8 +30,7 @@ A function is called via the [function-call operator `()`](10-expressions.md#fun parameter-list: ... - parameter-declaration-list - parameter-declaration-list , + parameter-declaration-list ,opt parameter-declaration-list , ... parameter-declaration-list: diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 05f1c2a..d312ded 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -656,8 +656,11 @@ octal-digit postfix-expression ( argument-expression-listopt ) argument-expression-list: - assignment-expression - argument-expression-list , assignment-expression + argument-expressions ,opt + + argument-expressions: + expression + argument-expressions , expression member-selection-expression: postfix-expression -> member-selection-designator @@ -1139,8 +1142,7 @@ octal-digit parameter-list: ... - parameter-declaration-list - parameter-declaration-list , + parameter-declaration-list ,opt parameter-declaration-list , ... parameter-declaration-list: From 149978b360d42f1e7310a587e14fc177f01b223d Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Mon, 15 Aug 2016 11:26:21 -0400 Subject: [PATCH 26/46] Optional trailing comma in generic type arg list A generic type argument list may optionally end in a comma. --- spec/14-generic-types-methods-and-functions.md | 2 +- spec/22-grammar.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/14-generic-types-methods-and-functions.md b/spec/14-generic-types-methods-and-functions.md index 6829e20..1b353d0 100644 --- a/spec/14-generic-types-methods-and-functions.md +++ b/spec/14-generic-types-methods-and-functions.md @@ -179,7 +179,7 @@ echo "\$c3 + \$c4 = " . Complex::add($c3, $c4) . "\n"; **Syntax**
 generic-type-argument-list:
-  <  generic-type-arguments  >
+  <  generic-type-arguments  ,opt  >
 generic-type-arguments:
   generic-type-argument
   generic-type-arguments  ,  generic-type-argument
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index d312ded..2503d8e 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -1117,7 +1117,7 @@ octal-digit
     -
 
   generic-type-argument-list:
-    <  generic-type-arguments  >
+    <  generic-type-arguments  ,opt  >
 
   generic-type-arguments:
     generic-type-argument

From 4b36c69e3f6bfdf499df6998893512845cf82fcc Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Mon, 15 Aug 2016 12:30:53 -0400
Subject: [PATCH 27/46] A type specifier list may end in a comma

A type specifier list -- used in tuple type and anonymous function type
productions -- may end in a comma.
---
 spec/05-types.md   | 5 ++++-
 spec/22-grammar.md | 9 ++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/spec/05-types.md b/spec/05-types.md
index ea0c745..a1c0de1 100644
--- a/spec/05-types.md
+++ b/spec/05-types.md
@@ -69,8 +69,11 @@ for `null`, use [`is_null`](http://www.php.net/is_null). Useful library function
   qualified-name generic-type-argument-listopt
 
 type-specifier-list:
+  type-specifiers  ,opt
+
+type-specifiers
   type-specifier
-  type-specifier-list , type-specifier
+  type-specifiers , type-specifier
 
 type-constraint:
   as  type-specifier
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 2503d8e..1773341 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -363,11 +363,14 @@ octal-digit
   qualified-name generic-type-argument-listopt
 
 type-specifier-list:
+  type-specifiers  ,opt
+
+type-specifiers:
   type-specifier
-  type-specifier-list , type-specifier
+  type-specifiers  ,  type-specifier
 
-  type-constraint:
-    as  type-specifier
+type-constraint:
+  as  type-specifier
 
 type-constant-type-name:
   name  ::  name

From cfe278b25e74db47cb617eb50c518a501ba8787e Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Mon, 15 Aug 2016 16:51:21 -0400
Subject: [PATCH 28/46] Fix formatting of scope resolution qualifier

The right hand side of a scope resolution qualifier may be the keyword
"class"; the grammar had "class" in italics, indicating that it was a
non-terminal, when a terminal was intended.
---
 spec/10-expressions.md | 2 +-
 spec/22-grammar.md     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index 07d4e4f..a7de5d9 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -1371,7 +1371,7 @@ $a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned
 
   scope-resolution-expression:
     scope-resolution-qualifier  ::  name
-    scope-resolution-qualifier  ::  class
+    scope-resolution-qualifier  ::  class
 
   scope-resolution-qualifier:
     qualified-name
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 1773341..22080ba 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -683,7 +683,7 @@ octal-digit
 
   scope-resolution-expression:
     scope-resolution-qualifier  ::  name
-    scope-resolution-qualifier  ::  class
+    scope-resolution-qualifier  ::  class
 
   scope-resolution-qualifier:
     qualified-name

From 0b318b16e7e036049725a81153fdd48b37fc9e9b Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Tue, 16 Aug 2016 12:01:57 -0400
Subject: [PATCH 29/46] The scope resolution operator can have a variable name
 on the right

The grammar did not indicate that the scope resolution operator could
have a variable name on the right. (Though the supporting text
indicated that it could be used to name a static property.)
---
 spec/10-expressions.md | 9 +++++++--
 spec/22-grammar.md     | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index a7de5d9..e98c404 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -1371,6 +1371,7 @@ $a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned
 
   scope-resolution-expression:
     scope-resolution-qualifier  ::  name
+    scope-resolution-qualifier  ::  variable-name
     scope-resolution-qualifier  ::  class
 
   scope-resolution-qualifier:
@@ -1389,9 +1390,13 @@ $a = array(100, 200); $v = $a[1]++; // old value of $ia[1] (200) is assigned
 
 **Constraints**
 
-If *name* is present, *qualified-name* must be the name of an enum, a class, or an interface type, and *name* must designate an enumeration constant or member within that type. Otherwise, *qualified-name* must be the name of a class or interface type.
+Scope resolution expressions of the form qualified-name`::`name must have the name of an enum, class or interface type on the left of the `::`, and an enumeration constant or type member on the right.
 
-*variable-name* must name a value having the [`classname` type](05-types.md#the-classname-type).
+Scope resolution expressions of the form qualified-name`::`variable-name must have the name of a class or interface type on the left of the `::`, and a static property of that type on the right.
+
+Scope resolution expressions of the form qualified-name`::`class must have the name of a class or interface type on the left of the `::`.
+
+Scope resolution expressions with a *variable-name* to the left of the `::` must name a variable having the [`classname` type](05-types.md#the-classname-type).
 
 *variable-name* `:: class` is not permitted.
 
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 22080ba..efc0bc2 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -683,6 +683,7 @@ octal-digit
 
   scope-resolution-expression:
     scope-resolution-qualifier  ::  name
+    scope-resolution-qualifier  ::  variable-name
     scope-resolution-qualifier  ::  class
 
   scope-resolution-qualifier:

From f52cd705335e84ee95bbd32ca8b2a98c460717c9 Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Wed, 17 Aug 2016 16:43:00 -0400
Subject: [PATCH 30/46] Add scope-qualified names to object creation expression
 grammar

Hack permits the class type designator of an object creation ("new")
expression to be a scope-qualified name ("$foo::$bar").

I also tidied up the normative text somewhat to be a bit more clear and
less redundant.
---
 spec/10-expressions.md | 18 +++++++++++-------
 spec/22-grammar.md     |  3 +++
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index e98c404..72cf1d3 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -811,8 +811,11 @@ $obj2 = clone $obj1;  // creates a new Manager that is a deep copy
     new  class-type-designator  (  argument-expression-listopt  )
 
   class-type-designator:
+    parent
+    self
     static
     qualified-name
+    scope-resolution-expression
     variable-name
 
@@ -820,19 +823,20 @@ $obj2 = clone $obj1; // creates a new Manager that is a deep copy * [*argument-expression-list*](10-expressions.md#function-call-operator) * [*qualified-name*](20-namespaces.md#defining-namespaces) +* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator) * [*variable-name*](09-lexical-structure.md#names) **Constraints** -*qualified-name* must name a class. +If the *class-type-designator* is a *scope-resolution-expression* then it must not have `class` as the right hand side of the `::` operator. -*variable-name* must name a value having the [`classname` type](05-types.md#the-classname-type). +If the *class-type-designator* is a *qualified-name* or *scope-resolution-expression* which resolves a qualified name, or `self`, or `parent`, then it must designate a class. -*variable-name* must designate a class that has the attribute [`__ConsistentConstruct`](21-attributes.md#attribute-__consistentconstruct), or that has an abstract constructor or a final constructor. +If the *class-type-designator* is a *variable-name* or *scope-resolution-expression* which resolves to the name of a property, then it must name a value having the [`classname` type](05-types.md#the-classname-type). Furthermore, it must designate a class that has the attribute [`__ConsistentConstruct`](21-attributes.md#attribute-__consistentconstruct), or that has an abstract constructor or a final constructor. -*class-type-designator* must not designate an [abstract class](16-classes.md#general). +The *class-type-designator* must not designate an [abstract class](16-classes.md#general). -*class-type-designator* must not be a [generic type parameter](14-generic-types-methods-and-functions.md#type-parameters). +The *class-type-designator* must not be a [generic type parameter](14-generic-types-methods-and-functions.md#type-parameters). *argument-expression-list* must contain an argument for each parameter in the [constructor's definition](15-functions.md#function-definitions) not having a default value, and each @@ -844,7 +848,7 @@ than there are corresponding parameters. **Semantics** The `new` operator allocates memory for an object that is an instance of -the class specified by *class-type-designator* or *variable-name*. +the class specified by the *class-type-designator*. The object is initialized by calling the class's constructor (16.8) passing it the optional *argument-expression-list*. If the class has no @@ -853,7 +857,7 @@ Otherwise, each instance property having any nullable type takes on the value `null`. The result of an *object-creation-expression* is a handle to an object -of the type specified by *class-type-designator* or *variable-name*. +of the type specified by the *class-type-designator*. From within a method, the use of `static` corresponds to the class in the inheritance context in which the method is called. The type of the object created by an expression of the form `new static` is [`this`](05-types.md#the-this-type). diff --git a/spec/22-grammar.md b/spec/22-grammar.md index efc0bc2..d788da4 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -626,9 +626,12 @@ octal-digit new class-type-designator ( argument-expression-listopt ) class-type-designator: + parent + self static qualified-name variable-name + scope-resolution-expression array-creation-expression: array ( array-initializeropt ) From 730053d779293cb8548754baf4225a83525cdb39 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 18 Aug 2016 09:57:11 -0400 Subject: [PATCH 31/46] More updates to object creation Hack allows the class designator to be of the form $x->$y, and a few other forms. I've updated the grammar and the supporting text. --- spec/10-expressions.md | 12 ++++++++++-- spec/22-grammar.md | 5 ++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 72cf1d3..9975f51 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -814,30 +814,38 @@ $obj2 = clone $obj1; // creates a new Manager that is a deep copy parent self static + member-selection-expression + null-safe-member-selection-expression qualified-name scope-resolution-expression + subscript-expression variable-name
**Defined elsewhere** * [*argument-expression-list*](10-expressions.md#function-call-operator) +* [*member-selection-expression*](10-expressions.md#member-selection-operator) +* [*null-safe-member-selection-expression*](10-expressions.md#null-safe-member-selection-operator) * [*qualified-name*](20-namespaces.md#defining-namespaces) * [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator) +* [*subscript-expression*](10-expressions.md#subscript-operator) * [*variable-name*](09-lexical-structure.md#names) **Constraints** If the *class-type-designator* is a *scope-resolution-expression* then it must not have `class` as the right hand side of the `::` operator. -If the *class-type-designator* is a *qualified-name* or *scope-resolution-expression* which resolves a qualified name, or `self`, or `parent`, then it must designate a class. +Otherwise, if the *class-type-designator* is a *qualified-name* or *scope-resolution-expression* which resolves a qualified name, or `self`, or `parent`, then it must designate a class. -If the *class-type-designator* is a *variable-name* or *scope-resolution-expression* which resolves to the name of a property, then it must name a value having the [`classname` type](05-types.md#the-classname-type). Furthermore, it must designate a class that has the attribute [`__ConsistentConstruct`](21-attributes.md#attribute-__consistentconstruct), or that has an abstract constructor or a final constructor. +Otherwise,the *class-type-designator* must be an expression evaluating to a value having the [`classname` type](05-types.md#the-classname-type). Furthermore, it must designate a class that has the attribute [`__ConsistentConstruct`](21-attributes.md#attribute-__consistentconstruct), or that has an abstract constructor or a final constructor. The *class-type-designator* must not designate an [abstract class](16-classes.md#general). The *class-type-designator* must not be a [generic type parameter](14-generic-types-methods-and-functions.md#type-parameters). +The *object-creation-expression* will invoke the constructor of the class designated by the *class-type-designator*. + *argument-expression-list* must contain an argument for each parameter in the [constructor's definition](15-functions.md#function-definitions) not having a default value, and each argument's type must be a subtype of the corresponding parameter's type. diff --git a/spec/22-grammar.md b/spec/22-grammar.md index d788da4..e69836f 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -629,9 +629,12 @@ octal-digit parent self static + member-selection-expression + null-safe-member-selection-expression qualified-name - variable-name scope-resolution-expression + subscript-expression + variable-name array-creation-expression: array ( array-initializeropt ) From 0e1a6753a0d7b548c7f65e88a43aac7ff3c1d246 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 18 Aug 2016 15:32:28 -0400 Subject: [PATCH 32/46] Member selections can have a variable on the right A member selection operator (-> or ?->) may have a variable on the right, eg, $x->$y, in strict mode. I also fixed some mis-edits in the grammar summary; it looks like at one time there was going to be a "designator" production as with "new". --- spec/10-expressions.md | 18 +++++++++++++++++- spec/22-grammar.md | 8 +++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 9975f51..48391d8 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -1279,12 +1279,14 @@ $anon(); // call the anonymous function
   member-selection-expression:
     postfix-expression  ->  name
+    postfix-expression  ->  variable-name
 
**Defined elsewhere** * [*name*](09-lexical-structure.md#names) * [*postfix-expression*](10-expressions.md#general-3) +* [*variable-name*](09-lexical-structure.md#names) **Constraints** @@ -1293,6 +1295,11 @@ $anon(); // call the anonymous function *name* must designate an instance property, or an instance method of the class designated by *postfix-expression*. +*variable-name* must name a variable which when evaluated produces a string +containing an instance property or an instance method of the class +designated by *postfix-expression*. + + **Semantics** A *member-selection-expression* designates an instance property or an @@ -1325,12 +1332,14 @@ $p1->move(3, 9); // calls public instance method move by name
 null-safe-member-selection-expression:
   postfix-expression  ?->  name
+  postfix-expression  ?->  variable-name
 
**Defined elsewhere** * [*name*](09-lexical-structure.md#names) * [*postfix-expression*](10-expressions.md#general-3) +* [*variable-name*](09-lexical-structure.md#names) **Constraints** @@ -1338,9 +1347,16 @@ $p1->move(3, 9); // calls public instance method move by name *name* must designate an instance property or an instance method of the class designated by *postfix-expression*. +*variable-name* must name a variable which when evaluated produces a string +containing an instance property or an instance method of the class +designated by *postfix-expression*. + **Semantics** -If *postfix-expression* is `null`, no property or method is selected and the resulting value is `null`. Otherwise, the behavior is like that of the [member-selection operator `->`](10-expressions.md#member-selection-operator), except that when *name* designates an instance property of the object designated by *postfix-expression*, the resulting value is not an lvalue. +If *postfix-expression* is `null`, no property or method is selected and the +resulting value is `null`. Otherwise, the behavior is like that of the +[member-selection operator `->`](10-expressions.md#member-selection-operator), +except that the resulting value is not an lvalue. ###Postfix Increment and Decrement Operators diff --git a/spec/22-grammar.md b/spec/22-grammar.md index e69836f..dbc828e 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -672,14 +672,12 @@ octal-digit argument-expressions , expression member-selection-expression: - postfix-expression -> member-selection-designator - - member-selection-designator: - name - expression + postfix-expression -> name + postfix-expression -> variable-name null-safe-member-selection-expression: postfix-expression ?-> name + postfix-expression ?-> variable-name postfix-increment-expression: unary-expression ++ From 93db39c90d79254ba969a1bfc76ee94819ca0a4e Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Mon, 29 Aug 2016 15:00:50 -0700 Subject: [PATCH 33/46] Update namespace use declarations Namespace use declarations may (1) specify the "kind", so that they can alias const or function members, and (2) have a "group" syntactic sugar to cut down on irritating redundancy. --- spec/20-namespaces.md | 36 +++++++++++++++++++++++++++++++----- spec/22-grammar.md | 15 ++++++++++++++- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/spec/20-namespaces.md b/spec/20-namespaces.md index 560a120..5fb2978 100644 --- a/spec/20-namespaces.md +++ b/spec/20-namespaces.md @@ -137,7 +137,9 @@ namespace NS3\Sub1;
   namespace-use-declaration:
-    use  namespace-use-clauses  ;
+    use namespace-use-kindopt  namespace-use-clauses  ;
+    use namespace-use-kind  namespace-name-as-a-prefix  { namespace-use-clauses  }  ;
+    use namespace-name-as-a-prefix  { namespace-use-kind-clauses  }  ;
 
   namespace-use-clauses:
     namespace-use-clause
@@ -146,8 +148,19 @@ namespace NS3\Sub1;
   namespace-use-clause:
     qualified-name  namespace-aliasing-clauseopt
 
+  namespace-use-kind-clauses:
+    namespace-use-kind-clause
+    namespace-use-kind-clauses  ,  namespace-use-kind-clause
+
+  namespace-use-kind-clause:
+    namespace-use-kindopt  qualified-name  namespace-aliasing-clauseopt
+
   namespace-aliasing-clause:
     as  name
+
+  namespace-use-kind:
+    function
+    const
 
**Defined elsewhere** @@ -165,10 +178,13 @@ scope, each occurrence must have a different alias. **Semantics** -*qualified-name* is always interpreted as referring to a class, -interface, or trait by that name. *namespace-use-clauses* can only -create aliases for classes, interfaces, or traits; it is not possible to -use them to create aliases to functions or constants. +If a *namespace-use-kind* is specified before the clauses or group prefix, +then all subsequent clauses must name constants or functions, as appropriate. + +Otherwise, if a *namespace-use-kind* is specified in a *namespace-use-kind-clause* +then the clause must name a constant or function, as appropriate. + +Otherwise, the clause must name a namespace, class, interface or trait. A *namespace-use-declaration* *imports*—that is, makes available—one or more names into a scope, optionally giving them each an alias. Each of @@ -177,6 +193,11 @@ interface, or a trait. If a namespace-alias-clause is present, its *name* is the alias for *qualified-name*. Otherwise, the right-most name in *qualified-name* is the implied alias for *qualified-name*. +The "group" form of a *namespace-use-declaration* is a convenient syntax when +importing many members of a given namespace. The "group" form logically concatenates +the prefix onto the *qualified-name* in each clause. See the following section for +an example. + **Examples** ```Hack @@ -198,4 +219,9 @@ namespace NS2 { $c2 = new C2; } ``` +The *namespace-use-declaration* in the example above could also be written in +"group" form as: +``` + use \NS1\ { C, I, T }; +``` diff --git a/spec/22-grammar.md b/spec/22-grammar.md index dbc828e..acb3524 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1353,7 +1353,9 @@ octal-digit namespace namespace-nameopt { declaration-listopt } namespace-use-declaration: - use namespace-use-clauses ; + use namespace-use-kindopt namespace-use-clauses ; + use namespace-use-kind namespace-name-as-a-prefix { namespace-use-clauses } ; + use namespace-name-as-a-prefix { namespace-use-kind-clauses } ; namespace-use-clauses: namespace-use-clause @@ -1362,9 +1364,20 @@ octal-digit namespace-use-clause: qualified-name namespace-aliasing-clauseopt + namespace-use-kind-clauses: + namespace-use-kind-clause + namespace-use-kind-clauses , namespace-use-kind-clause + + namespace-use-kind-clause: + namespace-use-kindopt qualified-name namespace-aliasing-clauseopt + namespace-aliasing-clause: as name + namespace-use-kind: + function + const + namespace-name: name namespace-name \ name From c944669ff323f288e66c9433e76492ef90d3226e Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 31 Aug 2016 12:40:04 -0700 Subject: [PATCH 34/46] A field specifier may be scope qualified The field specifier in a shape may be of the form "foo::bar". --- spec/10-expressions.md | 6 ++++-- spec/22-grammar.md | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 48391d8..24ad2f7 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -531,6 +531,7 @@ in *field-initializer* need not be compile-time constants. single-quoted-string-literal => expression integer-literal => expression qualified-name => expression + scope-resolution-expression => expression
**Defined elsewhere** @@ -538,16 +539,17 @@ in *field-initializer* need not be compile-time constants. * [*expression*](10-expressions.md#yield-operator) * [*integer-literal*](09-lexical-structure.md#integer-literals) * [*qualified-name*](20-namespaces.md#defining-namespaces) +* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator) * [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals) **Constraints** Each string in the set of strings designated by all the -*single-quoted-string-literals* and *qualified-names* in a +*single-quoted-string-literals*, *qualified-names* and *scope-resolution-expressions* in a *field-initializer-list* must have a distinct value, and each string must match exactly a field name in the shape type's [*shape-specifier*](05-types.md#shape-types). -Each integer in the set of *integer-literals* and *qualified-names* in a +Each integer in the set of *integer-literals*, *qualified-names* and *scope-resolution-expressions* in a *field-initializer-list* must have a distinct value, and each integer must match exactly a field name in the shape type's *shape-specifier*. diff --git a/spec/22-grammar.md b/spec/22-grammar.md index acb3524..e7ecbcf 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -566,6 +566,7 @@ octal-digit single-quoted-string-literal => expression integer-literal => expression qualified-name => expression + scope-resolution-expression => expression anonymous-function-creation-expression: asyncopt function ( anonymous-function-parameter-listopt ) anonymous-function-returnopt anonymous-function-use-clauseopt compound-statement From 2b252efae4d40c82519794128207a44e48ed975e Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 31 Aug 2016 13:19:41 -0700 Subject: [PATCH 35/46] Shape definitions may have scope resolutions The definition of a shape type may use the :: operator. --- spec/05-types.md | 19 ++++++++++++------- spec/22-grammar.md | 1 + 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/spec/05-types.md b/spec/05-types.md index a1c0de1..46ccc10 100644 --- a/spec/05-types.md +++ b/spec/05-types.md @@ -486,29 +486,33 @@ private ?(int, (string, float)) $prop = null; field-specifier: single-quoted-string-literal => type-specifier qualified-name => type-specifier + scope-resolution-expression => type-specifier **Defined elsewhere** * [*qualified-name*](20-namespaces.md#defining-namespaces) +* [*scope-resolution-expression*](10-expressions.md#scope-resolution-operator) * [*single-quoted-string-literal*](09-lexical-structure.md#single-quoted-string-literals) * [*type-specifier*](05-types.md#general) **Constraints** - -*qualified-name* must designate a [class constant](16-classes.md#constants) of type `int` or -`string`. +The *qualified-name* or *scope-resolution-expression* must designate +a [class constant](16-classes.md#constants) of type `int` or `string`. Each string in the set of strings designated by all the -*single-quoted-string-literals* and *qualified-names* in a +*single-quoted-string-literals*, *qualified-names* and +*scope-resolution-expressions* in a *field-specifier-list* must have a distinct value. -Each integer in the set of all the *qualified-names* +Each integer in the set of all the *qualified-names* and +*scope-resolution-expressions* in a *field-specifier-list* must have a distinct value. The *field-specifiers* in a *field-specifier-list* must all have the *single-quoted-string-literal* form, or all -have the *qualified-name* form; the forms must not be mixed. +have the *qualified-name* or *scope-resolution-expression* form; +the forms must not be mixed. **Semantics** @@ -517,7 +521,8 @@ a whole. [It takes on the role of what C and C# call a struct.] Such a construct is sometimes referred to as a "lightweight class". A *shape-specifier* defines a shape type as having an unordered set of fields -each of which has a name (indicated by *single-quoted-string-literal* or *qualified-name*) and a type (indicated by +each of which has a name (indicated by *single-quoted-string-literal*, +*qualified-name* or *scope-resolution-operator*) and a type (indicated by *type-specifier*). A field in a shape is accessed using its name as the key in a [*subscript-expression*](10-expressions.md#subscript-operator) that operates on a shape of the corresponding shape type. diff --git a/spec/22-grammar.md b/spec/22-grammar.md index e7ecbcf..6fd895d 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -415,6 +415,7 @@ octal-digit field-specifier: single-quoted-string-literal => type-specifier qualified-name => type-specifier + scope-resolution-expression => type-specifier ####Closure Types From 845365525b9f60ffe289670c2e08f42e56763e43 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 1 Sep 2016 13:51:42 -0700 Subject: [PATCH 36/46] A generic type parameter list may be comma-terminated A generic type parameter declaration list may be comma terminated: class List ... --- spec/14-generic-types-methods-and-functions.md | 2 +- spec/22-grammar.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/14-generic-types-methods-and-functions.md b/spec/14-generic-types-methods-and-functions.md index 1b353d0..d1339ad 100644 --- a/spec/14-generic-types-methods-and-functions.md +++ b/spec/14-generic-types-methods-and-functions.md @@ -67,7 +67,7 @@ Type parameters are discussed further in [§§](14-generic-types-methods-and-fun **Syntax**
 generic-type-parameter-list:
-  <  generic-type-parameters  >
+  <  generic-type-parameters  ,opt  >
 generic-type-parameters:
   generic-type-parameter
   generic-type-parameters  ,  generic-type-parameter
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index 6fd895d..e6aa428 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -1110,7 +1110,7 @@ octal-digit
 
 
   generic-type-parameter-list:
-    <  generic-type-parameters  >
+    <  generic-type-parameters  ,opt  >
 
   generic-type-parameters:
     generic-type-parameter

From 5ecf1a68962b5d9dddc1c05bd4270a2d3049c5fd Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Thu, 1 Sep 2016 15:27:59 -0700
Subject: [PATCH 37/46] Fix up type aliases

I could not make head nor tail of the constraints on type aliases; as
far as I can tell, the thing to the right can be any type, and I don't
know why there is all this verbiage -- some of it ungrammatical and
likely due to mis-edits -- about qualified names and what the name
means.

Also, a type alias may declare a generic type parameter list. I'm not
yet quite sure of what the semantics are. Once I figure that out I'll
come back and add some text describing it.
---
 spec/05-types.md   | 36 +++++++++++++-----------------------
 spec/22-grammar.md |  8 ++------
 2 files changed, 15 insertions(+), 29 deletions(-)

diff --git a/spec/05-types.md b/spec/05-types.md
index 46ccc10..e9a6774 100644
--- a/spec/05-types.md
+++ b/spec/05-types.md
@@ -734,40 +734,26 @@ class C2 {
 **Syntax**
 
 alias-declaration:
-  type  name  =  type-to-be-aliased  ;
-  newtype  name  type-constraintopt  =  type-to-be-aliased  ;
-
-type-to-be-aliased:
-  type-specifier
-  qualified-name
-
+ type name generic-type-parameter-listopt = type-specifier ; + newtype name generic-type-parameter-listopt type-constraintopt = type-specifier ; **Defined elsewhere** +* [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters) * [*name*](09-lexical-structure.md#names) -* [*qualified-name*](20-namespaces.md#defining-namespaces) * [*type-constraint*](05-types.md#general) * [*type-specifier*](05-types.md#general) **Constraints** -*type-specifier* in *type-to-be-aliased* must not be [*enum-specifier*](05-types.md#general) -or [*class-interface-trait-specifier*](05-types.md#general). - -*qualified-name* in *type-to-be-aliased* must be defined the *name* in an -[*enum-declaration*](13-enums.md#enum-declarations), in a [*class-declaration*](16-classes.md#class-declarations), or in an -[*interface-declaration*](17-interfaces.md#interface-declarations). - -*qualified-name* in *alias-type-specifier* must be defined as the *name* for a -type via an *alias-declaration*. - -*type-specifier* in *type-constraint* must be a subtype of *type-to-be-aliased*. +The *type-specifier* in the optional *type-constraint* must be a subtype +of the *type-specifier* to the right of the equals. **Semantics** -An *alias-declaration* creates an alias *name* for the type specified by -*type-to-be-aliased*. Once such a type alias has been defined, that alias can -be used in any context in which *type-specifier* is permitted. +An *alias-declaration* creates an alias *name* for the specified type. +Once such a type alias has been defined, that alias can +be used in any context in which a *type-specifier* is permitted. Any given type can have multiple aliases, and a type alias can itself have aliases. @@ -780,7 +766,11 @@ implementation. An alias created using `newtype` is an *opaque type alias*. In the absence of a *type-constraint*, each opaque alias type is distinct from its -underlying type and from any other types aliasing it or its underlying type. Only source code in the file that contains the definition of the opaque type alias is allowed access to the underlying implementation. As such, opaque type aliasing is an abstraction mechanism. Consider the following file, which contains an opaque alias definition: +underlying type and from any other types aliasing it or its underlying type. +Only source code in the file that contains the definition of the opaque type +alias is allowed access to the underlying implementation. As such, opaque type +aliasing is an abstraction mechanism. Consider the following file, which +contains an opaque alias definition: ```Hack newtype Point = (int, int); diff --git a/spec/22-grammar.md b/spec/22-grammar.md index e6aa428..f94c2d3 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -444,12 +444,8 @@ octal-digit
 alias-declaration:
-  type  name  =  type-to-be-aliased  ;
-  newtype  name  type-constraintopt  =  type-to-be-aliased  ;
-
-type-to-be-aliased:
-  type-specifier
-  qualified-name
+  type  name  generic-type-parameter-listopt  =  type-specifier  ;
+  newtype  name  generic-type-parameter-listopt  type-constraintopt  =  type-specifier  ;
 
###Variables From 54ada4d9ab30aacbf55c50f2e9b57169509bd613 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Tue, 6 Sep 2016 12:51:35 -0700 Subject: [PATCH 38/46] An alias declaration may have an attribute A type alias (type, newtype) declaration may have an <> on it, just like a class. --- spec/05-types.md | 5 +++-- spec/22-grammar.md | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/05-types.md b/spec/05-types.md index e9a6774..7d78bd4 100644 --- a/spec/05-types.md +++ b/spec/05-types.md @@ -734,11 +734,12 @@ class C2 { **Syntax**
 alias-declaration:
-  type  name  generic-type-parameter-listopt  =  type-specifier  ;
-  newtype  name  generic-type-parameter-listopt  type-constraintopt  =  type-specifier  ;
+  attribute-specificationopt  type  name  generic-type-parameter-listopt  =  type-specifier  ;
+  attribute-specificationopt  newtype  name  generic-type-parameter-listopt  type-constraintopt  =  type-specifier  ;
 
 **Defined elsewhere**
 
+* [*attribute-specification*](21-attributes.md#attribute-specification)
 * [*generic-type-parameter-list*](14-generic-types-methods-and-functions.md#type-parameters)
 * [*name*](09-lexical-structure.md#names)
 * [*type-constraint*](05-types.md#general)
diff --git a/spec/22-grammar.md b/spec/22-grammar.md
index f94c2d3..de68289 100644
--- a/spec/22-grammar.md
+++ b/spec/22-grammar.md
@@ -444,8 +444,8 @@ octal-digit
 
 
 alias-declaration:
-  type  name  generic-type-parameter-listopt  =  type-specifier  ;
-  newtype  name  generic-type-parameter-listopt  type-constraintopt  =  type-specifier  ;
+  attribute-specificationopt  type  name  generic-type-parameter-listopt  =  type-specifier  ;
+  attribute-specificationopt  newtype  name  generic-type-parameter-listopt  type-constraintopt  =  type-specifier  ;
 
###Variables From cab3047452ad40e429b1cf2b9451f874907a245e Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 7 Sep 2016 08:40:06 -0700 Subject: [PATCH 39/46] Simplify inclusion directive grammar An inclusion directive takes as its operand an expression. The grammar calls out that it could be an expression or a parenthesized expression, but a parenthesized expression already is an expression. We can simply say that the directive takes an expression, end of story. --- spec/12-script-inclusion.md | 3 +-- spec/22-grammar.md | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/spec/12-script-inclusion.md b/spec/12-script-inclusion.md index eb7863e..74d1f39 100644 --- a/spec/12-script-inclusion.md +++ b/spec/12-script-inclusion.md @@ -49,8 +49,8 @@ to resolve the include file's location.
 require-multiple-directive:
-  require  (  include-filename  )  ;
   require  include-filename  ;
+
 include-filename:
   expression
 
@@ -85,7 +85,6 @@ require ('Circle.php');
   require-once-directive:
-    require_once  (  include-filename  )  ;
     require_once  include-filename  ;
 
diff --git a/spec/22-grammar.md b/spec/22-grammar.md index de68289..7a65d27 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1070,14 +1070,12 @@ octal-digit require-once-directive require-multiple-directive: - require ( include-filename ) ; require include-filename ; include-filename: expression require-once-directive: - require_once ( include-filename ) ; require_once include-filename ;
From 538b28e4452b59f50c186bdf60206e6d508b1863 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 8 Sep 2016 10:27:04 -0700 Subject: [PATCH 40/46] The use-clause variable list may have a trailing comma The use-clause variable list may have a trailing comma --- spec/10-expressions.md | 2 +- spec/22-grammar.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 24ad2f7..2121a2e 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -598,7 +598,7 @@ shape('id' => null, 'url' => null, 'count' => 0) : return-type anonymous-function-use-clause: - use (  use-variable-name-list  ) + use (  use-variable-name-list ,opt ) use-variable-name-list: variable-name diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 7a65d27..d2e66e8 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -585,7 +585,7 @@ octal-digit : return-type anonymous-function-use-clause: - use ( use-variable-name-list ) + use ( use-variable-name-list ,opt ) use-variable-name-list: variable-name From 2278ef9c657051fd90865e5bf195b451638e90e9 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Thu, 8 Sep 2016 11:42:09 -0700 Subject: [PATCH 41/46] Field initializers can have a trailing comma Field initializers can have a trailing comma --- spec/10-expressions.md | 4 +++- spec/22-grammar.md | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/10-expressions.md b/spec/10-expressions.md index 2121a2e..1b88207 100644 --- a/spec/10-expressions.md +++ b/spec/10-expressions.md @@ -525,8 +525,10 @@ in *field-initializer* need not be compile-time constants. shape-literal: shape ( field-initializer-listopt ) field-initializer-list: + field-initializers ,opt + field-initializers: field-initializer - field-initializer-list , field-initializer + field-initializers , field-initializer field-initializer: single-quoted-string-literal => expression integer-literal => expression diff --git a/spec/22-grammar.md b/spec/22-grammar.md index d2e66e8..a62bd5d 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -556,8 +556,11 @@ octal-digit shape ( field-initializer-listopt ) field-initializer-list: + field-initializers ,opt + + field-initializers: field-initializer - field-initializer-list , field-initializer + field-initializers , field-initializer field-initializer: single-quoted-string-literal => expression From 337378d7b8c9d8a82ba0018b6b8b9ca79e87ce84 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Tue, 13 Sep 2016 14:28:34 -0700 Subject: [PATCH 42/46] The argument of a classname type can be generic The argument of a classname type can be generic --- spec/05-types.md | 2 +- spec/22-grammar.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/05-types.md b/spec/05-types.md index 7d78bd4..d9a972e 100644 --- a/spec/05-types.md +++ b/spec/05-types.md @@ -698,7 +698,7 @@ parameters. See [§§](14-generic-types-methods-and-functions.md#generic-types-m **Syntax**
 classname-type-specifier:
-  classname  <  qualified-name  >
+  classname  <  qualified-name  generic-type-argument-listopt  >
 
**Defined elsewhere** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index a62bd5d..a53598e 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -437,7 +437,7 @@ octal-digit
 classname-type-specifier:
-  classname   <   qualified-name   >
+  classname   <   qualified-name  generic-type-argument-listopt  >
 
####Type Aliases From c64eff285e1e2718fc470b716136e0640c1ecc9c Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 19 Oct 2016 11:50:32 -0700 Subject: [PATCH 43/46] Fix grammar for HEREDOC / NOWDOC string literals The lexical grammar as given in the spec required that the body of a HEREDOC/NOWDOC string literal contain at least one newline, but that is not required: <<p1 = >$myC->p1<\n"; // → $myC->p1 = >2<
   heredoc-string-literal::
-    <<<  hd-start-identifier   new-line   hd-char-sequenceopt  new-line hd-end-identifier  ;opt   new-line
+    <<<  hd-start-identifier   new-line   hd-bodyopt   hd-end-identifier  ;opt   new-line
 
   hd-start-identifier::
     name
@@ -727,6 +727,9 @@ echo "\$myC->p1 = >$myC->p1<\n";  // → $myC->p1 = >2<
   hd-end-identifier::
     name
 
+  hd-body::
+    hd-char-sequenceopt   new-line
+
   hd-char-sequence::
     hd-char
     hd-char-sequence   hd-char
@@ -797,12 +800,12 @@ Some more text<
 
 
   nowdoc-string-literal::
-    <<<  '  hd-start-identifier  '  new-line  hd-char-sequenceopt   new-line hd-end-identifier  ;opt   new-line
+    <<<  '  hd-start-identifier  '  new-line  hd-bodyopt   hd-end-identifier  ;opt   new-line
 
**Defined elsewhere** -* [*hd-char-sequence*](09-lexical-structure.md#heredoc-string-literals) +* [*hd-body*](09-lexical-structure.md#heredoc-string-literals) * [*hd-end-identifier*](09-lexical-structure.md#heredoc-string-literals) * [*hd-start-identifier*](09-lexical-structure.md#heredoc-string-literals) * [*new-line*](09-lexical-structure.md#comments) diff --git a/spec/22-grammar.md b/spec/22-grammar.md index a53598e..08effd9 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -252,7 +252,7 @@ octal-digit \X hexadecimal-digit hexadecimal-digitopt heredoc-string-literal:: - <<< hd-start-identifier new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line + <<< hd-start-identifier new-line hd-bodyopt hd-end-identifier ;opt new-line hd-start-identifier:: name @@ -260,6 +260,9 @@ octal-digit hd-end-identifier:: name + hd-body:: + hd-char-sequenceopt new-line + hd-char-sequence:: hd-char hd-char-sequence hd-char @@ -278,9 +281,8 @@ octal-digit hd-simple-escape-sequence:: one of \\ \$ \e \f \n \r \t \v - nowdoc-string-literal:: - <<< ' hd-start-identifier ' new-line hd-char-sequenceopt new-line hd-end-identifier ;opt new-line + <<< ' hd-start-identifier ' new-line hd-bodyopt hd-end-identifier ;opt new-line
####The Null Literal From d8039fdd48b7d152e0ae2cc0d1dd8e628be2f75e Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Wed, 19 Oct 2016 15:58:19 -0700 Subject: [PATCH 44/46] Enum declarations can have an attribute specification * An enum declaration can have an attribute specification * Fixed the formatting of the "defined elsewhere" list in the section on enums. --- spec/13-enums.md | 9 +++++++-- spec/22-grammar.md | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spec/13-enums.md b/spec/13-enums.md index 8cc1bb1..583c887 100644 --- a/spec/13-enums.md +++ b/spec/13-enums.md @@ -9,7 +9,7 @@ An *enumeration* consists of a set of zero or more named, constant values called **Syntax**
 enum-declaration:
-  enum  name  enum-base  type-constraintopt  {  enumerator-listopt  }
+  attribute-specificationopt   enum  name  enum-base  type-constraintopt  {  enumerator-listopt  }
 enum-base:
   :  int
   :  string
@@ -22,7 +22,12 @@ An *enumeration* consists of a set of zero or more named, constant values called
   name
 
-*name* is defined in [§§](09-lexical-structure.md#names); *type-constraint* is defined in [§§](05-types.md#general); and *constant-expression* is defined in [§§](10-expressions.md#constant-expressions). +**Defined elsewhere** + +* [*attribute-specification*](21-attributes.md#attribute-specification) +* [*constant-expression*](10-expressions.md#constant-expressions) +* [*name*](09-lexical-structure.md#names) +* [*type-constraint*](05-types.md#general) **Constraints** diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 08effd9..d59198a 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -1088,7 +1088,7 @@ octal-digit
   enum-declaration:
-  enum  name  enum-base  type-constraintopt  {  enumerator-listopt  }
+    attribute-specificationopt  enum  name  enum-base  type-constraintopt  {  enumerator-listopt  }
 
   enum-base:
     :  int

From 0c622e8a4ba3f6d4da75029720d2752b5320ba2f Mon Sep 17 00:00:00 2001
From: Eric Lippert 
Date: Mon, 24 Oct 2016 11:18:57 -0700
Subject: [PATCH 45/46] Describe heuristic for disambiguating casts

The spec only allowed for four things in a cast operator, but in fact
Hack allows eight keywords and any simple name. The grammar now matches
the implementation.

However, doing so introduces an ambiguity; (x)-$y could be a
subtraction or a cast.  The spec now describes a heuristic that an
implementation can use to tell whether or not (x) is to be parsed as a
cast or a parenthesized expression.

There is still more work to do here, not done in this diff:

(1) We need to describe the semantics of all possible casts.
(2) We should consider whether the cast type can be more than just a
simple name.  Can it be an array type, a shape type, a generic type, a
nullable type?  Can it be a qualified name?  And so on.
---
 spec/10-expressions.md | 43 ++++++++++++++++++++++++++++++++++--------
 spec/22-grammar.md     | 15 +++++++++++----
 2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index 1b88207..18c969e 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -848,7 +848,7 @@ The *class-type-designator* must not designate an [abstract class](16-classes.md
 
 The *class-type-designator* must not be a [generic type parameter](14-generic-types-methods-and-functions.md#type-parameters).
 
-The *object-creation-expression* will invoke the constructor of the class designated by the *class-type-designator*. 
+The *object-creation-expression* will invoke the constructor of the class designated by the *class-type-designator*.
 
 *argument-expression-list* must contain an argument for each parameter in the
 [constructor's definition](15-functions.md#function-definitions) not having a default value, and each
@@ -1300,7 +1300,7 @@ $anon();  // call the anonymous function
 method of the class designated by *postfix-expression*.
 
 *variable-name* must name a variable which when evaluated produces a string
-containing an instance property or an instance method of the class 
+containing an instance property or an instance method of the class
 designated by *postfix-expression*.
 
 
@@ -1352,14 +1352,14 @@ $p1->move(3, 9);  // calls public instance method move by name
 *name* must designate an instance property or an instance method of the class designated by *postfix-expression*.
 
 *variable-name* must name a variable which when evaluated produces a string
-containing an instance property or an instance method of the class 
+containing an instance property or an instance method of the class
 designated by *postfix-expression*.
 
 **Semantics**
 
-If *postfix-expression* is `null`, no property or method is selected and the 
-resulting value is `null`. Otherwise, the behavior is like that of the 
-[member-selection operator `->`](10-expressions.md#member-selection-operator), 
+If *postfix-expression* is `null`, no property or method is selected and the
+resulting value is `null`. Otherwise, the behavior is like that of the
+[member-selection operator `->`](10-expressions.md#member-selection-operator),
 except that the resulting value is not an lvalue.
 
 ###Postfix Increment and Decrement Operators
@@ -1730,14 +1730,41 @@ error message displayed.
   cast-expression:cast-type  ) unary-expression
 
-  cast-type: one of
-    bool  int  float  string
+  cast-type:
+    array
+    bool
+    double
+    float
+    int
+    object
+    string
+    name
 
**Defined elsewhere** +* [*name*](09-lexical-structure.md#names) * [*unary-expression*](10-expressions.md#general-4) +**Constraints** + +The grammar for the cast-expression introduces certain syntactic +ambiguities. For example, the expression `(x)-y` could be interpreted as a +cast of `-y` to type `x`, or as the arithmetical computation of `x-y`. + +This ambiguity is resolved as follows: + +* If the token inside the parentheses is `array`, `bool`, `double`, +`float`, `int`, `object` or `string` then the expression is a +*cast-expression*. +* Otherwise, if the token following the right parenthesis is `as` or +`instanceof` then `(` *name* `)` is a parenthesized expression, not a cast operator. +* Otherwise, if the token following the right parenthesis is is +`$$`, `@`, `~`, `!`, `(`, `+`, `-`, `++`, `--`, or any *name*, *qualified-name*, +or *variable-name*, or any numeric, string, Boolean or null literal, or any keyword +then the expression is a *cast-expression*. +* Otherwise, `(` *name* `)` is a parenthesized expression, not a cast operator. + **Semantics** The diff --git a/spec/22-grammar.md b/spec/22-grammar.md index d59198a..78e06c9 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -578,7 +578,7 @@ octal-digit anonymous-function-parameter-declaration-list anonymous-function-parameter-declaration-list , anonymous-function-parameter-declaration-list , ... - + anonymous-function-parameter-declaration-list: anonymous-function-parameter-declaration anonymous-function-parameter-declaration-list , anonymous-function-parameter-declaration @@ -734,8 +734,15 @@ octal-digit cast-expression: ( cast-type ) unary-expression - cast-type: one of - bool int float string + cast-type: + array + bool + double + float + int + object + string + name await-expression: await expression @@ -1276,7 +1283,7 @@ octal-digit attribute-specificationopt visibility-modifier function __destruct ( ) void-returnopt compound-statement void-return: - : void + : void type-constant-declaration: abstract-type-constant-declaration From 0efefcc9ec070479e65a6ab337bb333b3189c4c9 Mon Sep 17 00:00:00 2001 From: Eric Lippert Date: Mon, 24 Oct 2016 11:23:09 -0700 Subject: [PATCH 46/46] Remove byref assignment production The grammar listing has a byref-assignment-expression production which is nowhere mentioned elsewhere in the grammar or in the specification. I assume this is a mis-edit; when the feature was removed from the spec it was not removed from the grammar chapter. --- spec/22-grammar.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/spec/22-grammar.md b/spec/22-grammar.md index 78e06c9..9a0aa0b 100644 --- a/spec/22-grammar.md +++ b/spec/22-grammar.md @@ -886,9 +886,6 @@ octal-digit simple-assignment-expression: unary-expression = assignment-expression - byref-assignment-expression: - unary-expression = & assignment-expression - compound-assignment-expression: unary-expression compound-assignment-operator assignment-expression