Skip to content

Commit

Permalink
Fixed concatenation support of strings with double
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeyklay authored and dreamsxin committed Nov 6, 2019
1 parent 5357822 commit 097ffde
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 42 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Fixed
- Fixed concatenation support of strings with double numbers
[#1893](https://github.com/phalcon/zephir/issues/1893)

## [0.12.2] - 2019-08-05
### Added
Expand Down
146 changes: 104 additions & 42 deletions Library/Operators/Other/ConcatOperator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use function Zephir\add_slashes;
use Zephir\CompilationContext;
use Zephir\CompiledExpression;
use Zephir\Exception;
use Zephir\Exception\CompilerException;
use Zephir\Expression;
use Zephir\Operators\BaseOperator;
Expand All @@ -32,6 +33,8 @@ class ConcatOperator extends BaseOperator
* @param CompilationContext $compilationContext
*
* @return CompiledExpression
*
* @throws CompilerException
*/
public function compile($expression, CompilationContext $compilationContext)
{
Expand All @@ -58,7 +61,9 @@ public function compile($expression, CompilationContext $compilationContext)

$expected->setDynamicTypes('string');
$expectedCode = $compilationContext->backend->getVariableCode($expected);
$compilationContext->codePrinter->output('ZEPHIR_CONCAT_'.strtoupper($optimized[0]).'('.$expectedCode.', '.$optimized[1].');');
$compilationContext->codePrinter->output(
sprintf('ZEPHIR_CONCAT_%s(%s, %s);', strtoupper($optimized[0]), $expectedCode, $optimized[1])
);

return new CompiledExpression('variable', $expected->getName(), $expression);
}
Expand All @@ -67,35 +72,15 @@ public function compile($expression, CompilationContext $compilationContext)
* If the expression cannot be optimized, fall back to the standard compilation.
*/
$leftExpr = new Expression($expression['left']);
switch ($expression['left']['type']) {
case 'array-access':
case 'property-access':
$leftExpr->setReadOnly(true);
break;

default:
$leftExpr->setReadOnly($this->readOnly);
break;
}
$left = $leftExpr->compile($compilationContext);
$left = $this->compileExpression($leftExpr, $compilationContext, $expression['left']['type']);

if ('variable' == $left->getType()) {
$variableLeft = $compilationContext->symbolTable->getVariableForRead($left->getCode(), $compilationContext, $expression['right']);
$variableLeft = $compilationContext->backend->getVariableCode($variableLeft);
}

$rightExpr = new Expression($expression['right']);
switch ($expression['left']['type']) {
case 'array-access':
case 'property-access':
$rightExpr->setReadOnly(true);
break;

default:
$rightExpr->setReadOnly($this->readOnly);
break;
}
$right = $rightExpr->compile($compilationContext);
$right = $this->compileExpression($rightExpr, $compilationContext, $expression['left']['type']);

if ('variable' == $right->getType()) {
$variableRight = $compilationContext->symbolTable->getVariableForRead($right->getCode(), $compilationContext, $expression['right']);
Expand Down Expand Up @@ -128,11 +113,12 @@ public function compile($expression, CompilationContext $compilationContext)
* @param bool $isFullString
*
* @return array
*
* @throws CompilerException
*/
private function _getOptimizedConcat($expression, CompilationContext $compilationContext, &$isFullString)
{
$originalExpr = $expression;

$isFullString = true;

$parts = [];
Expand All @@ -156,21 +142,15 @@ private function _getOptimizedConcat($expression, CompilationContext $compilatio
foreach ($parts as $part) {
$expr = new Expression($part);
$expr->setStringOperation(true);
switch ($part['type']) {
case 'array-access':
case 'property-access':
$expr->setReadOnly(true);
break;
$compiledExpr = $this->compileExpression($expr, $compilationContext, $part['type']);

default:
$expr->setReadOnly($this->readOnly);
break;
}

$compiledExpr = $expr->compile($compilationContext);
switch ($compiledExpr->getType()) {
case 'variable':
$variable = $compilationContext->symbolTable->getVariableForRead($compiledExpr->getCode(), $compilationContext, $originalExpr);
$variable = $compilationContext->symbolTable->getVariableForRead(
$compiledExpr->getCode(),
$compilationContext,
$originalExpr
);
switch ($variable->getType()) {
case 'variable':
$key .= 'v';
Expand All @@ -184,15 +164,44 @@ private function _getOptimizedConcat($expression, CompilationContext $compilatio
break;

case 'int':
case 'uint':
case 'long':
case 'ulong':
$key .= 'v';
$tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite(
'variable',
$compilationContext
);
$compilationContext->backend->assignLong(
$tempVariable,
$compiledExpr->getCode(),
$compilationContext
);
$concatParts[] = $compilationContext->backend->getVariableCode($tempVariable);
break;

case 'double':
$key .= 'v';
$tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $originalExpr);
$compilationContext->backend->assignLong($tempVariable, $compiledExpr->getCode(), $compilationContext);
$tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite(
'variable',
$compilationContext
);
$compilationContext->backend->assignDouble(
$tempVariable,
$compiledExpr->getCode(),
$compilationContext
);
$concatParts[] = $compilationContext->backend->getVariableCode($tempVariable);
break;

default:
throw new CompilerException('Variable type: '.$variable->getType().' cannot be used in concat operation', $compiledExpr->getOriginal());
throw new CompilerException(
sprintf(
'Variable type: %s cannot be used in concat operation',
$variable->getType()
),
$compiledExpr->getOriginal()
);
}
break;

Expand All @@ -202,20 +211,73 @@ private function _getOptimizedConcat($expression, CompilationContext $compilatio
break;

case 'int':
case 'uint':
case 'long':
case 'ulong':
$key .= 'v';
$tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite('variable', $compilationContext, $originalExpr);
$compilationContext->codePrinter->output('ZVAL_LONG(&'.$tempVariable->getName().', '.$compiledExpr->getCode().');');
$tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite(
'variable',
$compilationContext
);
$compilationContext->codePrinter->output(
sprintf(
'ZVAL_LONG(&%s, %s);',
$tempVariable->getName(),
$compiledExpr->getCode()
)
);
$concatParts[] = '&'.$tempVariable->getName();
break;

case 'double':
$key .= 'v';
$tempVariable = $compilationContext->symbolTable->getTempLocalVariableForWrite(
'variable',
$compilationContext
);
$compilationContext->codePrinter->output(
sprintf(
'ZVAL_DOUBLE(&%s, %s);',
$tempVariable->getName(),
$compiledExpr->getCode()
)
);
$concatParts[] = '&'.$tempVariable->getName();
break;

default:
throw new CompilerException('Variable type: '.$compiledExpr->getType().' cannot be used in concat operation', $compiledExpr->getOriginal());
throw new CompilerException(
sprintf(
'Variable type: %s cannot be used in concat operation',
$compiledExpr->getType()
),
$compiledExpr->getOriginal()
);
}
}

$compilationContext->stringsManager->addConcatKey($key);

return [$key, implode(', ', $concatParts)];
}

private function compileExpression(Expression $expression, CompilationContext $context, $type)
{
try {
switch ($type) {
case 'array-access':
case 'property-access':
$expression->setReadOnly(true);
break;

default:
$expression->setReadOnly($this->readOnly);
break;
}

return $expression->compile($context);
} catch (Exception $e) {
throw new CompilerException($e->getMessage(), $expression->getExpression());
}
}
}
72 changes: 72 additions & 0 deletions ext/test/concat.zep.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions ext/test/concat.zep.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions test/concat.zep
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,34 @@ class Concat
let b .= a;
return b;
}

/**
* @link https://github.com/phalcon/zephir/issues/1893
*/
public function testConcat4(var value) -> string
{
var min, max;
string query = "";

let min = value / 100 * 25,
max = value / 100 * 50;

let query .= "SELECT * FROM TEST WHERE value <= " . max,
query .= " AND value >= " . min;

return query;
}

/**
* @link https://github.com/phalcon/zephir/issues/1893
*/
public function testConcat5(double number) -> string
{
string retval;
string left = "Concatenated string with number ";

let retval = left . number;

return retval;
}
}
Loading

0 comments on commit 097ffde

Please sign in to comment.