Skip to content

Commit b6d0269

Browse files
committed
Add support for the match expression
See xp-framework/ast#8
1 parent e50d2bf commit b6d0269

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/main/php/lang/ast/emit/PHP.class.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,34 @@ protected function emitSwitch($result, $switch) {
545545
$result->out->write('}');
546546
}
547547

548+
protected function emitMatch($result, $match) {
549+
$t= $result->temp();
550+
$result->out->write('('.$t.'=');
551+
$this->emitOne($result, $match->expression);
552+
$result->out->write(')');
553+
554+
$b= 0;
555+
foreach ($match->cases as $case) {
556+
foreach ($case->expressions as $expression) {
557+
$b && $result->out->write($t);
558+
$result->out->write('===');
559+
$this->emitOne($result, $expression);
560+
$result->out->write('?');
561+
$this->emitOne($result, $case->body[0]);
562+
$result->out->write(':(');
563+
$b++;
564+
}
565+
}
566+
567+
// Emit IIFE for raising an error until we have throw expressions
568+
if (null === $match->default) {
569+
$result->out->write('function() use('.$t.') { throw new \\Error("Unhandled match value of type ".gettype('.$t.')); })(');
570+
} else {
571+
$this->emitOne($result, $match->default[0]);
572+
}
573+
$result->out->write(str_repeat(')', $b));
574+
}
575+
548576
protected function emitCatch($result, $catch) {
549577
if (empty($catch->types)) {
550578
$result->out->write('catch(\\Throwable $'.$catch->variable.') {');

src/test/php/lang/ast/unittest/emit/ControlStructuresTest.class.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php namespace lang\ast\unittest\emit;
22

3+
use lang\Throwable;
34
use unittest\Assert;
45

56
class ControlStructuresTest extends EmittingTest {
@@ -61,4 +62,50 @@ public function run($arg) {
6162

6263
Assert::equals($expected, $r);
6364
}
65+
66+
#[@test, @values([[SEEK_SET, 10], [SEEK_CUR, 11], [SEEK_END, 6100]])]
67+
public function match($whence, $expected) {
68+
$r= $this->run('class <T> {
69+
public function run($arg) {
70+
$position= 1;
71+
$size= 6100;
72+
return match ($arg) {
73+
SEEK_SET => 10,
74+
SEEK_CUR => $position + 10,
75+
SEEK_END => min($size + $position, $size),
76+
};
77+
}
78+
}', $whence);
79+
80+
Assert::equals($expected, $r);
81+
}
82+
83+
#[@test, @values([[SEEK_SET, 10], [SEEK_CUR, 11], [SEEK_END, 6100]])]
84+
public function match_with_default($whence, $expected) {
85+
$r= $this->run('class <T> {
86+
public function run($arg) {
87+
$position= 1;
88+
$size= 6100;
89+
return match ($arg) {
90+
SEEK_SET => 10,
91+
SEEK_CUR => $position + 10,
92+
default => min($size + $position, $size),
93+
};
94+
}
95+
}', $whence);
96+
97+
Assert::equals($expected, $r);
98+
}
99+
100+
#[@test, @expect(['class' => Throwable::class, 'withMessage' => '/Unhandled match value of type .+/'])]
101+
public function unhandled_match() {
102+
$this->run('class <T> {
103+
public function run($arg) {
104+
return match ($arg) {
105+
SEEK_SET => 10,
106+
SEEK_CUR => $position + 10,
107+
};
108+
}
109+
}', SEEK_END);
110+
}
64111
}

0 commit comments

Comments
 (0)