Skip to content

Implement first-class callable syntax #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 12, 2021
Merged

Conversation

thekid
Copy link
Member

@thekid thekid commented Jul 2, 2021

Examples

// Old code without checks whether any of these are actually callable
$length= function(... $args) { return strlen(...$args); };
$run= function(... $args) use($instance) { return $instance->run(...$args); };
$of= function(... $args) { return Enum::valueOf(...$args); };

// Old code, requires PHP 7.1
$length= Closure::fromCallable('strlen');
$run= Closure::fromCallable([$instance, 'run']);
$of= Closure::fromCallable([Enum::class, 'valueOf']);

// Now possible, works on all PHP versions w/ XP Compiler
$length= strlen(...);
$run= $instance->run(...)
$of= Enum::valueOf(...);

See also

protected function emitCallable($result, $callable) {
$t= $result->temp();
$result->out->write('fn(...'.$t.') => ');
$this->emitOne($result, $callable->expression);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once the RFC merged to PHP 8.1, we should move this to a trait for PHP 7.4 and 8.0 and emit native code on PHP 8.1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the only thing we need to do is to remove the use CallablesAsClosures from the PHP81 emitter.

@thekid
Copy link
Member Author

thekid commented Jul 2, 2021

This implementation does not check for and subsequently disallow nullsafe calls as described in the PHP RFC, leaving it up to the runtime engine. This could be added easily (see below), however, it would be a first in the emitter, which doesn't throw errors up until now!

diff --git a/src/main/php/lang/ast/emit/PHP.class.php b/src/main/php/lang/ast/emit/PHP.class.php
index 3a10a60..ba460e9 100755
--- a/src/main/php/lang/ast/emit/PHP.class.php
+++ b/src/main/php/lang/ast/emit/PHP.class.php
@@ -1,5 +1,6 @@
 <?php namespace lang\ast\emit;

+use lang\IllegalStateException;
 use lang\ast\Code;
 use lang\ast\nodes\{InstanceExpression, ScopeExpression, BinaryExpression, Variable, Literal, ArrayLiteral, Block};
 use lang\ast\types\{IsUnion, IsFunction, IsArray, IsMap};
@@ -989,6 +990,10 @@ abstract class PHP extends Emitter {
   }

   protected function emitCallable($result, $callable) {
+    if ($callable->expression->kind === 'nullsafeinstance') {
+      throw new IllegalStateException('Cannot use ?-> with callables');
+    }
+
     $t= $result->temp();
     $result->out->write('fn(...'.$t.') => ');
     $this->emitOne($result, $callable->expression);

@thekid
Copy link
Member Author

thekid commented Jul 10, 2021

This can safely be merged, the vote is at 41:0 in favor of including this and thus very unlikely to fail.

thekid added 3 commits July 12, 2021 21:10
Calling static trait method T::__init is deprecated, it should only
be called on a class using the trait
@thekid thekid merged commit d6318ad into master Jul 12, 2021
@thekid thekid deleted the feature/callable_syntax branch July 12, 2021 19:35
@thekid
Copy link
Member Author

thekid commented Jul 12, 2021

@thekid
Copy link
Member Author

thekid commented Jul 12, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant