Skip to content

Commit d33f710

Browse files
committed
Add initial support for callable syntax
1 parent ee056be commit d33f710

File tree

3 files changed

+147
-1
lines changed

3 files changed

+147
-1
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"keywords": ["module", "xp"],
88
"require" : {
99
"xp-framework/core": "^10.0 | ^9.0 | ^8.0 | ^7.0",
10-
"xp-framework/ast": "^7.3",
10+
"xp-framework/ast": "dev-feature/first_class_callable_syntax as 7.4.0",
1111
"php" : ">=7.0.0"
1212
},
1313
"require-dev" : {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,13 @@ protected function emitNewClass($result, $new) {
988988
array_shift($result->type);
989989
}
990990

991+
protected function emitCallable($result, $callable) {
992+
$t= $result->temp();
993+
$result->out->write('fn(...'.$t.') => ');
994+
$this->emitOne($result, $callable->expression);
995+
$result->out->write('(... '.$t.')');
996+
}
997+
991998
protected function emitInvoke($result, $invoke) {
992999
$this->emitOne($result, $invoke->expression);
9931000
$result->out->write('(');
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php namespace lang\ast\unittest\emit;
2+
3+
use unittest\actions\RuntimeVersion;
4+
use unittest\{Action, Assert, Test, Values};
5+
6+
class CallableSyntaxTest extends EmittingTest {
7+
8+
#[Test]
9+
public function native_function() {
10+
$f= $this->run('class <T> {
11+
public function run() { return strlen(...); }
12+
}');
13+
14+
Assert::equals(4, $f('Test'));
15+
}
16+
17+
#[Test]
18+
public function instance_method() {
19+
$f= $this->run('class <T> {
20+
public function length($arg) { return strlen($arg); }
21+
public function run() { return $this->length(...); }
22+
}');
23+
24+
Assert::equals(4, $f('Test'));
25+
}
26+
27+
#[Test]
28+
public function class_method() {
29+
$f= $this->run('class <T> {
30+
public static function length($arg) { return strlen($arg); }
31+
public function run() { return self::length(...); }
32+
}');
33+
34+
Assert::equals(4, $f('Test'));
35+
}
36+
37+
#[Test]
38+
public function private_method() {
39+
$f= $this->run('class <T> {
40+
private function length($arg) { return strlen($arg); }
41+
public function run() { return $this->length(...); }
42+
}');
43+
44+
Assert::equals(4, $f('Test'));
45+
}
46+
47+
#[Test]
48+
public function variable_function() {
49+
$f= $this->run('class <T> {
50+
public function run() {
51+
$func= "strlen";
52+
return $func(...);
53+
}
54+
}');
55+
56+
Assert::equals(4, $f('Test'));
57+
}
58+
59+
#[Test]
60+
public function instance_method_reference() {
61+
$f= $this->run('class <T> {
62+
private $func= "strlen";
63+
public function run() {
64+
return ($this->func)(...);
65+
}
66+
}');
67+
68+
Assert::equals(4, $f('Test'));
69+
}
70+
71+
#[Test]
72+
public function variable_instance_method() {
73+
$f= $this->run('class <T> {
74+
private function length($arg) { return strlen($arg); }
75+
public function run() {
76+
$func= "length";
77+
return $this->$func(...);
78+
}
79+
}');
80+
81+
Assert::equals(4, $f('Test'));
82+
}
83+
84+
#[Test]
85+
public function variable_class_method() {
86+
$f= $this->run('class <T> {
87+
private static function length($arg) { return strlen($arg); }
88+
public function run() {
89+
$func= "length";
90+
return self::$func(...);
91+
}
92+
}');
93+
94+
Assert::equals(4, $f('Test'));
95+
}
96+
97+
#[Test]
98+
public function variable_class_method_with_variable_class() {
99+
$f= $this->run('class <T> {
100+
private static function length($arg) { return strlen($arg); }
101+
public function run() {
102+
$func= "length";
103+
$class= __CLASS__;
104+
return $class::$func(...);
105+
}
106+
}');
107+
108+
Assert::equals(4, $f('Test'));
109+
}
110+
111+
#[Test]
112+
public function string_function_reference() {
113+
$f= $this->run('class <T> {
114+
public function run() { return "strlen"(...); }
115+
}');
116+
117+
Assert::equals(4, $f('Test'));
118+
}
119+
120+
#[Test]
121+
public function array_instance_method_reference() {
122+
$f= $this->run('class <T> {
123+
public function length($arg) { return strlen($arg); }
124+
public function run() { return [$this, "length"](...); }
125+
}');
126+
127+
Assert::equals(4, $f('Test'));
128+
}
129+
130+
#[Test]
131+
public function array_class_method_reference() {
132+
$f= $this->run('class <T> {
133+
public static function length($arg) { return strlen($arg); }
134+
public function run() { return [self::class, "length"](...); }
135+
}');
136+
137+
Assert::equals(4, $f('Test'));
138+
}
139+
}

0 commit comments

Comments
 (0)