/** * Resolves an expression * * @param CompilationContext $compilationContext * @return bool|CompiledExpression|mixed * @throws CompilerException */ public function compile(CompilationContext $compilationContext) { $expression = $this->_expression; $type = $expression['type']; switch ($type) { case 'null': return new LiteralCompiledExpression('null', null, $expression); case 'int': case 'integer': return new LiteralCompiledExpression('int', $expression['value'], $expression); case 'long': return new LiteralCompiledExpression('long', $expression['value'], $expression); case 'double': return new LiteralCompiledExpression('double', $expression['value'], $expression); case 'bool': return new LiteralCompiledExpression('bool', $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': return new CompiledExpression('variable', $expression['value'], $expression); case 'constant': $constant = new Constants(); $constant->setReadOnly($this->isReadOnly()); $constant->setExpectReturn($this->_expecting, $this->_expectingVariable); return $constant->compile($expression, $compilationContext); case 'empty-array': return $this->emptyArray($expression, $compilationContext); case 'array-access': $arrayAccess = new NativeArrayAccess(); $arrayAccess->setReadOnly($this->isReadOnly()); $arrayAccess->setNoisy($this->isNoisy()); $arrayAccess->setExpectReturn($this->_expecting, $this->_expectingVariable); return $arrayAccess->compile($expression, $compilationContext); case 'property-access': $propertyAccess = new PropertyAccess(); $propertyAccess->setReadOnly($this->isReadOnly()); $propertyAccess->setNoisy($this->isNoisy()); $propertyAccess->setExpectReturn($this->_expecting, $this->_expectingVariable); return $propertyAccess->compile($expression, $compilationContext); case 'property-string-access': case 'property-dynamic-access': $propertyAccess = new PropertyDynamicAccess(); $propertyAccess->setReadOnly($this->isReadOnly()); $propertyAccess->setNoisy($this->isNoisy()); $propertyAccess->setExpectReturn($this->_expecting, $this->_expectingVariable); return $propertyAccess->compile($expression, $compilationContext); case 'static-constant-access': $staticConstantAccess = new StaticConstantAccess(); $staticConstantAccess->setReadOnly($this->isReadOnly()); $staticConstantAccess->setExpectReturn($this->_expecting, $this->_expectingVariable); return $staticConstantAccess->compile($expression, $compilationContext); case 'static-property-access': $staticPropertyAccess = new StaticPropertyAccess(); $staticPropertyAccess->setReadOnly($this->isReadOnly()); $staticPropertyAccess->setExpectReturn($this->_expecting, $this->_expectingVariable); return $staticPropertyAccess->compile($expression, $compilationContext); 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': $expr = new IssetOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'fetch': $expr = new FetchOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'empty': $expr = new EmptyOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'array': $array = new NativeArray(); $array->setReadOnly($this->isReadOnly()); $array->setExpectReturn($this->_expecting, $this->_expectingVariable); return $array->compile($expression, $compilationContext); case 'new': $expr = new NewInstanceOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'new-type': $expr = new NewInstanceTypeOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'not': $expr = new NotOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'bitwise_not': $expr = new BitwiseNotOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'equals': $expr = new EqualsOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'not-equals': $expr = new NotEqualsOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'identical': $expr = new IdenticalOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'not-identical': $expr = new NotIdenticalOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'greater': $expr = new GreaterOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'less': $expr = new LessOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'less-equal': $expr = new LessEqualOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'greater-equal': $expr = new GreaterEqualOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'add': $expr = new AddOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'minus': $expr = new MinusOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'sub': $expr = new SubOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'mul': $expr = new MulOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'div': $expr = new DivOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'mod': $expr = new ModOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'and': $expr = new AndOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'or': $expr = new OrOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'bitwise_and': $expr = new BitwiseAndOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'bitwise_or': $expr = new BitwiseOrOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'bitwise_xor': $expr = new BitwiseXorOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'bitwise_shiftleft': $expr = new ShiftLeftOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'bitwise_shiftright': $expr = new ShiftRightOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'concat': $expr = new ConcatOperator(); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'irange': $expr = new RangeInclusiveOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'erange': $expr = new RangeExclusiveOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); 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': $expr = new CastOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'type-hint': return $this->compileTypeHint($expression, $compilationContext); case 'instanceof': $expr = new InstanceOfOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'clone': $expr = new CloneOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'ternary': $expr = new TernaryOperator(); $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': $expr = new TypeOfOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'require': $expr = new RequireOperator(); $expr->setReadOnly($this->isReadOnly()); $expr->setExpectReturn($this->_expecting, $this->_expectingVariable); return $expr->compile($expression, $compilationContext); case 'closure': $closure = new Closure(); $closure->setReadOnly($this->isReadOnly()); $closure->setExpectReturn($this->_expecting, $this->_expectingVariable); return $closure->compile($expression, $compilationContext); case 'closure-arrow': $closure = new ClosureArrow(); $closure->setReadOnly($this->isReadOnly()); $closure->setExpectReturn($this->_expecting, $this->_expectingVariable); return $closure->compile($expression, $compilationContext); case 'reference': $reference = new Reference(); $reference->setReadOnly($this->isReadOnly()); $reference->setExpectReturn($this->_expecting, $this->_expectingVariable); return $reference->compile($expression, $compilationContext); default: throw new CompilerException("Unknown expression: " . $type, $expression); } }