>
> "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...