Skip to content

Commit 477dccd

Browse files
authored
Merge pull request #80 from xp-framework/feature/new_expr
Allow `new (<expr>)` as syntax
2 parents d3bdd89 + ff2d8c9 commit 477dccd

File tree

4 files changed

+99
-10
lines changed

4 files changed

+99
-10
lines changed

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ protected function emitCast($result, $cast) {
122122
static $native= ['string' => true, 'int' => true, 'float' => true, 'bool' => true, 'array' => true, 'object' => true];
123123

124124
$name= $cast->type->name();
125-
if ('?' === $name{0}) {
125+
if ('?' === $name[0]) {
126126
$result->out->write('cast(');
127127
$this->emitOne($result, $cast->expression);
128128
$result->out->write(',\''.$name.'\', false)');
@@ -662,9 +662,18 @@ protected function emitArguments($result, $arguments) {
662662
}
663663

664664
protected function emitNew($result, $new) {
665-
$result->out->write('new '.$new->type.'(');
666-
$this->emitArguments($result, $new->arguments);
667-
$result->out->write(')');
665+
if ($new->type instanceof Node) {
666+
$t= $result->temp();
667+
$result->out->write('('.$t.'= ');
668+
$this->emitOne($result, $new->type);
669+
$result->out->write(') ? new '.$t.'(');
670+
$this->emitArguments($result, $new->arguments);
671+
$result->out->write(') : null');
672+
} else {
673+
$result->out->write('new '.$new->type.'(');
674+
$this->emitArguments($result, $new->arguments);
675+
$result->out->write(')');
676+
}
668677
}
669678

670679
protected function emitNewClass($result, $new) {

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,19 +281,29 @@ public function __construct() {
281281
});
282282

283283
$this->prefix('new', 0, function($parse, $token) {
284-
$type= $parse->token;
285-
$parse->forward();
284+
if ('(' === $parse->token->value) {
285+
$parse->expecting('(', 'new type');
286+
$type= $this->expression($parse, 0);
287+
$parse->expecting(')', 'new type');
288+
} else if ('variable' === $parse->token->kind) {
289+
$type= '$'.$parse->token->value;
290+
$parse->forward();
291+
} else if ('class' === $parse->token->value) {
292+
$type= null;
293+
$parse->forward();
294+
} else {
295+
$type= $parse->scope->resolve($parse->token->value);
296+
$parse->forward();
297+
}
286298

287299
$parse->expecting('(', 'new arguments');
288300
$arguments= $this->expressions($parse);
289301
$parse->expecting(')', 'new arguments');
290302

291-
if ('variable' === $type->kind) {
292-
return new NewExpression('$'.$type->value, $arguments, $token->line);
293-
} else if ('class' === $type->value) {
303+
if (null === $type) {
294304
return new NewClassExpression($this->clazz($parse, null), $arguments, $token->line);
295305
} else {
296-
return new NewExpression($parse->scope->resolve($type->value), $arguments, $token->line);
306+
return new NewExpression($type, $arguments, $token->line);
297307
}
298308
});
299309

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php namespace lang\ast\unittest\emit;
2+
3+
use unittest\Assert;
4+
use util\Date;
5+
6+
class InstantiationTest extends EmittingTest {
7+
8+
#[@test]
9+
public function new_type() {
10+
$r= $this->run('class <T> {
11+
public function run() {
12+
return new \\util\\Date();
13+
}
14+
}');
15+
Assert::instance(Date::class, $r);
16+
}
17+
18+
#[@test]
19+
public function new_var() {
20+
$r= $this->run('class <T> {
21+
public function run() {
22+
$class= \\util\\Date::class;
23+
return new $class();
24+
}
25+
}');
26+
Assert::instance(Date::class, $r);
27+
}
28+
29+
#[@test]
30+
public function new_expr() {
31+
$r= $this->run('class <T> {
32+
private function factory() { return \\util\\Date::class; }
33+
34+
public function run() {
35+
return new ($this->factory())();
36+
}
37+
}');
38+
Assert::instance(Date::class, $r);
39+
}
40+
41+
#[@test]
42+
public function passing_argument() {
43+
$r= $this->run('class <T> {
44+
public $value;
45+
46+
public function __construct($value= null) { $this->value= $value; }
47+
48+
public function run() {
49+
return new self("Test");
50+
}
51+
}');
52+
Assert::equals('Test', $r->value);
53+
}
54+
}

src/test/php/lang/ast/unittest/parse/OperatorTest.class.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ public function new_type() {
157157
);
158158
}
159159

160+
#[@test]
161+
public function new_var() {
162+
$this->assertParsed(
163+
[new NewExpression('$class', [], self::LINE)],
164+
'new $class();'
165+
);
166+
}
167+
168+
#[@test]
169+
public function new_expr() {
170+
$this->assertParsed(
171+
[new NewExpression(new InvokeExpression(new Literal('factory', self::LINE), [], self::LINE), [], self::LINE)],
172+
'new (factory())();'
173+
);
174+
}
175+
160176
#[@test]
161177
public function new_type_with_args() {
162178
$this->assertParsed(

0 commit comments

Comments
 (0)