require 'socket' require 'ruby_parser' require 'sexp_processor' module Bitshift class Parser def initialize(source) @source = source end def parse parser = RubyParser.new tree = parser.parse(@source) return '{}' if tree.nil? processor = CachedWalker.new tree processor.process(tree) return processor.to_s end end class CachedWalker < SexpProcessor attr_accessor :symbols def initialize(tree) super() module_hash = Hash.new { |hash, key| hash[key] = { assignments: [], uses: [] } } class_hash = module_hash.clone function_hash = module_hash.clone var_hash = module_hash.clone @require_empty = false @symbols = { namespaces: module_hash, classes: class_hash, functions: function_hash, vars: var_hash } end def block_position(exp) end_ln = (start_ln = exp.line) cur_exp = exp while cur_exp.is_a? Sexp end_ln = cur_exp.line cur_exp = cur_exp.last break if cur_exp == nil end pos = [start_ln, -1, end_ln, -1] return pos end def statement_position(exp) pos = Hash.new end_ln = start_ln = exp.line pos = [start_ln, -1, end_ln, -1] return pos end def process_module(exp) pos = block_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:namespaces][name][:assignments] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_class(exp) pos = block_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:classes][name][:assignments] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_defn(exp) pos = block_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:functions][name][:assignments] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_call(exp) pos = statement_position(exp) exp.shift exp.shift while (name = exp.shift).is_a? Sexp end symbols[:functions][name][:uses] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_iasgn(exp) pos = statement_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:vars][name][:assignments] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_lasgn(exp) pos = statement_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:vars][name][:assignments] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_attrasgn(exp) pos = statement_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:vars][((name.to_s)[0..-2]).to_sym][:assignments] << pos exp.each_sexp {|s| process(s)} return exp.clear end def process_lvar(exp) pos = statement_position(exp) exp.shift while (name = exp.shift).is_a? Sexp end symbols[:vars][name][:uses] << pos exp.each_sexp {|s| process(s)} return exp.clear end def to_s new_symbols = Hash.new {|hash, key| hash[key] = Hash.new} symbols.each do |type, sym_list| sym_list.each do |name, sym| new_symbols[type.to_s][name.to_s] = { "assignments" => sym[:assignments], "uses" => sym[:uses]} end end str = new_symbols.to_s str = str.gsub(/=>/, ":") return str end end end