-
Notifications
You must be signed in to change notification settings - Fork 0
Make compatible with PHP's pattern matching RFC #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
In Python, the following works: match command.split():
case ["drop", *objects]:
for obj in objects:
character.drop(obj, current_room)
# The rest of your commands go hereMaybe we should be able to bind to variables when using the spread operator, too? Example: if ([1, 2, 3] is [1, ...$rest]) {
var_dump($rest); // [2, 3]
}POC: diff --git a/src/main/php/lang/ast/syntax/php/IsOperator.class.php b/src/main/php/lang/ast/syntax/php/IsOperator.class.php
index af55634..1d3b4f8 100755
--- a/src/main/php/lang/ast/syntax/php/IsOperator.class.php
+++ b/src/main/php/lang/ast/syntax/php/IsOperator.class.php
@@ -74,8 +74,16 @@ class IsOperator implements Extension {
$parse->forward();
if (']' !== $parse->token->value) do {
if ('...' === $parse->token->value) {
- $r->rest= true;
$parse->forward();
+
+ // Bind rest of array via `... $rest`
+ if ('variable' === $parse->token->kind) {
+ $parse->forward();
+ $r->rest= new Variable($parse->token->value);
+ $parse->forward();
+ } else {
+ $r->rest= true;
+ }
break;
}
@@ -233,6 +241,21 @@ class IsOperator implements Extension {
$match($codegen, new OffsetExpression($temp, $offset), $p),
));
}
+
+ if ($pattern->rest instanceof Variable) {
+ $true= new Literal('true');
+ return new BinaryExpression($compound, '&&', new Braced(
+ new TernaryExpression(
+ new Braced(new Assignment($pattern->rest, '=', isset($key)
+ ? new InvokeExpression(new Literal('array_slice'), [$temp, new Literal((string)($key + 1))])
+ : $temp
+ )),
+ $true,
+ $true
+ ))
+ );
+ }
+
return $compound;
} else if ($pattern instanceof IsObjectStructure) {
$temp= new Variable($codegen->symbol());
diff --git a/src/test/php/lang/ast/syntax/php/unittest/VariableBindingTest.class.php b/src/test/php/lang/ast/syntax/php/unittest/VariableBindingTest.class.php
index 57645d0..57b82e7 100755
--- a/src/test/php/lang/ast/syntax/php/unittest/VariableBindingTest.class.php
+++ b/src/test/php/lang/ast/syntax/php/unittest/VariableBindingTest.class.php
@@ -29,6 +29,9 @@ class VariableBindingTest extends EmittingTest {
yield ['[0, 1, 2] is [$x, $y, $z] ? [$x, $y, $z] : null', [0, 1, 2]];
yield ['[1, [1]] is [1, $rest] ? $rest : null', [1]];
+ yield ['[1, [1]] is [1, ...$rest] ? $rest : null', [[1]]];
+ yield ['[1, 2, 3] is [...$rest] ? $rest : null', [1, 2, 3]];
+ yield ['[1, 2, 3] is [1, ...$rest] ? $rest : null', [2, 3]];
yield ['["one" => 1, "two" => 2] is ["one" => 1, "two" => $t] ? $t : null', 2];
yield ['["one" => 0, "two" => 2] is ["one" => 1, "two" => $t] ? $t : null', null]; |
The latter is only for numerical comparison
|
Variable bindings can replace destructuring assignments in most cases:
The if ($list is [$a, $b, ...]) {
var_dump($a, $b);
}
// Equivalent of, guarded by type and length checks to prevent errors
if (is_array($list) && sizeof($list) >= 2) {
[$a, $b]= $list;
var_dump($a, $b);
} |
|
Following the idea of replacing destructuring assignments, I wanted to see whether I would be able to parse Composer files. Here's what I came up with: use lang\FormatException;
use util\cmd\Console;
class ComposerFile {
private function __construct(
public private(set) string $name,
public private(set) ?string $type,
public private(set) array $dependencies,
public private(set) array $development= [],
public private(set) array $scripts= [],
) { }
private static function parse(string $input): self {
if (json_decode($input, true) is [
'name' => $name & string,
'type' => $type & ?string ?? null,
'require' => $dependencies & array,
'require-dev' => $development & array ?? [],
'scripts' => $scripts & array ?? [],
...
]) return new self($name, $type, $dependencies, $development, $scripts);
throw new FormatException('Cannnot parse given input');
}
public static function main(array $args): void {
file_get_contents($args[0])
|> self::parse(...)
|> Console::writeLine(...)
;
}
}The missing piece is having a way to make certain keys optional, which I implemented using the null-coalescing operator, inspired by https://wiki.php.net/rfc/destructuring_coalesce |
This PR extends the basic type matching capabilities and implements all of https://wiki.php.net/rfc/pattern-matching
Implementation status
&and|match (...) is, see https://wiki.php.net/rfc/pattern-matching#match_is_placementNotes
See also