String splitting problem

S

Saladin Mundi

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.
 
J

Joe

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
 
J

Joe

I made a small mistake

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

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

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.
 
P

Phrogz

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.

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
 
S

Saladin Mundi

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 :)

thanks again!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top