String splitting problem

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.

···

--
Posted via http://www.ruby-forum.com/.

hey,

I didn't test this too well, but it works for your string. I doubt
it's the most clever way to do it, but it should get the job done.

stack = Array.new
input = "z.methodx(z.methody(),z.methodz(z.methodx))"

last = 0
count = 0

while last < input.length
        cur = input.index(/[\)\(,]/, last)
        if cur then
                b = input[cur,1]
                if (/[\(,]/.match(input[last-1,1]) &&
/[\),]/.match(b)) && cur-last > 1 then
                        count += 1
                        puts count.to_s + " " + input[last, cur-last]
                        stack[-1] += count.to_s
                end

                case b
                        when '('
                                stack.push(input[last, cur-last] + "(")
                        when ')'
                                count += 1
                                puts count.to_s + " " + stack.pop + ")"
                                stack[-1] += count.to_s
                        when ','
                                stack[-1] += ','
                end

                last = cur+1
        end
end

Joe

···

On Dec 14, 2007 9:03 AM, Saladin Mundi <saladin.mundi@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.
--
Posted via http://www.ruby-forum.com/\.

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

···

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.

I made a small mistake

change
stack[-1] += count.to_s
to
stack[-1] += count.to_s if stack[-1]

···

On Dec 14, 2007 7:44 PM, Joe <qbproger@gmail.com> wrote:

hey,

I didn't test this too well, but it works for your string. I doubt
it's the most clever way to do it, but it should get the job done.

stack = Array.new
input = "z.methodx(z.methody(),z.methodz(z.methodx))"

last = 0
count = 0

while last < input.length
        cur = input.index(/[\)\(,]/, last)
        if cur then
                b = input[cur,1]
                if (/[\(,]/.match(input[last-1,1]) &&
/[\),]/.match(b)) && cur-last > 1 then
                        count += 1
                        puts count.to_s + " " + input[last, cur-last]
                        stack[-1] += count.to_s
                end

                case b
                        when '('
                                stack.push(input[last, cur-last] + "(")
                        when ')'
                                count += 1
                                puts count.to_s + " " + stack.pop + ")"
                                stack[-1] += count.to_s
                        when ','
                                stack[-1] += ','
                end

                last = cur+1
        end
end

Joe

On Dec 14, 2007 9:03 AM, Saladin Mundi <saladin.mundi@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.
> --
> Posted via http://www.ruby-forum.com/\.
>
>

thank you for all of your great code. I'll have a close look on it and
check if its similar to what I had thought of :slight_smile:

thanks again!

···

--
Posted via http://www.ruby-forum.com/.