class SExpr
  def initialize(str)
    @original = str
    @data = parse_sexpr(str)
  end
  attr_reader :data, :original

  def to_sexpr
    @data.to_sexpr
  end

  private

  def parse_sexpr(str)
    state = :token_start
    tokens = []
    word = 
    str.each_char do |char|
      case state

      when :token_start
        case char
        when  
          tokens << :lbr
        when  
          tokens << :rbr
        when /\s/
          
        when  ''
          tokens << word
          state = :token_start
        else
          word << char
        end

      when :read_string_or_number
        case char
        when /\s/
          tokens << symbol_or_number(word)
          state = :token_start
        when ')'
          tokens << symbol_or_number(word)
          tokens << :rbr
          state = :token_start
        else
          word << char
        end
      end
    end

    sexpr_tokens_to_array(tokens)
  end

  def symbol_or_number(word)
    Integer(word)
  rescue ArgumentError
    begin 
      Float(word)
    rescue ArgumentError
      word.to_sym
    end
  end

  def sexpr_tokens_to_array(tokens, idx = 0)
    result = []
    while idx < tokens.length
      case tokens[idx]
      when :lbr
        tmp, idx = sexpr_tokens_to_array(tokens, idx + 1)
        result << tmp
      when :rbr
        return [result, idx]
      else 
        result << tokens[idx]
      end
      idx += 1
    end
    result[0]
  end
end

class Object
  def to_sexpr
    self
  end
end

class String
  def to_sexpr
    self.match(/[\s()]/)? self.inspect: self
  end
end

class Symbol
  alias :to_sexpr :to_s
end

class Array
  def to_sexpr
     % inject([]) {|a, elem| a << elem.to_sexpr}.join()
  end
end


sexpr = SExpr.new <<END
((data  123 4.5)
 (data (!@
END

puts 
puts 
puts