masamune-ast 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
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,8 @@ GEM
|
|
26
28
|
concurrent-ruby (~> 1.0)
|
27
29
|
|
28
30
|
PLATFORMS
|
31
|
+
arm64-darwin-22
|
32
|
+
x86_64-darwin-21
|
29
33
|
x86_64-linux
|
30
34
|
|
31
35
|
DEPENDENCIES
|
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
|