Module: Maccro::CodeUtil

Defined in:
lib/maccro/code_util.rb

Class Method Summary collapse

Class Method Details

.code_position_to_index(source, lineno, column) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/maccro/code_util.rb', line 3

def self.code_position_to_index(source, lineno, column)
  source_lines = source.lines # including newline at the end of line
  if source_lines.size < lineno
    raise "too few lines for specified position: lineno:#{lineno}, column:#{column}"
  end
  counter = 1
  index = 0
  while counter < lineno
    index += source_lines.shift.size
    counter += 1
  end
  if source_lines.empty?
    raise "too few lines for specified position: lineno:#{lineno}, column:#{column}"
  end
  # column is 0 origin
  if source_lines.first.size < 1
    raise "empty line at the end of source"
  end
  if source_lines.first.size < column
    raise "too few chars in the line for specified position: lineno:#{lineno}, column:#{column}"
  end
  return index + column
end

.code_range_to_code(source, code_range) ⇒ Object



33
34
35
# File 'lib/maccro/code_util.rb', line 33

def self.code_range_to_code(source, code_range)
  source[code_range_to_range(source, code_range)]
end

.code_range_to_range(source, code_range) ⇒ Object



27
28
29
30
31
# File 'lib/maccro/code_util.rb', line 27

def self.code_range_to_range(source, code_range)
  begin_index = code_position_to_index(source, code_range.first_lineno, code_range.first_column)
  end_index = code_position_to_index(source, code_range.last_lineno, code_range.last_column)
  Range.new(begin_index, end_index, true) # exclude end char
end

.dig_method_node(node, def_type, method_name_index, method_name, lineno, column) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/maccro/code_util.rb', line 93

def self.dig_method_node(node, def_type, method_name_index, method_name, lineno, column)
  return nil unless node.is_a?(RubyVM::AbstractSyntaxTree::Node)
  if node.type == def_type && node.children[method_name_index] == method_name && node.first_lineno == lineno && node.first_column == column
    return node
  elsif node.respond_to?(:children)
    node.children.each do |n|
      r = dig_method_node(n, def_type, method_name_index, method_name, lineno, column)
      return r if r
    end
  end
  nil
end

.extend_tree_with_wrapper(tree) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/maccro/code_util.rb', line 61

def self.extend_tree_with_wrapper(tree)
  return unless tree.is_a?(RubyVM::AbstractSyntaxTree::Node)
  tree.extend Maccro::DSL::ASTNodeWrapper unless tree.is_a?(Maccro::DSL::ASTNodeWrapper)
  tree.children.each do |c|
    extend_tree_with_wrapper(c)
  end
end

.get_method_node(node, method_name, lineno, column, singleton_method: false) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/maccro/code_util.rb', line 83

def self.get_method_node(node, method_name, lineno, column, singleton_method: false)
  if singleton_method
    # TODO: consider receiver filter
    # 0: (SELF@57:6-57:10)
    dig_method_node(node, :DEFS, 1, method_name, lineno, column)
  else
    dig_method_node(node, :DEFN, 0, method_name, lineno, column)
  end
end

.get_source_path_iseq(method) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/maccro/code_util.rb', line 69

def self.get_source_path_iseq(method)
  iseq ||= CodeUtil.proc_to_iseq(method)
  if !iseq
    raise "Native methods can't be redefined"
  end
  path ||= iseq.absolute_path
  if !path # STDIN or -e
    raise "Methods from stdin or -e can't be redefined"
  end
  source ||= File.read(path)

  return source, path, iseq
end

.parse_to_ast(code) ⇒ Object



45
46
47
48
49
# File 'lib/maccro/code_util.rb', line 45

def self.parse_to_ast(code)
  suppress_warning do
    RubyVM::AbstractSyntaxTree.parse(code)
  end
end

.proc_to_ast(block) ⇒ Object



51
52
53
54
55
# File 'lib/maccro/code_util.rb', line 51

def self.proc_to_ast(block)
  suppress_warning do
    RubyVM::AbstractSyntaxTree.of(block)
  end
end

.proc_to_iseq(block) ⇒ Object



57
58
59
# File 'lib/maccro/code_util.rb', line 57

def self.proc_to_iseq(block)
  RubyVM::InstructionSequence.of(block)
end

.suppress_warningObject



37
38
39
40
41
42
43
# File 'lib/maccro/code_util.rb', line 37

def self.suppress_warning
  v = $VERBOSE
  $VERBOSE = nil
  yield
ensure
  $VERBOSE = v
end