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.

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

I made a small mistake

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

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!

On Dec 14, 7:03 am, Saladin M. [email protected] wrote:

 ...

[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 M. [email protected] wrote:

 ...

[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