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
2 changes: 2 additions & 0 deletions ext/standard/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public function getFunctions(): array
new round(),
new sqrt(),
new intval(),
new floatval(),
new boolval(),
new gettype(),
new int_min(),
new int_max(),
Expand Down
110 changes: 110 additions & 0 deletions ext/standard/boolval.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?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\Builder;
use PHPLLVM\Value;

/**
* boolval() for scalar values supported by this compiler (subset of PHP).
*/
final class boolval extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== count($frame->calledArgs)) {
throw new \LogicException('boolval() requires exactly one argument');
}
$v = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
$frame->returnVar->bool(self::isTruthy($v));
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
$this->context = $context;
if (1 !== count($args)) {
throw new \LogicException('boolval() requires exactly one argument');
}
switch ($args[0]->type) {
case JITVariable::TYPE_NATIVE_LONG:
$v = $context->helper->loadValue($args[0]);
$zero = $v->typeOf()->constInt(0, false);

return $context->builder->icmp(Builder::INT_NE, $v, $zero);
case JITVariable::TYPE_NATIVE_DOUBLE:
$v = $context->helper->loadValue($args[0]);
$zero = $v->typeOf()->constReal(0.0);

return $context->builder->fcmp(Builder::REAL_ONE, $v, $zero);
case JITVariable::TYPE_NATIVE_BOOL:
return $context->helper->loadValue($args[0]);
case JITVariable::TYPE_STRING:
return $this->stringTruthy($context, $context->helper->loadValue($args[0]));
case JITVariable::TYPE_NULL:
return $context->constantFromBool(false);
default:
throw new \LogicException('boolval() does not support this value type in this compiler build');
}
}

private static function isTruthy(Variable $v): bool
{
switch ($v->type) {
case Variable::TYPE_NULL:
return false;
case Variable::TYPE_INTEGER:
return 0 !== $v->toInt();
case Variable::TYPE_FLOAT:
return 0.0 !== $v->toFloat();
case Variable::TYPE_BOOLEAN:
return $v->toBool();
case Variable::TYPE_STRING:
$s = $v->toString();

return '' !== $s && '0' !== $s;
default:
throw new \LogicException('boolval() does not support this value type in this compiler build');
}
}

private function stringTruthy(Context $context, Value $strPtr): Value
{
$structName = $strPtr->typeOf()->getElementType()->getName();
$map = $context->structFieldMap[$structName];
$len = $context->builder->load(
$context->builder->structGep($strPtr, $map['length'])
);
$zero = $len->typeOf()->constInt(0, false);
$isEmpty = $context->builder->icmp(Builder::INT_EQ, $len, $zero);
$one = $len->typeOf()->constInt(1, false);
$isOne = $context->builder->icmp(Builder::INT_EQ, $len, $one);
$ch = $context->builder->load(
$context->builder->structGep($strPtr, $map['value'])
);
$charZero = $ch->typeOf()->constInt(ord('0'), false);
$isCharZero = $context->builder->icmp(Builder::INT_EQ, $ch, $charZero);
$onlyZero = $context->builder->and($isOne, $isCharZero);
$falsy = $context->builder->or($isEmpty, $onlyZero);

return $context->builder->not($falsy);
}
}
67 changes: 67 additions & 0 deletions ext/standard/floatval.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?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;

/**
* floatval() for integer or float arguments (subset of PHP standard library).
*/
final class floatval extends Internal
{
public function execute(Frame $frame): void
{
if (1 !== count($frame->calledArgs)) {
throw new \LogicException('floatval() requires exactly one argument');
}
$v = $frame->calledArgs[0]->resolveIndirect();
if (null === $frame->returnVar) {
return;
}
if (Variable::TYPE_INTEGER === $v->type) {
$frame->returnVar->float((float) $v->toInt());

return;
}
if (Variable::TYPE_FLOAT === $v->type) {
$frame->returnVar->float($v->toFloat());

return;
}
throw new \LogicException('floatval() only supports integers and floats in this compiler build');
}

public Context $context;

public function call(Context $context, JITVariable ...$args): Value
{
$this->context = $context;
if (1 !== count($args)) {
throw new \LogicException('floatval() requires exactly one argument');
}
$v = $context->helper->loadValue($args[0]);
$double = $context->getTypeFromString('double');
switch ($args[0]->type) {
case JITVariable::TYPE_NATIVE_LONG:
return $context->builder->siToFp($v, $double);
case JITVariable::TYPE_NATIVE_DOUBLE:
return $v;
default:
throw new \LogicException('floatval() only supports integers and floats in this compiler build');
}
}
}
3 changes: 3 additions & 0 deletions ext/standard/gettype.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ public function call(Context $context, JITVariable ...$args): Value
case JITVariable::TYPE_STRING:
$label = 'string';
break;
case JITVariable::TYPE_NULL:
$label = 'NULL';
break;
default:
throw new \LogicException('gettype() does not support this value type in this compiler build');
}
Expand Down
4 changes: 4 additions & 0 deletions ext/types/is_type.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ public function call(Context $context, JITVariable ... $args): Value {
return $this->context->constantFromBool($this->type === Variable::TYPE_INTEGER);
case JITVariable::TYPE_NATIVE_DOUBLE:
return $this->context->constantFromBool($this->type === Variable::TYPE_FLOAT);
case JITVariable::TYPE_NATIVE_BOOL:
return $this->context->constantFromBool($this->type === Variable::TYPE_BOOLEAN);
case JITVariable::TYPE_STRING:
return $this->context->constantFromBool($this->type === Variable::TYPE_STRING);
case JITVariable::TYPE_NULL:
return $this->context->constantFromBool($this->type === Variable::TYPE_NULL);
default:
throw new \LogicException('Non-implemented type handled for ' . $this->name . '(): ' . JITVariable::getStringType($args[0]->type));
}
Expand Down
25 changes: 25 additions & 0 deletions test/compliance/cases/stdlib/boolval.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
stdlib boolval() for scalar values
--FILE--
<?php
echo boolval(0) ? 'y' : 'n', "\n";
echo boolval(1) ? 'y' : 'n', "\n";
echo boolval(0.0) ? 'y' : 'n', "\n";
echo boolval(2.5) ? 'y' : 'n', "\n";
echo boolval(true) ? 'y' : 'n', "\n";
echo boolval(false) ? 'y' : 'n', "\n";
echo boolval('') ? 'y' : 'n', "\n";
echo boolval('0') ? 'y' : 'n', "\n";
echo boolval('x') ? 'y' : 'n', "\n";
echo boolval(null) ? 'y' : 'n', "\n";
--EXPECT--
n
y
n
y
y
n
n
n
y
n
13 changes: 13 additions & 0 deletions test/compliance/cases/stdlib/floatval.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
stdlib floatval() for integers and floats
--FILE--
<?php
echo floatval(3), "\n";
echo floatval(-2), "\n";
echo floatval(1.5), "\n";
echo floatval(0.0), "\n";
--EXPECT--
3
-2
1.5
0
7 changes: 7 additions & 0 deletions test/compliance/cases/stdlib/gettype_null.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
--TEST--
stdlib gettype() for null
--FILE--
<?php
echo gettype(null), "\n";
--EXPECT--
NULL
13 changes: 13 additions & 0 deletions test/real/cases/stdlib_casts.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Integration: floatval, boolval, and gettype for null
--FILE--
<?php
echo floatval(intval(2.9)), "\n";
echo boolval(floatval(1)) ? 'y' : 'n', "\n";
echo gettype(null), "\n";
echo is_bool(boolval(true)) ? 'y' : 'n', "\n";
--EXPECT--
2
y
NULL
y
6 changes: 6 additions & 0 deletions test/real/cases/stdlib_digest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ echo intval(ceil(2.1)), "\n";
echo intval(floor(2.9)), "\n";
echo round(sqrt(9)), "\n";
echo gettype(abs(-1)), "\n";
echo floatval(2), "\n";
echo boolval(0) ? 'y' : 'n', "\n";
echo gettype(null), "\n";
--EXPECT--
3
0
Expand All @@ -28,3 +31,6 @@ echo gettype(abs(-1)), "\n";
2
3
integer
2
n
NULL