forked from whitequark/parser
/
tree_rewriter.rb
133 lines (122 loc) · 3.46 KB
/
tree_rewriter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# frozen_string_literal: true
module Parser
##
# {Parser::TreeRewriter} offers a basic API that makes it easy to rewrite
# existing ASTs. It's built on top of {Parser::AST::Processor} and
# {Parser::Source::TreeRewriter}
#
# For example, assume you want to remove `do` tokens from a while statement.
# You can do this as following:
#
# require 'parser/current'
#
# class RemoveDo < Parser::TreeRewriter
# def on_while(node)
# # Check if the statement starts with "do"
# if node.location.begin.is?('do')
# remove(node.location.begin)
# end
# end
# end
#
# code = <<-EOF
# while true do
# puts 'hello'
# end
# EOF
#
# ast = Parser::CurrentRuby.parse code
# buffer = Parser::Source::Buffer.new('(example)', source: code)
# rewriter = RemoveDo.new
#
# # Rewrite the AST, returns a String with the new form.
# puts rewriter.rewrite(buffer, ast)
#
# This would result in the following Ruby code:
#
# while true
# puts 'hello'
# end
#
# Keep in mind that {Parser::TreeRewriter} does not take care of indentation when
# inserting/replacing code so you'll have to do this yourself.
#
# See also [a blog entry](http://whitequark.org/blog/2013/04/26/lets-play-with-ruby-code/)
# describing rewriters in greater detail.
#
# @api public
#
class TreeRewriter < Parser::AST::Processor
##
# Rewrites the AST/source buffer and returns a String containing the new
# version.
#
# @param [Parser::Source::Buffer] source_buffer
# @param [Parser::AST::Node] ast
# @param [Symbol] crossing_deletions:, different_replacements:, swallowed_insertions:
# policy arguments for TreeRewriter (optional)
# @return [String]
#
def rewrite(source_buffer,
ast,
**policy)
@source_rewriter = Parser::Source::TreeRewriter.new(source_buffer, **policy)
process(ast)
@source_rewriter.process
end
##
# Returns `true` if the specified node is an assignment node, returns false
# otherwise.
#
# @param [Parser::AST::Node] node
# @return [Boolean]
#
def assignment?(node)
[:lvasgn, :ivasgn, :gvasgn, :cvasgn, :casgn].include?(node.type)
end
##
# Removes the source range.
#
# @param [Parser::Source::Range] range
#
def remove(range)
@source_rewriter.remove(range)
end
##
# Wraps the given source range with the given values.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def wrap(range, before, after)
@source_rewriter.wrap(range, before, after)
end
##
# Inserts new code before the given source range.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def insert_before(range, content)
@source_rewriter.insert_before(range, content)
end
##
# Inserts new code after the given source range.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def insert_after(range, content)
@source_rewriter.insert_after(range, content)
end
##
# Replaces the code of the source range `range` with `content`.
#
# @param [Parser::Source::Range] range
# @param [String] content
#
def replace(range, content)
@source_rewriter.replace(range, content)
end
end
end