masamune-ast 1.1.0 → 1.1.2
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 +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
|