/**
  * @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);
 }