/** * @param RuntimeConfiguration $configuration * * @return NewOperator */ public function generate(RuntimeConfiguration $configuration) { $this->typeCheck->generate(func_get_args()); $validatorNamespaceCall = new Call(new StaticMember(QualifiedIdentifier::fromString('\\Eloquent\\Cosmos\\ClassName'), new Constant(new Identifier('fromString')))); $validatorNamespaceCall->add(new Literal($configuration->validatorNamespace()->string())); $newConfigurationCall = new Call(QualifiedIdentifier::fromString('\\Eloquent\\Typhoon\\Configuration\\RuntimeConfiguration')); $newConfigurationCall->add($validatorNamespaceCall); $newConfigurationCall->add(new Literal($configuration->useNativeCallable())); return new NewOperator($newConfigurationCall); }
/** * @param RuntimeConfiguration $configuration * @param null &$className * * @return SyntaxTree */ public function generateSyntaxTree(RuntimeConfiguration $configuration, &$className = null) { $this->typeCheck->generateSyntaxTree(func_get_args()); $className = $configuration->validatorNamespace()->joinAtoms('DummyValidator'); $classDefinition = new ClassDefinition(new Identifier($className->shortName()->string())); $classDefinition->setParentName(QualifiedIdentifier::fromString('AbstractValidator')); $classDefinition->add($this->generateCallMethod()); $primaryBlock = new PhpBlock(); $primaryBlock->add(new NamespaceStatement(QualifiedIdentifier::fromString($className->parent()->toRelative()->string()))); $primaryBlock->add($classDefinition); $syntaxTree = new SyntaxTree(); $syntaxTree->add($primaryBlock); return $syntaxTree; }
/** * @return ConcreteMethod */ protected function generateConstructor() { $this->typeCheck->generateConstructor(func_get_args()); $parameterNameIdentifier = new Identifier('parameterName'); $parameterNameVariable = new Variable($parameterNameIdentifier); $indexIdentifier = new Identifier('index'); $indexVariable = new Variable($indexIdentifier); $expectedTypeIdentifier = new Identifier('expectedType'); $expectedTypeVariable = new Variable($expectedTypeIdentifier); $previousIdentifier = new Identifier('previous'); $thisVariable = new Variable(new Identifier('this')); $thisParameterNameMember = new Member($thisVariable, new Constant($parameterNameIdentifier)); $thisIndexMember = new Member($thisVariable, new Constant($indexIdentifier)); $thisExpectedTypeMember = new Member($thisVariable, new Constant($expectedTypeIdentifier)); $method = new ConcreteMethod(new Identifier('__construct'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter($parameterNameIdentifier)); $method->addParameter(new Parameter($indexIdentifier)); $method->addParameter(new Parameter($expectedTypeIdentifier)); $previousParameter = new Parameter($previousIdentifier, new ObjectTypeHint(QualifiedIdentifier::fromString('\\Exception'))); $previousParameter->setDefaultValue(new Literal(null)); $method->addParameter($previousParameter); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisParameterNameMember, $parameterNameVariable))); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisIndexMember, $indexVariable))); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisExpectedTypeMember, $expectedTypeVariable))); $sprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $sprintfCall->add(new Literal("Missing argument for parameter '%s' at index %d. Expected '%s'.")); $sprintfCall->add($parameterNameVariable); $sprintfCall->add($indexVariable); $sprintfCall->add($expectedTypeVariable); $parentConstructCall = new Call(new StaticMember(new Constant(new Identifier('parent')), new Constant(new Identifier('__construct')))); $parentConstructCall->add($sprintfCall); $parentConstructCall->add(new Variable($previousIdentifier)); $method->statementBlock()->add(new ExpressionStatement($parentConstructCall)); return $method; }
/** * @return ConcreteMethod */ protected function generateStreamTypeMethod() { $this->typeCheck->generateStreamTypeMethod(func_get_args()); $valueIdentifier = new Identifier('value'); $valueVariable = new Variable($valueIdentifier); $metaDataVariable = new Variable(new Identifier('metaData')); $metaDataModeSubscript = new Subscript($metaDataVariable, new Literal('mode')); $readableVariable = new Variable(new Identifier('readable')); $writableVariable = new Variable(new Identifier('writable')); $method = new ConcreteMethod(new Identifier('streamType'), AccessModifier::PROTECTED_()); $method->addParameter(new Parameter($valueIdentifier)); $streamGetMetaDataCall = new Call(QualifiedIdentifier::fromString('\\stream_get_meta_data')); $streamGetMetaDataCall->add($valueVariable); $method->statementBlock()->add(new ExpressionStatement(new Assign($metaDataVariable, $streamGetMetaDataCall))); $readablePregMatchCall = new Call(QualifiedIdentifier::fromString('\\preg_match')); $readablePregMatchCall->add(new Literal('/[r+]/')); $readablePregMatchCall->add($metaDataModeSubscript); $readableIf = new IfStatement($readablePregMatchCall, new StatementBlock(), new StatementBlock()); $readableIf->trueBranch()->add(new ExpressionStatement(new Assign($readableVariable, new Literal('true')))); $readableIf->falseBranch()->add(new ExpressionStatement(new Assign($readableVariable, new Literal('false')))); $method->statementBlock()->add($readableIf); $writablePregMatchCall = new Call(QualifiedIdentifier::fromString('\\preg_match')); $writablePregMatchCall->add(new Literal('/[waxc+]/')); $writablePregMatchCall->add($metaDataModeSubscript); $writableIf = new IfStatement($writablePregMatchCall, new StatementBlock(), new StatementBlock()); $writableIf->trueBranch()->add(new ExpressionStatement(new Assign($writableVariable, new Literal('true')))); $writableIf->falseBranch()->add(new ExpressionStatement(new Assign($writableVariable, new Literal('false')))); $method->statementBlock()->add($writableIf); $sprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $sprintfCall->add(new Literal('stream {readable: %s, writable: %s}')); $sprintfCall->add($readableVariable); $sprintfCall->add($writableVariable); $method->statementBlock()->add(new ReturnStatement($sprintfCall)); return $method; }
/** * @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; }
/** * @return ConcreteMethod */ protected function generateCallMethod() { $this->typeCheck->generateCallMethod(func_get_args()); $nameIdentifier = new Identifier('name'); $nameVariable = new Variable($nameIdentifier); $argumentsIdentifier = new Identifier('arguments'); $validatorMethodNameVariable = new Variable(new Identifier('validatorMethodName')); $thisVariable = new Variable(new Identifier('this')); $reflectorMember = new Member($thisVariable, new Constant(new Identifier('reflector'))); $method = new ConcreteMethod(new Identifier('__call'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter($nameIdentifier)); $method->addParameter(new Parameter($argumentsIdentifier, new ArrayTypeHint())); $ltrimCall = new Call(QualifiedIdentifier::fromString('\\ltrim')); $ltrimCall->add($nameVariable); $ltrimCall->add(new Literal('_')); $ucfirstCall = new Call(QualifiedIdentifier::fromString('\\ucfirst')); $ucfirstCall->add($ltrimCall); $validatorMethodNameSprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $validatorMethodNameSprintfCall->add(new Literal('validate%s')); $validatorMethodNameSprintfCall->add($ucfirstCall); $method->statementBlock()->add(new ExpressionStatement(new Assign($validatorMethodNameVariable, $validatorMethodNameSprintfCall))); $reflectorHasMethodCall = new Call(new Member($reflectorMember, new Constant(new Identifier('hasMethod')))); $reflectorHasMethodCall->add($validatorMethodNameVariable); $undefinedMethodIf = new IfStatement(new LogicalNot($reflectorHasMethodCall)); $exceptionMessageSprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $exceptionMessageSprintfCall->add(new Literal('Call to undefined method %s::%s().')); $exceptionMessageSprintfCall->add(new Constant(new Identifier('__CLASS__'))); $exceptionMessageSprintfCall->add($nameVariable); $newBadMethodCallExceptionCall = new Call(QualifiedIdentifier::fromString('\\BadMethodCallException')); $newBadMethodCallExceptionCall->add($exceptionMessageSprintfCall); $undefinedMethodIf->trueBranch()->add(new ThrowStatement(new NewOperator($newBadMethodCallExceptionCall))); $method->statementBlock()->add($undefinedMethodIf); $getMethodCall = new Call(new Member($reflectorMember, new Constant(new Identifier('getMethod')))); $getMethodCall->add($validatorMethodNameVariable); $invokeArgsCall = new Call(new Member($getMethodCall, new Constant(new Identifier('invokeArgs')))); $invokeArgsCall->add($thisVariable); $invokeArgsCall->add(new Variable($argumentsIdentifier)); $method->statementBlock()->add(new ReturnStatement($invokeArgsCall)); return $method; }
/** * @param RuntimeConfiguration $configuration * * @return ConcreteMethod */ protected function generateDefineValidatorMethod(RuntimeConfiguration $configuration) { $this->typeCheck->generateDefineValidatorMethod(func_get_args()); $classNameIdentifier = new Identifier('className'); $classNameVariable = new Variable($classNameIdentifier); $classGeneratorIdentifier = new Identifier('classGenerator'); $classGeneratorVariable = new Variable($classGeneratorIdentifier); $classGeneratorClassIdentifier = QualifiedIdentifier::fromString('\\Eloquent\\Typhoon\\Generator\\ValidatorClassGenerator'); $method = new ConcreteMethod(new Identifier('defineValidator'), AccessModifier::PROTECTED_(), true); $method->addParameter(new Parameter($classNameIdentifier)); $classGeneratorParameter = new Parameter($classGeneratorIdentifier, new ObjectTypeHint($classGeneratorClassIdentifier)); $classGeneratorParameter->setDefaultValue(new Literal(null)); $method->addParameter($classGeneratorParameter); $nullClassGeneratorIf = new IfStatement(new StrictEquals(new Literal(null), $classGeneratorVariable)); $nullClassGeneratorIf->trueBranch()->add(new ExpressionStatement(new Assign($classGeneratorVariable, new NewOperator($classGeneratorClassIdentifier)))); $method->statementBlock()->add($nullClassGeneratorIf); $evalCall = new Call(QualifiedIdentifier::fromString('eval')); $generateFromClassCall = new Call(new Member($classGeneratorVariable, new Constant(new Identifier('generateFromClass')))); $generateFromClassCall->add(new Call(new StaticMember(new Constant(new Identifier('static')), new Constant(new Identifier('configuration'))))); $newReflectorCall = new Call(QualifiedIdentifier::fromString('\\ReflectionClass')); $newReflectorCall->add($classNameVariable); $newReflector = new NewOperator($newReflectorCall); $generateFromClassCall->add($newReflector); $evalCall->add(new Concat(new Literal('?>'), $generateFromClassCall)); $method->statementBlock()->add(new ExpressionStatement($evalCall)); return $method; }
/** * @param RuntimeConfiguration $configuration * * @return ConcreteMethod */ protected function generateConstructor(RuntimeConfiguration $configuration) { $this->typeCheck->generateConstructor(func_get_args()); $indexIdentifier = new Identifier('index'); $indexVariable = new Variable($indexIdentifier); $valueIdentifier = new Identifier('value'); $valueVariable = new Variable($valueIdentifier); $previousIdentifier = new Identifier('previous'); $previousVariable = new Variable($previousIdentifier); $typeInspectorIdentifier = new Identifier('typeInspector'); $typeInspectorVariable = new Variable($typeInspectorIdentifier); $thisVariable = new Variable(new Identifier('this')); $thisIndexMember = new Member($thisVariable, new Constant($indexIdentifier)); $thisValueMember = new Member($thisVariable, new Constant($valueIdentifier)); $thisTypeInspectorMember = new Member($thisVariable, new Constant($typeInspectorIdentifier)); $thisUnexpectedTypeMember = new Member($thisVariable, new Constant(new Identifier('unexpectedType'))); $typeInspectorClassName = QualifiedIdentifier::fromString($configuration->validatorNamespace()->joinAtoms('TypeInspector')->string()); $method = new ConcreteMethod(new Identifier('__construct'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter($indexIdentifier)); $method->addParameter(new Parameter($valueIdentifier)); $previousParameter = new Parameter($previousIdentifier, new ObjectTypeHint(QualifiedIdentifier::fromString('\\Exception'))); $previousParameter->setDefaultValue(new Literal(null)); $method->addParameter($previousParameter); $typeInspectorParameter = new Parameter($typeInspectorIdentifier, new ObjectTypeHint($typeInspectorClassName)); $typeInspectorParameter->setDefaultValue(new Literal(null)); $method->addParameter($typeInspectorParameter); $nullTypeInspectorIf = new IfStatement(new StrictEquals(new Literal(null), $typeInspectorVariable)); $nullTypeInspectorIf->trueBranch()->add(new ExpressionStatement(new Assign($typeInspectorVariable, new NewOperator(new Call($typeInspectorClassName))))); $method->statementBlock()->add($nullTypeInspectorIf); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisIndexMember, $indexVariable))); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisValueMember, $valueVariable))); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisTypeInspectorMember, $typeInspectorVariable))); $typeInspectorTypeCall = new Call(new Member($typeInspectorVariable, new Constant(new Identifier('type')))); $typeInspectorTypeCall->add($thisValueMember); $method->statementBlock()->add(new ExpressionStatement(new Assign($thisUnexpectedTypeMember, $typeInspectorTypeCall))); $sprintfCall = new Call(QualifiedIdentifier::fromString('\\sprintf')); $sprintfCall->add(new Literal("Unexpected argument of type '%s' at index %d.")); $sprintfCall->add($thisUnexpectedTypeMember); $sprintfCall->add($indexVariable); $parentConstructCall = new Call(new StaticMember(new Constant(new Identifier('parent')), new Constant(new Identifier('__construct')))); $parentConstructCall->add($sprintfCall); $parentConstructCall->add(new Variable($previousIdentifier)); $method->statementBlock()->add(new ExpressionStatement($parentConstructCall)); return $method; }
/** * @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); }
/** * @return ConcreteMethod */ protected function generateConstructor() { $this->typeCheck->generateConstructor(func_get_args()); $messageIdentifier = new Identifier('message'); $previousIdentifier = new Identifier('previous'); $method = new ConcreteMethod(new Identifier('__construct'), AccessModifier::PUBLIC_()); $method->addParameter(new Parameter($messageIdentifier)); $previousParameter = new Parameter($previousIdentifier, new ObjectTypeHint(QualifiedIdentifier::fromString('\\Exception'))); $previousParameter->setDefaultValue(new Literal(null)); $method->addParameter($previousParameter); $parentConstructCall = new Call(new StaticMember(new Constant(new Identifier('parent')), new Constant(new Identifier('__construct')))); $parentConstructCall->add(new Variable($messageIdentifier)); $parentConstructCall->add(new Literal(0)); $parentConstructCall->add(new Variable($previousIdentifier)); $method->statementBlock()->add(new ExpressionStatement($parentConstructCall)); return $method; }