private static function dumpTree(NodeInterface $node, $verbose, $indent = 0)
    {
        list($attributes, $nodes) = self::extract($node);

        $dump = get_class($node);

        if ($attributes) {
            $dump .= ' (';

            $dump .= implode(', ', array_map(
                function ($key, $value) use ($verbose) {
                    return ($verbose ? sprintf('%s = ', $key) : '').self::stringify($value);
                },
                array_keys($attributes),
                array_values($attributes)
            ));

            $dump .= ')';
        }

        if ($nodes) {
            $dump .= ' {'.PHP_EOL;

            foreach ($nodes as $key => $node) {
                $dump .= str_repeat('  ', $indent + 1);

                if ($verbose && is_string($key)) {
                    $dump .= sprintf('%s = ', $key);
                }

                if (is_array($node)) {
                    $dump .= '['.PHP_EOL;

                    foreach ($node as $item) {
                        $dump .= str_repeat('  ', $indent + 2).self::dumpTree($item, $verbose, $indent + 2).PHP_EOL;
                    }

                    $dump .= str_repeat('  ', $indent + 1).']'.PHP_EOL;
                } else {
                    $dump .= self::dumpTree($node, $verbose, $indent + 1).PHP_EOL;
                }
            }

            $dump .= str_repeat('  ', $indent).'}';
        }

        return $dump;
    }