Skip to content

Commit

Permalink
Merge pull request #32 from xp-framework/feature/new-callable
Browse files Browse the repository at this point in the history
Support `new T(...)` callable syntax
  • Loading branch information
thekid authored Oct 6, 2021
2 parents 603879c + 6df762b commit ee2b34e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 1 deletion.
16 changes: 16 additions & 0 deletions src/main/php/lang/ast/nodes/CallableNewExpression.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php namespace lang\ast\nodes;

use lang\ast\Node;

class CallableNewExpression extends Node {
public $kind= 'callablenew';
public $type;

public function __construct($type, $line= -1) {
$this->type= $type;
$this->line= $line;
}

/** @return iterable */
public function children() { return [$this->type]; }
}
25 changes: 25 additions & 0 deletions src/main/php/lang/ast/syntax/PHP.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Braced,
BreakStatement,
CallableExpression,
CallableNewExpression,
CaseLabel,
CastExpression,
CatchStatement,
Expand Down Expand Up @@ -321,6 +322,30 @@ public function __construct() {
}

$parse->expecting('(', 'new arguments');

// Resolve ambiguity by looking ahead: `new T(...)` which is a first-class
// callable reference vs. `new T(...$it)` - a call with an unpacked argument
if ('...' === $parse->token->value) {
$dots= $parse->token;
$parse->forward();
if (')' === $parse->token->value) {
$parse->forward();

if (null === $type) {
$class= $this->clazz($parse, null);
$class->annotations= $annotations;
$new= new NewClassExpression($class, null, $token->line);
} else {
$new= new NewExpression($type, null, $token->line);
}

return new CallableNewExpression($new, $token->line);
}

$parse->queue[]= $parse->token;
$parse->token= $dots;
}

$arguments= $this->arguments($parse);
$parse->expecting(')', 'new arguments');

Expand Down
20 changes: 19 additions & 1 deletion src/test/php/lang/ast/unittest/parse/InvokeTest.class.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
<?php namespace lang\ast\unittest\parse;

use lang\ast\nodes\{CallableExpression, InstanceExpression, InvokeExpression, UnpackExpression, ScopeExpression, Literal, Variable};
use lang\ast\nodes\{
CallableExpression,
CallableNewExpression,
NewExpression,
InstanceExpression,
InvokeExpression,
UnpackExpression,
ScopeExpression,
Literal,
Variable
};
use unittest\{Assert, Test};

/**
Expand Down Expand Up @@ -87,4 +97,12 @@ public function first_class_callable_static() {
'self::length(...);'
);
}

#[Test]
public function first_class_callable_object_creation() {
$this->assertParsed(
[new CallableNewExpression(new NewExpression('\\T', null, self::LINE), self::LINE)],
'new T(...);'
);
}
}

0 comments on commit ee2b34e

Please sign in to comment.