A semantic search engine for source code https://bitshift.benkurtovic.com/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

138 lines
3.4 KiB

  1. require 'ripper'
  2. def parse
  3. source = STDIN.read
  4. walker = TreeWalker.new(source)
  5. walker.parse
  6. puts walker.to_s
  7. end
  8. class TreeWalker < Ripper::SexpBuilder
  9. attr_accessor :symbols
  10. def initialize(source)
  11. ns_hash = Hash.new {
  12. |hash, key|
  13. hash[key] = {
  14. :assignments => [], :uses => []
  15. }
  16. }
  17. class_hash = ns_hash.clone
  18. function_hash = ns_hash.clone
  19. var_hash = ns_hash.clone
  20. @symbols = {
  21. :namespaces => ns_hash,
  22. :classes => class_hash,
  23. :functions => function_hash,
  24. :vars => var_hash
  25. }
  26. super(source)
  27. end
  28. def block_position(node)
  29. last_node = node[0]
  30. while last_node.is_a? Array
  31. sp = last_node
  32. while not (last_el = last_node[last_node.count - 1]) or
  33. (last_el.is_a? Array and last_el[last_el.count - 1].nil?)
  34. last_node = last_node[0..last_node.count - 2]
  35. end
  36. last_node = last_el
  37. end
  38. last_node = node[0]
  39. while last_node.is_a? Array
  40. ep = last_node
  41. while not (last_el = last_node[last_node.count - 1]) or
  42. (last_el.is_a? Array and last_el[last_el.count - 1].nil?)
  43. last_node = last_node[0..last_node.count - 2]
  44. end
  45. last_node = last_el
  46. end
  47. if sp == ep
  48. return sp + [sp[0], -1]
  49. end
  50. return sp + ep
  51. end
  52. def on_module(*node)
  53. pos = block_position(node)
  54. name = node[0][1][1]
  55. symbols[:namespaces][name][:assignments] << pos
  56. return node
  57. end
  58. def on_class(*node)
  59. pos = block_position(node)
  60. name = node[0][1][1]
  61. symbols[:classes][name][:assignments] << pos
  62. return node
  63. end
  64. def on_def(*node)
  65. pos = block_position(node)
  66. name = node[0][1]
  67. symbols[:functions][name][:assignments] << pos
  68. return node
  69. end
  70. def on_call(*node)
  71. pos = block_position(node)
  72. name = node[node.count - 1][1]
  73. symbols[:functions][name][:uses] << pos
  74. return node
  75. end
  76. def on_vcall(*node)
  77. pos = block_position(node)
  78. name = node[0][1]
  79. symbols[:functions][name][:uses] << pos
  80. return node
  81. end
  82. def on_assign(*node)
  83. pos = block_position(node)
  84. return node if not node[0][0].is_a? Array
  85. name = node[0][0][1]
  86. symbols[:vars][name][:assignments] << pos
  87. return node
  88. end
  89. def on_var_field(*node)
  90. pos = block_position(node)
  91. name = node[0][1]
  92. symbols[:vars][name][:uses] << pos
  93. return node
  94. end
  95. def on_var_ref(*node)
  96. pos = block_position(node)
  97. name = node[0][1]
  98. symbols[:vars][name][:uses] << pos
  99. return node
  100. end
  101. def on_command(*node)
  102. # catch require statements
  103. end
  104. def to_s
  105. new_symbols = Hash.new {|hash, key| hash[key] = Hash.new}
  106. symbols.each do |type, sym_list|
  107. sym_list.each do |name, sym|
  108. new_symbols[type.to_s][name.to_s] = {
  109. "assignments" => sym[:assignments],
  110. "uses" => sym[:uses]}
  111. end
  112. end
  113. str = new_symbols.to_s
  114. str = str.gsub(/=>/, ":")
  115. return str
  116. end
  117. end