masamune-ast 1.1.0 → 1.1.2
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/Gemfile.lock +1 -1
- data/README.md +30 -0
- data/lib/masamune/abstract_syntax_tree/block_var.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/brace_block.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/call.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/def.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/do_block.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/params.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/string_content.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/var_field.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/var_ref.rb +1 -1
- data/lib/masamune/abstract_syntax_tree/vcall.rb +1 -1
- data/lib/masamune/abstract_syntax_tree.rb +33 -13
- data/lib/masamune/slasher.rb +32 -0
- data/lib/masamune/version.rb +1 -1
- data/lib/masamune.rb +1 -0
- metadata +3 -3
- data/lib/masamune/slicer.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cafe74abe55158e29178163ef544558f8e8d042d8adae0668a8625e1883c843
|
4
|
+
data.tar.gz: f0068f9e6783403ba0d17f65902c0ecfded0806424383c8d325168ce0b4c7a58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6647c5ea9745d2e1f842a0d0eea3de05e795c7afa9a3241cf9d6a87dd802c4c62e7c9fdb266afcbc8e54ffe51af25d9bacc32830d4f28009f9c34b2a4f733a8
|
7
|
+
data.tar.gz: d7781f44d57a0bca23d7a61eaed10cdb687431a66540433ac0e01f43c6a625cd05aea2cd06168b1ea980d2fffaa827634ba3633ca8a94950df2110a60d4f9f5c
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -13,8 +13,38 @@ Or add the following to your Gemfile and run `bundle install`
|
|
13
13
|
gem "masamune-ast"
|
14
14
|
```
|
15
15
|
|
16
|
+
Then require the gem in a file like this:
|
17
|
+
```ruby
|
18
|
+
require "masamune"
|
19
|
+
```
|
20
|
+
|
16
21
|
## Usage
|
17
22
|
|
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
|
+
```ruby
|
25
|
+
code = <<~CODE
|
26
|
+
10.times do |n|
|
27
|
+
puts n
|
28
|
+
end
|
29
|
+
|
30
|
+
def n
|
31
|
+
"n"
|
32
|
+
end
|
33
|
+
CODE
|
34
|
+
|
35
|
+
msmn = Masamune::AbstractSyntaxTree.new(code)
|
36
|
+
msmn.replace(type: :variables, old_token: "n", new_token: "foo")
|
37
|
+
|
38
|
+
# This will produce the following code in string form.
|
39
|
+
10.times do |foo|
|
40
|
+
puts foo
|
41
|
+
end
|
42
|
+
|
43
|
+
def n
|
44
|
+
"n"
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
18
48
|
Pinpoint variables and methods in your source code even when other tokens have the same or similar spelling:
|
19
49
|
```ruby
|
20
50
|
code = <<CODE
|
@@ -14,7 +14,7 @@ module Masamune
|
|
14
14
|
# nice to find out and implement it document/implement it somewhere.
|
15
15
|
def extract_data_nodes
|
16
16
|
@contents[1][1].map do |content|
|
17
|
-
|
17
|
+
DataNode.new(content, @ast_id)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -11,7 +11,7 @@ module Masamune
|
|
11
11
|
|
12
12
|
def params
|
13
13
|
# This node should exist already, so we search for it in the ast object.
|
14
|
-
block_var =
|
14
|
+
block_var = BlockVar.new(contents[1], ast_id)
|
15
15
|
ast.node_list.find {|node| node.contents == block_var.contents}
|
16
16
|
end
|
17
17
|
end
|
@@ -11,7 +11,7 @@ module Masamune
|
|
11
11
|
|
12
12
|
def params
|
13
13
|
# This node should exist already, so we search for it in the ast object.
|
14
|
-
block_var =
|
14
|
+
block_var = BlockVar.new(contents[1], ast_id)
|
15
15
|
ast.node_list.find {|node| node.contents == block_var.contents}
|
16
16
|
end
|
17
17
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module Masamune
|
2
2
|
class AbstractSyntaxTree
|
3
|
-
attr_reader :tree
|
3
|
+
attr_reader :code, :tree
|
4
4
|
attr_accessor :node_list, :data_node_list, :lex_nodes
|
5
5
|
|
6
6
|
def initialize(code)
|
7
|
+
@code = code
|
7
8
|
@tree = Ripper.sexp(code)
|
8
9
|
raw_lex_nodes = Ripper.lex(code)
|
9
10
|
@lex_nodes = raw_lex_nodes.map do |lex_node|
|
10
|
-
|
11
|
+
LexNode.new(raw_lex_nodes.index(lex_node), lex_node, self.__id__)
|
11
12
|
end
|
12
13
|
|
13
14
|
@node_list = []
|
@@ -21,7 +22,7 @@ module Masamune
|
|
21
22
|
msmn_node = klass.new(tree_node, self.__id__)
|
22
23
|
else
|
23
24
|
# Create a general node if the node is a single value.
|
24
|
-
msmn_node =
|
25
|
+
msmn_node = Node.new(tree_node, self.__id__)
|
25
26
|
end
|
26
27
|
|
27
28
|
# Register nodes and any data nodes housed within it.
|
@@ -69,6 +70,14 @@ module Masamune
|
|
69
70
|
def brace_block_params
|
70
71
|
end
|
71
72
|
|
73
|
+
# @tree only shows comments as a type of `:void_stmt` and
|
74
|
+
# doesn't have a data node, so we get comments from @lex_nodes.
|
75
|
+
def comments(content: nil)
|
76
|
+
comments = @lex_nodes.select {|node| node.type == :comment}
|
77
|
+
comments.select {|comment| comment.token == content} if content
|
78
|
+
comments.map {|comment| {position: comment.position, token: comment.token}}
|
79
|
+
end
|
80
|
+
|
72
81
|
def all_methods
|
73
82
|
method_definitions + method_calls
|
74
83
|
end
|
@@ -83,37 +92,48 @@ module Masamune
|
|
83
92
|
# Ensure the classes are in an array
|
84
93
|
token_classes = [token_classes].flatten
|
85
94
|
|
86
|
-
|
95
|
+
nodes = []
|
87
96
|
token_classes.each do |klass|
|
88
|
-
|
97
|
+
nodes << @node_list.select {|node| node.class == klass}
|
89
98
|
end
|
90
99
|
|
91
100
|
# Searching for multiple classes will yield multi-dimensional arrays,
|
92
101
|
# so we ensure everything is flattened out before moving forward.
|
93
|
-
|
102
|
+
nodes.flatten!
|
94
103
|
|
95
104
|
if token
|
96
|
-
|
105
|
+
# TODO: This most likely shouldn't be `node.data_nodes.first`.
|
106
|
+
# There are probably more data_nodes we need to check depending on the node class.
|
107
|
+
nodes = nodes.select {|node| node.data_nodes.first.token == token}.flatten
|
97
108
|
end
|
98
109
|
|
99
110
|
final_result = []
|
100
|
-
|
101
|
-
node.data_nodes.each {|dn| final_result << dn.position_and_token}
|
111
|
+
nodes.each do |node|
|
112
|
+
node.data_nodes.each {|dn| final_result << dn.position_and_token} if node.data_nodes
|
102
113
|
end
|
103
114
|
|
104
|
-
|
115
|
+
DataNode.order_results_by_position(final_result)
|
116
|
+
end
|
117
|
+
|
118
|
+
def replace(type:, old_token:, new_token:)
|
119
|
+
Slasher.replace(
|
120
|
+
type: type,
|
121
|
+
old_token: old_token,
|
122
|
+
new_token: new_token,
|
123
|
+
code: @code,
|
124
|
+
ast: self
|
125
|
+
)
|
105
126
|
end
|
106
127
|
|
107
128
|
private
|
108
129
|
|
109
130
|
def get_node_class(type)
|
110
131
|
begin
|
111
|
-
|
112
|
-
klass = class_name.constantize
|
132
|
+
"Masamune::AbstractSyntaxTree::#{type.to_s.camelize}".constantize
|
113
133
|
rescue NameError
|
114
134
|
# For all other nodes that we haven't covered yet, we just make a general class.
|
115
135
|
# We can worry about adding the classes for other nodes as we go.
|
116
|
-
|
136
|
+
Node
|
117
137
|
end
|
118
138
|
end
|
119
139
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Masamune
|
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
|
+
position_and_token_ary = if type.is_a?(Symbol) && ast.respond_to?(type)
|
7
|
+
ast.send(type)
|
8
|
+
elsif type.is_a?(Array)
|
9
|
+
type.map {|klass| ast.find_nodes(klass)}.flatten
|
10
|
+
end
|
11
|
+
|
12
|
+
tokens_to_replace = position_and_token_ary.select do |pos_and_tok|
|
13
|
+
pos_and_tok[:token] == old_token
|
14
|
+
end
|
15
|
+
|
16
|
+
# Build from lex nodes
|
17
|
+
result = ast.lex_nodes.map do |lex_node|
|
18
|
+
match_found = false
|
19
|
+
tokens_to_replace.each do |position_and_token|
|
20
|
+
if position_and_token[:position] == lex_node.position
|
21
|
+
match_found = true
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
match_found ? new_token : lex_node.token
|
27
|
+
end
|
28
|
+
|
29
|
+
result.join
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/masamune/version.rb
CHANGED
data/lib/masamune.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative "masamune/version"
|
|
4
4
|
require "ripper"
|
5
5
|
require "active_support/core_ext/string/inflections"
|
6
6
|
require "masamune/lex_node"
|
7
|
+
require "masamune/slasher"
|
7
8
|
require "masamune/abstract_syntax_tree"
|
8
9
|
require "masamune/abstract_syntax_tree/node"
|
9
10
|
require "masamune/abstract_syntax_tree/data_node"
|
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.1.
|
4
|
+
version: 1.1.2
|
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-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -55,7 +55,7 @@ files:
|
|
55
55
|
- lib/masamune/abstract_syntax_tree/var_ref.rb
|
56
56
|
- lib/masamune/abstract_syntax_tree/vcall.rb
|
57
57
|
- lib/masamune/lex_node.rb
|
58
|
-
- lib/masamune/
|
58
|
+
- lib/masamune/slasher.rb
|
59
59
|
- lib/masamune/version.rb
|
60
60
|
- sig/masamune.rbs
|
61
61
|
homepage: https://www.github.com/gazayas/masamune-ast
|
data/lib/masamune/slicer.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Masamune
|
2
|
-
module Slicer
|
3
|
-
def initialize(ast)
|
4
|
-
@ast = ast
|
5
|
-
end
|
6
|
-
|
7
|
-
# TODO
|
8
|
-
|
9
|
-
# def replace(type, token)
|
10
|
-
# @ast.search(type, token)
|
11
|
-
# end
|
12
|
-
|
13
|
-
# def insert_inside_block
|
14
|
-
# end
|
15
|
-
|
16
|
-
# def append_to_block
|
17
|
-
# end
|
18
|
-
end
|
19
|
-
end
|