Example #1
0
 /**
  * @param TupleType $type
  *
  * @return LogicalAnd|Closure
  */
 public function visitTupleType(TupleType $type)
 {
     $this->typeCheck->visitTupleType(func_get_args());
     $tupleSize = count($type->types());
     $isArrayCall = new Call(QualifiedIdentifier::fromString('\\is_array'));
     $isArrayCall->add($this->valueExpression());
     $arrayKeysCall = new Call(QualifiedIdentifier::fromString('\\array_keys'));
     $arrayKeysCall->add($this->valueExpression());
     $rangeCall = new Call(QualifiedIdentifier::fromString('\\range'));
     $rangeCall->add(new Literal(0));
     $rangeCall->add(new Literal($tupleSize - 1));
     $sequentialKeyExpression = new StrictEquals($arrayKeysCall, $rangeCall);
     $expressions = array($isArrayCall, $sequentialKeyExpression);
     $closures = array();
     $closureCalls = array();
     $checkVariable = new Variable(new Identifier('check'));
     foreach ($type->types() as $index => $subType) {
         $this->valueIndex = $index;
         $expression = $subType->accept($this);
         if ($expression instanceof Closure) {
             $closures[] = $expression;
             $checkCall = new Call($checkVariable);
             $checkCall->add($this->valueExpression());
             $closureCalls[] = $checkCall;
         } else {
             $expressions[] = $expression;
         }
     }
     $this->valueIndex = null;
     $tupleExpression = null;
     foreach ($expressions as $expression) {
         if ($tupleExpression) {
             $tupleExpression->add($expression);
         } else {
             $tupleExpression = new LogicalAnd($expression);
         }
     }
     $numClosures = count($closures);
     if ($numClosures < 1) {
         return $tupleExpression;
     }
     $closure = new Closure();
     $closure->addParameter(new Parameter($this->valueIdentifier));
     $ifStatement = new IfStatement(new LogicalNot($tupleExpression));
     $ifStatement->trueBranch()->add(new ReturnStatement(new Literal(false)));
     $closure->statementBlock()->add($ifStatement);
     $lastClosureIndex = $numClosures - 1;
     for ($i = 0; $i < $lastClosureIndex; $i++) {
         $closure->statementBlock()->add(new ExpressionStatement(new Assign($checkVariable, $closures[$i])));
         $ifStatement = new IfStatement(new LogicalNot($closureCalls[$i]));
         $ifStatement->trueBranch()->add(new ReturnStatement(new Literal(false)));
         $closure->statementBlock()->add($ifStatement);
     }
     $closure->statementBlock()->add(new ExpressionStatement(new Assign($checkVariable, $closures[$lastClosureIndex])));
     $closure->statementBlock()->add(new ReturnStatement($closureCalls[$lastClosureIndex]));
     return $closure;
 }
 /**
  * @param ParameterList $parameterList
  *
  * @return array<integer,IStatement>
  */
 public function visitParameterList(ParameterList $parameterList)
 {
     $this->typeCheck->visitParameterList(func_get_args());
     $expressions = array();
     $parameters = $parameterList->parameters();
     $parameterCount = count($parameters);
     $argumentsVariable = new Variable(new Identifier('arguments'));
     // empty parameter list
     if ($parameterCount < 1) {
         $zeroLiteral = new Literal(0);
         $countCall = new Call(QualifiedIdentifier::fromString('\\count'));
         $countCall->add($argumentsVariable);
         $newExceptionCall = new Call(QualifiedIdentifier::fromString($this->validatorNamespace()->joinAtoms('Exception', 'UnexpectedArgumentException')->string()));
         $newExceptionCall->add($zeroLiteral);
         $newExceptionCall->add(new Subscript($argumentsVariable, $zeroLiteral));
         $ifStatement = new IfStatement(new Greater($countCall, $zeroLiteral));
         $ifStatement->trueBranch()->add(new ThrowStatement(new NewOperator($newExceptionCall)));
         $expressions[] = $ifStatement;
         return $this->wrapExpressions($expressions);
     }
     $argumentCountVariable = new Variable(new Identifier('argumentCount'));
     $argumentCountCall = new Call(QualifiedIdentifier::fromString('\\count'));
     $argumentCountCall->add($argumentsVariable);
     $expressions[] = new Assign($argumentCountVariable, $argumentCountCall);
     // missing parameter checks
     $requiredParameterCount = count($parameterList->requiredParameters());
     $lastRequiredParameterIndex = $requiredParameterCount - 1;
     $missingParametersStatement = null;
     if ($requiredParameterCount > 0) {
         $missingParametersStatement = new IfStatement(new Less($argumentCountVariable, new Literal($requiredParameterCount)));
         for ($i = 0; $i < $lastRequiredParameterIndex; $i++) {
             $newExceptionCall = new Call(QualifiedIdentifier::fromString($this->validatorNamespace()->joinAtoms('Exception', 'MissingArgumentException')->string()));
             $newExceptionCall->add(new Literal($parameters[$i]->name()));
             $newExceptionCall->add(new Literal($i));
             $newExceptionCall->add(new Literal($this->renderTypeName($parameters[$i]->type())));
             $ifStatement = new IfStatement(new Less($argumentCountVariable, new Literal($i + 1)));
             $ifStatement->trueBranch()->add(new ThrowStatement(new NewOperator($newExceptionCall)));
             $missingParametersStatement->trueBranch()->add($ifStatement);
         }
         $newExceptionCall = new Call(QualifiedIdentifier::fromString($this->validatorNamespace()->joinAtoms('Exception', 'MissingArgumentException')->string()));
         $newExceptionCall->add(new Literal($parameters[$lastRequiredParameterIndex]->name()));
         $newExceptionCall->add(new Literal($lastRequiredParameterIndex));
         $newExceptionCall->add(new Literal($this->renderTypeName($parameters[$lastRequiredParameterIndex]->type())));
         $missingParametersStatement->trueBranch()->add(new ThrowStatement(new NewOperator($newExceptionCall)));
     }
     // unexpected arguments check
     if (!$parameterList->isVariableLength()) {
         $parameterCountLiteral = new Literal($parameterCount);
         $newExceptionCall = new Call(QualifiedIdentifier::fromString($this->validatorNamespace()->joinAtoms('Exception', 'UnexpectedArgumentException')->string()));
         $newExceptionCall->add($parameterCountLiteral);
         $newExceptionCall->add(new Subscript($argumentsVariable, $parameterCountLiteral));
         $tooManyParametersStatement = new IfStatement(new Greater($argumentCountVariable, $parameterCountLiteral));
         $tooManyParametersStatement->trueBranch()->add(new ThrowStatement(new NewOperator($newExceptionCall)));
         if ($missingParametersStatement) {
             $missingParametersStatement->setFalseBranch($tooManyParametersStatement);
         } else {
             $expressions[] = $tooManyParametersStatement;
         }
     }
     if ($missingParametersStatement) {
         $expressions[] = $missingParametersStatement;
     }
     // type checks
     foreach ($parameters as $index => $parameter) {
         $isVariableLength = $parameterList->isVariableLength() && $index === $parameterCount - 1;
         $indexLiteral = new Literal($index);
         $oldArgumentExpression = $this->argumentExpression;
         $oldIndexExpression = $this->indexExpression;
         if (!$isVariableLength) {
             $this->indexExpression = $indexLiteral;
             $this->argumentExpression = new Subscript($argumentsVariable, $this->indexExpression);
         }
         $parameterExpressions = $parameter->accept($this);
         if (count($parameterExpressions) < 1) {
             $this->argumentExpression = $oldArgumentExpression;
             $this->indexExpression = $oldIndexExpression;
             continue;
         }
         array_unshift($parameterExpressions, new ExpressionStatement(new Assign(new Variable(new Identifier('value')), $this->argumentExpression)));
         $parameterExpressions = $this->wrapExpressions($parameterExpressions);
         // wrap variable length in loop
         if ($isVariableLength) {
             $closure = new Closure();
             $closure->addParameter(new ParameterASTNode(new Identifier('argument')));
             $closure->addParameter(new ParameterASTNode(new Identifier('index')));
             foreach ($parameterExpressions as $expression) {
                 $closure->statementBlock()->add($expression);
             }
             $checkVariable = new Variable(new Identifier('check'));
             $indexVariable = new Variable(new Identifier('index'));
             $checkCall = new Call($checkVariable);
             $checkCall->add(new Subscript($argumentsVariable, $indexVariable));
             $checkCall->add($indexVariable);
             $loopContents = new StatementBlock();
             $loopContents->add(new ExpressionStatement($checkCall));
             $parameterExpressions = array(new ExpressionStatement(new Assign($checkVariable, $closure)), new ForStatement(new Assign($indexVariable, $indexLiteral), new Less($indexVariable, $argumentCountVariable), new PostfixIncrement($indexVariable), $loopContents));
         }
         // wrap optional in if statement
         if ($parameter->isOptional()) {
             $if = new IfStatement(new Greater($argumentCountVariable, $indexLiteral));
             foreach ($parameterExpressions as $expression) {
                 $if->trueBranch()->add($expression);
             }
             $parameterExpressions = array($if);
         }
         foreach ($parameterExpressions as $expression) {
             $expressions[] = $expression;
         }
         $this->argumentExpression = $oldArgumentExpression;
         $this->indexExpression = $oldIndexExpression;
     }
     return $this->wrapExpressions($expressions);
 }