masamune-ast 1.2.1 → 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 +4 -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 -134
- 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 -22
- metadata +29 -27
- data/lib/masamune/abstract_syntax_tree/data_node.rb +0 -49
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: caf2d78e9516f9431e751db61028a2dd90354b2dce71eecc116a848b7b171344
|
4
|
+
data.tar.gz: c556d620be50a699a6757981ce692929298baf92cd9ebbaa86256f7277e28d9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62015efa9a2e971af08db707acccf0df1761fc4a6b89fa14ca3ee830732d02ad3c06434c14c9b153006a938217f01e80370ec1dda11fa108f954ec8b47575b5a
|
7
|
+
data.tar.gz: 125c5527076511907993aee66d47e66caee9c416c33d44f63585e31676c214cbe959f5bf35165a748199fca2c87d3fda181f0f55a51331edd45c382998796178
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [2.0.0] - 2023-10-13
|
4
|
+
|
5
|
+
- Migrate to Prism by @gazayas in #60
|
6
|
+
- Return array of Prism nodes for `Masamune::AbstractSyntaxTree` search methods.
|
7
|
+
- Refactor NodeHelper into inline extensions by @kaspth in #61
|
8
|
+
- Remove functionality to replace source code by Node name (the `type` keyword now only accepts Symbols such as `:variable` and `:method_call`).
|
9
|
+
|
3
10
|
## [1.0.0] - 2023-05-01
|
4
11
|
|
5
12
|
- Change `MasamuneAst` module to `Masamune`.
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
masamune-ast (
|
4
|
+
masamune-ast (2.0.0)
|
5
5
|
activesupport
|
6
|
+
prism (>= 0.13.0)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
@@ -18,6 +19,7 @@ GEM
|
|
18
19
|
concurrent-ruby (~> 1.0)
|
19
20
|
method_source (1.0.0)
|
20
21
|
minitest (5.18.0)
|
22
|
+
prism (0.13.0)
|
21
23
|
pry (0.14.2)
|
22
24
|
coderay (~> 1.1)
|
23
25
|
method_source (~> 1.0)
|
@@ -26,6 +28,7 @@ GEM
|
|
26
28
|
concurrent-ruby (~> 1.0)
|
27
29
|
|
28
30
|
PLATFORMS
|
31
|
+
arm64-darwin-22
|
29
32
|
x86_64-darwin-21
|
30
33
|
x86_64-linux
|
31
34
|
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Masamune
|
2
2
|
|
3
|
-
## A
|
3
|
+
## A covenience wrapper around Prism, a Ruby source code parser
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -23,25 +23,21 @@ require "masamune"
|
|
23
23
|
Isolate and replace variables, methods, or strings in your Ruby source code according to the specific tokens allotted when the code is intially parsed:
|
24
24
|
```ruby
|
25
25
|
code = <<~CODE
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def n
|
31
|
-
"n"
|
26
|
+
:hello
|
27
|
+
hello = "hello"
|
28
|
+
def hello
|
29
|
+
puts hello
|
32
30
|
end
|
33
31
|
CODE
|
34
32
|
|
35
33
|
msmn = Masamune::AbstractSyntaxTree.new(code)
|
36
|
-
msmn.replace(type: :variable,
|
34
|
+
msmn.replace(type: :variable, old_token_value: "hello", new_token_value: "greeting")
|
37
35
|
|
38
36
|
# This will produce the following code in string form.
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def n
|
44
|
-
"n"
|
37
|
+
:hello
|
38
|
+
greeting = "hello"
|
39
|
+
def hello
|
40
|
+
puts greeting
|
45
41
|
end
|
46
42
|
```
|
47
43
|
|
@@ -56,22 +52,20 @@ CODE
|
|
56
52
|
|
57
53
|
msmn = Masamune::AbstractSyntaxTree.new(code)
|
58
54
|
|
55
|
+
# Returns an array of Prism nodes
|
59
56
|
msmn.variables
|
60
|
-
#=> [{:line_number=>1, :index_on_line=>0, :token=>"java"},
|
61
|
-
#=> {:line_number=>2, :index_on_line=>0, :token=>"javascript"},
|
62
|
-
#=> {:line_number=>2, :index_on_line=>13, :token=>"java"},
|
63
|
-
#=> {:line_number=>3, :index_on_line=>5, :token=>"java"},
|
64
|
-
#=> {:line_number=>3, :index_on_line=>25, :token=>"javascript"}]
|
65
57
|
|
58
|
+
msmn.variables.first.token_value
|
59
|
+
#=> "java"
|
60
|
+
msmn.variables.first.token_location
|
61
|
+
#=> (1,0)-(1,4)
|
62
|
+
|
63
|
+
# Returns an array of Prism nodes
|
66
64
|
msmn.strings
|
67
|
-
#=> [{:line_number=>1, :index_on_line=>8, :token=>"java"},
|
68
|
-
#=> {:line_number=>2, :index_on_line=>21, :token=>"script"},
|
69
|
-
#=> {:line_number=>3, :index_on_line=>13, :token=>" is not "}]
|
70
65
|
|
71
|
-
msmn.variables(
|
72
|
-
|
73
|
-
#=>
|
74
|
-
#=> {:line_number=>3, :index_on_line=>5, :token=>"java"}]
|
66
|
+
last_java_node = msmn.variables(token_value: "java").last
|
67
|
+
last_java_node.token_location
|
68
|
+
#=> (3,5)-(3,9)
|
75
69
|
|
76
70
|
code = <<CODE
|
77
71
|
ary = [1, 2, 3]
|
@@ -87,68 +81,22 @@ CODE
|
|
87
81
|
|
88
82
|
msmn = Masamune::AbstractSyntaxTree.new(code)
|
89
83
|
|
90
|
-
msmn.
|
91
|
-
#=>
|
92
|
-
#=> {:line_number=>2, :index_on_line=>8, :token=>"times"},
|
93
|
-
#=> {:line_number=>3, :index_on_line=>2, :token=>"puts"},
|
94
|
-
#=> {:line_number=>6, :index_on_line=>4, :token=>"foo"},
|
95
|
-
#=> {:line_number=>8, :index_on_line=>0, :token=>"foo"},
|
96
|
-
#=> {:line_number=>9, :index_on_line=>0, :token=>"foo"}]
|
97
|
-
|
98
|
-
msmn.method_calls
|
99
|
-
#=> [{:line_number=>2, :index_on_line=>4, :token=>"sum"},
|
100
|
-
#=> {:line_number=>2, :index_on_line=>8, :token=>"times"},
|
101
|
-
#=> {:line_number=>3, :index_on_line=>2, :token=>"puts"},
|
102
|
-
#=> {:line_number=>8, :index_on_line=>0, :token=>"foo"},
|
103
|
-
#=> {:line_number=>9, :index_on_line=>0, :token=>"foo"}]
|
104
|
-
|
105
|
-
msmn.method_definitions
|
106
|
-
#=> [{:line_number=>6, :index_on_line=>4, :token=>"foo"}]
|
107
|
-
```
|
84
|
+
msmn.method_definitions.size
|
85
|
+
#=> 1
|
108
86
|
|
109
|
-
|
110
|
-
|
111
|
-
code = <<~CODE
|
112
|
-
"ruby"
|
113
|
-
"rails"
|
114
|
-
CODE
|
87
|
+
msmn.method_calls.size
|
88
|
+
#=> 5
|
115
89
|
|
116
|
-
msmn
|
117
|
-
|
118
|
-
#=> [#<Masamune::AbstractSyntaxTree::StringContent:0x00007ff2d987c020
|
119
|
-
#=> @ast_id=406820,
|
120
|
-
#=> @contents=[:string_content, [:@tstring_content, "ruby", [1, 1]]],
|
121
|
-
#=> @data_nodes=
|
122
|
-
#=> [#<Masamune::AbstractSyntaxTree::DataNode:0x00007ff2d9883fc8
|
123
|
-
#=> @ast_id=406820,
|
124
|
-
#=> @contents=[:@tstring_content, "ruby", [1, 1]],
|
125
|
-
#=> @data_nodes=nil,
|
126
|
-
#=> @index_on_line=1,
|
127
|
-
#=> @line_number=1,
|
128
|
-
#=> @parent=#<Masamune::AbstractSyntaxTree::StringContent:0x00007ff2d987c020 ...>,
|
129
|
-
#=> @token="ruby",
|
130
|
-
#=> @type=:@tstring_content>]>,
|
131
|
-
#=> #<Masamune::AbstractSyntaxTree::StringContent:0x00007ff2d9883190
|
132
|
-
#=> @ast_id=406820,
|
133
|
-
#=> @contents=[:string_content, [:@tstring_content, "rails", [2, 1]]],
|
134
|
-
#=> @data_nodes=
|
135
|
-
#=> [#<Masamune::AbstractSyntaxTree::DataNode:0x00007ff2d9883168
|
136
|
-
#=> @ast_id=406820,
|
137
|
-
#=> @contents=[:@tstring_content, "rails", [2, 1]],
|
138
|
-
#=> @data_nodes=nil,
|
139
|
-
#=> @index_on_line=1,
|
140
|
-
#=> @line_number=2,
|
141
|
-
#=> @parent=#<Masamune::AbstractSyntaxTree::StringContent:0x00007ff2d9883190 ...>,
|
142
|
-
#=> @token="rails",
|
143
|
-
#=> @type=:@tstring_content>]>]
|
90
|
+
msmn.all_methods.size
|
91
|
+
#=> 6
|
144
92
|
```
|
145
93
|
|
146
|
-
In some cases, it can be easier to look at the given lex nodes to analyze your source code
|
94
|
+
In some cases, it can be easier to look at the given lex nodes to analyze your source code:
|
147
95
|
```ruby
|
148
96
|
msmn.lex_nodes
|
149
|
-
=> [#<Masamune::LexNode:0x00007fd61810cac0 @ast_id=1200, @index=0, @
|
150
|
-
#<Masamune::LexNode:0x00007fd61810c930 @ast_id=1200, @index=1, @
|
151
|
-
#<Masamune::LexNode:0x00007fd61810c7c8 @ast_id=1200, @index=2, @
|
97
|
+
=> [#<Masamune::LexNode:0x00007fd61810cac0 @ast_id=1200, @index=0, @location=[1, 0], @state=CMDARG, @token="java", @type=:ident>,
|
98
|
+
#<Masamune::LexNode:0x00007fd61810c930 @ast_id=1200, @index=1, @location=[1, 4], @state=CMDARG, @token=" ", @type=:sp>,
|
99
|
+
#<Masamune::LexNode:0x00007fd61810c7c8 @ast_id=1200, @index=2, @location=[1, 5], @state=BEG, @token="=", @type=:op>,
|
152
100
|
…
|
153
101
|
]
|
154
102
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Prism
|
2
|
+
class Node
|
3
|
+
def comment? = false
|
4
|
+
|
5
|
+
def self.node_predicate(name, body = -> { true })
|
6
|
+
define_method(name, &body)
|
7
|
+
Node.define_method(name) { false } unless Node.respond_to?(name, false)
|
8
|
+
end
|
9
|
+
|
10
|
+
def line_number
|
11
|
+
token_location.start_line
|
12
|
+
end
|
13
|
+
|
14
|
+
# #location provides helpful information for the source code of a node as a whole, but in
|
15
|
+
# Masamune we generally want the token value itself, so we primarily get the token value's location.
|
16
|
+
def token_location
|
17
|
+
location
|
18
|
+
end
|
19
|
+
|
20
|
+
# The source code of Prism nodes can be retrieved by calling #slice.
|
21
|
+
# However, the output tends to vary from node to node, and other methods
|
22
|
+
# like `name`, `message`, etc. are available in Prism nodes which means you
|
23
|
+
# have to know exactly which method to call the get the results you want.
|
24
|
+
#
|
25
|
+
# The `token` method simplifies all of this, and just gives you the
|
26
|
+
# variable, method name, etc. in String form by just calling `token_value`.
|
27
|
+
def token_value
|
28
|
+
content
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class DefNode
|
33
|
+
node_predicate :method?
|
34
|
+
node_predicate :method_definition?
|
35
|
+
def token_location = name_loc
|
36
|
+
def token_value = name.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
class CallNode
|
40
|
+
def method? = true
|
41
|
+
node_predicate :method_call?
|
42
|
+
def token_location = message_loc
|
43
|
+
def token_value = message
|
44
|
+
end
|
45
|
+
|
46
|
+
class LocalVariableWriteNode
|
47
|
+
node_predicate :variable?
|
48
|
+
def token_location = name_loc
|
49
|
+
def token_value = name.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
class LocalVariableReadNode
|
53
|
+
def variable? = true
|
54
|
+
def token_value = name.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
class RequiredParameterNode
|
58
|
+
def variable? = true
|
59
|
+
def token_value = slice
|
60
|
+
end
|
61
|
+
|
62
|
+
class StringNode
|
63
|
+
node_predicate :string?
|
64
|
+
def token_location = content_loc
|
65
|
+
def token_value = content
|
66
|
+
end
|
67
|
+
|
68
|
+
class SymbolNode
|
69
|
+
node_predicate :symbol?
|
70
|
+
node_predicate :symbol_literal?, -> { closing_loc.nil? }
|
71
|
+
node_predicate :symbol_string?, -> { closing_loc.present? }
|
72
|
+
|
73
|
+
def token_location = value_loc
|
74
|
+
def token_value = value
|
75
|
+
end
|
76
|
+
|
77
|
+
class Comment
|
78
|
+
def comment? = true
|
79
|
+
def token_location = location
|
80
|
+
def token_value = location.slice
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class BlockParametersVisitors < Prism::Visitor
|
4
|
+
attr_reader :results
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@results = []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Since block parameters nodes can house multiple variables in one node,
|
11
|
+
# we don't have to check for a token_value.
|
12
|
+
def visit_block_parameters_node(node)
|
13
|
+
results << node
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class MethodCallsVisitor < Prism::Visitor
|
4
|
+
attr_reader :token_value, :results
|
5
|
+
|
6
|
+
def initialize(token_value)
|
7
|
+
@token_value = token_value
|
8
|
+
@results = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_call_node(node)
|
12
|
+
if node.method_call?
|
13
|
+
results << node if token_value.nil? || token_value == node.name
|
14
|
+
end
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class MethodDefinitionsVisitor < Prism::Visitor
|
4
|
+
attr_reader :token_value, :results
|
5
|
+
|
6
|
+
def initialize(token_value)
|
7
|
+
@token_value = token_value
|
8
|
+
@results = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_def_node(node)
|
12
|
+
results << node if token_value.nil? || token_value == node.name.to_s
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class ParametersVisitor < Prism::Visitor
|
4
|
+
attr_reader :results
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@results = []
|
8
|
+
end
|
9
|
+
|
10
|
+
# Since parameters nodes can house multiple variables in one node,
|
11
|
+
# we don't have to check for a token_value.
|
12
|
+
def visit_parameters_node(node)
|
13
|
+
results << node
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class StringsVisitor < Prism::Visitor
|
4
|
+
attr_reader :token_value, :results
|
5
|
+
|
6
|
+
def initialize(token_value)
|
7
|
+
@token_value = token_value
|
8
|
+
@results = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_string_node(node)
|
12
|
+
results << node if token_value.nil? || token_value == node.content
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class SymbolsVisitor < Prism::Visitor
|
4
|
+
attr_reader :token_value, :results
|
5
|
+
|
6
|
+
def initialize(token_value)
|
7
|
+
@token_value = token_value
|
8
|
+
@results = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_symbol_node(node)
|
12
|
+
results << node if token_value.nil? || token_value == node.value
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Masamune
|
2
|
+
class AbstractSyntaxTree
|
3
|
+
class VariablesVisitor < Prism::Visitor
|
4
|
+
attr_reader :token_value, :results
|
5
|
+
|
6
|
+
def initialize(token_value)
|
7
|
+
@token_value = token_value
|
8
|
+
@results = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_local_variable_write_node(node)
|
12
|
+
results << node if token_value.nil? || token_value == node.name.to_s
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit_local_variable_read_node(node)
|
17
|
+
results << node if token_value.nil? || token_value == node.name.to_s
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def visit_required_parameter_node(node)
|
22
|
+
results << node if token_value.nil? || token_value == node.name.to_s
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def visit_call_node(node)
|
27
|
+
if node.variable_call?
|
28
|
+
results << node if token_value.nil? || token_value == node.name
|
29
|
+
end
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,162 +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
16
|
end
|
23
17
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
18
|
+
def variables(token_value: nil)
|
19
|
+
visitor = VariablesVisitor.new(token_value)
|
20
|
+
@prism.value.accept(visitor)
|
21
|
+
visitor.results
|
42
22
|
end
|
43
23
|
|
44
|
-
def
|
45
|
-
|
46
|
-
@
|
47
|
-
|
24
|
+
def strings(token_value: nil)
|
25
|
+
visitor = StringsVisitor.new(token_value)
|
26
|
+
@prism.value.accept(visitor)
|
27
|
+
visitor.results
|
48
28
|
end
|
49
29
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
# TODO: Add block_params: true to the arguments.
|
54
|
-
def variables(name: nil, result_type: Hash)
|
55
|
-
results = find_nodes([VarField, VarRef, Params], token: name, result_type: result_type)
|
56
|
-
order_results(results)
|
57
|
-
end
|
58
|
-
|
59
|
-
def strings(content: nil, result_type: Hash)
|
60
|
-
results = find_nodes(StringContent, token: content, result_type: result_type)
|
61
|
-
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))
|
62
32
|
end
|
63
33
|
|
64
|
-
def method_definitions(
|
65
|
-
|
66
|
-
|
34
|
+
def method_definitions(token_value: nil)
|
35
|
+
visitor = MethodDefinitionsVisitor.new(token_value)
|
36
|
+
@prism.value.accept(visitor)
|
37
|
+
visitor.results
|
67
38
|
end
|
68
39
|
|
69
|
-
def method_calls(
|
70
|
-
|
71
|
-
|
40
|
+
def method_calls(token_value: nil)
|
41
|
+
visitor = MethodCallsVisitor.new(token_value)
|
42
|
+
@prism.value.accept(visitor)
|
43
|
+
visitor.results
|
72
44
|
end
|
73
45
|
|
74
|
-
|
75
|
-
|
46
|
+
def symbols(token_value: nil)
|
47
|
+
visitor = SymbolsVisitor.new(token_value)
|
48
|
+
@prism.value.accept(visitor)
|
49
|
+
visitor.results
|
76
50
|
end
|
77
51
|
|
78
|
-
|
79
|
-
|
80
|
-
end
|
52
|
+
def symbol_literals(token_value: nil)
|
53
|
+
result = symbols(token_value: token_value)
|
81
54
|
|
82
|
-
|
83
|
-
|
84
|
-
order_results(results)
|
55
|
+
# TODO: Describe why closing_loc has to happen.
|
56
|
+
result.select{|node| node.closing_loc.nil?}
|
85
57
|
end
|
86
58
|
|
87
|
-
def
|
88
|
-
|
89
|
-
order_results(results)
|
90
|
-
end
|
59
|
+
def string_symbols(token_value: nil)
|
60
|
+
result = symbols(token_value: token_value)
|
91
61
|
|
92
|
-
|
93
|
-
|
94
|
-
order_results(results)
|
62
|
+
# TODO: Describe why closing_loc has to happen.
|
63
|
+
result.reject{|node| node.closing_loc.nil?}
|
95
64
|
end
|
96
65
|
|
97
|
-
|
98
|
-
|
99
|
-
|
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
|
100
71
|
end
|
101
72
|
|
102
|
-
def
|
103
|
-
|
104
|
-
|
73
|
+
def parameters(token_value: nil)
|
74
|
+
visitor = ParametersVisitor.new(token_value)
|
75
|
+
@prism.value.accept(visitor)
|
76
|
+
visitor.results
|
105
77
|
end
|
106
78
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
order_results(results)
|
79
|
+
# TODO: Search by token_value if necessary.
|
80
|
+
def comments
|
81
|
+
@prism.comments
|
111
82
|
end
|
112
83
|
|
113
|
-
def
|
114
|
-
token_classes = Array(token_classes)
|
115
|
-
|
116
|
-
nodes = []
|
117
|
-
token_classes.each do |klass|
|
118
|
-
if klass == Comment
|
119
|
-
nodes = @comment_list.dup
|
120
|
-
else
|
121
|
-
nodes << @node_list.select {|node| node.class == klass}
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# Searching for multiple classes will yield multi-dimensional arrays,
|
126
|
-
# so we ensure everything is flattened out before moving forward.
|
127
|
-
nodes.flatten!
|
128
|
-
|
129
|
-
return nodes if result_type == :nodes
|
130
|
-
|
131
|
-
if token
|
132
|
-
# TODO: This most likely shouldn't be `node.data_nodes.first`.
|
133
|
-
# There are probably more data_nodes we need to check depending on the node class.
|
134
|
-
nodes = nodes.select {|node| node.data_nodes.first.token == token}.flatten
|
135
|
-
end
|
136
|
-
|
137
|
-
final_result = []
|
138
|
-
nodes.each do |node|
|
139
|
-
# Data for symbols are housed within a nested node, so we handle those differently here.
|
140
|
-
# Read the comments for `get_symbol_data` in the symbol node classes for details.
|
141
|
-
if node.class == SymbolLiteral || node.class == DynaSymbol
|
142
|
-
final_result << node.get_symbol_data.line_data_and_token
|
143
|
-
else
|
144
|
-
node.data_nodes.each {|dn| final_result << dn.line_data_and_token} if node.data_nodes
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Only order the information if we're returning hashes.
|
149
|
-
# TODO: We might want to change the placement of order_results_by_position
|
150
|
-
# if the operation is being done against hashes and not data nodes.
|
151
|
-
# nodes.first.class.is_a?(Hash) ? DataNode.order_results_by_position(final_result) : final_result
|
152
|
-
final_result
|
153
|
-
end
|
154
|
-
|
155
|
-
def replace(type:, old_token:, new_token:)
|
84
|
+
def replace(type:, old_token_value:, new_token_value:)
|
156
85
|
Slasher.replace(
|
157
86
|
type: type,
|
158
|
-
|
159
|
-
|
87
|
+
old_token_value: old_token_value,
|
88
|
+
new_token_value: new_token_value,
|
160
89
|
code: @code,
|
161
90
|
ast: self
|
162
91
|
)
|
@@ -164,18 +93,12 @@ module Masamune
|
|
164
93
|
|
165
94
|
private
|
166
95
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
# i.e. - {position: [4, 7], token: "project"}
|
174
|
-
def order_results(results)
|
175
|
-
if results.first.is_a?(Hash)
|
176
|
-
DataNode.order_results_by_position(results)
|
177
|
-
else
|
178
|
-
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
|
179
102
|
end
|
180
103
|
end
|
181
104
|
end
|