Skip to content

Commit

Permalink
MFH
Browse files Browse the repository at this point in the history
  • Loading branch information
thekid committed Aug 27, 2024
2 parents edaf89c + 2c2c6d9 commit b7a2ce1
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 63 deletions.
27 changes: 26 additions & 1 deletion src/main/php/lang/ast/emit/PHP.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,32 @@ protected function emitProperty($result, $property) {
$result->codegen->scope[0]->init['$this->'.$property->name]= $property->expression;
}
}
$result->out->write(';');

if ($property->hooks) {
$result->out->write('{');
foreach ($property->hooks as $type => $hook) {
$hook->byref && $result->out->write('&');
$result->out->write($type);
if ($hook->parameter) {
$result->out->write('(');
$this->emitOne($result, $hook->parameter);
$result->out->write(')');
}

if (null === $hook->expression) {
$result->out->write(';');
} else if ($hook->expression instanceof Block) {
$this->emitOne($result, $hook->expression);
} else {
$result->out->write('=>');
$this->emitOne($result, $hook->expression);
$result->out->write(';');
}
}
$result->out->write('}');
} else {
$result->out->write(';');
}
}

protected function emitMethod($result, $method) {
Expand Down
82 changes: 82 additions & 0 deletions src/main/php/lang/ast/emit/PHP84.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php namespace lang\ast\emit;

use ReflectionProperty;
use lang\ast\types\{
IsArray,
IsFunction,
IsGeneric,
IsIntersection,
IsLiteral,
IsMap,
IsNullable,
IsUnion,
IsValue
};

/**
* PHP 8.4 syntax
*
* @see https://wiki.php.net/rfc#php_84
*/
class PHP84 extends PHP {
use RewriteBlockLambdaExpressions;
use PropertyHooks, AsymmetricVisibility {
PropertyHooks::emitProperty as emitPropertyHooks;
AsymmetricVisibility::emitProperty as emitAsymmetricVisibility;
}

public $targetVersion= 80400;

/** Sets up type => literal mappings */
public function __construct() {
$this->literals= [
IsArray::class => function($t) { return 'array'; },
IsMap::class => function($t) { return 'array'; },
IsFunction::class => function($t) { return 'callable'; },
IsValue::class => function($t) { return $t->literal(); },
IsNullable::class => function($t) {
if (null === ($l= $this->literal($t->element))) return null;
return $t->element instanceof IsUnion ? $l.'|null' : '?'.$l;
},
IsIntersection::class => function($t) {
$i= '';
foreach ($t->components as $component) {
if (null === ($l= $this->literal($component))) return null;
$i.= '&'.$l;
}
return substr($i, 1);
},
IsUnion::class => function($t) {
$u= '';
foreach ($t->components as $component) {
if (null === ($l= $this->literal($component))) return null;
$u.= '|'.$l;
}
return substr($u, 1);
},
IsLiteral::class => function($t) { return $t->literal(); },
IsGeneric::class => function($t) { return null; }
];
}

protected function emitProperty($result, $property) {
static $asymmetric= null;
static $hooks= null;

// TODO Remove once https://github.com/php/php-src/pull/15063 and
// https://github.com/php/php-src/pull/13455 are merged
if (
!($asymmetric ?? $asymmetric= method_exists(ReflectionProperty::class, 'isPrivateSet')) &&
array_intersect($property->modifiers, ['private(set)', 'protected(set)', 'public(set)'])
) {
return $this->emitAsymmetricVisibility($result, $property);
} else if (
!($hooks ?? $hooks= method_exists(ReflectionProperty::class, 'getHooks')) &&
$property->hooks
) {
return $this->emitPropertyHooks($result, $property);
}

parent::emitProperty($result, $property);
}
}
64 changes: 2 additions & 62 deletions src/main/php/lang/ast/emit/PropertyHooks.class.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?php namespace lang\ast\emit;

use ReflectionProperty;
use lang\ast\nodes\{
Assignment,
Block,
Expand Down Expand Up @@ -71,15 +70,15 @@ protected function withScopeCheck($modifiers, $nodes) {
}
}

protected function emitEmulatedHooks($result, $property) {
protected function emitProperty($result, $property) {
static $lookup= [
'public' => MODIFIER_PUBLIC,
'protected' => MODIFIER_PROTECTED,
'private' => MODIFIER_PRIVATE,
'static' => MODIFIER_STATIC,
'final' => MODIFIER_FINAL,
'abstract' => MODIFIER_ABSTRACT,
'readonly' => 0x0080, // XP 10.13: MODIFIER_READONLY
'readonly' => MODIFIER_READONLY,
];

// Emit XP meta information for the reflection API
Expand Down Expand Up @@ -157,63 +156,4 @@ protected function emitEmulatedHooks($result, $property) {
$scope->init[sprintf('$this->__virtual["%s"]', $property->name)]= $property->expression;
}
}

protected function emitNativeHooks($result, $property) {
$result->codegen->scope[0]->meta[self::PROPERTY][$property->name]= [
DETAIL_RETURNS => $property->type ? $property->type->name() : 'var',
DETAIL_ANNOTATIONS => $property->annotations,
DETAIL_COMMENT => $property->comment,
DETAIL_TARGET_ANNO => [],
DETAIL_ARGUMENTS => []
];

$property->comment && $this->emitOne($result, $property->comment);
$property->annotations && $this->emitOne($result, $property->annotations);
$result->at($property->declared)->out->write(implode(' ', $property->modifiers).' '.$this->propertyType($property->type).' $'.$property->name);
if (isset($property->expression)) {
if ($this->isConstant($result, $property->expression)) {
$result->out->write('=');
$this->emitOne($result, $property->expression);
} else if (in_array('static', $property->modifiers)) {
$result->codegen->scope[0]->statics['self::$'.$property->name]= $property->expression;
} else {
$result->codegen->scope[0]->init['$this->'.$property->name]= $property->expression;
}
}

// TODO move this to lang.ast.emit.PHP once https://github.com/php/php-src/pull/13455 is merged
$result->out->write('{');
foreach ($property->hooks as $type => $hook) {
$hook->byref && $result->out->write('&');
$result->out->write($type);
if ($hook->parameter) {
$result->out->write('(');
$this->emitOne($result, $hook->parameter);
$result->out->write(')');
}

if (null === $hook->expression) {
$result->out->write(';');
} else if ($hook->expression instanceof Block) {
$this->emitOne($result, $hook->expression);
} else {
$result->out->write('=>');
$this->emitOne($result, $hook->expression);
$result->out->write(';');
}
}
$result->out->write('}');
}

protected function emitProperty($result, $property) {
static $hooks= null;

if (empty($property->hooks)) {
parent::emitProperty($result, $property);
} else if ($hooks ?? $hooks= method_exists(ReflectionProperty::class, 'getHooks')) {
$this->emitNativeHooks($result, $property);
} else {
$this->emitEmulatedHooks($result, $property);
}
}
}

0 comments on commit b7a2ce1

Please sign in to comment.