class Opal::Nodes::Match3Node

with a right-hand side value and assigning the match result to a left-hand side variable.
Handles match_with_lvasgn nodes which represent matching a regular expression

def compile

def compile
  sexp = s(:send, lhs, :=~, rhs)
  # Handle named matches like: /(?<abc>b)/ =~ 'b'
  if lhs.type == :regexp && lhs.children.first.type == :str
    names = extract_names(lhs)
    unless names.empty?
      names_def = generate_names_definition
      names_assignments = generate_names_assignments(names)
      sexp = if stmt?
               handle_statement(sexp, names_def, names_assignments)
             else
               handle_non_statement(sexp, names_def, names_assignments)
             end
    end
  end
  push process(sexp, @level)
end

def extract_names(regexp_node)

def extract_names(regexp_node)
  re = regexp_node.children.first.children.first
  re.scan(/\(\?<([^>]*)>/).flatten.map(&:to_sym)
end

def generate_names_assignments(names)

def generate_names_assignments(names)
  # Generate names assignments: abc = $m3names[:abc]
  names.map do |name|
    s(:lvasgn, name,
      s(:send,
        s(:lvar, :$m3names),
        :[],
        s(:sym, name)
      )
    )
  end
end

def generate_names_definition

def generate_names_definition
  # Generate names definition: $m3names = $~ ? $~.named_captures : {}
  s(:lvasgn, :$m3names,
    s(:if,
      s(:gvar, :$~),
      s(:send, s(:gvar, :$~), :named_captures),
      s(:hash)
    )
  )
end

def handle_non_statement(sexp, names_def, names_assignments)

def handle_non_statement(sexp, names_def, names_assignments)
  # We actually do care about a return value, so we must
  # keep it saved.
  #
  # $m3tmp = (/(?<abc>b)/ =~ 'f')
  # $m3names = $~ ? $~.named_captures : {}
  # abc = $m3names[:abc]
  # $m3tmp
  s(:begin,
    s(:lvasgn, :$m3tmp, sexp),
    names_def,
    *names_assignments,
    s(:lvar, :$m3tmp)
  )
end

def handle_statement(sexp, names_def, names_assignments)

def handle_statement(sexp, names_def, names_assignments)
  # We don't care about a return value of this one, so we
  # ignore it and just assign the local variables.
  #
  # (/(?<abc>b)/ =~ 'f')
  # $m3names = $~ ? $~.named_captures : {}
  # abc = $m3names[:abc]
  s(:begin, sexp, names_def, *names_assignments)
end