#!/usr/bin/ruby
=begin
  parser/ruby.rb - parser for ruby script

  Copyright (C) 2003-2005  Masao Mutoh
  Copyright (C) 2001,2002  Yasushi Shoji, Masao Mutoh
 
      Yasushi Shoji   <yashi@yashi.com>
      Masao Mutoh     <mutoh@highway.ne.jp>
 
  You may redistribute it and/or modify it under the same
  license terms as Ruby.

  $Id: ruby.rb,v 1.1.1.1 2005/08/13 02:38:09 mutoh Exp $
=end

require 'irb/ruby-lex'
require 'irb/ruby-token'
require 'stringio'

class RubyLexX < RubyLex
  def initialize
    super
    @prompt = nil
    @here_header = nil
    @lex_state = nil
  end

  def token
    tk = super
    if $DEBUG
      if tk.is_a? TkSTRING
        $stderr.puts("#{tk}: #{tk.value}")
      elsif tk.is_a? TkIDENTIFIER
        $stderr.puts("#{tk}: #{tk.name}")
      else
        $stderr.puts(tk)
      end
    end
    tk
  end

  def read_escape
    case ch = getc
    when "\n", "\r", "\f"
    when "\\", "n", "t", "r", "f", "v", "a", "e", "b" #"
      return "\\".concat(ch)
    when /[0-7]/
      ungetc ch
      3.times do
        case ch = getc
        when /[0-7]/
        when nil
          break
        else
          ungetc
          break
        end
      end
      
    when "x"
      2.times do
        case ch = getc
        when /[0-9a-fA-F]/
        when nil
          break
        else
          ungetc
          break
        end
      end
      
    when "M"
      if (ch = getc) != '-'
        ungetc
      else
        if (ch = getc) == "\\" #"
          read_escape
        end
      end
      
    when "C", "c", "^"
      if ch == "C" and (ch = getc) != "-"
        ungetc
      elsif (ch = getc) == "\\" #"
        read_escape
      end
    when '#'
      return ch
    else
      # other characters
    end
  end

  def identify_string(ltype, quoted = ltype)
    @ltype = ltype
    @quoted = quoted
    subtype = nil
    str = ''
    begin
      while ch = getc
        if @quoted == ch
	  break
        elsif @ltype != "'" && @ltype != "]" and ch == "#"
          subtype = true
        elsif ch == '\\' #'
          e = read_escape
          str.concat e unless e.nil?
        else
          str.concat ch
        end
      end
      if @ltype == "/"
	if peek(0) =~ /i|o|n|e|s/
	  getc
	end
      end
      if subtype
        tk = Token(DLtype2Token[ltype], str)
      else
        tk = Token(Ltype2Token[ltype], str)
      end
    ensure
      @ltype = nil
      @quoted = nil
      @lex_state = EXPR_END
    end
  end
end

######################################################################
# GetText::RubyParser

module GetText
  module RubyParser
    ID = ['gettext', '_', 'N_', 'sgettext', 's_']
    PLURAL_ID = ['ngettext', 'n_']

    module_function
    def parse(file, targets = [])
      lines = IO.readlines(file)
      parse_lines(file, lines, targets)
    end

    def parse_lines(file_name, lines, targets)
      file = StringIO.new(lines.join + "\n")
      rl = RubyLexX.new
      rl.set_input(file)
      rl.skip_space = true
      rl.readed_auto_clean_up = true

      target = nil
      msgid = nil
      line_no = nil
      while tk = rl.token
        case tk
        when RubyToken::TkIDENTIFIER, RubyToken::TkCONSTANT
          if ID.include?(tk.name)
            target = :normal
          elsif PLURAL_ID.include?(tk.name)
            target = :plural
          else
            target = nil
          end
          line_no = tk.line_no.to_s
        when RubyToken::TkSTRING
          if target
            if msgid
              msgid += tk.value
            else
              msgid = tk.value 
            end
          end
        when RubyToken::TkPLUS, RubyToken::TkNL
          #do nothing
        when RubyToken::TkCOMMA
          if msgid and target == :plural
            msgid += "\000"
            target = :normal
          end
        else
          if msgid
            key_existed = targets.assoc(msgid)
            if key_existed 
              targets[targets.index(key_existed)] = key_existed <<
                file_name + ":" + line_no
            else
              targets << [msgid.gsub(/\n/, '\n'), file_name + ":" + line_no]
            end
            msgid = nil
            target = nil
          end
        end
        targets
      end
      targets
    end

    def target?(file)
      true # always true, as default parser.
    end
    
  end 
end  

if __FILE__ == $0
  # ex) ruby c.rb foo.rb bar.rb
  ARGV.each do |file|
    p GetText::RubyParser.parse(file)
  end
end
