Meta_parse: my first metaprogram


#1

Hi guys,

After messing up with racc for a couple of hours I realized that most of
the
parse functions look pretty much the same, so I thought of stretching my
metaprogramming muscles and I wrote my first meta_parse function.

require ‘strscan’

def meta_parse(*ary)
case_str = <<ENDSTRING
def parse(str)
@q = []
scanner = StringScanner.new str
until scanner.empty?
case
ENDSTRING

ary.each do |type, exp, meth|
if meth
case_str << " when m = scanner.scan(#{exp}) ; @q <<
[:#{type},
m.#{meth}]\n"
else
case_str << " when m = scanner.scan(#{exp}) ; @q <<
[:#{type},
m]\n"
end
end

case_str <<<<END_STRING
end
end
@q << [false,false]
do_parse
end
END_STRING
eval case_str
end

Here is a usage example:

meta_parse [:A, ‘/a/’], [:NUMBER, ‘/\d+/’, :to_i], [:WS, ‘/(\s|\t)+/’]
parse("a aaa 12132 ").each{|type,val| puts “#{type}: ‘#{val}’”}

I would like to hear your comments on it, but please be gentle :wink:

Cheers,
Ed

Encontrá a “Tu psicópata favorito” http://tuxmaniac.blogspot.com

Thou shalt study thy libraries and strive not to reinvent them without
cause,
that thy code may be short and readable and thy days pleasant and
productive.
– Seventh commandment for C programmers


#2

After messing up with racc for a couple of hours I realized
that most of the parse functions look pretty much the same,
so I thought of stretching my metaprogramming muscles and I
wrote my first meta_parse function.

I would like to hear your comments on it, but please be
gentle :wink:

I usually try to avoid those inline strings. I don’t like them.
As long as you don’t pass a block in the call to the
dynamically defined method, you can use “define_method”
instead. I moved a bit of code and came up with the code below.

(Next time, please provide runnable code… )

gegroet,
Erik V. - http://www.erikveen.dds.nl/


require ‘strscan’

def meta_parse(*ary)
self.class.module_eval do
define_method :parse do |str|
@q = []
scanner = StringScanner.new(str)
until scanner.empty?
ary.each do |type, exp, meth|
if m = scanner.scan(exp)
@q << [type, (meth ? m.send(meth) : m)]
end
end
end
@q << [false,false]
do_parse
end
end
end

def do_parse
p $q
@q
end

meta_parse [:A, /a/], [:NUMBER, /\d+/, :to_i], [:WS, /(\s|\t)+/]
parse("a aaa 12132 ").each{|type,val| puts “#{type}: ‘#{val}’”}


#3

“Erik V.” removed_email_address@domain.invalid writes:

dynamically defined method, you can use “define_method”
instead. I moved a bit of code and came up with the code below.

I’d just return a block for this case, though.

def meta_parse(*ary)
self.class.module_eval do
define_method :parse do |str|


#4

I usually try to avoid those inline strings. I don’t like them.
As long as you don’t pass a block in the call to the
dynamically defined method, you can use “define_method”
instead.

Seconded, metaprogramming code like that will get a major performance
hit if
you whack YARV at it. Unless there’s a shaman embedding voodoo chants
into
YARV code for optimization of variable evals.

(Sidenote: it seems #eval is slightly faster than #define_method in
trivial
benchmarks.)

David V.