/** * {expr}::{expr}(); * * @param \PhpParser\Node\Expr\StaticCall $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { if ($expr->class instanceof \PhpParser\Node\Name) { $scope = $expr->class->parts[0]; $name = $expr->name; if ($scope == 'self') { if ($context->scope instanceof ClassDefinition) { $context->notice('scall-self-not-context', sprintf('No scope. You cannot call from %s out from class scope', $name, $scope), $expr); return new CompiledExpression(); } /** @var ClassDefinition $classDefinition */ $classDefinition = $context->scope; if (!$classDefinition->hasMethod($name, true)) { $context->notice('undefined-scall', sprintf('Static method %s() does not exist in %s scope', $name, $scope), $expr); return new CompiledExpression(); } $method = $classDefinition->getMethod($name); if (!$method->isStatic()) { $context->notice('undefined-scall', sprintf('Method %s() is not static but it was called as static way', $name), $expr); return new CompiledExpression(); } } return new CompiledExpression(); } $context->debug('Unknown static function call'); return new CompiledExpression(); }
/** * @param \PhpParser\Node\Stmt\Static_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $compiler = $context->getExpressionCompiler(); foreach ($stmt->vars as $var) { $compiler->compile($var->default); } }
/** * [] array() * * @param \PhpParser\Node\Expr\Array_ $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $compiler = $context->getExpressionCompiler(); if ($expr->items === []) { return new CompiledExpression(CompiledExpression::ARR, []); } $resultArray = []; foreach ($expr->items as $item) { $compiledValueResult = $compiler->compile($item->value); if ($item->key) { $compiledKeyResult = $compiler->compile($item->key); switch ($compiledKeyResult->getType()) { case CompiledExpression::INTEGER: case CompiledExpression::DOUBLE: case CompiledExpression::BOOLEAN: case CompiledExpression::NULL: case CompiledExpression::STRING: $resultArray[$compiledKeyResult->getValue()] = $compiledValueResult->getValue(); } } else { $resultArray[] = $compiledValueResult->getValue(); } } return new CompiledExpression(CompiledExpression::ARR, $resultArray); }
/** * @param \PhpParser\Node\Stmt\Const_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $compiler = $context->getExpressionCompiler(); foreach ($stmt->consts as $const) { $compiler->compile($const->value); } }
/** * isset({expr]}) * * @param \PhpParser\Node\Expr\Isset_ $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $result = false; foreach ($expr->vars as $var) { if ($var instanceof VariableNode) { $varName = $var->name; if ($varName instanceof Name) { $varName = $varName->parts[0]; } $variable = $context->getSymbol($varName); if ($variable) { $variable->incUse(); if ($variable->getValue() !== null) { $result = true; continue; // this variable is set, continue } } return CompiledExpression::fromZvalValue(false); // one of the vars is not set } } return CompiledExpression::fromZvalValue($result); // if all are set return true, else false }
/** * classname->property * * @param \PhpParser\Node\Expr\PropertyFetch $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $compiler = $context->getExpressionCompiler(); $propertNameCE = $compiler->compile($expr->name); $scopeExpression = $compiler->compile($expr->var); if ($scopeExpression->isObject()) { $scopeExpressionValue = $scopeExpression->getValue(); if ($scopeExpressionValue instanceof ClassDefinition) { $propertyName = $propertNameCE->isString() ? $propertNameCE->getValue() : false; if ($propertyName) { if ($scopeExpressionValue->hasProperty($propertyName, true)) { $property = $scopeExpressionValue->getProperty($propertyName, true); return $compiler->compile($property); } else { $context->notice('language_error', sprintf('Property %s does not exist in %s scope', $propertyName, $scopeExpressionValue->getName()), $expr); } } } return new CompiledExpression(); } elseif ($scopeExpression->canBeObject()) { return new CompiledExpression(); } $context->notice('language_error', "It's not possible to fetch a property on a non-object", $expr, Check::CHECK_BETA); return new CompiledExpression(); }
/** * @param \PhpParser\Node\Stmt\Catch_ $statement * @param Context $context */ public function compile($statement, Context $context) { $context->addVariable(new Variable($statement->var, null, CompiledExpression::OBJECT)); foreach ($statement->stmts as $stmt) { \PHPSA\nodeVisitorFactory($stmt, $context); } }
/** * @param \PhpParser\Node\Expr\Closure $expr * @param Context $context * @return mixed */ protected function compile($expr, Context $context) { $closure = new ClosureDefinition($expr); $closure->setFilepath($context->getFilepath()); $closure->preCompile(clone $context); return new CompiledExpression(CompiledExpression::CALLABLE_TYPE, $closure); }
/** * @param \PhpParser\Node\Stmt\Echo_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $compiler = $context->getExpressionCompiler(); foreach ($stmt->exprs as $expr) { $compiler->compile($expr); } }
/** * Compile function to check it * * @param Context $context * @return bool */ public function compile(Context $context) { if ($this->compiled) { return true; } $context->setFilepath($this->filepath); $this->compiled = true; $context->clearSymbols(); $context->scopePointer = $this->getPointer(); $context->setScope(null); if (count($this->statement->stmts) == 0) { return $context->notice('not-implemented-function', sprintf('Closure %s() is not implemented', $this->name), $this->statement); } if (count($this->statement->params) > 0) { /** @var Node\Param $parameter */ foreach ($this->statement->params as $parameter) { $type = CompiledExpression::UNKNOWN; if ($parameter->type) { if (is_string($parameter->type)) { $type = Types::getType($parameter->type); } elseif ($parameter->type instanceof Node\Name) { $type = CompiledExpression::OBJECT; } } $context->addVariable(new Parameter($parameter->name, null, $type, $parameter->byRef)); } } foreach ($this->statement->stmts as $st) { \PHPSA\nodeVisitorFactory($st, $context); } return true; }
/** * @param Stmt\Case_ $case * @param Context $context * @return bool */ private function checkCaseStatement(Stmt\Case_ $case, Context $context) { /* * switch(…) { * case 41: * case 42: * case 43: * return 'the truth, or almost.'; * } */ if (!$case->stmts) { return false; } foreach ($case->stmts as $node) { // look for a break statement if ($node instanceof Stmt\Break_) { return false; } // or for a return if ($node instanceof Stmt\Return_) { return false; } } $context->notice('missing_break_statement', 'Missing "break" statement', $case); return true; }
/** * yield {value}, yield {key} => {value} * * @param \PhpParser\Node\Expr\Yield_ $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $key = $context->getExpressionCompiler()->compile($expr->key); $value = $context->getExpressionCompiler()->compile($expr->value); // @TODO implement yield return new CompiledExpression(); }
/** * @param Expr $expr * @param Context $context * @return bool */ public function pass(Expr $expr, Context $context) { $castType = CompiledExpression::UNKNOWN; switch (get_class($expr)) { case Expr\Cast\Array_::class: $castType = CompiledExpression::ARR; break; case Expr\Cast\Bool_::class: $castType = CompiledExpression::BOOLEAN; break; case Expr\Cast\Int_::class: $castType = CompiledExpression::INTEGER; break; case Expr\Cast\Double::class: $castType = CompiledExpression::DOUBLE; break; case Expr\Cast\Object_::class: $castType = CompiledExpression::OBJECT; break; case Expr\Cast\String_::class: $castType = CompiledExpression::STRING; break; } $compiledExpression = $context->getExpressionCompiler()->compile($expr->expr); $exprType = $compiledExpression->getType(); $typeName = $compiledExpression->getTypeName(); if ($castType === $exprType) { $context->notice('stupid.cast', sprintf("You are trying to cast '%s' to '%s'", $typeName, $typeName), $expr); return true; } elseif (get_class($expr) == Expr\Cast\Unset_::class && $exprType === CompiledExpression::NULL) { $context->notice('stupid.cast', "You are trying to cast 'null' to 'unset' (null)", $expr); return true; } return false; }
/** * {expr}++ * * @param \PhpParser\Node\Expr\PostDec $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { if ($expr->var instanceof \PHPParser\Node\Expr\Variable) { $variableName = $expr->var->name; if ($variableName instanceof Name) { $variableName = $variableName->parts[0]; } $variable = $context->getSymbol($variableName); if ($variable) { $variable->incUse(); switch ($variable->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: $variable->dec(); return CompiledExpression::fromZvalValue($variable->getValue()); } $context->notice('postdec.variable.wrong-type', 'You are trying to use post derement operator on variable $' . $variableName . ' with type: ' . $variable->getTypeName(), $expr); } else { $context->notice('postdec.undefined-variable', 'You are trying to use post derement operator on undefined variable: ' . $variableName, $expr); } return new CompiledExpression(CompiledExpression::UNKNOWN); } $expression = new Expression($context); $compiledExpression = $expression->compile($expr->var); switch ($compiledExpression->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: $value = $compiledExpression->getValue(); return CompiledExpression::fromZvalValue($value++); } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * @param \PhpParser\Node\Stmt\Do_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $context->getExpressionCompiler()->compile($stmt->cond); foreach ($stmt->stmts as $statement) { \PHPSA\nodeVisitorFactory($statement, $context); } }
/** * @param \PhpParser\Node\Expr\BinaryOp\Concat $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $compiler = new Expression($context); $leftExpression = $compiler->compile($expr->left); $rightExpression = $compiler->compile($expr->right); switch ($leftExpression->getType()) { case CompiledExpression::ARR: $context->notice('unsupported-operand-types', 'Unsupported operand types -{array}', $expr); break; } switch ($rightExpression->getType()) { case CompiledExpression::ARR: $context->notice('unsupported-operand-types', 'Unsupported operand types -{array}', $expr); break; } switch ($leftExpression->getType()) { case CompiledExpression::STRING: case CompiledExpression::NUMBER: case CompiledExpression::INTEGER: case CompiledExpression::DOUBLE: switch ($rightExpression->getType()) { case CompiledExpression::STRING: case CompiledExpression::NUMBER: case CompiledExpression::INTEGER: case CompiledExpression::DOUBLE: return new CompiledExpression(CompiledExpression::STRING, $leftExpression->getValue() . $rightExpression->getValue()); break; } break; } return new CompiledExpression(CompiledExpression::NULL); }
/** * @param Context $context * @return boolean|null */ public function compile(Context $context) { $context->getEventManager()->fire(Event\StatementBeforeCompile::EVENT_NAME, new Event\StatementBeforeCompile($this->statement, $context)); $this->compiled = true; $context->scopePointer = $this->getPointer(); /** * It's not needed to compile empty method via it's abstract */ if ($this->isAbstract()) { /** @var ClassDefinition $scope */ $scope = $context->scope; if (!$scope->isAbstract()) { $context->notice('not-abstract-class-with-abstract-method', 'Class must be abstract', $this->statement); } return true; } if ($this->statement->params) { foreach ($this->statement->params as $parameter) { $type = CompiledExpression::UNKNOWN; if ($parameter->type) { if (is_string($parameter->type)) { $type = Types::getType($parameter->type); } elseif ($parameter->type instanceof Node\Name) { $type = CompiledExpression::OBJECT; } } $context->addVariable(new Parameter($parameter->name, null, $type, $parameter->byRef)); } } foreach ($this->statement->stmts as $st) { \PHPSA\nodeVisitorFactory($st, $context); } }
/** * {expr} + {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Plus $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $left = $context->getExpressionCompiler()->compile($expr->left); $right = $context->getExpressionCompiler()->compile($expr->right); switch ($left->getType()) { case CompiledExpression::INTEGER: switch ($right->getType()) { case CompiledExpression::INTEGER: /** * php -r "var_dump(1 + 1);" int(2) */ return new CompiledExpression(CompiledExpression::INTEGER, $left->getValue() + $right->getValue()); case CompiledExpression::DOUBLE: /** * php -r "var_dump(1 + 1.0);" double(2) */ return new CompiledExpression(CompiledExpression::DOUBLE, $left->getValue() + $right->getValue()); } break; case CompiledExpression::DOUBLE: switch ($right->getType()) { case CompiledExpression::INTEGER: case CompiledExpression::DOUBLE: /** * php -r "var_dump(1.0 + 1);" double(2) * php -r "var_dump(1.0 + 1.0);" double(2) */ return new CompiledExpression(CompiledExpression::DOUBLE, $left->getValue() + $right->getValue()); } } return new CompiledExpression(); }
/** * {expr} / {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Div $expr * @param Context $context * @return CompiledExpression */ public function compile($expr, Context $context) { $expression = new Expression($context); $left = $expression->compile($expr->left); $expression = new Expression($context); $right = $expression->compile($expr->right); switch ($left->getType()) { case CompiledExpression::DNUMBER: if ($left->isEquals(0)) { $context->notice('division-zero', sprintf('You trying to use division from %s/{expr}', $left->getValue()), $expr); return new CompiledExpression(CompiledExpression::DNUMBER, 0.0); } break; case CompiledExpression::LNUMBER: case CompiledExpression::BOOLEAN: if ($left->isEquals(0)) { $context->notice('division-zero', sprintf('You trying to use division from %s/{expr}', $left->getValue()), $expr); switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::BOOLEAN: return new CompiledExpression(CompiledExpression::LNUMBER, 0); case CompiledExpression::DNUMBER: return new CompiledExpression(CompiledExpression::DNUMBER, 0.0); } } break; } switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: if ($right->isEquals(0)) { $context->notice('division-zero', sprintf('You trying to use division on {expr}/%s', $right->getValue()), $expr); return new CompiledExpression(CompiledExpression::UNKNOWN); } } switch ($left->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: switch ($right->getType()) { case CompiledExpression::BOOLEAN: /** * Boolean is true via isEquals(0) check is not passed before * {int}/1 = {int} * {double}/1 = {double} */ $context->notice('division-on-true', 'You trying to use stupid division {expr}/true ~ {expr}/1 = {expr}', $expr); //no break //no break case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: return CompiledExpression::fromZvalValue($left->getValue() / $right->getValue()); } break; } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * (int) {$expr} * * @param \PhpParser\Node\Expr\Cast\Int_ $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $compiledExpression = $context->getExpressionCompiler()->compile($expr->expr); if ($compiledExpression->isTypeKnown()) { return new CompiledExpression(CompiledExpression::INTEGER, (int) $compiledExpression->getValue()); } return new CompiledExpression(); }
/** * @param Expr\Array_ $expr * @param Context $context * @return bool */ public function pass(Expr\Array_ $expr, Context $context) { if ($expr->getAttribute('kind') == Expr\Array_::KIND_LONG) { $context->notice('array.short-syntax', 'Please use [] (short syntax) for array definition.', $expr); return true; } return false; }
/** * @param Scalar\LNumber $lNum * @param Context $context * @return bool */ public function pass(Scalar\LNumber $lNum, Context $context) { if ($lNum->getAttribute('kind') != Scalar\LNumber::KIND_DEC) { $context->notice('l_number_kind', 'Avoid using octal, hexadecimal or binary', $lNum); return true; } return false; }
/** * @param For_ $stmt * @param Context $context * @return bool */ public function pass(For_ $stmt, Context $context) { if (count($stmt->cond) > 1) { $context->notice('for_condition', 'You should merge the conditions into one with &&', $stmt); return false; } return true; }
/** * @param Expr\Ternary $expr * @param Context $context * @return bool */ public function pass(Expr\Ternary $expr, Context $context) { if ($expr->if instanceof Expr\Ternary || $expr->else instanceof Expr\Ternary) { $context->notice('nested_ternary', 'Nested ternaries are confusing you should use if instead.', $expr); return true; } return false; }
/** * @param Stmt $stmt * @param Context $context * @return bool */ public function pass(Stmt $stmt, Context $context) { if ($stmt->getDocComment() === null) { $context->notice('missing_docblock', 'Missing Docblock', $stmt); return true; } return false; }
/** * @param Expr $expr * @param Context $context * @return bool */ public function pass(Expr $expr, Context $context) { if (get_class($expr->expr) == get_class($expr)) { $context->notice('multiple_unary_operators', "You are using multiple unary operators. This has no effect", $expr); return true; } return false; }
/** * include {expr}, require {expr} * * @param \PhpParser\Node\Expr\Include_ $expr * @param Context $context * @return CompiledExpression */ protected function compile($expr, Context $context) { $compiled = $context->getExpressionCompiler()->compile($expr->expr); if ($compiled->isString()) { return CompiledExpression::fromZvalValue(1); } return CompiledExpression::fromZvalValue(false); }
/** * @param \PhpParser\Node\Expr\FuncCall $expr * @return CompiledExpression[] */ protected function parseArgs($expr, Context $context) { $arguments = []; foreach ($expr->args as $argument) { $arguments[] = $context->getExpressionCompiler()->compile($argument->value); } return $arguments; }
/** * @param Expr $expr * @param Context $context * @return bool */ public function pass(Expr $expr, Context $context) { if (get_class($expr->expr) != get_class($expr)) { $context->notice('stupid_unary_operators', 'Better to use type casting then unary plus.', $expr); return true; } return false; }
/** * @param Property $prop * @param Context $context * @return bool */ public function pass(Property $prop, Context $context) { if (count($prop->props) > 1) { $context->notice('limit.properties', 'Number of properties larger than one.', $prop); return true; } return false; }