masamune-ast 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile.lock +5 -1
  4. data/README.md +30 -82
  5. data/lib/masamune/abstract_syntax_tree/prism/node_extensions.rb +82 -0
  6. data/lib/masamune/abstract_syntax_tree/visitors/block_parameters_visitor.rb +18 -0
  7. data/lib/masamune/abstract_syntax_tree/visitors/method_calls_visitor.rb +19 -0
  8. data/lib/masamune/abstract_syntax_tree/visitors/method_definitions_visitor.rb +17 -0
  9. data/lib/masamune/abstract_syntax_tree/visitors/parameters_visitor.rb +18 -0
  10. data/lib/masamune/abstract_syntax_tree/visitors/strings_visitor.rb +17 -0
  11. data/lib/masamune/abstract_syntax_tree/visitors/symbols_visitor.rb +17 -0
  12. data/lib/masamune/abstract_syntax_tree/visitors/variables_visitor.rb +34 -0
  13. data/lib/masamune/abstract_syntax_tree.rb +57 -151
  14. data/lib/masamune/lex_node.rb +6 -6
  15. data/lib/masamune/slasher.rb +9 -15
  16. data/lib/masamune/version.rb +1 -1
  17. data/lib/masamune.rb +10 -23
  18. metadata +26 -24
  19. data/lib/masamune/abstract_syntax_tree/data_node.rb +0 -65
  20. data/lib/masamune/abstract_syntax_tree/node.rb +0 -41
  21. data/lib/masamune/abstract_syntax_tree/nodes/assign.rb +0 -11
  22. data/lib/masamune/abstract_syntax_tree/nodes/blocks/brace_block.rb +0 -13
  23. data/lib/masamune/abstract_syntax_tree/nodes/blocks/do_block.rb +0 -13
  24. data/lib/masamune/abstract_syntax_tree/nodes/call.rb +0 -17
  25. data/lib/masamune/abstract_syntax_tree/nodes/command.rb +0 -64
  26. data/lib/masamune/abstract_syntax_tree/nodes/def.rb +0 -17
  27. data/lib/masamune/abstract_syntax_tree/nodes/params.rb +0 -23
  28. data/lib/masamune/abstract_syntax_tree/nodes/program.rb +0 -16
  29. data/lib/masamune/abstract_syntax_tree/nodes/string_content.rb +0 -17
  30. data/lib/masamune/abstract_syntax_tree/nodes/support_nodes/block.rb +0 -18
  31. data/lib/masamune/abstract_syntax_tree/nodes/support_nodes/comment.rb +0 -25
  32. data/lib/masamune/abstract_syntax_tree/nodes/symbol.rb +0 -17
  33. data/lib/masamune/abstract_syntax_tree/nodes/symbols/dyna_symbol.rb +0 -20
  34. data/lib/masamune/abstract_syntax_tree/nodes/symbols/symbol_literal.rb +0 -21
  35. data/lib/masamune/abstract_syntax_tree/nodes/variables/block_var.rb +0 -22
  36. data/lib/masamune/abstract_syntax_tree/nodes/variables/var_field.rb +0 -17
  37. data/lib/masamune/abstract_syntax_tree/nodes/variables/var_ref.rb +0 -19
  38. data/lib/masamune/abstract_syntax_tree/nodes/vcall.rb +0 -17
@@ -1,173 +1,91 @@
1
+ require_relative "abstract_syntax_tree/prism/node_extensions"
2
+
1
3
  module Masamune
2
4
  class AbstractSyntaxTree
3
- attr_reader :code, :tree, :comment_list
4
- attr_accessor :node_list, :data_node_list, :lex_nodes
5
+ attr_reader :code, :prism, :ripper
6
+ attr_accessor :lex_nodes
5
7
 
6
8
  def initialize(code)
7
9
  @code = code
8
- @tree = Ripper.sexp(code)
10
+ @prism = Prism.parse(code)
11
+ @ripper = Ripper.sexp(code)
9
12
  raw_lex_nodes = Ripper.lex(code)
10
13
  @lex_nodes = raw_lex_nodes.map do |lex_node|
11
14
  LexNode.new(raw_lex_nodes.index(lex_node), lex_node, self.__id__)
12
15
  end
13
-
14
- @node_list = []
15
- @data_node_list = []
16
- @comment_list = []
17
- register_nodes(@tree)
18
-
19
- # Refer to Masamune::AbstractSyntaxTree::Comment
20
- # to see why we register these separately.
21
- register_comments
22
- end
23
-
24
- def register_nodes(tree_node = self.tree)
25
- if tree_node.is_a?(Array)
26
- klass = get_node_class(tree_node.first)
27
- msmn_node = klass.new(tree_node, self.__id__)
28
- else
29
- # Create a general node if the node is a single value.
30
- msmn_node = Node.new(tree_node, self.__id__)
31
- end
32
-
33
- # Register nodes and any data nodes housed within it.
34
- # See Masamune::AbstractSyntaxTree::DataNode for more details on what a data node is.
35
- @node_list << msmn_node
36
- msmn_node.data_nodes.each { |dn| @data_node_list << dn } if msmn_node.data_nodes
37
-
38
- # Continue down the tree until base case is reached.
39
- if !msmn_node.nil? && msmn_node.contents.is_a?(Array)
40
- msmn_node.contents.each { |node| register_nodes(node) }
41
- end
42
16
  end
43
17
 
44
- def register_comments
45
- comment_lex_nodes = @lex_nodes.select {|node| node.type == :comment}.flatten
46
- @comment_list << comment_lex_nodes.map {|node| Comment.new(node, self.__id__)}
47
- @comment_list.flatten!
18
+ def variables(token_value: nil)
19
+ visitor = VariablesVisitor.new(token_value)
20
+ @prism.value.accept(visitor)
21
+ visitor.results
48
22
  end
49
23
 
50
- # TODO: A lot of these methods have the same content,
51
- # so I want to come up with a way to refactor these.
52
-
53
- # TODO: Add block_params: true to the arguments.
54
- def variables(name: nil, result_type: Hash)
55
- var_classes = [
56
- :var_field,
57
- :var_ref,
58
- :params
59
- ].map {|type| get_node_class(type)}
60
- results = find_nodes(var_classes, token: name, result_type: result_type)
61
- order_results(results)
24
+ def strings(token_value: nil)
25
+ visitor = StringsVisitor.new(token_value)
26
+ @prism.value.accept(visitor)
27
+ visitor.results
62
28
  end
63
29
 
64
- def strings(content: nil, result_type: Hash)
65
- results = find_nodes(get_node_class(:string_content), token: content, result_type: result_type)
66
- order_results(results)
30
+ def all_methods(token_value: nil)
31
+ order_nodes(method_definitions(token_value: token_value) + method_calls(token_value: token_value))
67
32
  end
68
33
 
69
- def method_definitions(name: nil, result_type: Hash)
70
- results = find_nodes(get_node_class(:def), token: name, result_type: result_type)
71
- order_results(results)
34
+ def method_definitions(token_value: nil)
35
+ visitor = MethodDefinitionsVisitor.new(token_value)
36
+ @prism.value.accept(visitor)
37
+ visitor.results
72
38
  end
73
39
 
74
- def method_calls(name: nil, result_type: Hash)
75
- method_classes = [
76
- :vcall,
77
- :call,
78
- :command
79
- ].map {|type| get_node_class(type)}
80
- results = find_nodes(method_classes, token: name, result_type: result_type)
81
- order_results(results)
40
+ def method_calls(token_value: nil)
41
+ visitor = MethodCallsVisitor.new(token_value)
42
+ @prism.value.accept(visitor)
43
+ visitor.results
82
44
  end
83
45
 
84
- # TODO
85
- def do_block_params
46
+ def symbols(token_value: nil)
47
+ visitor = SymbolsVisitor.new(token_value)
48
+ @prism.value.accept(visitor)
49
+ visitor.results
86
50
  end
87
51
 
88
- # TODO
89
- def brace_block_params
90
- end
91
-
92
- def symbols(content: nil, result_type: Hash)
93
- results = symbol_literals(content: content, result_type: result_type) + string_symbols(content: content, result_type: result_type)
94
- order_results(results)
95
- end
52
+ def symbol_literals(token_value: nil)
53
+ result = symbols(token_value: token_value)
96
54
 
97
- def symbol_literals(content: nil, result_type: Hash)
98
- results = find_nodes(get_node_class(:symbol_literal), token: content, result_type: result_type)
99
- order_results(results)
55
+ # TODO: Describe why closing_loc has to happen.
56
+ result.select{|node| node.closing_loc.nil?}
100
57
  end
101
58
 
102
- def string_symbols(content: nil, result_type: Hash)
103
- results = find_nodes(get_node_class(:dyna_symbol), token: content, result_type: result_type)
104
- order_results(results)
105
- end
59
+ def string_symbols(token_value: nil)
60
+ result = symbols(token_value: token_value)
106
61
 
107
- def comments(content: nil, result_type: Hash)
108
- results = find_nodes(get_node_class(:comment), token: content, result_type: result_type)
109
- order_results(results)
62
+ # TODO: Describe why closing_loc has to happen.
63
+ result.reject{|node| node.closing_loc.nil?}
110
64
  end
111
65
 
112
- def all_methods(name: nil, result_type: Hash)
113
- results = method_definitions(name: name, result_type: result_type) + method_calls(name: name, result_type: result_type)
114
- order_results(results)
66
+ # Retrieves all parameters within pipes (i.e. - |x, y, z|).
67
+ def block_parameters
68
+ visitor = BlockParametersVisitor.new
69
+ @prism.value.accept(visitor)
70
+ visitor.results
115
71
  end
116
72
 
117
- def block_params(content: nil, result_type: Hash)
118
- # TODO: do_block_params + brace_block_params
119
- results = find_nodes(get_node_class(:params), token: content, result_type: result_type)
120
- order_results(results)
73
+ def parameters(token_value: nil)
74
+ visitor = ParametersVisitor.new(token_value)
75
+ @prism.value.accept(visitor)
76
+ visitor.results
121
77
  end
122
78
 
123
- def find_nodes(token_classes, token: nil, result_type: Hash)
124
- # Ensure the classes are in an array
125
- token_classes = [token_classes].flatten
126
-
127
- nodes = []
128
- token_classes.each do |klass|
129
- if klass == Masamune::AbstractSyntaxTree::Comment
130
- nodes = @comment_list.dup
131
- else
132
- nodes << @node_list.select {|node| node.class == klass}
133
- end
134
- end
135
-
136
- # Searching for multiple classes will yield multi-dimensional arrays,
137
- # so we ensure everything is flattened out before moving forward.
138
- nodes.flatten!
139
-
140
- return nodes if result_type == :nodes
141
-
142
- if token
143
- # TODO: This most likely shouldn't be `node.data_nodes.first`.
144
- # There are probably more data_nodes we need to check depending on the node class.
145
- nodes = nodes.select {|node| node.data_nodes.first.token == token}.flatten
146
- end
147
-
148
- final_result = []
149
- nodes.each do |node|
150
- # Data for symbols are housed within a nested node, so we handle those differently here.
151
- # Read the comments for `get_symbol_data` in the symbol node classes for details.
152
- if node.class == Masamune::AbstractSyntaxTree::SymbolLiteral || node.class == Masamune::AbstractSyntaxTree::DynaSymbol
153
- final_result << node.get_symbol_data.line_data_and_token
154
- else
155
- node.data_nodes.each {|dn| final_result << dn.line_data_and_token} if node.data_nodes
156
- end
157
- end
158
-
159
- # Only order the information if we're returning hashes.
160
- # TODO: We might want to change the placement of order_results_by_position
161
- # if the operation is being done against hashes and not data nodes.
162
- # nodes.first.class.is_a?(Hash) ? DataNode.order_results_by_position(final_result) : final_result
163
- final_result
79
+ # TODO: Search by token_value if necessary.
80
+ def comments
81
+ @prism.comments
164
82
  end
165
83
 
166
- def replace(type:, old_token:, new_token:)
84
+ def replace(type:, old_token_value:, new_token_value:)
167
85
  Slasher.replace(
168
86
  type: type,
169
- old_token: old_token,
170
- new_token: new_token,
87
+ old_token_value: old_token_value,
88
+ new_token_value: new_token_value,
171
89
  code: @code,
172
90
  ast: self
173
91
  )
@@ -175,24 +93,12 @@ module Masamune
175
93
 
176
94
  private
177
95
 
178
- def get_node_class(type)
179
- begin
180
- "Masamune::AbstractSyntaxTree::#{type.to_s.camelize}".constantize
181
- rescue NameError
182
- # For all other nodes that we haven't covered yet, we just make a general class.
183
- # We can worry about adding the classes for other nodes as we go.
184
- Node
185
- end
186
- end
187
-
188
- # We only order results when they are a Hash.
189
- # The contents from the Hash are pulled from data nodes.
190
- # i.e. - {position: [4, 7], token: "project"}
191
- def order_results(results)
192
- if results.first.is_a?(Hash)
193
- DataNode.order_results_by_position(results)
194
- else
195
- results
96
+ # Order results according to their token location.
97
+ def order_nodes(nodes)
98
+ nodes.sort do |a, b|
99
+ by_line = a.token_location.start_line <=> b.token_location.start_line
100
+ # If we're on the same line, refer to the inner index for order.
101
+ by_line.zero? ? a.token_location.start_column <=> b.token_location.start_column : by_line
196
102
  end
197
103
  end
198
104
  end
@@ -1,17 +1,17 @@
1
1
  module Masamune
2
2
  # https://docs.ruby-lang.org/en/3.0/Ripper.html#method-c-lex
3
3
  #
4
- # @position: Line number and starting point on the line. i.e. - [4, 7].
4
+ # @location: Line number and starting point on the line. i.e. - [4, 7].
5
5
  # @type: The type of token. i.e. - :kw (is a keyword).
6
6
  # @token: The raw string which represents the actual ruby code. i.e. - "do".
7
7
  # @state: Ripper::Lexer::State. i.e. - CMDARG.
8
8
  class LexNode
9
- attr_accessor :position, :type, :token, :state, :ast_id
9
+ attr_accessor :location, :type, :token, :state, :ast_id
10
10
  attr_reader :index
11
11
 
12
12
  def initialize(index, raw_lex_node, ast_id)
13
13
  @index = index
14
- @position, @type, @token, @state = raw_lex_node
14
+ @location, @type, @token, @state = raw_lex_node
15
15
  @type = @type.to_s.gsub(/^[a-z]*_/, "").to_sym
16
16
 
17
17
  # Since the Abstract Syntax Tree can get very large,
@@ -25,15 +25,15 @@ module Masamune
25
25
 
26
26
  def variable?
27
27
  return false unless identifier?
28
- ast.variables(name: @token).any?
28
+ ast.variables(token_value: @token).any?
29
29
  end
30
30
 
31
31
  def method_definition?
32
- ast.method_definitions(name: @token).any?
32
+ ast.method_definitions(token_value: @token).any?
33
33
  end
34
34
 
35
35
  def method_call?
36
- ast.method_calls(name: @token).any?
36
+ ast.method_calls(token_value: @token).any?
37
37
  end
38
38
 
39
39
  def method?
@@ -1,34 +1,28 @@
1
1
  module Masamune
2
2
  module Slasher
3
- def self.replace(type:, old_token:, new_token:, code:, ast:)
4
- # `type` can either be a method from the ast like `method_definitions`,
5
- # or it can be a list of Masamune::AbstractSyntaxTree node classes.
6
- line_data_and_token_ary = if type.is_a?(Symbol)
3
+ def self.replace(type:, old_token_value:, new_token_value:, code:, ast:)
4
+ # `type` refers to the singluar form of a method name from the ast like `method_definitions`.
5
+ nodes = if type.is_a?(Symbol)
7
6
  type_to_method = type.to_s.pluralize.to_sym
8
7
  ast.send(type_to_method)
9
- elsif type.is_a?(Array)
10
- type.map {|klass| ast.find_nodes(klass)}.flatten
11
8
  end
12
9
 
13
- tokens_to_replace = line_data_and_token_ary.select do |line_data_and_token|
14
- line_data_and_token[:token] == old_token
10
+ nodes_of_tokens_to_replace = nodes.select do |node|
11
+ node.token_value == old_token_value
15
12
  end
16
13
 
17
14
  # Build from lex nodes
18
15
  result = ast.lex_nodes.map do |lex_node|
19
16
  match_found = false
20
- tokens_to_replace.each do |line_data_and_token|
21
- position = [
22
- line_data_and_token[:line_number],
23
- line_data_and_token[:index_on_line]
24
- ]
25
- if position == lex_node.position
17
+ nodes_of_tokens_to_replace.each do |node|
18
+ location = [node.token_location.start_line, node.token_location.start_column]
19
+ if location == lex_node.location
26
20
  match_found = true
27
21
  break
28
22
  end
29
23
  end
30
24
 
31
- match_found ? new_token : lex_node.token
25
+ match_found ? new_token_value : lex_node.token
32
26
  end
33
27
 
34
28
  result.join
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Masamune
4
- VERSION = "1.2.0"
4
+ VERSION = "2.0.0"
5
5
  end
data/lib/masamune.rb CHANGED
@@ -2,35 +2,22 @@
2
2
 
3
3
  require_relative "masamune/version"
4
4
  require "ripper"
5
+ require "prism"
5
6
  require "active_support/core_ext/string/inflections"
7
+
8
+ require "masamune/abstract_syntax_tree/visitors/block_parameters_visitor"
9
+ require "masamune/abstract_syntax_tree/visitors/method_definitions_visitor"
10
+ require "masamune/abstract_syntax_tree/visitors/method_calls_visitor"
11
+ require "masamune/abstract_syntax_tree/visitors/parameters_visitor"
12
+ require "masamune/abstract_syntax_tree/visitors/strings_visitor"
13
+ require "masamune/abstract_syntax_tree/visitors/symbols_visitor"
14
+ require "masamune/abstract_syntax_tree/visitors/variables_visitor"
15
+
6
16
  require "masamune/lex_node"
7
17
  require "masamune/slasher"
8
18
  require "masamune/abstract_syntax_tree"
9
- require "masamune/abstract_syntax_tree/node"
10
- require "masamune/abstract_syntax_tree/data_node"
11
-
12
- require "masamune/abstract_syntax_tree/nodes/support_nodes/block"
13
- require "masamune/abstract_syntax_tree/nodes/support_nodes/comment"
14
-
15
- require "masamune/abstract_syntax_tree/nodes/blocks/brace_block"
16
- require "masamune/abstract_syntax_tree/nodes/blocks/do_block"
17
- require "masamune/abstract_syntax_tree/nodes/symbols/dyna_symbol"
18
- require "masamune/abstract_syntax_tree/nodes/symbols/symbol_literal"
19
- require "masamune/abstract_syntax_tree/nodes/variables/block_var"
20
- require "masamune/abstract_syntax_tree/nodes/variables/var_field"
21
- require "masamune/abstract_syntax_tree/nodes/variables/var_ref"
22
- require "masamune/abstract_syntax_tree/nodes/assign"
23
- require "masamune/abstract_syntax_tree/nodes/call"
24
- require "masamune/abstract_syntax_tree/nodes/command"
25
- require "masamune/abstract_syntax_tree/nodes/def"
26
- require "masamune/abstract_syntax_tree/nodes/params"
27
- require "masamune/abstract_syntax_tree/nodes/program"
28
- require "masamune/abstract_syntax_tree/nodes/string_content"
29
- require "masamune/abstract_syntax_tree/nodes/symbol"
30
- require "masamune/abstract_syntax_tree/nodes/vcall"
31
19
 
32
20
  require "pp"
33
- require "pry"
34
21
 
35
22
  module Masamune
36
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: masamune-ast
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Zayas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-27 00:00:00.000000000 Z
11
+ date: 2023-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: prism
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.13.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.13.0
27
41
  description: A layer of abstraction on top of Ripper for handling Abstract Syntax
28
42
  Trees in Ruby.
29
43
  email:
@@ -40,26 +54,14 @@ files:
40
54
  - Rakefile
41
55
  - lib/masamune.rb
42
56
  - lib/masamune/abstract_syntax_tree.rb
43
- - lib/masamune/abstract_syntax_tree/data_node.rb
44
- - lib/masamune/abstract_syntax_tree/node.rb
45
- - lib/masamune/abstract_syntax_tree/nodes/assign.rb
46
- - lib/masamune/abstract_syntax_tree/nodes/blocks/brace_block.rb
47
- - lib/masamune/abstract_syntax_tree/nodes/blocks/do_block.rb
48
- - lib/masamune/abstract_syntax_tree/nodes/call.rb
49
- - lib/masamune/abstract_syntax_tree/nodes/command.rb
50
- - lib/masamune/abstract_syntax_tree/nodes/def.rb
51
- - lib/masamune/abstract_syntax_tree/nodes/params.rb
52
- - lib/masamune/abstract_syntax_tree/nodes/program.rb
53
- - lib/masamune/abstract_syntax_tree/nodes/string_content.rb
54
- - lib/masamune/abstract_syntax_tree/nodes/support_nodes/block.rb
55
- - lib/masamune/abstract_syntax_tree/nodes/support_nodes/comment.rb
56
- - lib/masamune/abstract_syntax_tree/nodes/symbol.rb
57
- - lib/masamune/abstract_syntax_tree/nodes/symbols/dyna_symbol.rb
58
- - lib/masamune/abstract_syntax_tree/nodes/symbols/symbol_literal.rb
59
- - lib/masamune/abstract_syntax_tree/nodes/variables/block_var.rb
60
- - lib/masamune/abstract_syntax_tree/nodes/variables/var_field.rb
61
- - lib/masamune/abstract_syntax_tree/nodes/variables/var_ref.rb
62
- - lib/masamune/abstract_syntax_tree/nodes/vcall.rb
57
+ - lib/masamune/abstract_syntax_tree/prism/node_extensions.rb
58
+ - lib/masamune/abstract_syntax_tree/visitors/block_parameters_visitor.rb
59
+ - lib/masamune/abstract_syntax_tree/visitors/method_calls_visitor.rb
60
+ - lib/masamune/abstract_syntax_tree/visitors/method_definitions_visitor.rb
61
+ - lib/masamune/abstract_syntax_tree/visitors/parameters_visitor.rb
62
+ - lib/masamune/abstract_syntax_tree/visitors/strings_visitor.rb
63
+ - lib/masamune/abstract_syntax_tree/visitors/symbols_visitor.rb
64
+ - lib/masamune/abstract_syntax_tree/visitors/variables_visitor.rb
63
65
  - lib/masamune/lex_node.rb
64
66
  - lib/masamune/slasher.rb
65
67
  - lib/masamune/version.rb
@@ -79,14 +81,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
81
  requirements:
80
82
  - - ">="
81
83
  - !ruby/object:Gem::Version
82
- version: 2.6.0
84
+ version: 2.7.0
83
85
  required_rubygems_version: !ruby/object:Gem::Requirement
84
86
  requirements:
85
87
  - - ">="
86
88
  - !ruby/object:Gem::Version
87
89
  version: '0'
88
90
  requirements: []
89
- rubygems_version: 3.3.7
91
+ rubygems_version: 3.5.0.dev
90
92
  signing_key:
91
93
  specification_version: 4
92
94
  summary: Masamune
@@ -1,65 +0,0 @@
1
- # A data node represents an abstraction in the AST which has details about a specific type.
2
- # i.e. - [:@ident, "variable_name", [4, 7]]
3
- # These values are the `type`, `token`, and `position`, respectively.
4
- # It is simliar to what you see in `Ripper.lex(code)` and `Masamune::AbstractSyntaxTree's @lex_nodes`.
5
-
6
- # We break this down into a simpler structure, `line_data_and_token`,
7
- # which looks like this: {line_number: 4, index_on_line: 7, token: "ruby"}
8
-
9
- module Masamune
10
- class AbstractSyntaxTree
11
- class DataNode < Node
12
- attr_reader :type, :token, :line_number, :index_on_line
13
-
14
- def initialize(contents, ast_id, parent)
15
- @type, @token, line_position = contents
16
- @line_number, @index_on_line = line_position
17
- @parent = parent
18
- super(contents, ast_id)
19
- end
20
-
21
- # Results here represent the position and token of the
22
- # data we're searching in the form of a Hash like the following:
23
- # [
24
- # {line_number: 4, index_on_line: 7, token: "ruby"},
25
- # {line_number: 7, index_on_line: 7, token: "rails"}
26
- # ]
27
- # TODO: Worry about using a faster sorting algorithm later.
28
- def self.order_results_by_position(results)
29
- final_result = []
30
-
31
- line_numbers = results.map {|result| result[:line_number]}.uniq.sort
32
- line_numbers.each do |line_number|
33
- # Group data together in an array if they're on the same line.
34
- shared_line_data = results.select {|result| result[:line_number] == line_number}
35
-
36
- # Sort the positions on each line number respectively.
37
- indexes_on_line = shared_line_data.map {|data| data[:index_on_line]}.sort
38
-
39
- # Apply to the final result.
40
- indexes_on_line.each do |index_on_line|
41
- shared_line_data.each do |data|
42
- if data[:index_on_line] == index_on_line
43
- final_result << data
44
- end
45
- end
46
- end
47
- end
48
-
49
- final_result
50
- end
51
-
52
- def line_data_and_token
53
- {
54
- line_number: @line_number,
55
- index_on_line: @index_on_line,
56
- token: @token
57
- }
58
- end
59
-
60
- def position
61
- [@line_number, @index_on_line]
62
- end
63
- end
64
- end
65
- end
@@ -1,41 +0,0 @@
1
- # TODO: Add description
2
-
3
- module Masamune
4
- class AbstractSyntaxTree
5
- class Node
6
- attr_reader :ast_id, :contents, :index_stack, :data_nodes
7
-
8
- def initialize(contents, ast_id)
9
- @ast_id = ast_id
10
- @contents = contents
11
- @data_nodes = extract_data_nodes
12
- end
13
-
14
- def ast
15
- ObjectSpace._id2ref(@ast_id)
16
- end
17
-
18
- # TODO: Consider removing the :type and :typeless methods.
19
-
20
- # Ripper's abstract syntax tree nodes are either typed or typeless.
21
- # Types consist of values such as :def, :do_block, :var_ref, etc.
22
- # Typed nodes house one of these types as its first element,
23
- # whereas typeless nodes simply have arrays as top-level elements.
24
- # Example of a typed node: [:@tstring_content, "ruby", [4, 7]]
25
- def typed?
26
- @contents.is_a?(Array) && @contents.first.is_a?(Symbol)
27
- end
28
-
29
- def typeless?
30
- !typed?
31
- end
32
-
33
- # By default, we assume a node has no data nodes to extract.
34
- # Because the structure for each node is different, we handle
35
- # extraction separately for each node within its respective class.
36
- def extract_data_nodes
37
- # TODO: Might want to make this [] instead of nil.
38
- end
39
- end
40
- end
41
- end
@@ -1,11 +0,0 @@
1
- # TODO: Add description.
2
-
3
- module Masamune
4
- class AbstractSyntaxTree
5
- class Assign < Node
6
- def initialize(contents, ast_id)
7
- super
8
- end
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- # TODO: Add description.
2
-
3
- module Masamune
4
- class AbstractSyntaxTree
5
- class BraceBlock < Block
6
- attr_accessor :ast_id
7
-
8
- def initialize(contents, ast_id)
9
- super
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # TODO: Add description.
2
-
3
- module Masamune
4
- class AbstractSyntaxTree
5
- class DoBlock < Block
6
- attr_accessor :ast_id
7
-
8
- def initialize(contents, ast_id)
9
- super
10
- end
11
- end
12
- end
13
- end
@@ -1,17 +0,0 @@
1
- # TODO: Add description.
2
-
3
- module Masamune
4
- class AbstractSyntaxTree
5
- class Call < Node
6
- def initialize(contents, ast_id)
7
- super
8
- end
9
-
10
- def extract_data_nodes
11
- [
12
- DataNode.new(@contents.last, @ast_id, self)
13
- ]
14
- end
15
- end
16
- end
17
- end