/** * {expr} + {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Plus $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::LNUMBER: switch ($right->getType()) { case CompiledExpression::LNUMBER: /** * php -r "var_dump(1 + 1);" int(2) */ return new CompiledExpression(CompiledExpression::LNUMBER, $left->getValue() + $right->getValue()); case CompiledExpression::DNUMBER: /** * php -r "var_dump(1 + 1.0);" double(2) */ return new CompiledExpression(CompiledExpression::DNUMBER, $left->getValue() + $right->getValue()); } break; case CompiledExpression::DNUMBER: switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: /** * php -r "var_dump(1.0 + 1);" double(2) * php -r "var_dump(1.0 + 1.0);" double(2) */ return new CompiledExpression(CompiledExpression::DNUMBER, $left->getValue() + $right->getValue()); } break; } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * {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); }
/** * @param \PhpParser\Node\Expr\FuncCall $expr * @return array */ protected function parseArgs($expr, Context $context) { $arguments = array(); foreach ($expr->args as $argument) { $expression = new Expression($context); $arguments[] = $expression->compile($argument->value); } return $arguments; }
/** * @param $st * @return Expression|Statement */ function nodeVisitorFactory($st, Context $context) { if ($st instanceof Node\Stmt) { $visitor = new Statement($st, $context); return $visitor; } $visitor = new Expression($context); return $visitor->compile($st); }
/** * @param \PhpParser\Node\Stmt\While_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $expression = new Expression($context); $expression->compile($stmt->cond); if (count($stmt->stmts) > 0) { foreach ($stmt->stmts as $statement) { \PHPSA\nodeVisitorFactory($statement, $context); } } else { $context->notice('not-implemented-body', 'Missing body', $stmt); } }
/** * ~{expr} * * @param \PhpParser\Node\Expr\BitwiseNot $expr * @param Context $context * @return CompiledExpression */ public function compile($expr, Context $context) { $expression = new Expression($context); $compiledExpression = $expression->compile($expr->expr); switch ($compiledExpression->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: return CompiledExpression::fromZvalValue(~$compiledExpression->getValue()); } return new CompiledExpression(); }
/** * @param \PhpParser\Node\Expr\MethodCall $expr * @param Context $context * @return CompiledExpression */ public function compile($expr, Context $context) { if ($expr->var instanceof Variable) { $symbol = $context->getSymbol($expr->var->name); if ($symbol) { switch ($symbol->getType()) { case CompiledExpression::OBJECT: case CompiledExpression::DYNAMIC: $symbol->incUse(); /** @var ClassDefinition $calledObject */ $calledObject = $symbol->getValue(); if ($calledObject instanceof ClassDefinition) { $methodName = is_string($expr->name) ? $expr->name : false; if ($expr->name instanceof Variable) { /** * @todo implement fetch from symbol table */ //$methodName = $expr->name->name; } if ($methodName) { if (!$calledObject->hasMethod($methodName)) { $context->notice('undefined-mcall', sprintf('Method %s() does not exist in %s scope', $methodName, $expr->var->name), $expr); //it's needed to exit return new CompiledExpression(); } if ($calledObject->getMethod($methodName)->isStatic()) { $context->notice('undefined-mcall', sprintf('Method %s() is a static function but called like class method in $%s variable', $methodName, $expr->var->name), $expr); } return new CompiledExpression(); } return new CompiledExpression(); } /** * It's a wrong type or value, maybe it's implemented and We need to fix it in another compilers */ $context->debug('Unknown $calledObject - is ' . gettype($calledObject)); return new CompiledExpression(); } $context->notice('variable-wrongtype.mcall', sprintf('Variable %s is not object\\callable and cannot be called like this', $expr->var->name), $expr); return new CompiledExpression(); } else { $context->notice('undefined-variable.mcall', sprintf('Variable %s is not defined in this scope', $expr->var->name), $expr); return new CompiledExpression(); } } $expression = new Expression($context); $expression->compile($expr->var); $context->debug('Unknown method call'); return new CompiledExpression(); }
/** * -{expr} * * @param \PhpParser\Node\Expr\UnaryPlus $expr * @param Context $context * @return CompiledExpression */ public function compile($expr, Context $context) { $expression = new Expression($context); $left = $expression->compile($expr->expr); switch ($left->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: case CompiledExpression::STRING: case CompiledExpression::NULL: return new CompiledExpression(CompiledExpression::INTEGER, $left->getValue()); case CompiledExpression::ARR: $context->notice('unsupported-operand-types', 'Unsupported operand types -{array}', $expr); return new CompiledExpression(); } return new CompiledExpression(); }
/** * {expr} $operator {expr} * * @param \PhpParser\Node\Expr\BinaryOp $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::LNUMBER: case CompiledExpression::DNUMBER: switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: return new CompiledExpression(CompiledExpression::BOOLEAN, $this->compare($left->getValue(), $right->getValue())); } break; } return new CompiledExpression(); }
/** * @param \PhpParser\Node\Stmt\Return_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $expression = new Expression($context); $compiledExpression = $expression->compile($stmt->expr); if ($context->scopePointer) { /** * If it is a Class's method we need to work on return types, return possible values */ if ($context->scopePointer->isClassMethod()) { /** @var ClassMethod $classMethod */ $classMethod = $context->scopePointer->getObject(); $classMethod->addNewType($compiledExpression->getType()); if ($compiledExpression->isCurrectTypeValue()) { $classMethod->addReturnPossibleValue($compiledExpression->getValue()); } } } }
/** * It's used in conditions * {left-expr} === {right-expr} * * @param \PhpParser\Node\Expr\BinaryOp\Identical $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::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: return new CompiledExpression(CompiledExpression::BOOLEAN, $left->getValue() === $right->getValue()); } } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * {expr}++ * * @param \PhpParser\Node\Expr\PostDec $expr * @param Context $context * @return CompiledExpression */ public function compile($expr, Context $context) { if ($expr->var instanceof \PHPParser\Node\Expr\Variable) { $name = $expr->var->name; $variable = $context->getSymbol($name); if ($variable) { $variable->inc(); $variable->incUse(); return CompiledExpression::fromZvalValue($variable->getValue()); } } $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); }
/** * {expr} % {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Mod $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::LNUMBER: case CompiledExpression::BOOLEAN: case CompiledExpression::DNUMBER: if ($left->isEquals(0)) { $context->notice('division-zero', 'You trying to use division from ' . $left->getValue() . '%{expr}', $expr); } break; } switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: if ($right->isEquals(0)) { $context->notice('division-zero', 'You trying to use division on {expr}%' . $right->getValue(), $expr); return new CompiledExpression(CompiledExpression::UNKNOWN); } break; } switch ($left->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: switch ($right->getType()) { case CompiledExpression::BOOLEAN: case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: return CompiledExpression::fromZvalValue($left->getValue() % $right->getValue()); } break; } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * @param \PhpParser\Node\Stmt\If_ $ifStatement * @param Context $context * @return CompiledExpression */ public function compile($ifStatement, Context $context) { $expression = new Expression($context); $expression->compile($ifStatement->cond); if (count($ifStatement->stmts) > 0) { foreach ($ifStatement->stmts as $stmt) { \PHPSA\nodeVisitorFactory($stmt, $context); } } else { $context->notice('not-implemented-body', 'Missing body', $ifStatement); } if (count($ifStatement->elseifs) > 0) { foreach ($ifStatement->elseifs as $elseIfStatement) { $expression = new Expression($context); $expression->compile($elseIfStatement->cond); if (count($elseIfStatement->stmts) > 0) { foreach ($elseIfStatement->stmts as $stmt) { \PHPSA\nodeVisitorFactory($stmt, $context); } } else { $context->notice('not-implemented-body', 'Missing body', $elseIfStatement); } } } else { //@todo implement } if ($ifStatement->else) { if (count($ifStatement->else->stmts) > 0) { foreach ($ifStatement->else->stmts as $stmt) { \PHPSA\nodeVisitorFactory($stmt, $context); } } else { $context->notice('not-implemented-body', 'Missing body', $ifStatement->else); } } }
/** * @param Node\Stmt\If_ $st */ public function passIf(Node\Stmt\If_ $ifStatement) { $expression = new Expression($this->context); $compiledExpression = $expression->compile($ifStatement->cond); if (count($ifStatement->stmts) > 0) { foreach ($ifStatement->stmts as $st) { $result = \PHPSA\nodeVisitorFactory($st, $this->context); } } else { //@todo implement } if (count($ifStatement->elseifs) > 0) { foreach ($ifStatement->elseifs as $elseIfStatement) { $expression = new Expression($this->context); $compiledExpression = $expression->compile($elseIfStatement->cond); if (count($elseIfStatement->stmts) > 0) { foreach ($elseIfStatement->stmts as $st) { $result = \PHPSA\nodeVisitorFactory($st, $this->context); } } else { //@todo implement } } } else { //@todo implement } if ($ifStatement->else) { if (count($ifStatement->else->stmts) > 0) { foreach ($ifStatement->else->stmts as $st) { $result = \PHPSA\nodeVisitorFactory($st, $this->context); } } else { //@todo implement } } }
/** * {expr} || {expr} * * @param \PhpParser\Node\Expr\BinaryOp\BooleanOr $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::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::STRING: case CompiledExpression::BOOLEAN: case CompiledExpression::NULL: switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::STRING: case CompiledExpression::BOOLEAN: case CompiledExpression::NULL: return CompiledExpression::fromZvalValue($left->getValue() || $right->getValue()); } break; } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * @param $expr * @return \PHPSA\CompiledExpression */ protected function compileExpression($expr) { $visitor = new Expression($this->getContext()); return $visitor->compile($expr); }
/** * Convert const fetch expr to CompiledExpression * * @param Node\Expr\ConstFetch $expr * @return CompiledExpression */ protected function constFetch(Node\Expr\ConstFetch $expr) { if ($expr->name instanceof Node\Name) { if ($expr->name->parts[0] === 'true') { return new CompiledExpression(CompiledExpression::BOOLEAN, true); } if ($expr->name->parts[0] === 'false') { return new CompiledExpression(CompiledExpression::BOOLEAN, false); } } /** * @todo Implement check */ $expression = new Expression($this->context); $compiledExpr = $expression->compile($expr->name); return $compiledExpr; }