Showing posts with label parsetree. Show all posts
Showing posts with label parsetree. Show all posts

Tuesday, April 04, 2006

More ParseTree Goodness

Sean and I decided to work on finding noops in conditionals for checkr. It turns out ParseTree made this a lot easier than we thought it would. Here's the abbreviated code:

class CheckR
  def clean_conditional?(klass)
    ParseTest.new.process(ParseTree.new.parse_tree(klass))
    false
  end
end

class ParseTest < SexpProcessor
  def assignment_in_conditional?(exp)
    @saw_lasgn = false
    test_result = process(exp.shift)
    raise CheckRAssignmentInConditional if @saw_lasgn
    test_result
  end

  # new method
  def noop_in_conditional?(exp)
    raise CheckRNoop unless exp
    exp
  end

  def process_if(exp)
    sexp_type = exp.shift
    else_exp = exp.pop
    then_exp = exp.pop

    s(sexp_type,
      assignment_in_conditional?(exp),
      process(noop_in_conditional?(then_exp)),
      process(else_exp))
  end
end
I'm sure there's some more refactoring in there, but I can't see it right now. Probably because I should already be in bed. I guess I'll write a new test for Sean in the morning.

Monday, April 03, 2006

Workin' in the coal mine

Sometimes, it doesn't look like there's anything as dark and forbidding as a coal mine, unless it's the inside of Ruby's C implementation. Recently, Sean Carley and I have been poking around in there while we work on checkr. Fortunately, zenspider and Eric Hodel have been a wonderful pair of guides for us. We started working with case statements, and we quickly ran into big problems. It turns out that parse_tree doesn't deal well with things like
case;
when foo == 1; puts "it was one"
when foo == 2; puts "it was two"
end
Digging into it has meant grabbing gdb, gprof, and looking at lots of parse_tree output. It's turned Sean into another fan of unit_diff. It's also given me a chance to figure out a lot more about C than I thought possible in such a short time. Who would have thought that this would have been part of troubleshooting a Ruby issue:

$ gdb ~/ruby-debug/bin/ruby
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, 
and you are welcome to change it and/or distribute copies of it 
under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" 
for details.
This GDB was configured as "i586-suse-linux"...Using host libthread_db/library/lib/tls/libthread_db.so.1".

(gdb) set args 'good_case.rb'

(gdb) b eval.c :2949
Breakpoint 1 at 0x8056ea2: file eval.c, line 2949.

(gdb) run
Starting program: /home/eylerpm/ruby-debug/bin/ruby 'good_case.rb'
1

Program exited normally.

(gdb) set args 'case.rb'
(gdb) run
Starting program: /home/eylerpm/ruby-debug/bin/ruby 'case.rb'

Breakpoint 1, rb_eval (self=1075685744, n=0x401cb024) at eval.c:2949
2949            while (node) {

(gdb) c
Continuing.

Breakpoint 1, rb_eval (self=1075685744, n=0x401cb024) at eval.c:2949
2949            while (node) {

(gdb) c
Continuing.

Breakpoint 1, rb_eval (self=1075685744, n=0x401cb024) at eval.c:2949
2949            while (node) {

(gdb) c
Continuing.
nothing matched

Program exited normally.

(gdb)
But it turned out to be just the key Sean and zenspider needed to track down the issue in parse_tree.