xp-framework / compiler

Compiles future PHP to today's PHP.
19 stars 0 forks source link

do expression #148

Closed thekid closed 1 year ago

thekid commented 1 year ago

Before

// Example 1
if (isset($stored['state'])) {
  $state= $stored['state'];
} else {
  $state= bin2hex($this->rand->bytes(16));
  $session->register('state', $state);
}

// Example 2
$found= false;
foreach ($this->list as $element) {
  if ($search === $element) {
    $found= true;
    break;
  }
}

After

// Example 1
$state= $stored['state'] ?? do {
  $state= bin2hex($this->rand->bytes(16));
  $session->register('state', $state);
  return $state;
};

// Example 2
$found= do {
  foreach ($this->list as $element) {
    if ($search === $element) return true;
  }
  return false;
};

Emitted as IIFE

Easiest to emit, orders of magnitude more expensive than if/else code before (first tests show a factor between 5 and 6)

// Example 1
$state= $stored['state'] ?? (fn() => {
  $state= bin2hex($this->rand->bytes(16));
  $session->register('state', $state);
  return $state;
})();

// Example 2
$found= (fn() => {
  foreach ($this->list as $element) {
    if ($search === $element) return true;
  }
  return false;
})();

See https://babeljs.io/docs/en/babel-plugin-proposal-do-expressions

Note: For example 2, generator comprehensions could also work, see #59 and https://stackoverflow.com/questions/55004849/using-list-comprehension-for-finding-1-element-in-a-list

thekid commented 1 year ago

Can we emit using goto? Strategy would be to:

// Example 2
foreach ($this->list as $element) {
  if ($search === $element) { $found= true; goto __l0; }
}
{ $found= false; goto __l0; } // Maybe optimize this last line to omit the goto
__l0:

Unclear how this would work for example 1 though.

thekid commented 1 year ago

Still don't have a good idea, closing for now.

thekid commented 1 year ago

See also https://externals.io/message/120606 ("Expression code blocks"):

Sometimes it would be nice to have a code block inside an expression, like this:


public function f(string $key) {
  return $this->cache[$key] ??= {
    // Calculate a value for $key.
    [...]
    return $value;
  };
}