src/Eloquent/Typhoon/Generator/ParameterListGenerator.php
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);
    }
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);
    }
@param ParameterList $parameterList

@return array<integer,IStatement>