class SyntaxTree::Parser

def on_hshptn(constant, keywords, keyword_rest)

) -> HshPtn
(nil | VarField) keyword_rest
Array[[Label | StringContent, untyped]] keywords,
(nil | untyped) constant,
on_hshptn: (
:call-seq:
def on_hshptn(constant, keywords, keyword_rest)
  keywords =
    (keywords || []).map do |(label, value)|
      if label.is_a?(Label)
        [label, value]
      else
        tstring_beg_index =
          tokens.rindex do |token|
            token.is_a?(TStringBeg) &&
              token.location.start_char < label.location.start_char
          end
        tstring_beg = tokens.delete_at(tstring_beg_index)
        label_end_index =
          tokens.rindex do |token|
            token.is_a?(LabelEnd) &&
              token.location.start_char == label.location.end_char
          end
        label_end = tokens.delete_at(label_end_index)
        [
          DynaSymbol.new(
            parts: label.parts,
            quote: label_end.value[0],
            location: tstring_beg.location.to(label_end.location)
          ),
          value
        ]
      end
    end
  if keyword_rest
    # We're doing this to delete the token from the list so that it doesn't
    # confuse future patterns by thinking they have an extra ** on the end.
    consume_operator(:**)
  elsif (token = find_operator(:**))
    tokens.delete(token)
    # Create an artificial VarField if we find an extra ** on the end. This
    # means the formatting will be a little more consistent.
    keyword_rest = VarField.new(value: nil, location: token.location)
  end
  parts = [constant, *keywords.flatten(1), keyword_rest].compact
  # If there's no constant, there may be braces, so we're going to look for
  # those to get our bounds.
  unless constant
    lbrace = find_token(LBrace)
    rbrace = find_token(RBrace)
    if lbrace && rbrace
      parts = [lbrace, *parts, rbrace]
      tokens.delete(lbrace)
      tokens.delete(rbrace)
    end
  end
  HshPtn.new(
    constant: constant,
    keywords: keywords,
    keyword_rest: keyword_rest,
    location: parts[0].location.to(parts[-1].location)
  )
end