/**
* Resolves an expression
*
* @param CompilationContext $compilationContext
* @return bool|CompiledExpression|mixed
* @throws CompilerException
*/
public function compile(CompilationContext $compilationContext)
{
$expression = $this->_expression;
$type = $expression['type'];
$compilableExpression = null;
switch ($type) {
case 'null':
return new LiteralCompiledExpression('null', null, $expression);
case 'int':
case 'integer':
return new LiteralCompiledExpression('int', $expression['value'], $expression);
case 'long':
case 'double':
case 'bool':
return new LiteralCompiledExpression($type, $expression['value'], $expression);
case 'string':
if (!$this->_stringOperation) {
if (ctype_digit($expression['value'])) {
return new CompiledExpression('int', $expression['value'], $expression);
}
}
return new LiteralCompiledExpression('string', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
case 'istring':
return new LiteralCompiledExpression('istring', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
case 'char':
if (!strlen($expression['value'])) {
throw new CompilerException("Invalid empty char literal", $expression);
}
if (strlen($expression['value']) > 2) {
if (strlen($expression['value']) > 10) {
throw new CompilerException("Invalid char literal: '" . substr($expression['value'], 0, 10) . "...'", $expression);
} else {
throw new CompilerException("Invalid char literal: '" . $expression['value'] . "'", $expression);
}
}
return new LiteralCompiledExpression('char', $expression['value'], $expression);
case 'variable':
$var = $compilationContext->symbolTable->getVariable($expression['value']);
if ($var) {
if ($var->getRealName() == 'this') {
$var = 'this';
} else {
$var = $var->getName();
}
} else {
$var = $expression['value'];
}
return new CompiledExpression('variable', $var, $expression);
case 'constant':
$compilableExpression = new Constants();
break;
case 'empty-array':
return $this->emptyArray($expression, $compilationContext);
case 'array-access':
$compilableExpression = new NativeArrayAccess();
$compilableExpression->setNoisy($this->isNoisy());
break;
case 'property-access':
$compilableExpression = new PropertyAccess();
$compilableExpression->setNoisy($this->isNoisy());
break;
case 'property-string-access':
case 'property-dynamic-access':
$compilableExpression = new PropertyDynamicAccess();
$compilableExpression->setNoisy($this->isNoisy());
break;
case 'static-constant-access':
$compilableExpression = new StaticConstantAccess();
break;
case 'static-property-access':
$compilableExpression = new StaticPropertyAccess();
break;
case 'fcall':
$functionCall = new FunctionCall();
return $functionCall->compile($this, $compilationContext);
case 'mcall':
$methodCall = new MethodCall();
return $methodCall->compile($this, $compilationContext);
case 'scall':
$staticCall = new StaticCall();
return $staticCall->compile($this, $compilationContext);
case 'isset':
$compilableExpression = new IssetOperator();
break;
case 'fetch':
$compilableExpression = new FetchOperator();
break;
case 'empty':
$compilableExpression = new EmptyOperator();
break;
case 'array':
$compilableExpression = new NativeArray();
break;
case 'new':
$compilableExpression = new NewInstanceOperator();
break;
case 'new-type':
$compilableExpression = new NewInstanceTypeOperator();
break;
case 'not':
$compilableExpression = new NotOperator();
break;
case 'bitwise_not':
$compilableExpression = new BitwiseNotOperator();
break;
case 'equals':
$compilableExpression = new EqualsOperator();
break;
case 'not-equals':
$compilableExpression = new NotEqualsOperator();
break;
case 'identical':
$compilableExpression = new IdenticalOperator();
break;
case 'not-identical':
$compilableExpression = new NotIdenticalOperator();
break;
case 'greater':
$compilableExpression = new GreaterOperator();
break;
case 'less':
$compilableExpression = new LessOperator();
break;
case 'less-equal':
$compilableExpression = new LessEqualOperator();
break;
case 'greater-equal':
$compilableExpression = new GreaterEqualOperator();
break;
case 'add':
$compilableExpression = new AddOperator();
break;
case 'minus':
$compilableExpression = new MinusOperator();
break;
case 'sub':
$compilableExpression = new SubOperator();
break;
case 'mul':
$compilableExpression = new MulOperator();
break;
case 'div':
$compilableExpression = new DivOperator();
break;
case 'mod':
$compilableExpression = new ModOperator();
break;
case 'and':
$compilableExpression = new AndOperator();
break;
case 'or':
$compilableExpression = new OrOperator();
break;
case 'bitwise_and':
$compilableExpression = new BitwiseAndOperator();
break;
case 'bitwise_or':
$compilableExpression = new BitwiseOrOperator();
break;
case 'bitwise_xor':
$compilableExpression = new BitwiseXorOperator();
break;
case 'bitwise_shiftleft':
$compilableExpression = new ShiftLeftOperator();
break;
case 'bitwise_shiftright':
$compilableExpression = new ShiftRightOperator();
break;
case 'concat':
$expr = new ConcatOperator();
$expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
return $expr->compile($expression, $compilationContext);
case 'irange':
$compilableExpression = new RangeInclusiveOperator();
break;
case 'erange':
$compilableExpression = new RangeExclusiveOperator();
break;
case 'list':
if ($expression['left']['type'] == 'list') {
$compilationContext->logger->warning("Unnecessary extra parentheses", "extra-parentheses", $expression);
}
$numberPrints = $compilationContext->codePrinter->getNumberPrints();
$expr = new Expression($expression['left']);
$expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
$resolved = $expr->compile($compilationContext);
if ($compilationContext->codePrinter->getNumberPrints() - $numberPrints <= 1) {
if (strpos($resolved->getCode(), ' ') !== false) {
return new CompiledExpression($resolved->getType(), '(' . $resolved->getCode() . ')', $expression);
}
}
return $resolved;
case 'cast':
$compilableExpression = new CastOperator();
break;
case 'type-hint':
return $this->compileTypeHint($expression, $compilationContext);
case 'instanceof':
$compilableExpression = new InstanceOfOperator();
break;
case 'clone':
$compilableExpression = new CloneOperator();
break;
case 'ternary':
$compilableExpression = new TernaryOperator();
break;
case 'short-ternary':
$expr = new ShortTernaryOperator();
$expr->setReadOnly($this->isReadOnly());
$expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
return $expr->compile($expression, $compilationContext);
case 'likely':
if (!$this->_evalMode) {
throw new CompilerException("'likely' operator can only be used in evaluation expressions", $expression);
}
$expr = new LikelyOperator();
$expr->setReadOnly($this->isReadOnly());
return $expr->compile($expression, $compilationContext);
case 'unlikely':
if (!$this->_evalMode) {
throw new CompilerException("'unlikely' operator can only be used in evaluation expressions", $expression);
}
$expr = new UnlikelyOperator();
$expr->setReadOnly($this->isReadOnly());
return $expr->compile($expression, $compilationContext);
case 'typeof':
$compilableExpression = new TypeOfOperator();
break;
case 'require':
$compilableExpression = new RequireOperator();
break;
case 'closure':
$compilableExpression = new Closure();
break;
case 'closure-arrow':
$compilableExpression = new ClosureArrow();
break;
case 'reference':
$compilableExpression = new Reference();
break;
default:
throw new CompilerException("Unknown expression: " . $type, $expression);
}
if (!$compilableExpression) {
throw new CompilerException("Unknown expression passed as compilableExpression", $expression);
}
$compilableExpression->setReadOnly($this->isReadOnly());
$compilableExpression->setExpectReturn($this->_expecting, $this->_expectingVariable);
return $compilableExpression->compile($expression, $compilationContext);
}