Author: Elliot Levin (elliotlevin@hotmail.com)
Inheritance: implements Serializable
Ejemplo n.º 1
0
 /**
  * @dataProvider expressions
  * @covers \Pinq\Expressions\ExpressionVisitor
  */
 public function testExpressionVisitorVisitsTheCorrectMethod(O\Expression $expression)
 {
     $method = 'visit' . $expression->getExpressionTypeName();
     $expressionVisitorMock = $this->getMock('\\Pinq\\Expressions\\ExpressionVisitor', [$method]);
     $expressionVisitorMock->expects($this->once())->method($method)->with($this->equalTo($expression));
     $expressionVisitorMock->walk($expression);
 }
Ejemplo n.º 2
0
 protected function getMetadata(O\Expression $expression)
 {
     if (!isset($this->metadata[$expression])) {
         throw new TypeException('Cannot get metadata for expression of type \'%s\': the expression has no associated metadata', $expression->getType());
     }
     return $this->metadata[$expression];
 }
Ejemplo n.º 3
0
 public function __construct(O\Expression $expression, IParameterHasher $hasher, IFunction $function = null, $data = null)
 {
     parent::__construct($hasher, $data);
     if ($function !== null) {
         $this->contextFactory = $function->getEvaluationContextFactory();
         $this->evaluator = $expression->asEvaluator($this->contextFactory->getEvaluationContext());
     } else {
         $this->evaluator = $expression->asEvaluator();
     }
     $this->data = $data;
 }
Ejemplo n.º 4
0
 public function __construct(Providers\IQueryProvider $provider, Queries\ISourceInfo $sourceInfo, O\TraversalExpression $queryExpression = null, IIteratorScheme $scheme = null)
 {
     parent::__construct($provider);
     $this->sourceInfo = $sourceInfo;
     $this->expression = $queryExpression ?: O\Expression::value($this);
     $this->scheme = $scheme ?: Iterators\SchemeProvider::getDefault();
 }
Ejemplo n.º 5
0
 public function appendFunction(IFunction $function)
 {
     if ($function->isInternal()) {
         throw new Exception('Internal functions are not supported');
     }
     $this->append('{');
     if ($function->countBodyExpressions() === 0) {
         $this->append('}');
     } elseif ($function->countBodyExpressions() === 1) {
         $this->append(' ');
         $this->append($function->getBodyExpressions()[0]->compile() . ';');
         $this->append(' }');
     } else {
         $this->appendLine();
         $this->append(implode(';' . PHP_EOL, Expression::compileAll($function->getBodyExpressions())) . ';');
         $this->appendLine();
         $this->append('}');
     }
     $parameterMap = $function->getParameterScopedVariableMap();
     if (!empty($parameterMap)) {
         $this->append(' with parameters: [');
         $parameters = [];
         foreach ($parameterMap as $variableName) {
             $parameters[] = "\${$variableName}";
         }
         $this->append(implode(', ', $parameters));
         $this->append(']');
     }
 }
Ejemplo n.º 6
0
 /**
  * @dataProvider interpreters
  */
 public function testParameterExpressions()
 {
     $this->assertParametersAre(function ($i) {
     }, [O\Expression::parameter('i')]);
     $this->assertParametersAre(function ($i, $foo) {
     }, [O\Expression::parameter('i'), O\Expression::parameter('foo')]);
     $this->assertParametersAre(function ($i = null) {
     }, [O\Expression::parameter('i', null, O\Expression::value(null))]);
     $this->assertParametersAre(function ($i = 'bar') {
     }, [O\Expression::parameter('i', null, O\Expression::value('bar'))]);
     $this->assertParametersAre(function (\DateTime $i) {
     }, [O\Expression::parameter('i', '\\DateTime')]);
     $this->assertParametersAre(function (self $i) {
     }, [O\Expression::parameter('i', '\\' . __CLASS__)]);
     $this->assertParametersAre(function (parent $i) {
     }, [O\Expression::parameter('i', '\\' . get_parent_class())]);
     $this->assertParametersAre(function (MiscInterpreterTest $i) {
     }, [O\Expression::parameter('i', '\\' . __CLASS__)]);
     $this->assertParametersAre(function (ParameterClassTest $i) {
     }, [O\Expression::parameter('i', '\\' . __NAMESPACE__ . '\\ParameterClassTest')]);
     $this->assertParametersAre(function (namespace\ParameterClassTest $i) {
     }, [O\Expression::parameter('i', '\\' . __NAMESPACE__ . '\\ParameterClassTest')]);
     $this->assertParametersAre(function (&$i) {
     }, [O\Expression::parameter('i', null, null, true)]);
     $this->assertParametersAre(function (\stdClass &$i = null, array $array = ['foo']) {
     }, [O\Expression::parameter('i', '\\stdClass', O\Expression::value(null), true), O\Expression::parameter('array', 'array', O\Expression::value(['foo']))]);
     $this->assertParametersAre(function (callable &$v = null) {
     }, [O\Expression::parameter('v', 'callable', O\Expression::value(null), true)]);
     $this->assertParametersAre(function ($v = [1, 2, 3, 'test' => 'foo', [2 => 'boo', '']]) {
     }, [O\Expression::parameter('v', null, O\Expression::value([1, 2, 3, 'test' => 'foo', [2 => 'boo', '']]))]);
 }
Ejemplo n.º 7
0
 public function walkVariable(VariableExpression $expression)
 {
     $name = $expression->getName();
     if ($name instanceof O\ValueExpression) {
         return $expression->update(O\Expression::value($this->prefix . $name->getValue()));
     }
     return $expression->update(O\Expression::binaryOperation(O\Expression::value($this->prefix), O\Operators\Binary::CONCATENATION, $name));
 }
Ejemplo n.º 8
0
 public function testAssignmentToBinaryOperatorEquivalent()
 {
     foreach ([O\Operators\Assignment::EQUAL, O\Operators\Assignment::EQUAL_REFERENCE] as $operatorThatShouldNotChange) {
         $assignment = O\Expression::assign(O\Expression::variable(O\Expression::value('foo')), $operatorThatShouldNotChange, O\Expression::variable(O\Expression::value('bar')));
         $this->assertSame($assignment, $assignment->toBinaryOperationEquivalent());
     }
     $assignment = O\Expression::assign(O\Expression::variable(O\Expression::value('foo')), O\Operators\Assignment::ADDITION, O\Expression::variable(O\Expression::value('bar')));
     $this->assertEquals(O\Expression::assign(O\Expression::variable(O\Expression::value('foo')), O\Operators\Assignment::EQUAL, O\Expression::binaryOperation(O\Expression::variable(O\Expression::value('foo')), O\Operators\Binary::ADDITION, O\Expression::variable(O\Expression::value('bar')))), $assignment->toBinaryOperationEquivalent());
 }
Ejemplo n.º 9
0
 public function testFunctionGetsReturnWithoutValueExpression()
 {
     /** @var $function Functions\ProjectionBase */
     $function = $this->functionWithEmptyReturnStatement();
     $this->assertSame(true, $function->hasReturnExpression());
     $this->assertEquals(O\Expression::returnExpression(), $function->getReturnExpression());
     $this->assertSame(false, $function->hasReturnValueExpression());
     $this->assertEquals(null, $function->getReturnValueExpression());
 }
Ejemplo n.º 10
0
 private function recompile(Parsing\IFunctionReflection $reflection, Parsing\IFunctionStructure $structure, &$closureExpression = null)
 {
     $signature = $reflection->getSignature();
     $usedVariables = array_map(function ($name) {
         return O\Expression::closureUsedVariable($name);
     }, $signature->getScopedVariableNames() ?: []);
     $closureExpression = O\Expression::closure($signature->returnsReference(), $reflection->getInnerReflection()->getClosureScopeClass() === null, $signature->getParameterExpressions(), $usedVariables, $structure->getBodyExpressions());
     return $closureExpression->evaluate($reflection->asEvaluationContext());
 }
Ejemplo n.º 11
0
 public function testExpressionWalkerWorks()
 {
     $expression = O\Expression::variable(O\Expression::value('foo'));
     $expressionWalker = new O\DynamicExpressionWalker([O\ValueExpression::getType() => function (O\ValueExpression $expression) {
         return O\Expression::value('bar');
     }]);
     $newExpression = $expressionWalker->walk($expression);
     $this->assertNotEquals($expression, $newExpression);
     $this->assertSame($newExpression->getName()->getValue(), 'bar');
 }
Ejemplo n.º 12
0
 public function testWalksBodyAndParameterExpressions()
 {
     $processor = $this->getMock('Pinq\\Providers\\DSL\\Compilation\\Processors\\Expression\\ExpressionProcessor', ['walkValue']);
     $processor->expects($this->exactly(2))->method('walkValue')->will($this->returnValue(O\Expression::value('updated')));
     /** @var ExpressionProcessor $processor */
     $function = new Functions\ElementProjection('', null, null, [], [O\Expression::parameter('param', 'abc', O\Expression::value('default'))], [O\Expression::value('body')]);
     $processedFunction = $processor->processFunction($function);
     $this->assertEquals([O\Expression::value('updated')], $processedFunction->getBodyExpressions());
     $this->assertEquals(O\Expression::parameter('param', 'abc', O\Expression::value('updated')), $processedFunction->getParameters()->getValue());
 }
Ejemplo n.º 13
0
 public function testFullParameters()
 {
     /** @var $function Functions\Aggregator */
     $function = $this->buildFunction('', null, null, [], [O\Expression::parameter('aggregate'), O\Expression::parameter('value')]);
     $this->assertSame(true, $function->getParameters()->hasAggregateValue());
     $this->assertSame('aggregate', $function->getParameters()->getAggregateValue()->getName());
     $this->assertSame(true, $function->getParameters()->hasValue());
     $this->assertSame('value', $function->getParameters()->getValue()->getName());
     $this->assertSame(false, $function->getParameters()->hasRequiredUnusedParameters());
     $this->assertSame([], $function->getParameters()->getRequiredUnusedParameters());
     $this->assertSame([], $function->getParameters()->getUnused());
     $this->assertSame([], $function->getParameters()->getUnusedParameterDefaultMap());
 }
Ejemplo n.º 14
0
 protected final function visit(O\Expression $expression)
 {
     if ($expression instanceof O\ValueExpression) {
         $queryable = $expression->getValue();
         if (!$queryable instanceof IQueryable) {
             throw new PinqException('Invalid scope expression: must originate from %s, %s given', IQueryable::IQUERYABLE_TYPE, Utilities::getTypeOrClass($queryable));
         }
         if ($queryable->isSource()) {
             $this->addSegment(function () use($queryable) {
                 $this->interpretation->interpretScopeSource($queryable);
             });
             return;
         }
         $expression = $queryable->getExpression();
     }
     $methodName = $this->getMethodName($expression);
     $this->segmentCounter++;
     $this->segmentId = "{$this->segmentCounter}-{$methodName}";
     if (!method_exists($this, "visit{$methodName}")) {
         throw new PinqException('Cannot interpret query scope with method call \'%s\'', $methodName);
     }
     $this->{"visit{$methodName}"}($expression);
 }
Ejemplo n.º 15
0
 public function testFullParameters()
 {
     /** @var $function Functions\ConnectorProjection */
     $function = $this->buildFunction('', null, null, [], [O\Expression::parameter('outer-value'), O\Expression::parameter('inner-value'), O\Expression::parameter('outer-key'), O\Expression::parameter('inner-key')]);
     $this->assertSame(true, $function->getParameters()->hasOuterKey());
     $this->assertSame('outer-value', $function->getParameters()->getOuterValue()->getName());
     $this->assertSame(true, $function->getParameters()->hasInnerValue());
     $this->assertSame('inner-value', $function->getParameters()->getInnerValue()->getName());
     $this->assertSame(true, $function->getParameters()->hasOuterKey());
     $this->assertSame('outer-key', $function->getParameters()->getOuterKey()->getName());
     $this->assertSame(true, $function->getParameters()->hasInnerKey());
     $this->assertSame('inner-key', $function->getParameters()->getInnerKey()->getName());
     $this->assertSame(false, $function->getParameters()->hasRequiredUnusedParameters());
     $this->assertSame([], $function->getParameters()->getRequiredUnusedParameters());
     $this->assertSame([], $function->getParameters()->getUnused());
     $this->assertSame([], $function->getParameters()->getUnusedParameterDefaultMap());
 }
Ejemplo n.º 16
0
 public function testFunctionWithDefaultRelativeConstant()
 {
     /** @var $function Functions\ElementProjection */
     $function = $this->buildFunction('', null, __NAMESPACE__, [], [O\Expression::parameter('value'), O\Expression::parameter('key'), O\Expression::parameter('excessive1', null, O\Expression::constant('__RELATIVE_CONSTANT')), O\Expression::parameter('excessive2', null, O\Expression::value([false]))]);
     $this->assertSame(false, $function->getParameters()->hasRequiredUnusedParameters());
     $this->assertEquals([], $function->getParameters()->getRequiredUnusedParameters());
     $this->assertEquals([O\Expression::parameter('excessive1', null, O\Expression::constant('__RELATIVE_CONSTANT')), O\Expression::parameter('excessive2', null, O\Expression::value([false]))], $function->getParameters()->getUnused());
     $this->assertEquals(['excessive1' => O\Expression::constant('__RELATIVE_CONSTANT'), 'excessive2' => O\Expression::value([false])], $function->getParameters()->getUnusedParameterDefaultMap());
     //This fails in PHP due to strange behaviour with closures and relative constants.
     //Bug reported: https://bugs.php.net/bug.php?id=67897
     if (defined('HHVM_VERSION')) {
         define('__RELATIVE_CONSTANT', 'in global namespace');
         $this->assertEquals(['excessive1' => 'in global namespace', 'excessive2' => [false]], $function->getEvaluationContextFactory()->getEvaluationContext()->getVariableTable());
         //Should take precedence
         define(__NAMESPACE__ . '\\__RELATIVE_CONSTANT', 'in relative namespace');
         $this->assertEquals(['excessive1' => 'in relative namespace', 'excessive2' => [false]], $function->getEvaluationContextFactory()->getEvaluationContext()->getVariableTable());
     }
 }
Ejemplo n.º 17
0
 public function testFunctionWithReturnStatement()
 {
     $function = $this->functionWithReturnStatement();
     $this->assertSame('', $function->getCallableId());
     $this->assertSame(1, $function->getParameters()->count());
     $this->assertEquals([O\Expression::parameter('foo')], $function->getParameters()->getAll());
     $this->assertEquals(['param' => 'scope'], $function->getParameterScopedVariableMap());
     $this->assertEquals(['', 'param'], $function->getParameterIds());
     $this->assertSame(true, $function->hasScopeType());
     $this->assertSame(__CLASS__, $function->getScopeType());
     $this->assertSame(true, $function->hasNamespace());
     $this->assertSame(__NAMESPACE__, $function->getNamespace());
     $this->assertSame(4, $function->countBodyExpressions());
     $this->assertSame(2, $function->countBodyExpressionsUntilReturn());
     $this->assertEquals([O\Expression::value('before'), O\Expression::returnExpression(O\Expression::value('return')), O\Expression::value('after'), O\Expression::functionCall(O\Expression::value('boom'))], $function->getBodyExpressions());
     $this->assertEquals([O\Expression::value('before'), O\Expression::returnExpression(O\Expression::value('return'))], $function->getBodyExpressionsUntilReturn());
     $this->assertEquals(new O\EvaluationContext(__NAMESPACE__, __CLASS__, null, ['scope' => 'value']), $function->getEvaluationContextFactory()->getEvaluationContext(new ResolvedParameterRegistry(['param' => 'value'])));
 }
Ejemplo n.º 18
0
 public function interpretSource(O\Expression $expression)
 {
     $isQueryScope = false;
     $queryableQueryResolver = new O\DynamicExpressionWalker([O\TraversalExpression::getType() => function (O\TraversalExpression $expression, O\ExpressionWalker $self) use(&$isQueryScope) {
         $expression = $expression->updateValue($self->walk($expression->getValue()));
         if ($isQueryScope) {
             return $expression;
         } else {
             return $self->walk(O\Expression::value($expression->evaluate($this->evaluationContext)));
         }
     }, O\ValueExpression::getType() => function (O\ValueExpression $expression) use(&$isQueryScope) {
         if ($expression->getValue() instanceof IQueryable) {
             $isQueryScope = true;
         }
         return $expression;
     }]);
     $expression = $queryableQueryResolver->walk($expression);
     if ($isQueryScope) {
         $this->scopeInterpreter->interpretScope($expression);
         $this->interpretation->interpretQueryScope($this->getId('source-scope'), $this->scopeInterpreter->getInterpretation());
     } else {
         $this->interpretation->interpretArrayOrIterator($this->getId('source-iterator'), $expression->evaluate($this->evaluationContext));
     }
 }
Ejemplo n.º 19
0
 public function inline(IFunction $function, O\Expression $expression, Parameters\ResolvedParameterRegistry $parameters)
 {
     /** @var $expression O\VariableExpression */
     return $expression->update($this->getResolvedValueExpression($parameters, $expression->getName()));
 }
Ejemplo n.º 20
0
 public function tryComputeResults(O\Expression $queryExpression, &$results)
 {
     if (isset($this->storage[$queryExpression])) {
         $results = $this->storage[$queryExpression];
         return true;
     }
     $foundApplicableResults = false;
     //Searches the query expression tree and checks if any parent expressions have saved results
     //If so, the expression tree is updated with a Traversable implementation with the saved results
     $applicableScopeFinder = function (O\Expression $expression, O\ExpressionWalker $self) use(&$foundApplicableResults) {
         if (isset($this->storage[$expression])) {
             $foundApplicableResults = true;
             return O\Expression::value($this->newTraversable($this->storage[$expression]));
         }
         if ($expression instanceof O\ValueExpression) {
             return $expression;
         }
         /** @var $expression O\TraversalExpression */
         return $expression->updateValue($self->walk($expression->getValue()));
     };
     $traversalWalker = new O\DynamicExpressionWalker([O\TraversalExpression::getType() => $applicableScopeFinder, O\ValueExpression::getType() => $applicableScopeFinder]);
     $remainingQueryExpression = $traversalWalker->walk($queryExpression);
     //If found applicable results, execute the updated expression tree against the Traversable
     //implementation to compute the result of the query.
     $results = $foundApplicableResults ? $remainingQueryExpression->evaluate() : null;
     return $foundApplicableResults;
 }
Ejemplo n.º 21
0
 protected function validateStaticClassName(O\Expression $expression, $type)
 {
     if ($expression instanceof O\ValueExpression) {
         return $expression->getValue();
     } else {
         throw new TypeException('Invalid %s expression: dynamic class types are not supported', $type);
     }
 }
Ejemplo n.º 22
0
 /**
  * @dataProvider parsers
  */
 public function testArgumentUnpacking()
 {
     $this->assertParsedAs([$this->parameters, 'argumentUnpacking'], [O\Expression::functionCall(O\Expression::value('func'), [O\Expression::argument(O\Expression::arrayExpression([]), true)])]);
 }
Ejemplo n.º 23
0
 public function walkConstant(O\ConstantExpression $expression)
 {
     $resolvedMagicConstant = $this->resolveMagicConstantValue($expression->getName());
     if ($resolvedMagicConstant !== null) {
         return O\Expression::value($resolvedMagicConstant);
     } else {
         return $expression;
     }
 }
Ejemplo n.º 24
0
 protected function compileCode(&$code)
 {
     $this->assignTo->compileCode($code);
     $code .= ' ' . $this->operator . ' ';
     $this->assignmentValue->compileCode($code);
 }
Ejemplo n.º 25
0
 private function parseOperatorNode(Node\Expr $node)
 {
     $nodeType = str_replace('Expr_', '', $node->getType());
     switch (true) {
         case isset(self::$assignOperatorsMap[$nodeType]):
             return Expression::assign($this->parseNode($node->var), self::$assignOperatorsMap[$nodeType], $this->parseNode($node->expr));
         case $node instanceof Node\Expr\Instanceof_:
             return Expression::binaryOperation($this->parseNode($node->expr), Operators\Binary::IS_INSTANCE_OF, $this->parseNameNode($node->class));
         case isset(self::$binaryOperatorsMap[$nodeType]):
             return Expression::binaryOperation($this->parseNode($node->left), self::$binaryOperatorsMap[$nodeType], $this->parseNode($node->right));
         case isset(self::$unaryOperatorsMap[$nodeType]):
             return Expression::unaryOperation(self::$unaryOperatorsMap[$nodeType], $this->parseNode(isset($node->expr) ? $node->expr : $node->var));
         case isset(self::$castOperatorMap[$nodeType]):
             return Expression::cast(self::$castOperatorMap[$nodeType], $this->parseNode($node->expr));
         default:
             return null;
     }
 }
Ejemplo n.º 26
0
 protected function visitEmpty(O\EmptyExpression $expression)
 {
     $this->walk(O\Expression::unaryOperation(Operators\Unary::NOT, $expression->getValue()));
 }
Ejemplo n.º 27
0
 private static function getParameterExpression(\ReflectionParameter $parameter)
 {
     $typeHint = null;
     if ($parameter->isArray()) {
         $typeHint = 'array';
     } elseif ($parameter->isCallable()) {
         $typeHint = 'callable';
     } elseif ($parameter->getClass() !== null) {
         $typeHint = $parameter->getClass()->getName();
         $typeHint = $typeHint[0] === '\\' ? $typeHint : '\\' . $typeHint;
     }
     return O\Expression::parameter($parameter->getName(), $typeHint, $parameter->isDefaultValueAvailable() ? O\Expression::value($parameter->getDefaultValue()) : null, $parameter->isPassedByReference(), method_exists($parameter, 'isVariadic') && $parameter->isVariadic());
 }
Ejemplo n.º 28
0
 public function createReference(O\Expression $expression, O\Expression $referencedExpression)
 {
     $this->expressionTypes[$expression->hash()] =& $this->expressionTypes[$referencedExpression->hash()];
 }
Ejemplo n.º 29
0
 protected function parseQueryExpression(callable $queryFunction, O\IEvaluationContext &$evaluationContext = null)
 {
     $reflection = $this->functionInterpreter->getReflection($queryFunction);
     $evaluationContext = $reflection->asEvaluationContext();
     $function = $this->functionInterpreter->getStructure($reflection);
     $expressions = $function->getBodyExpressions();
     $this->assertCount(1, $expressions);
     //Resolve the parameter variable with the queryable value and $this
     $parameterName = $reflection->getSignature()->getParameterExpressions()[0]->getName();
     $expression = $expressions[0];
     foreach ([$parameterName => $this->queryable, 'this' => $this] as $variable => $value) {
         $variableReplacer = new O\DynamicExpressionWalker([O\VariableExpression::getType() => function (O\VariableExpression $expression) use($variable, &$value) {
             if ($expression->getName() instanceof O\ValueExpression && $expression->getName()->getValue() === $variable) {
                 return O\Expression::value($value);
             } else {
                 return $expression;
             }
         }, O\ClosureExpression::getType() => function ($closure) {
             return $closure;
         }]);
         $expression = $variableReplacer->walk($expression);
     }
     if ($expression instanceof O\ReturnExpression) {
         return $expression->getValue();
     } else {
         return $expression;
     }
 }
Ejemplo n.º 30
0
 /**
  * @param string  $name
  * @param mixed[] $arguments
  *
  * @return O\MethodCallExpression
  */
 protected function newMethod($name, array $arguments = [])
 {
     return O\Expression::methodCall($this->expression, O\Expression::value($name), array_map([O\Expression::getType(), 'argument'], array_map([O\Expression::getType(), 'value'], $arguments)));
 }