=begin Pi
1. module Opname
演算子の記号表記と名前表記を相互に変換する。
メソッド名にも対応する。
1.1. 定数
: PATTERN_OP : String
  演算子にマッチするパターン
: PATTERN_METHOD : String
  メソッドにマッチするパターン
: RE_OP : Regexp
  演算子にマッチする正規表現
: RE_METHOD : Regexp
  メソッドにマッチする正規表現
  %c:'self' + op% 形式にも対応する。
: NAME2OP : Hash
  演算子の名前表記をキーとし記号表記を値とするハッシュ
: OP2NAME : Hash
  %c:== NAME2OP.invert%
1.1. 関数
: op2name(op) : String
  演算子の記号表記から名前表記を求める。
  %c:[]% は %c:/\[.*?\]/% として評価する。
: name2op(name) : String
  演算子の名前表記から記号表記を求める。
: method_len(s) : Fixnum
  文字列の先頭からメソッド名を取り出し、その長さを返す。
: method_str(s) : String
  文字列の先頭からメソッド名を取り出す。
1.1. 注意
1.1.1. %c:'self' + op% 形式
rbdoc 由来の形式であって、推奨されない。
  例えば
    %c:: self[n]%
    %c:: self===%
  これは
    %c:: [n]%
    %c:: ===%
  と書くべきである。
1.1. バグ
* %c:op2name%
  %c:'self'% から始まるメソッド名は %c:'self'% が捨てられてしまう。
=end

module Opname
  PATTERN_OP = '\[.*?\]=?|[<=>\+\-\*\/%&|~^@\?!/]*'
  PATTERN_METHOD = '[\w\d]+[?!=]?|' << "(self)?(#{PATTERN_OP})"
  
  RE_OP = Regexp.compile('^' << PATTERN_OP)
  RE_METHOD = Regexp.compile('^' << PATTERN_METHOD)
  
  NAME2OP = Hash[*%w[
	aset	[]=
	aref	[]
	cmp	<=>
	le	<=
	shl	<<
	lt	<
	ge	>=
	shr	>>
	gt	>
	eqq	===
	eq	==
	match	=~
	assign	=
	uplus	+@
	plus	+
	uminus	-@
	minus	-
	pow	**
	times	*
	div	/
	mod	%
	and	&
	or	|
	not	~
	xor	^
  ]]
  OP2NAME = NAME2OP.invert
  
  module_function
  
  def op2name(op)
    case op
    when /^self/
      op2name($')
    when /^[\w\d]+([?!=]?)/
      cap = $&
      if $1.empty?
        op
      else
        op.chop <<
        case $1
        when '?'; '_p'
        when '!'; '_bang'
        when '='; '_asgn'
        end
      end
    when /^\[.*?\](=?)/
      '_' << if $1 == '=' then 'aset' else 'aref' end
    else
      name = OP2NAME[op] || ''
      '_' << name
    end
  end
  
  def name2op(name)
    case name
    when /^_/
      NAME2OP[name[1..-1]]
    when /_(\w+)$/
      $` +
      case $1
      when 'p'; '?'
      when 'bang'; '!'
      when 'asgn'; '='
      else $1
      end
    else
      name
    end
  end
  
  def method_len(s)
    if s.nil?
      return 0
    end
    len = 0
    case s[len]
    when ?[
      len = s.index(']')+1
      len+= 1 if s[len] == ?=
    when ?<
      len+= 1
      case s[len]
      when ?=
        len+= 1
        case s[len]
        when ?>; len+= 1
        end
      when ?<; len+= 1
      end
    when ?>
      len+= 1
      case s[len]
      when ?=, ?>; len+= 1
      end
    when ?=
      len+= 1
      case s[len]
      when ?=
        len+= 1
        case s[len]
        when ?=; len+= 1
        end
      when ?~; len+= 1
      end
    when ?+
      len+= 1
      case s[len]
      when ?@; len+= 1
      end
    when ?*
      len+= 1
      case s[len]
      when ?*; len+= 1
      end
    when ?-
      len+= 1
      case s[len]
      when ?@; len+= 1
      end
    when ?/, ?%, ?&, ?|, ?~, ?^; len+= 1
    else
      case s
      when /^self/
        len = method_len($') + 4
      when /^[\w\d]+[?!=]?/
        len = $&.length
      end
    end
    len
  end
  
  def method_str(s)
    s[0...method_len(s)]
  end
  
end

if $0 == __FILE__
  while line = gets
    line.scan(/(\S+?)?#(\S+)?/){|c,m|
      str = Opname.method_str(m)
      name = Opname.op2name(str)
      op = Opname.name2op(name)
      p [str, name, op]
    }
  end
end
