|
|
|
|
@ -265,10 +265,11 @@ trait TypeCheckGenerator |
|
|
|
|
protected function genUnionParamTypeErrorExpr(ArgInfo $argInfo, string $valueExpr, string $argNoExpr): string |
|
|
|
|
{ |
|
|
|
|
$fnName = $this->getTypeCheckCallableName(); |
|
|
|
|
$paramName = $this->unescapeVarName($argInfo->name); |
|
|
|
|
return 'php::concat({' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr($fnName . '(): Argument #', true) . '), ' |
|
|
|
|
. 'php::toString(' . $argNoExpr . '), ' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr(' ($' . $argInfo->name . ') must be of type ', true) . '), ' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr(' ($' . $paramName . ') must be of type ', true) . '), ' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr($argInfo->typeStr, true) . '), ' |
|
|
|
|
. 'php::Str(", "), ' |
|
|
|
|
. $valueExpr . '.typeStr(), ' |
|
|
|
|
@ -310,4 +311,118 @@ trait TypeCheckGenerator |
|
|
|
|
return $code; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected function genClosureParamCheck(ArgInfo $argInfo, int $argIndex): string |
|
|
|
|
{ |
|
|
|
|
if (empty($argInfo->typeCheck)) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($argInfo->variadic) { |
|
|
|
|
return $this->genClosureVariadicParamCheck($argInfo, $argIndex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$conditions = []; |
|
|
|
|
foreach ($argInfo->typeCheck as $entry) { |
|
|
|
|
$cond = $this->genSingleTypeCondition($argInfo->name, $entry); |
|
|
|
|
if ($cond !== '') { |
|
|
|
|
$conditions[] = $cond; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (empty($conditions)) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$orExpr = implode(' || ', $conditions); |
|
|
|
|
$msgExpr = $this->genClosureParamTypeErrorExpr($argInfo, $argInfo->name, (string) ($argIndex + 1)); |
|
|
|
|
|
|
|
|
|
$code = $this->getIndent() . 'if (UNEXPECTED(!(' . $orExpr . '))) {' . PHP_EOL; |
|
|
|
|
$this->indentLevel++; |
|
|
|
|
$code .= $this->getIndent() . 'return php::throwException(zend_ce_type_error, (' . $msgExpr . ').toCString());' . PHP_EOL; |
|
|
|
|
$this->indentLevel--; |
|
|
|
|
$code .= $this->getIndent() . '}' . PHP_EOL; |
|
|
|
|
|
|
|
|
|
return $code; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected function genClosureVariadicParamCheck(ArgInfo $argInfo, int $argIndex): string |
|
|
|
|
{ |
|
|
|
|
$valueVar = $this->genTmpVarName(); |
|
|
|
|
$iterVar = $this->genTmpVarName(); |
|
|
|
|
$argNoVar = $this->genTmpVarName(); |
|
|
|
|
|
|
|
|
|
$conditions = []; |
|
|
|
|
foreach ($argInfo->typeCheck as $entry) { |
|
|
|
|
$cond = $this->genSingleTypeCondition($valueVar, $entry); |
|
|
|
|
if ($cond !== '') { |
|
|
|
|
$conditions[] = $cond; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (empty($conditions)) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$orExpr = implode(' || ', $conditions); |
|
|
|
|
$msgExpr = $this->genClosureParamTypeErrorExpr($argInfo, $valueVar, $argNoVar); |
|
|
|
|
|
|
|
|
|
$code = $this->getIndent() . 'for (auto ' . $iterVar . ' = ' . $argInfo->name . '.begin(); ' . $iterVar . ' != ' . $argInfo->name . '.end(); ++' . $iterVar . ') {' . PHP_EOL; |
|
|
|
|
$this->indentLevel++; |
|
|
|
|
$code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = ' . $iterVar . '.value();' . PHP_EOL; |
|
|
|
|
$code .= $this->getIndent() . self::TYPE_INT . ' ' . $argNoVar . ' = ' . ($argIndex + 1) . ' + ' . $iterVar . '.index();' . PHP_EOL; |
|
|
|
|
$code .= $this->getIndent() . 'if (UNEXPECTED(!(' . $orExpr . '))) {' . PHP_EOL; |
|
|
|
|
$this->indentLevel++; |
|
|
|
|
$code .= $this->getIndent() . 'return php::throwException(zend_ce_type_error, (' . $msgExpr . ').toCString());' . PHP_EOL; |
|
|
|
|
$this->indentLevel--; |
|
|
|
|
$code .= $this->getIndent() . '}' . PHP_EOL; |
|
|
|
|
$this->indentLevel--; |
|
|
|
|
$code .= $this->getIndent() . '}' . PHP_EOL; |
|
|
|
|
|
|
|
|
|
return $code; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected function genClosureParamTypeErrorExpr(ArgInfo $argInfo, string $valueExpr, string $argNoExpr): string |
|
|
|
|
{ |
|
|
|
|
$paramName = $this->unescapeVarName($argInfo->name); |
|
|
|
|
return 'php::concat({' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr('{closure}(): Argument #', true) . '), ' |
|
|
|
|
. 'php::toString(' . $argNoExpr . '), ' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr(' ($' . $paramName . ') must be of type ', true) . '), ' |
|
|
|
|
. 'php::Str(' . $this->genCharPtr($argInfo->typeStr, true) . '), ' |
|
|
|
|
. 'php::Str(", "), ' |
|
|
|
|
. $valueExpr . '.typeStr(), ' |
|
|
|
|
. 'php::Str(" given")' |
|
|
|
|
. '})'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected function genClosureReturnCheck(string $varName): string |
|
|
|
|
{ |
|
|
|
|
$typeCheck = $this->context->closureReturnTypeCheck; |
|
|
|
|
if (empty($typeCheck)) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$conditions = []; |
|
|
|
|
foreach ($typeCheck as $entry) { |
|
|
|
|
$cond = $this->genSingleTypeCondition($varName, $entry); |
|
|
|
|
if ($cond !== '') { |
|
|
|
|
$conditions[] = $cond; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (empty($conditions)) { |
|
|
|
|
return ''; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$orExpr = implode(' || ', $conditions); |
|
|
|
|
$typeStr = $this->context->closureReturnTypeStr; |
|
|
|
|
$msgExpr = 'php::concat(php::concat(php::Str(' . $this->genCharPtr('{closure}', true) . ' "(): Return value must be of type " ' |
|
|
|
|
. $this->genCharPtr($typeStr, true) . ' ", "), ' . $varName . '.typeStr()), php::Str(" given"))'; |
|
|
|
|
|
|
|
|
|
$code = $this->getIndent() . 'if (UNEXPECTED(!(' . $orExpr . '))) {' . PHP_EOL; |
|
|
|
|
$this->indentLevel++; |
|
|
|
|
$code .= $this->getIndent() . 'return php::throwException(zend_ce_type_error, (' . $msgExpr . ').toCString());' . PHP_EOL; |
|
|
|
|
$this->indentLevel--; |
|
|
|
|
$code .= $this->getIndent() . '}' . PHP_EOL; |
|
|
|
|
|
|
|
|
|
return $code; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|