/** * @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); }
/** * {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); }
/** * {expr} + {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Plus $expr * @param Context $context * @return CompiledExpression */ protected 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); }
/** * @param $stmt * @return Expression|Statement */ function nodeVisitorFactory($stmt, Context $context) { if ($stmt instanceof Node\Stmt) { $visitor = new Statement($stmt, $context); return $visitor; } $visitor = new Expression($context); return $visitor->compile($stmt); }
/** * @param \PhpParser\Node\Expr\MethodCall $expr * @param Context $context * @return CompiledExpression */ protected 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, true)) { $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(); } $method = $calledObject->getMethod($methodName); if (!$method) { $context->debug('getMethod is not working'); return new CompiledExpression(); } if ($method->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(); }
/** * @param \PhpParser\Node\Stmt\Do_ $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 */ protected 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(); }
/** * -{expr} * * @param \PhpParser\Node\Expr\UnaryMinus $expr * @param Context $context * @return CompiledExpression */ protected 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 CompiledExpression::fromZvalValue(-$left->getValue()); case CompiledExpression::ARR: $context->notice('unsupported-operand-types', 'Unsupported operand types -{array}', $expr); } return new CompiledExpression(); }
/** * {expr} / {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Div $expr * @param Context $context * @return CompiledExpression */ protected 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: 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); } 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); }
/** * {expr} $operator {expr} * * @param \PhpParser\Node\Expr\BinaryOp $expr * @param Context $context * @return CompiledExpression */ protected 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\Foreach_ $stmt * @param Context $context * @return CompiledExpression */ public function compile($stmt, Context $context) { $expression = new Expression($context); $expression->compile($stmt->expr); if ($stmt->keyVar) { $keyExpression = new Expression($context); $keyExpression->declareVariable($stmt->keyVar); } if ($stmt->valueVar) { $valueExpression = new Expression($context); $valueExpression->declareVariable($stmt->valueVar); } if (count($stmt->stmts) > 0) { foreach ($stmt->stmts as $statement) { \PHPSA\nodeVisitorFactory($statement, $context); } } else { return $context->notice('not-implemented-body', 'Missing body', $stmt); } }
/** * {expr} % {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Mod $expr * @param Context $context * @return CompiledExpression */ protected 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); }
/** * It's used in conditions * {left-expr} !== {right-expr} * * @param \PhpParser\Node\Expr\BinaryOp\NotIdentical $expr * @param Context $context * @return CompiledExpression */ protected 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: case CompiledExpression::NUMBER: case CompiledExpression::NULL: switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: case CompiledExpression::BOOLEAN: case CompiledExpression::NUMBER: case CompiledExpression::NULL: return new CompiledExpression(CompiledExpression::BOOLEAN, $left->getValue() !== $right->getValue()); } } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * {expr} - {expr} * * @param \PhpParser\Node\Expr\BinaryOp\Minus $expr * @param Context $context * @return CompiledExpression */ protected 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: return new CompiledExpression(CompiledExpression::LNUMBER, $left->getValue() - $right->getValue()); } break; case CompiledExpression::DNUMBER: switch ($right->getType()) { case CompiledExpression::LNUMBER: case CompiledExpression::DNUMBER: return new CompiledExpression(CompiledExpression::DNUMBER, $left->getValue() - $right->getValue()); } break; } return new CompiledExpression(CompiledExpression::UNKNOWN); }
/** * @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); switch ($compiledExpression->getType()) { case CompiledExpression::VOID: $context->notice('return.void', 'You are trying to return void', $stmt); break; } 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->isCorrectValue()) { $classMethod->addReturnPossibleValue($compiledExpression->getValue()); } } } }
/** * @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); } } }
/** * 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; }
/** * @param \PhpParser\Node\Expr\FuncCall $expr * @return CompiledExpression[] */ 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 object $expr * @param Context|null $expr * @return \PHPSA\CompiledExpression */ protected function compileExpression($expr, Context $context = null) { $visitor = new Expression(is_null($context) ? $this->getContext() : $context); return $visitor->compile($expr); }