diff --git a/src/main/php/lang/ast/emit/PHP.class.php b/src/main/php/lang/ast/emit/PHP.class.php index b542850f..7c274d95 100755 --- a/src/main/php/lang/ast/emit/PHP.class.php +++ b/src/main/php/lang/ast/emit/PHP.class.php @@ -122,7 +122,7 @@ protected function emitCast($result, $cast) { static $native= ['string' => true, 'int' => true, 'float' => true, 'bool' => true, 'array' => true, 'object' => true]; $name= $cast->type->name(); - if ('?' === $name{0}) { + if ('?' === $name[0]) { $result->out->write('cast('); $this->emitOne($result, $cast->expression); $result->out->write(',\''.$name.'\', false)'); @@ -662,9 +662,18 @@ protected function emitArguments($result, $arguments) { } protected function emitNew($result, $new) { - $result->out->write('new '.$new->type.'('); - $this->emitArguments($result, $new->arguments); - $result->out->write(')'); + if ($new->type instanceof Node) { + $t= $result->temp(); + $result->out->write('('.$t.'= '); + $this->emitOne($result, $new->type); + $result->out->write(') ? new '.$t.'('); + $this->emitArguments($result, $new->arguments); + $result->out->write(') : null'); + } else { + $result->out->write('new '.$new->type.'('); + $this->emitArguments($result, $new->arguments); + $result->out->write(')'); + } } protected function emitNewClass($result, $new) { diff --git a/src/main/php/lang/ast/syntax/PHP.class.php b/src/main/php/lang/ast/syntax/PHP.class.php index ea704d7a..38f3fe2c 100755 --- a/src/main/php/lang/ast/syntax/PHP.class.php +++ b/src/main/php/lang/ast/syntax/PHP.class.php @@ -281,19 +281,29 @@ public function __construct() { }); $this->prefix('new', 0, function($parse, $token) { - $type= $parse->token; - $parse->forward(); + if ('(' === $parse->token->value) { + $parse->expecting('(', 'new type'); + $type= $this->expression($parse, 0); + $parse->expecting(')', 'new type'); + } else if ('variable' === $parse->token->kind) { + $type= '$'.$parse->token->value; + $parse->forward(); + } else if ('class' === $parse->token->value) { + $type= null; + $parse->forward(); + } else { + $type= $parse->scope->resolve($parse->token->value); + $parse->forward(); + } $parse->expecting('(', 'new arguments'); $arguments= $this->expressions($parse); $parse->expecting(')', 'new arguments'); - if ('variable' === $type->kind) { - return new NewExpression('$'.$type->value, $arguments, $token->line); - } else if ('class' === $type->value) { + if (null === $type) { return new NewClassExpression($this->clazz($parse, null), $arguments, $token->line); } else { - return new NewExpression($parse->scope->resolve($type->value), $arguments, $token->line); + return new NewExpression($type, $arguments, $token->line); } }); diff --git a/src/test/php/lang/ast/unittest/emit/InstantiationTest.class.php b/src/test/php/lang/ast/unittest/emit/InstantiationTest.class.php new file mode 100755 index 00000000..ce4af54d --- /dev/null +++ b/src/test/php/lang/ast/unittest/emit/InstantiationTest.class.php @@ -0,0 +1,54 @@ +run('class { + public function run() { + return new \\util\\Date(); + } + }'); + Assert::instance(Date::class, $r); + } + + #[@test] + public function new_var() { + $r= $this->run('class { + public function run() { + $class= \\util\\Date::class; + return new $class(); + } + }'); + Assert::instance(Date::class, $r); + } + + #[@test] + public function new_expr() { + $r= $this->run('class { + private function factory() { return \\util\\Date::class; } + + public function run() { + return new ($this->factory())(); + } + }'); + Assert::instance(Date::class, $r); + } + + #[@test] + public function passing_argument() { + $r= $this->run('class { + public $value; + + public function __construct($value= null) { $this->value= $value; } + + public function run() { + return new self("Test"); + } + }'); + Assert::equals('Test', $r->value); + } +} \ No newline at end of file diff --git a/src/test/php/lang/ast/unittest/parse/OperatorTest.class.php b/src/test/php/lang/ast/unittest/parse/OperatorTest.class.php index 81ce8177..c979722f 100755 --- a/src/test/php/lang/ast/unittest/parse/OperatorTest.class.php +++ b/src/test/php/lang/ast/unittest/parse/OperatorTest.class.php @@ -157,6 +157,22 @@ public function new_type() { ); } + #[@test] + public function new_var() { + $this->assertParsed( + [new NewExpression('$class', [], self::LINE)], + 'new $class();' + ); + } + + #[@test] + public function new_expr() { + $this->assertParsed( + [new NewExpression(new InvokeExpression(new Literal('factory', self::LINE), [], self::LINE), [], self::LINE)], + 'new (factory())();' + ); + } + #[@test] public function new_type_with_args() { $this->assertParsed(