Permalink
Browse files

Merge pull request #876 from komax/komax_ast_tool_rewrite

bin/ast Add of IR Debugging Features
  • Loading branch information...
2 parents 31ffca9 + d8f367d commit 0eb216a0f8a24004e7a75fb2883a8d7df575c124 @enebo enebo committed Jul 11, 2013
Showing with 129 additions and 49 deletions.
  1. +129 −49 bin/ast
View
178 bin/ast
@@ -1,16 +1,28 @@
#!/usr/bin/env jruby
require 'optparse'
+require 'jruby'
opts = {}
options = {
:print_source => false,
:print_sexp => false,
:print_ast => true,
:print_ir => false,
+ :print_pass => nil,
+ :pretty_ir => false,
:dot_format => false
}
+def get_ir_passes
+ ir_manager = org.jruby.ir.IRManager
+ ir_manager.DEFAULT_COMPILER_PASSES.split(',').map do |pass|
+ pass.to_sym
+ end
+end
+
+ir_passes = get_ir_passes
+
OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options]"
@@ -26,6 +38,14 @@ OptionParser.new do |opts|
opts.on('-i', '--ir', 'Dump all IR passes without executing') do |h|
options[:print_ir] = true
end
+
+ opts.on('-p', "--pass #{ir_passes}", ir_passes, 'Dump IR after running a pass') do |pass|
+ options[:print_pass] = pass
+ end
+
+ opts.on('-f', '--formatted-ir', 'Pretty printer for IR (without CFG)') do |f|
+ options[:pretty_ir] = f
+ end
opts.on('-s', '--sexp', 'Display the S-Expression for the AST') do |t|
options[:print_sexp] = true
@@ -56,7 +76,9 @@ elsif ! options.has_key?(:expression)
abort "No script specified (see --help)"
end
-require 'jruby'
+if options[:print_ir] && options[:print_pass]
+ abort "-p and -i is not valid. Use only one of them (see --help)"
+end
$indent_string = " "
@@ -85,77 +107,92 @@ def indent(string)
string.gsub(/,\s*$/, '').squeeze("\n")
end
-def dot_label(node)
- extra = case node
- when org.jruby.ast.StrNode then
- ": '#{node.value}'"
- when org.jruby.ast.FixnumNode then
- ": #{node.value}"
- when org.jruby.ast.FloatNode then
- ": #{node.value}"
- when org.jruby.ast.types.INameNode then
- ": #{node.name}"
- else
- ""
- end
-
- "#{short_name(node)}#{extra}"
-end
-
-def short_name(node)
- node.class.name.split("::")[-1].gsub("Node", "")
-end
-
-def dot_node_def(node)
- %Q{#{node.hash} [label="#{dot_label(node)}"];\n}
+if options[:print_source]
+ puts "Source:"
+ puts options[:expression]
+ puts
end
-def dot(defs, parent)
- defs[parent.hash] = dot_node_def(parent)
+module DotGraph
+ def self.dot_label(node)
+ extra = case node
+ when org.jruby.ast.StrNode then
+ ": '#{node.value}'"
+ when org.jruby.ast.FixnumNode then
+ ": #{node.value}"
+ when org.jruby.ast.FloatNode then
+ ": #{node.value}"
+ when org.jruby.ast.types.INameNode then
+ ": #{node.name}"
+ else
+ ""
+ end
- "".tap do |str|
- parent.child_nodes.each do |child|
- str << "#{parent.hash} -> #{child.hash};\n"
- str << dot(defs, child)
- end
+ "#{short_name(node)}#{extra}"
end
-end
-def print_passes_on(scope, passes)
- if !scope.kind_of? org.jruby.ir.IRClosure
- passes.each { |pass| pass.run(scope) }
+ def self.short_name(node)
+ node.class.name.split("::")[-1].gsub("Node", "")
end
- scope.lexical_scopes.each do |child_scope|
- print_passes_on(child_scope, passes)
+ def self.dot_node_def(node)
+ %Q{#{node.hash} [label="#{dot_label(node)}"];\n}
end
-end
-root = JRuby.parse(options[:expression])
+ def self.dot(defs, parent)
+ defs[parent.hash] = dot_node_def(parent)
-if options[:print_source]
- puts "Source:"
- puts options[:expression]
- puts
-end
+ "".tap do |str|
+ parent.child_nodes.each do |child|
+ str << "#{parent.hash} -> #{child.hash};\n"
+ str << dot(defs, child)
+ end
+ end
+ end
-if options[:print_ast]
- if options[:dot_format]
+ def self.print_graph(root_node)
defs = {}
- graph_section = dot(defs, root)
+ graph_section = DotGraph.dot(defs, root_node)
puts "digraph AST {"
puts defs.values.join('')
puts graph_section
puts "}"
+ end
+end
+
+root = JRuby.parse(options[:expression])
+
+if options[:print_ast]
+ if options[:dot_format]
+ DotGraph.print_graph(root)
else
print "AST:"
puts indent(root.to_string)
puts
end
end
-if options[:print_ir]
- require 'jruby'
+def print_passes_on(scope, passes)
+ if !scope.kind_of? org.jruby.ir.IRClosure
+ passes.each { |pass| pass.run(scope) }
+ end
+
+ scope.lexical_scopes.each do |child_scope|
+ print_passes_on(child_scope, passes)
+ end
+end
+
+def print_pass_on(scope, pass)
+ if !scope.kind_of? org.jruby.ir.IRClosure
+ pass.run(scope)
+ end
+
+ scope.lexical_scopes.each do |child_scope|
+ print_pass_on(child_scope, pass)
+ end
+end
+
+def ir_setup(root)
runtime = JRuby::runtime
manager = runtime.ir_manager
@@ -167,6 +204,49 @@ if options[:print_ir]
scope = builder.new(manager).build_root(root)
passes = manager.get_compiler_passes(scope)
+ [scope, passes]
+end
+
+module IRPrettyPrinter
+ def self.pretty_ir(scope, indent="")
+ i = 0
+ pretty_str = scope.instrs.map do |instr|
+ f_str = "%s%3i\s\s%s" % [indent, i, instr]
+ i += 1
+ f_str
+ end
+ pretty_str = [indent + scope.to_s] + pretty_str
+ scope.lexical_scopes.each do |lex_scope|
+ pretty_str += pretty_ir(lex_scope, indent + "\s" * 4)
+ end
+ pretty_str
+ end
+
+ def self.print_ir(scope)
+ instrs = pretty_ir(scope)
+ instrs.each do |instr|
+ puts instr
+ end
+ end
+end
+
+if options[:pretty_ir]
+ scope, passes = ir_setup(root)
+ puts "IR:"
+ IRPrettyPrinter.print_ir(scope)
+end
+
+if options[:print_pass]
+ scope, passes = ir_setup(root)
+ pass_name = options[:print_pass]
+ pass = passes.find do |p|
+ p.java_class.to_s.include?(pass_name.to_s)
+ end
+ print_pass_on(scope, pass)
+end
+
+if options[:print_ir]
+ scope, passes = ir_setup(root)
print_passes_on(scope, passes)
end

0 comments on commit 0eb216a

Please sign in to comment.