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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +5 -1
- data/README.md +30 -82
- data/lib/masamune/abstract_syntax_tree/prism/node_extensions.rb +82 -0
- data/lib/masamune/abstract_syntax_tree/visitors/block_parameters_visitor.rb +18 -0
- data/lib/masamune/abstract_syntax_tree/visitors/method_calls_visitor.rb +19 -0
- data/lib/masamune/abstract_syntax_tree/visitors/method_definitions_visitor.rb +17 -0
- data/lib/masamune/abstract_syntax_tree/visitors/parameters_visitor.rb +18 -0
- data/lib/masamune/abstract_syntax_tree/visitors/strings_visitor.rb +17 -0
- data/lib/masamune/abstract_syntax_tree/visitors/symbols_visitor.rb +17 -0
- data/lib/masamune/abstract_syntax_tree/visitors/variables_visitor.rb +34 -0
- data/lib/masamune/abstract_syntax_tree.rb +57 -151
- data/lib/masamune/lex_node.rb +6 -6
- data/lib/masamune/slasher.rb +9 -15
- data/lib/masamune/version.rb +1 -1
- data/lib/masamune.rb +10 -23
- metadata +26 -24
- data/lib/masamune/abstract_syntax_tree/data_node.rb +0 -65
- data/lib/masamune/abstract_syntax_tree/node.rb +0 -41
- data/lib/masamune/abstract_syntax_tree/nodes/assign.rb +0 -11
- data/lib/masamune/abstract_syntax_tree/nodes/blocks/brace_block.rb +0 -13
- data/lib/masamune/abstract_syntax_tree/nodes/blocks/do_block.rb +0 -13
- data/lib/masamune/abstract_syntax_tree/nodes/call.rb +0 -17
- data/lib/masamune/abstract_syntax_tree/nodes/command.rb +0 -64
- data/lib/masamune/abstract_syntax_tree/nodes/def.rb +0 -17
- data/lib/masamune/abstract_syntax_tree/nodes/params.rb +0 -23
- data/lib/masamune/abstract_syntax_tree/nodes/program.rb +0 -16
- data/lib/masamune/abstract_syntax_tree/nodes/string_content.rb +0 -17
- data/lib/masamune/abstract_syntax_tree/nodes/support_nodes/block.rb +0 -18
- data/lib/masamune/abstract_syntax_tree/nodes/support_nodes/comment.rb +0 -25
- data/lib/masamune/abstract_syntax_tree/nodes/symbol.rb +0 -17
- data/lib/masamune/abstract_syntax_tree/nodes/symbols/dyna_symbol.rb +0 -20
- data/lib/masamune/abstract_syntax_tree/nodes/symbols/symbol_literal.rb +0 -21
- data/lib/masamune/abstract_syntax_tree/nodes/variables/block_var.rb +0 -22
- data/lib/masamune/abstract_syntax_tree/nodes/variables/var_field.rb +0 -17
- data/lib/masamune/abstract_syntax_tree/nodes/variables/var_ref.rb +0 -19
- 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, :
|
4
|
-
attr_accessor :
|
5
|
+
attr_reader :code, :prism, :ripper
|
6
|
+
attr_accessor :lex_nodes
|
5
7
|
|
6
8
|
def initialize(code)
|
7
9
|
@code = code
|
8
|
-
@
|
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
|
45
|
-
|
46
|
-
@
|
47
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
65
|
-
|
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(
|
70
|
-
|
71
|
-
|
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(
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
85
|
-
|
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
|
-
|
89
|
-
|
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
|
-
|
98
|
-
|
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(
|
103
|
-
|
104
|
-
order_results(results)
|
105
|
-
end
|
59
|
+
def string_symbols(token_value: nil)
|
60
|
+
result = symbols(token_value: token_value)
|
106
61
|
|
107
|
-
|
108
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
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
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
-
|
124
|
-
|
125
|
-
|
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:,
|
84
|
+
def replace(type:, old_token_value:, new_token_value:)
|
167
85
|
Slasher.replace(
|
168
86
|
type: type,
|
169
|
-
|
170
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
#
|
183
|
-
|
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
|
data/lib/masamune/lex_node.rb
CHANGED
@@ -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
|
-
# @
|
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 :
|
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
|
-
@
|
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(
|
28
|
+
ast.variables(token_value: @token).any?
|
29
29
|
end
|
30
30
|
|
31
31
|
def method_definition?
|
32
|
-
ast.method_definitions(
|
32
|
+
ast.method_definitions(token_value: @token).any?
|
33
33
|
end
|
34
34
|
|
35
35
|
def method_call?
|
36
|
-
ast.method_calls(
|
36
|
+
ast.method_calls(token_value: @token).any?
|
37
37
|
end
|
38
38
|
|
39
39
|
def method?
|
data/lib/masamune/slasher.rb
CHANGED
@@ -1,34 +1,28 @@
|
|
1
1
|
module Masamune
|
2
2
|
module Slasher
|
3
|
-
def self.replace(type:,
|
4
|
-
# `type`
|
5
|
-
|
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
|
-
|
14
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
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 ?
|
25
|
+
match_found ? new_token_value : lex_node.token
|
32
26
|
end
|
33
27
|
|
34
28
|
result.join
|
data/lib/masamune/version.rb
CHANGED
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:
|
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-
|
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/
|
44
|
-
- lib/masamune/abstract_syntax_tree/
|
45
|
-
- lib/masamune/abstract_syntax_tree/
|
46
|
-
- lib/masamune/abstract_syntax_tree/
|
47
|
-
- lib/masamune/abstract_syntax_tree/
|
48
|
-
- lib/masamune/abstract_syntax_tree/
|
49
|
-
- lib/masamune/abstract_syntax_tree/
|
50
|
-
- lib/masamune/abstract_syntax_tree/
|
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.
|
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.
|
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,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
|