>
>  "Cheating" in the sense that you wrote out a "general syntax",
>
I got it.

> That's not the problem; the problem is that the following are all
equivalent expressions:
>  (((foo())))

In principle, this is not a problem because the expression in parentheses
preceded by `spawn` is unambiguously a call expression.
That is, from an analysis perspective, everything is fine here because the
expression `spawn ()` is a syntax error.

On the other hand, the expression `spawn (())` is also an error, but a
semantic one, because there is nothing to call.

The expression spawn ((), (), ()) is also an error because it attempts to
specify a list of parameters without a call expression.

It seems I didn't make any mistakes anywhere?

>
> But from a user's point of view, I hate rules like that which mean subtle
changes completely change the meaning of the code, in a very specific
context.
>

>From the user's perspective, what is the difference between these two
expressions?

```php
spawn function(): string { ... };
spawn (function(): string { ... });
```

>
>  All of these are examples of the keyword being followed by *a function
call*, not *any expression*. Which honestly I think is the right way to go.
>

I created these examples according to the syntax rules from the Bison file
for `function_call`.
Of course, I might have missed something, but overall, the list above
essentially represents what `function_call` should expand into.

If we define the rule `spawn function_call`, then `spawn` acts as a prefix
in this expression. However, everything that is already defined for
`function_call` in PHP must remain valid.

If we take the most complex part:
```bison
|   callable_expr { $<num>$ = CG(zend_lineno); } argument_list {
        $$ = zend_ast_create(ZEND_AST_CALL, $1, $3);
        $$->lineno = $<num>2;
    }

callable_expr:
    callable_variable       { $$ = $1; }
  | '(' expr ')'           { $$ = $2; }
  | dereferenceable_scalar { $$ = $1; }
  | new_dereferenceable    { $$ = $1; }
;
```

we can see that the expression (((some()))) corresponds to the second line,
and arguments must follow.
However, in this case, arguments become *mandatory*. This means that after
(((some()))), there must also be ().

And another good thing about this syntax: a coroutine is an execution
context, and a function call is a transition to a block of code.
This means that the expression `spawn function_call` can be understood
literally as:

* Create a new execution context
* Execute `function_call`

The syntax for `function_call` is already defined in PHP, and nothing
changes in it.

The second form of the `spawn` expression is:
```php
spawn inline_function
```

where inline_function is a definition from bison:

```bison
inline_function:
function returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars
return_type
...;
```

Another advantage of this solution is that if `function_call` constructs
change in the future, we won’t need to modify the definitions for `spawn`.

>
>  If it's going to be a special case for an "inline coroutine", just use a
keyword other than "function", so it doesn't look like an expression when
it's not, like "spawn block { ... }"; or no keyword at all, just "spawn {
... }"
>

Well, yes, but here we again face the issue with `returnType` syntax, which
ends up hanging in the air...

Reply via email to