Skip to content

Instantly share code, notes, and snippets.

@thekid
Created January 31, 2026 11:01
Show Gist options
  • Select an option

  • Save thekid/56ccd4057a3aa7c2e32447d076d52fb5 to your computer and use it in GitHub Desktop.

Select an option

Save thekid/56ccd4057a3aa7c2e32447d076d52fb5 to your computer and use it in GitHub Desktop.
Match pattern matching inside branches
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 30832b5..9c3f126 100755
--- a/src/main/php/lang/ast/syntax/php/IsOperator.class.php
+++ b/src/main/php/lang/ast/syntax/php/IsOperator.class.php
@@ -125,6 +125,8 @@ class IsOperator implements Extension {
});
$language->prefix('match', 0, function($parse, $token) use($pattern) {
+ static $id= 0;
+
$patterns= null;
$condition= null;
@@ -132,22 +134,9 @@ class IsOperator implements Extension {
$parse->forward();
$condition= $this->expression($parse, 0);
$parse->expecting(')', 'match');
-
- // See https://wiki.php.net/rfc/pattern-matching#match_is_placement
- if ('is' === $parse->token->value) {
- $parse->forward();
-
- $true= new Literal('true');
- if ($condition instanceof Variable) {
- $patterns= $condition;
- $condition= $true;
- } else {
- $patterns= new Variable('Ṁ');
- $condition= new BinaryExpression(new Braced(new Assignment($patterns, '=', $condition)), '||', $true);
- }
- }
}
+ $is= false;
$default= null;
$cases= [];
$parse->expecting('{', 'match');
@@ -156,8 +145,10 @@ class IsOperator implements Extension {
$parse->forward();
$parse->expecting('=>', 'match');
$default= $this->expression($parse, 0);
- } else if ($patterns) {
- $match= [new PatternMatch($patterns, $pattern($parse, $this), $parse->token->line)];
+ } else if ('is' === $parse->token->value) {
+ $is= true;
+ $parse->forward();
+ $match= [new PatternMatch(null, $pattern($parse, $this), $parse->token->line)];
$parse->expecting('=>', 'match');
$cases[]= new MatchCondition($match, $this->expression($parse, 0), $parse->token->line);
} else {
@@ -175,6 +166,26 @@ class IsOperator implements Extension {
}
$parse->expecting('}', 'match');
+ // If one of the branches contains an `is` match, rewrite the statement
+ if ($is) {
+ $patterns= new Variable('Ṁ'.($id++));
+ $condition= new BinaryExpression(
+ new Braced(new Assignment($patterns, '=', $condition)),
+ '||',
+ new Literal('true')
+ );
+
+ foreach ($cases as $case) {
+ foreach ($case->expressions as &$match) {
+ if ($match instanceof PatternMatch) {
+ $match->expression= $patterns;
+ } else {
+ $match= new BinaryExpression($match, '===', $patterns);
+ }
+ }
+ }
+ }
+
return new MatchExpression($condition, $cases, $default, $token->line);
});
diff --git a/src/test/php/lang/ast/syntax/php/unittest/IsOperatorTest.class.php b/src/test/php/lang/ast/syntax/php/unittest/IsOperatorTest.class.php
index e6b3709..93fb797 100755
--- a/src/test/php/lang/ast/syntax/php/unittest/IsOperatorTest.class.php
+++ b/src/test/php/lang/ast/syntax/php/unittest/IsOperatorTest.class.php
@@ -36,13 +36,14 @@ class IsOperatorTest extends EmittingTest {
}', $arg));
}
- #[Test, Values([[1, 'int'], ['test', 'string']])]
+ #[Test, Values([[1, 'int'], ['', 'string'], ['test', 'string'], [null, 'undefined']])]
public function match_is_variant($arg, $expected) {
Assert::equals($expected, $this->run('class %T {
- public function run(string|int $arg) {
- return match ($arg) is {
- string => "string",
- int => "int",
+ public function run(?string|int $arg) {
+ return match ($arg) {
+ is string => "string",
+ is int => "int",
+ null => "undefined",
};
}
}', $arg));
@@ -57,9 +58,9 @@ class IsOperatorTest extends EmittingTest {
$invoked++;
return 1;
};
- return match ($arg()) is {
- 0 => ["zero", $invoked],
- 1 => ["one", $invoked],
+ return match ($arg()) {
+ is 0 => ["zero", $invoked],
+ is 1 => ["one", $invoked],
};
}
}'));
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 3c02f5e..80fcd3d 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
@@ -49,8 +49,8 @@ class VariableBindingTest extends EmittingTest {
public function compound_binding($input) {
Assert::equals('apple', $this->run('class %T {
public function run($command) {
- return match ($command) is {
- ["get", $object]|["pick", "up", $object]|["pick", $object, "up"] => $object,
+ return match ($command) {
+ is ["get", $object]|["pick", "up", $object]|["pick", $object, "up"] => $object,
default => null,
};
}
@@ -61,8 +61,8 @@ class VariableBindingTest extends EmittingTest {
public function bind_with_subpattern($input, $expected) {
Assert::equals($expected, $this->run('class %T {
public function run($command) {
- return match ($command) is {
- ["go", $direction & ("north"|"south"|"east"|"west")] => $direction,
+ return match ($command) {
+ is ["go", $direction & ("north"|"south"|"east"|"west")] => $direction,
default => null,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment