Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ext/standard/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,13 @@ public function getFunctions(): array
new str_ends_with(),
new strncmp(),
new array_count(),
new array_count('sizeof'),
new array_key_exists(),
new in_array(),
new array_push(),
new array_pop(),
new array_shift(),
new array_values(),
new explode(),
new implode(),
];
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/array_count.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
*/
final class array_count extends Internal
{
public function __construct()
public function __construct(string $name = 'count')
{
parent::__construct('count');
parent::__construct($name);
}

public function execute(Frame $frame): void
Expand Down
53 changes: 53 additions & 0 deletions ext/standard/array_pop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* array_pop() for packed list arrays (subset of PHP; VM only).
*/
final class array_pop extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== \count($frame->calledArgs)) {
throw new \LogicException('array_pop() requires exactly one argument');
}
$array = $frame->calledArgs[0]->resolveIndirect();
if (Variable::TYPE_ARRAY !== $array->type) {
throw new \LogicException('array_pop() argument must be an array in this compiler build');
}
$popped = $array->toArray()->popLast();
if (null === $frame->returnVar) {
return;
}
if (null === $popped) {
$frame->returnVar->null();

return;
}
$frame->returnVar->copyFrom($popped);
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
throw new \LogicException('array_pop() is not implemented for JIT in this compiler build');
}
}
53 changes: 53 additions & 0 deletions ext/standard/array_shift.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* array_shift() for packed list arrays (subset of PHP; VM only).
*/
final class array_shift extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== \count($frame->calledArgs)) {
throw new \LogicException('array_shift() requires exactly one argument');
}
$array = $frame->calledArgs[0]->resolveIndirect();
if (Variable::TYPE_ARRAY !== $array->type) {
throw new \LogicException('array_shift() argument must be an array in this compiler build');
}
$shifted = $array->toArray()->shiftFirst();
if (null === $frame->returnVar) {
return;
}
if (null === $shifted) {
$frame->returnVar->null();

return;
}
$frame->returnVar->copyFrom($shifted);
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
throw new \LogicException('array_shift() is not implemented for JIT in this compiler build');
}
}
47 changes: 47 additions & 0 deletions ext/standard/array_values.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-Compiler, a PHP CFG Compiler for PHP code
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCompiler\ext\standard;

use PHPCompiler\Frame;
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;

/**
* array_values() re-indexing list values (subset of PHP; VM only).
*/
final class array_values extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== \count($frame->calledArgs)) {
throw new \LogicException('array_values() requires exactly one argument');
}
$array = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
if (Variable::TYPE_ARRAY !== $array->type) {
throw new \LogicException('array_values() argument must be an array in this compiler build');
}
$frame->returnVar->array($array->toArray()->valuesCopy());
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
throw new \LogicException('array_values() is not implemented for JIT in this compiler build');
}
}
73 changes: 73 additions & 0 deletions lib/VM/HashTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,79 @@ public function getNumElements(): int
return $this->numElements;
}

/**
* Remove and return the last element of a packed list array (no holes).
* Returns null when the array is empty.
*/
public function popLast(): ?Variable
{
$this->assertConsistent();
if (0 === $this->numElements) {
return null;
}
if (!$this->isWithoutHoles()) {
throw new \LogicException('popLast() only supports packed list arrays without holes');
}
$this->refcount->assertSeparated();
$lastSlot = $this->numUsed - 1;
$bucket = $this->buckets->read($lastSlot);
$result = new Variable();
$result->copyFrom($bucket->value->resolveIndirect());
--$this->numUsed;
--$this->numElements;
--$this->nextFreeElement;
$this->rehash();

return $result;
}

/**
* Remove and return the first element of a packed list array (no holes).
* Returns null when the array is empty.
*/
public function shiftFirst(): ?Variable
{
$this->assertConsistent();
if (0 === $this->numElements) {
return null;
}
if (!$this->isWithoutHoles()) {
throw new \LogicException('shiftFirst() only supports packed list arrays without holes');
}
$this->refcount->assertSeparated();
$firstBucket = $this->buckets->read(0);
$result = new Variable();
$result->copyFrom($firstBucket->value->resolveIndirect());
for ($i = 0; $i < $this->numUsed - 1; ++$i) {
$src = $this->buckets->read($i + 1);
$dst = $this->buckets->read($i);
$dst->value->copyFrom($src->value);
$dst->hash = $i;
$dst->key = null;
}
--$this->numUsed;
--$this->numElements;
--$this->nextFreeElement;
$this->rehash();

return $result;
}

/**
* Copy all defined values into a new packed list array.
*/
public function valuesCopy(): HashTable
{
$out = new self();
foreach ($this->iterate(true) as $value) {
$copy = new Variable();
$copy->copyFrom($value);
$out->append($copy);
}

return $out;
}

public function hasKey(Variable $index): bool
{
$this->assertConsistent();
Expand Down
18 changes: 18 additions & 0 deletions test/compliance/cases/stdlib/array_pop.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
stdlib array_pop()
--FILE--
<?php
$a = array(1, 2, 3);
echo array_pop($a), "\n";
echo count($a), "\n";
echo array_pop($a), "\n";
echo array_pop($a), "\n";
echo array_pop($a) === null ? 'y' : 'n', "\n";
echo count($a), "\n";
--EXPECT--
3
2
2
1
y
0
16 changes: 16 additions & 0 deletions test/compliance/cases/stdlib/array_shift.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
stdlib array_shift()
--FILE--
<?php
$a = array(10, 20, 30);
echo array_shift($a), "\n";
echo count($a), "\n";
echo array_shift($a), "\n";
echo array_shift($a), "\n";
echo array_shift($a) === null ? 'y' : 'n', "\n";
--EXPECT--
10
2
20
30
y
13 changes: 13 additions & 0 deletions test/compliance/cases/stdlib/array_values.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
stdlib array_values()
--FILE--
<?php
$a = array('x', 'y');
$b = array_values($a);
echo count($b), "\n";
echo in_array('x', $b) ? 'y' : 'n', "\n";
echo in_array('y', $b) ? 'y' : 'n', "\n";
--EXPECT--
2
y
y
10 changes: 10 additions & 0 deletions test/compliance/cases/stdlib/sizeof.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
stdlib sizeof() alias of count()
--FILE--
<?php
$a = array(1, 2);
echo sizeof($a), "\n";
echo sizeof(array()), "\n";
--EXPECT--
2
0
22 changes: 22 additions & 0 deletions test/real/cases/stdlib_array_stack.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Integration: array_push, array_pop, array_shift, array_values
--FILE--
<?php
$list = array('a');
array_push($list, 'b', 'c');
echo count($list), "\n";
echo array_pop($list), "\n";
echo count($list), "\n";
echo array_shift($list), "\n";
echo count($list), "\n";
$vals = array_values(array('x', 'y'));
echo count($vals), "\n";
echo sizeof($vals), "\n";
--EXPECT--
3
c
2
a
1
2
2
Loading