Lisper says to rubyist: gimmie your syntax tree

module Tracer
if $DEBUG
def trace(str)
STDERR.puts(str)
end
else
def trace(str)
end
end
end

class Application
include Tracer

def initialize
trace “initializing…”
# …
end

def run
trace “running…”
# …
end
end

I have unit tests to confirm things are working well, etc, however in
complex multi-threaded code there’s no substitute for the trace output
when problems arise. However even an empty method call is significant,

require ‘benchmark’
include Tracer
Benchmark.bm(16) { |b|
n = 10_000_000
b.report(“with trace”) { n.times { trace } }
b.report(“without trace”) { n.times { } }
}

                  user     system      total        real

with trace 3.090000 0.000000 3.090000 ( 3.094240)
without trace 1.010000 0.000000 1.010000 ( 1.015994)

So … why not …

Manipulate the AST

SyntaxTree.each_node { |node|
if node.ast_type == :method_call and node.method_name == “trace”
node.ast_type = :noop # or remove it, or whatever
end
}

No more trace statements!

Application.new.run

Now I could gsub out those trace statements manually (or for a cleaner
approach maybe ParseTree on RubyForge could be used). But that extra
step is cumbersome compared to the magic I desire. If SyntaxTree were
implemented, I think we would be close to having that bit of power
which lisp provides but ruby does not. Removing trace statements
would only be a trivial use of this Ultimate Power!

In my example SyntaxTree is using the code running in memory, but in
principle I could say

code = SyntaxTree.entry_point { Application.new.run }
code.each_node { |node|

… manipulate the code …

}

Execute some alternate-universe version of Application.new.run

code.call

Now THAT would be getting lispy.

[email protected] a écrit :

So … why not …

Manipulate the AST

SyntaxTree.each_node { |node|
if node.ast_type == :method_call and node.method_name == “trace”
node.ast_type = :noop # or remove it, or whatever
end
}

I am also looking for something similar in Ruby (programNodeEnumerator
of Smalltalk is so great !)

I’ve found these remarks :

-http://www.jroller.com/murphee/entry/ruby_let_s_get_an
-http://r2.ifs.hsr.ch/rubyrefactoring.pdf

Hope this helps.
JC

Tracer doesn’t inject “trace statements” into the AST. It calls
set_trace_func, so there’s a callback for every event (method call,
method return, new line, etc.).

The performance bottleneck of Tracer is that one of the arguments to the
trace function is a binding; creating this binding is an expensive
operation. AFAIK the only way to avoid this is to use the C API to call
rb_add_event_hook instead of using set_trace_func from Ruby. This is
what the ruby-debug gem does, e.g.:

rdebug --trace test.rb

As for your idea of dynamically modifying program structure at run-time,
I’ve toyed with this idea, but it’s not trivial. The biggest hurdle is
Ruby’s handling of local/dynamic variables. IMO the AST is too
low-level a program representation to be used for this. An intermediate
representation that abstracts away some of the details of the AST is I
think what’s needed.

Paul

On Tue, Apr 08, 2008 at 03:19:28AM +0900, Ryan D. wrote:

I’m going this direction with the UnifiedRuby rewriter in ParseTree
(which I will probably extract into its own release), but it is
currently still too low level. I’m working on pulling it up a bit and
making it the default output from ParseTree and ruby_parser. There
will still be “raw” versions you can call.

Nifty!

This will be very powerful when you are done. I wish I had the time…
:slight_smile:

Paul

On Apr 7, 2008, at 10:34 , Paul B. wrote:

An intermediate representation that abstracts away some of the
details of the AST is I think what’s needed.

Yup yup.

I’m going this direction with the UnifiedRuby rewriter in ParseTree
(which I will probably extract into its own release), but it is
currently still too low level. I’m working on pulling it up a bit and
making it the default output from ParseTree and ruby_parser. There
will still be “raw” versions you can call.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs