Skip to content

Commit

Permalink
Improve printer logic
Browse files Browse the repository at this point in the history
  • Loading branch information
SerafimArts committed Oct 24, 2023
1 parent 66724c0 commit f134379
Showing 1 changed file with 80 additions and 4 deletions.
84 changes: 80 additions & 4 deletions src/PrettyPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace TypeLang\Printer;

use TypeLang\Parser\Node\Node;
use TypeLang\Parser\Node\Stmt\Literal\LiteralNode;
use TypeLang\Parser\Node\Stmt\Type\Callable\ArgumentNodeInterface;
use TypeLang\Parser\Node\Stmt\Type\Callable\NamedArgumentNode;
Expand All @@ -25,10 +26,51 @@
use TypeLang\Parser\Node\Stmt\Statement;
use TypeLang\Parser\Node\Stmt\Type\Template\ParameterNode;
use TypeLang\Parser\Node\Stmt\Type\Template\ParametersListNode;
use TypeLang\Parser\Node\Stmt\Type\TypeStatement;
use TypeLang\Parser\Node\Stmt\Type\UnionTypeNode;
use TypeLang\Parser\Traverser;

class PrettyPrinter extends Printer
{
/**
* Wrap union type (joined by "|") by whitespaces.
*
* ```
* $wrapUnionType = true;
* // Type | Some | Any
*
* $wrapUnionType = false;
* // Type|Some|Any
* ```
*/
public bool $wrapUnionType = false;

/**
* Wrap intersection type (joined by "&") by whitespaces.
*
* ```
* $wrapIntersectionType = true;
* // Type & Some & Any
*
* $wrapIntersectionType = false;
* // Type&Some&Any
* ```
*/
public bool $wrapIntersectionType = true;

/**
* Add whitespace at the start of callable return type.
*
* ```
* $wrapCallableReturnType = true;
* // callable(): void
*
* $wrapCallableReturnType = false;
* // callable():void
* ```
*/
public bool $wrapCallableReturnType = true;

/**
* @return non-empty-string
*/
Expand Down Expand Up @@ -96,16 +138,46 @@ protected function printCallableTypeNode(CallableTypeNode $node): string
if ($node->type !== null) {
$returnType = $this->make($node->type);

if ($node->type instanceof LogicalTypeNode) {
if ($this->shouldWrapReturnType($node->type)) {
$returnType = \sprintf('(%s)', $returnType);
}

$result .= \sprintf(':%s', $returnType);
$returnTypeFormat = $this->wrapCallableReturnType ? ': %s' : ':%s';
$result .= \sprintf($returnTypeFormat, $returnType);
}

return $result;
}

protected function shouldWrapReturnType(TypeStatement $type): bool
{
if ($type instanceof LogicalTypeNode) {
return true;
}

$visitor = Traverser::through(
visitor: new Traverser\ClassNameMatcherVisitor(
class: LogicalTypeNode::class,
break: static function (Node $node): bool {
// Break on non-empty template parameters.
$isInTemplate = $node instanceof NamedTypeNode
&& $node->parameters !== null
&& $node->parameters->list !== [];

// Break on non-empty shape fields.
$isInShape = $node instanceof NamedTypeNode
&& $node->fields !== null
&& $node->fields->list !== [];

return $isInTemplate || $isInShape;
},
),
nodes: [$type],
);

return $visitor->isFound();
}

/**
* @return non-empty-string
*/
Expand All @@ -129,10 +201,12 @@ protected function printCallableArgumentNode(ArgumentNodeInterface $node): strin
*/
protected function printUnionTypeNode(UnionTypeNode $node): string
{
$delimiter = $this->wrapUnionType ? ' | ' : '|';

try {
/** @var non-empty-string */
return \vsprintf($this->nesting > 0 ? '(%s)' : '%s', [
\implode('|', [
\implode($delimiter, [
...$this->unwrapAndPrint($node),
]),
]);
Expand All @@ -146,10 +220,12 @@ protected function printUnionTypeNode(UnionTypeNode $node): string
*/
protected function printIntersectionTypeNode(IntersectionTypeNode $node): string
{
$delimiter = $this->wrapIntersectionType ? ' & ' : '&';

try {
/** @var non-empty-string */
return \vsprintf($this->nesting > 0 ? '(%s)' : '%s', [
\implode(' & ', [
\implode($delimiter, [
...$this->unwrapAndPrint($node),
]),
]);
Expand Down

0 comments on commit f134379

Please sign in to comment.