masamune-ast 1.1.5 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +49 -45
- data/lib/masamune/abstract_syntax_tree/data_node.rb +26 -24
- data/lib/masamune/abstract_syntax_tree.rb +4 -3
- data/lib/masamune/slasher.rb +9 -5
- data/lib/masamune/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3029256236d8953d9f258d370abb57d1dac4a425b9112f7f4a5a42e951634943
|
4
|
+
data.tar.gz: 123f4977244d1db7d1cbceebee495e6a7d8494401f1db86f4a8360de27b06f2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3282cd14e7c591bff140c5d92d782a9724be2af32e9cc2542a0aab949fd469ad4c526c2a11255be267546cb2d1634e97ea7d950c8762c21635fc4274fe5f487c
|
7
|
+
data.tar.gz: d652c21b25b38d460045336d9dd330afb302470358a98f43a0eacb7f79128cdc26e8efe6d233f41067f2be28af3314585ba03b0df1f83e47f8f7d8419a018d98
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -57,21 +57,21 @@ CODE
|
|
57
57
|
msmn = Masamune::AbstractSyntaxTree.new(code)
|
58
58
|
|
59
59
|
msmn.variables
|
60
|
-
#=> [{:
|
61
|
-
#=> {:
|
62
|
-
#=> {:
|
63
|
-
#=> {:
|
64
|
-
#=> {:
|
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
65
|
|
66
66
|
msmn.strings
|
67
|
-
#=> [{:
|
68
|
-
#=> {:
|
69
|
-
#=> {:
|
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
70
|
|
71
71
|
msmn.variables(name: "java")
|
72
|
-
#=> [{
|
73
|
-
#=> {
|
74
|
-
#=> {
|
72
|
+
#=> [{:line_number=>1, :index_on_line=>0, :token=>"java"},
|
73
|
+
#=> {:line_number=>2, :index_on_line=>13, :token=>"java"},
|
74
|
+
#=> {:line_number=>3, :index_on_line=>5, :token=>"java"}]
|
75
75
|
|
76
76
|
code = <<CODE
|
77
77
|
ary = [1, 2, 3]
|
@@ -88,22 +88,22 @@ CODE
|
|
88
88
|
msmn = Masamune::AbstractSyntaxTree.new(code)
|
89
89
|
|
90
90
|
msmn.all_methods
|
91
|
-
#=> [{:
|
92
|
-
#=> {:
|
93
|
-
#=> {:
|
94
|
-
#=> {:
|
95
|
-
#=> {:
|
96
|
-
#=> {:
|
91
|
+
#=> [{:line_number=>2, :index_on_line=>4, :token=>"sum"},
|
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
97
|
|
98
98
|
msmn.method_calls
|
99
|
-
#=> [{:
|
100
|
-
#=> {:
|
101
|
-
#=> {:
|
102
|
-
#=> {:
|
103
|
-
#=> {:
|
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
104
|
|
105
105
|
msmn.method_definitions
|
106
|
-
#=> [{:
|
106
|
+
#=> [{:line_number=>6, :index_on_line=>4, :token=>"foo"}]
|
107
107
|
```
|
108
108
|
|
109
109
|
You can also return the node classes themselves and get the data from there:
|
@@ -115,28 +115,32 @@ CODE
|
|
115
115
|
|
116
116
|
msmn = Masamune::AbstractSyntaxTree.new(code)
|
117
117
|
msmn.strings(result_type: :nodes)
|
118
|
-
#=> [#<Masamune::AbstractSyntaxTree::StringContent:
|
119
|
-
#=>
|
120
|
-
#=>
|
121
|
-
#=>
|
122
|
-
#=>
|
123
|
-
#=>
|
124
|
-
#=>
|
125
|
-
#=>
|
126
|
-
#=>
|
127
|
-
#=>
|
128
|
-
#=>
|
129
|
-
#=>
|
130
|
-
#=>
|
131
|
-
#=>
|
132
|
-
#=>
|
133
|
-
#=> [
|
134
|
-
#=>
|
135
|
-
#=>
|
136
|
-
#=>
|
137
|
-
#=>
|
138
|
-
#=>
|
139
|
-
#=>
|
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>]>]
|
140
144
|
```
|
141
145
|
|
142
146
|
In some cases, it can be easier to look at the given lex nodes to analyze your source code since you can easily see the index and the line position it's on:
|
@@ -3,16 +3,17 @@
|
|
3
3
|
# These values are the `type`, `token`, and `position`, respectively.
|
4
4
|
# It is simliar to what you see in `Ripper.lex(code)` and `Masamune::AbstractSyntaxTree's @lex_nodes`.
|
5
5
|
|
6
|
-
# We break this down into a simpler structure, `
|
7
|
-
# which looks like this: {
|
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
8
|
|
9
9
|
module Masamune
|
10
10
|
class AbstractSyntaxTree
|
11
11
|
class DataNode < Node
|
12
|
-
attr_reader :type, :token, :
|
12
|
+
attr_reader :type, :token, :line_number, :index_on_line
|
13
13
|
|
14
14
|
def initialize(contents, ast_id, parent)
|
15
|
-
@type, @token,
|
15
|
+
@type, @token, line_position = contents
|
16
|
+
@line_number, @index_on_line = line_position
|
16
17
|
@parent = parent
|
17
18
|
super(contents, ast_id)
|
18
19
|
end
|
@@ -20,33 +21,26 @@ module Masamune
|
|
20
21
|
# Results here represent the position and token of the
|
21
22
|
# data we're searching in the form of a Hash like the following:
|
22
23
|
# [
|
23
|
-
# {
|
24
|
-
# {
|
24
|
+
# {line_number: 4, index_on_line: 7, token: "ruby"},
|
25
|
+
# {line_number: 7, index_on_line: 7, token: "rails"}
|
25
26
|
# ]
|
26
27
|
# TODO: Worry about using a faster sorting algorithm later.
|
27
|
-
def self.order_results_by_position(
|
28
|
-
# Extract the line numbers first, i.e - 4 from [4, 7]
|
29
|
-
line_numbers = position_and_token_ary.map do |position_and_token|
|
30
|
-
position_and_token[:position].first
|
31
|
-
end.uniq.sort
|
32
|
-
|
28
|
+
def self.order_results_by_position(results)
|
33
29
|
final_result = []
|
30
|
+
|
31
|
+
line_numbers = results.map {|result| result[:line_number]}.uniq.sort
|
34
32
|
line_numbers.each do |line_number|
|
35
33
|
# Group data together in an array if they're on the same line.
|
36
|
-
shared_line_data =
|
37
|
-
position_and_token[:position].first == line_number
|
38
|
-
end
|
34
|
+
shared_line_data = results.select {|result| result[:line_number] == line_number}
|
39
35
|
|
40
36
|
# Sort the positions on each line number respectively.
|
41
|
-
|
42
|
-
position_and_token[:position].last
|
43
|
-
end.sort
|
37
|
+
indexes_on_line = shared_line_data.map {|data| data[:index_on_line]}.sort
|
44
38
|
|
45
39
|
# Apply to the final result.
|
46
|
-
|
47
|
-
shared_line_data.each do |
|
48
|
-
if
|
49
|
-
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
|
50
44
|
end
|
51
45
|
end
|
52
46
|
end
|
@@ -55,8 +49,16 @@ module Masamune
|
|
55
49
|
final_result
|
56
50
|
end
|
57
51
|
|
58
|
-
def
|
59
|
-
{
|
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]
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
@@ -150,16 +150,17 @@ module Masamune
|
|
150
150
|
# Data for symbols are housed within a nested node, so we handle those differently here.
|
151
151
|
# Read the comments for `get_symbol_data` in the symbol node classes for details.
|
152
152
|
if node.class == Masamune::AbstractSyntaxTree::SymbolLiteral || node.class == Masamune::AbstractSyntaxTree::DynaSymbol
|
153
|
-
final_result << node.get_symbol_data.
|
153
|
+
final_result << node.get_symbol_data.line_data_and_token
|
154
154
|
else
|
155
|
-
node.data_nodes.each {|dn| final_result << dn.
|
155
|
+
node.data_nodes.each {|dn| final_result << dn.line_data_and_token} if node.data_nodes
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
159
|
# Only order the information if we're returning hashes.
|
160
160
|
# TODO: We might want to change the placement of order_results_by_position
|
161
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
|
162
|
+
# nodes.first.class.is_a?(Hash) ? DataNode.order_results_by_position(final_result) : final_result
|
163
|
+
final_result
|
163
164
|
end
|
164
165
|
|
165
166
|
def replace(type:, old_token:, new_token:)
|
data/lib/masamune/slasher.rb
CHANGED
@@ -3,22 +3,26 @@ module Masamune
|
|
3
3
|
def self.replace(type:, old_token:, new_token:, code:, ast:)
|
4
4
|
# `type` can either be a method from the ast like `method_definitions`,
|
5
5
|
# or it can be a list of Masamune::AbstractSyntaxTree node classes.
|
6
|
-
|
6
|
+
line_data_and_token_ary = if type.is_a?(Symbol)
|
7
7
|
type_to_method = type.to_s.pluralize.to_sym
|
8
8
|
ast.send(type_to_method)
|
9
9
|
elsif type.is_a?(Array)
|
10
10
|
type.map {|klass| ast.find_nodes(klass)}.flatten
|
11
11
|
end
|
12
12
|
|
13
|
-
tokens_to_replace =
|
14
|
-
|
13
|
+
tokens_to_replace = line_data_and_token_ary.select do |line_data_and_token|
|
14
|
+
line_data_and_token[:token] == old_token
|
15
15
|
end
|
16
16
|
|
17
17
|
# Build from lex nodes
|
18
18
|
result = ast.lex_nodes.map do |lex_node|
|
19
19
|
match_found = false
|
20
|
-
tokens_to_replace.each do |
|
21
|
-
|
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
|
22
26
|
match_found = true
|
23
27
|
break
|
24
28
|
end
|
data/lib/masamune/version.rb
CHANGED
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.
|
4
|
+
version: 1.2.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-
|
11
|
+
date: 2023-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|