class SyntaxTree::FlowControlFormatter

Formats either a Break, Next, or Return node.

def format(q)

def format(q)
  # If there are no arguments associated with this flow control, then we can
  # safely just print the keyword and return.
  if node.arguments.nil?
    q.text(keyword)
    return
  end
  q.group do
    q.text(keyword)
    parts = node.arguments.parts
    length = parts.length
    if length == 0
      # Here there are no arguments at all, so we're not going to print
      # anything. This would be like if we had:
      #
      #     break
      #
    elsif length >= 2
      # If there are multiple arguments, format them all. If the line is
      # going to break into multiple, then use brackets to start and end the
      # expression.
      format_arguments(q, " [", "]")
    else
      # If we get here, then we're formatting a single argument to the flow
      # control keyword.
      part = parts.first
      case part
      when Paren
        statements = part.contents.body
        if statements.length == 1
          statement = statements.first
          if statement.is_a?(ArrayLiteral)
            contents = statement.contents
            if contents && contents.parts.length >= 2
              # Here we have a single argument that is a set of parentheses
              # wrapping an array literal that has at least 2 elements.
              # We're going to print the contents of the array directly.
              # This would be like if we had:
              #
              #     break([1, 2, 3])
              #
              # which we will print as:
              #
              #     break 1, 2, 3
              #
              q.text(" ")
              format_array_contents(q, statement)
            else
              # Here we have a single argument that is a set of parentheses
              # wrapping an array literal that has 0 or 1 elements. We're
              # going to skip the parentheses but print the array itself.
              # This would be like if we had:
              #
              #     break([1])
              #
              # which we will print as:
              #
              #     break [1]
              #
              q.text(" ")
              q.format(statement)
            end
          elsif skip_parens?(statement)
            # Here we have a single argument that is a set of parentheses
            # that themselves contain a single statement. That statement is
            # a simple value that we can skip the parentheses for. This
            # would be like if we had:
            #
            #     break(1)
            #
            # which we will print as:
            #
            #     break 1
            #
            q.text(" ")
            q.format(statement)
          else
            # Here we have a single argument that is a set of parentheses.
            # We're going to print the parentheses themselves as if they
            # were the set of arguments. This would be like if we had:
            #
            #     break(foo.bar)
            #
            q.format(part)
          end
        else
          q.format(part)
        end
      when ArrayLiteral
        contents = part.contents
        if contents && contents.parts.length >= 2
          # Here there is a single argument that is an array literal with at
          # least two elements. We skip directly into the array literal's
          # elements in order to print the contents. This would be like if
          # we had:
          #
          #     break [1, 2, 3]
          #
          # which we will print as:
          #
          #     break 1, 2, 3
          #
          q.text(" ")
          format_array_contents(q, part)
        else
          # Here there is a single argument that is an array literal with 0
          # or 1 elements. In this case we're going to print the array as it
          # is because skipping the brackets would change the remaining.
          # This would be like if we had:
          #
          #     break []
          #     break [1]
          #
          q.text(" ")
          q.format(part)
        end
      else
        # Here there is a single argument that hasn't matched one of our
        # previous cases. We're going to print the argument as it is. This
        # would be like if we had:
        #
        #     break foo
        #
        format_arguments(q, "(", ")")
      end
    end
  end
end

def format_arguments(q, opening, closing)

def format_arguments(q, opening, closing)
  q.if_break { q.text(opening) }
  q.indent do
    q.breakable_space
    q.format(node.arguments)
  end
  q.breakable_empty
  q.if_break { q.text(closing) }
end

def format_array_contents(q, array)

def format_array_contents(q, array)
  q.if_break { q.text("[") }
  q.indent do
    q.breakable_empty
    q.format(array.contents)
  end
  q.breakable_empty
  q.if_break { q.text("]") }
end

def initialize(keyword, node)

def initialize(keyword, node)
  @keyword = keyword
  @node = node
end

def skip_parens?(node)

def skip_parens?(node)
  case node
  when FloatLiteral, Imaginary, Int, RationalLiteral
    true
  when VarRef
    case node.value
    when Const, CVar, GVar, IVar, Kw
      true
    else
      false
    end
  else
    false
  end
end