On Dec 14, 7:03 am, Saladin Mundi <saladin.mu... / gmx.de> wrote:
> hey guys
>
> I'm trying to split an string (which contains various method calls).
> The result of the splitting of the string should be an array (or
> something like that) which contains a sequence which an interpreter
> would have called the methods.
> Example
>
> class X
>    def test(input)
>      ...
>    end
> end
>
> x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")
>
> If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
> afterwards an arry like this:
>
>  [0] -> var1 = z.methody()
>  [1] -> var2 = z.methodx
>  [2] -> var3 = z.methodz(var2)
>  [3] -> z.methodx(var1,var3)
>
> so the call(s on different methods) given by an input string shall be
> extracted into the real execution sequence like an interpreter would
> excecute this string it.

On Dec 14, 7:03 am, Saladin Mundi <saladin.mu... / gmx.de> wrote:
> hey guys
>
> I'm trying to split an string (which contains various method calls).
> The result of the splitting of the string should be an array (or
> something like that) which contains a sequence which an interpreter
> would have called the methods.
> Example
>
> class X
>    def test(input)
>      ...
>    end
> end
>
> x.new.test("z.methodx(z.methody(),z.methodz(z.methodx))")
>
> If I pass "z.methodx(z.methody(),z.methodz(z.methodx))" there should be
> afterwards an arry like this:
>
>  [0] -> var1 = z.methody()
>  [1] -> var2 = z.methodx
>  [2] -> var3 = z.methodz(var2)
>  [3] -> z.methodx(var1,var3)
>
> so the call(s on different methods) given by an input string shall be
> extracted into the real execution sequence like an interpreter would
> excecute this string it.
>
> I hope you can help me with my problem.

Wow, that was harder than I expected. The big issue was parsing nested
commands; I couldn't use regexps, so I had to create a little stack-
based parser. Thanks for the fun challenge.

In summary:

puts
MethodMunger.variable_stack( "z.methodx(z.methody(),z.methodz(z.methodx))" )
#=> var0 = z.methodx()
#=> var1 = z.methody()
#=> var2 = z.methodz( var0 )
#=> z.methodx( var1, var2 )


And now, the code, all unit tested:

# Put MWI in the core! enum_for is retarded!
module Enumerable
  def map_with_index
    idx = -1
    map{ |v| yield v,idx+=1 }
  end
end

module MethodMunger
  require 'strscan'

  #  MethodMunger.parse_method( "z.foo( bar( x ), y )" )
  #  #=>  {
  #  #=>    :name=>"z.foo",
  #  #=>    :args=>[
  #  #=>      {
  #  #=>        :name=>"bar",
  #  #=>        :args=>[
  #  #=>          {:name=>"x"}
  #  #=>        ]
  #  #=>      },
  #  #=>      {:name=>"y"}
  #  #=>    ]
  #  #=>  }
  def self.parse_method( source )
    stack = [ ]
    current_method = nil
    mode = :prepare_method

    scanner = StringScanner.new( source )
    until scanner.eos?
      case mode
        when :prepare_method
          new_method = {}
          current_method = new_method
          mode = :find_content

        when :add_argument
          new_method = {}
          (current_method[:args] ||= []) << new_method
          stack << current_method
          current_method = new_method
          mode = :find_content

        when :find_content
          if chunk = scanner.scan( /[\w.]+/ )
            current_method[ :name ] = chunk

          elsif chunk = scanner.scan( /\(\s*/ )
            mode = :add_argument

          elsif chunk = scanner.scan( /\s*,\s*/ )
            current_method.delete(:args) if current_method[:args] ==
[{}]
            current_method = stack.pop
            mode = :add_argument

          elsif chunk = scanner.scan( /\s*\)/ )
            current_method.delete(:args) if current_method[:args] ==
[{}]
            current_method = stack.pop

          end
      end
    end

    current_method.delete(:args) if current_method[:args] ==
[{}]
    current_method
  end

  def self.variable_stack( source )
    method = parse_method( source )
    variable_stack_from_parse( method )
  end

  private
    def self.variable_stack_from_parse( method )
      if method[:args]
        lines = []
        params = method[:args].map{ |arg|
          var_lines = variable_stack_from_parse( arg )
          arg_close = var_lines.pop
          lines.concat( var_lines )
          arg_close
        }
        total_lines = lines.length
        params.each_with_index{ |var,i|
          lines << "var#{i+total_lines} = #{var}"
        }
        lines << "#{method[:name]}( #{
          params.map_with_index{ |v,i|
            "var#{i + total_lines}"
          }.join(', ')
        } )"
      else
        ["#{method[:name]}()"]
      end
    end
end

puts
MethodMunger.variable_stack( "z.methodx(z.methody(),z.methodz(z.methodx))" )
#=> var0 = z.methodx()
#=> var1 = z.methody()
#=> var2 = z.methodz( var0 )
#=> z.methodx( var1, var2 )

if __FILE__==$0
  require 'test/unit'
  class TestParser < Test::Unit::TestCase
    def testa_no_arguments
      result = MethodMunger.parse_method "z.go( )"
      assert_equal( {
        :name=>"z.go"
      }, result )

      result = MethodMunger.parse_method "z.go()"
      assert_equal( {
        :name=>"z.go"
      }, result )

      result = MethodMunger.parse_method "z.go"
      assert_equal( {
        :name=>"z.go"
      }, result )
    end
    def testb_no_nesting
      result = MethodMunger.parse_method "z.go( x )"
      assert_equal( {
        :name=>"z.go",
        :args=>[
          { :name=>"x" }
        ]
      }, result )

      result = MethodMunger.parse_method "z.go( x, y )"
      assert_equal( {
        :name=>"z.go",
        :args=>[
          { :name=>"x" },
          { :name=>"y" },
        ]
      }, result )

      result = MethodMunger.parse_method "z.go( w, x, y )"
      assert_equal( {
        :name=>"z.go",
        :args=>[
          { :name=>"w" },
          { :name=>"x" },
          { :name=>"y" },
        ]
      }, result )
    end
    def testc_nesting
      result = MethodMunger.parse_method "z.go( x( y ) )"
      assert_equal( {
        :name=>"z.go",
        :args=>[
          {
            :name=>"x",
            :args=>[
              { :name=>"y" }
            ]
          },
        ]
      }, result )

      result = MethodMunger.parse_method "z.go( x( y, w ) )"
      assert_equal( {
        :name=>"z.go",
        :args=>[
          {
            :name=>"x",
            :args=>[
              { :name=>"y" },
              { :name=>"w" },
            ]
          },
        ]
      }, result )

      result = MethodMunger.parse_method "z.go( foo( bar ),x( y,
w ) )"
      assert_equal( {
        :name=>"z.go",
        :args=>[
          {
            :name=>"foo",
            :args=>[
              { :name=>"bar" },
            ]
          },
          {
            :name=>"x",
            :args=>[
              { :name=>"y" },
              { :name=>"w" },
            ]
          },
        ]
      }, result )

    end
  end
  class TestMunger < Test::Unit::TestCase
    def test_a_no_args
      result = MethodMunger.variable_stack "z.go()"
      assert_equal( ["z.go()"], result )

      result = MethodMunger.variable_stack "z.go( )"
      assert_equal( ["z.go()"], result )

      result = MethodMunger.variable_stack "z.go"
      assert_equal( ["z.go()"], result )
    end
    def test_b_one_arg
      result = MethodMunger.variable_stack "z.go(y.foo)"
      assert_equal( ["var0 = y.foo()","z.go( var0 )"], result )

      result = MethodMunger.variable_stack "z.go( y.foo( ) )"
      assert_equal( ["var0 = y.foo()","z.go( var0 )"], result )
    end
    def test_c_multi_args
      result = MethodMunger.variable_stack "z.go(y.foo,x.bar)"
      assert_equal( [
        "var0 = y.foo()",
        "var1 = x.bar()",
        "z.go( var0, var1 )"
      ], result )

      result = MethodMunger.variable_stack "z.go( y.foo(), x.bar() )"
      assert_equal( [
        "var0 = y.foo()",
        "var1 = x.bar()",
        "z.go( var0, var1 )"
      ], result )
    end
    def test_d_nest_singles
      result = MethodMunger.variable_stack "z.go( y.foo( x.bar ) )"
      assert_equal( [
        "var0 = x.bar()",
        "var1 = y.foo( var0 )",
        "z.go( var1 )"
      ], result )

      result = MethodMunger.variable_stack
"z.go( y.foo( x.bar( w.jim ) ) )"
      assert_equal( [
        "var0 = w.jim()",
        "var1 = x.bar( var0 )",
        "var2 = y.foo( var1 )",
        "z.go( var2 )"
      ], result )
    end
    def test_e_nest_more
      result = MethodMunger.variable_stack "z.go( y.foo( x.bar,
w.jim ) )"
      assert_equal( [
        "var0 = x.bar()",
        "var1 = w.jim()",
        "var2 = y.foo( var0, var1 )",
        "z.go( var2 )"
      ], result )
    end
  end
end