/** * @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; }
/** * Visit a tuple type. * * @param TupleType $type The type. * * @return mixed The result of visitation. */ public function visitTupleType(TupleType $type) { $subTypes = array(); foreach ($type->types() as $subType) { $subTypes[] = $subType->accept($this); } return sprintf('tuple<%s>', implode(',', $subTypes)); }