File: generation.rb

package info (click to toggle)
ruby-unparser 0.6.13-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 936 kB
  • sloc: ruby: 7,691; sh: 6; makefile: 4
file content (256 lines) | stat: -rw-r--r-- 4,929 bytes parent folder | download
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# frozen_string_literal: true

module Unparser
  # rubocop:disable Metrics/ModuleLength
  module Generation
    EXTRA_NL = %i[kwbegin def defs module class sclass].freeze

    private_constant(*constants(false))

    def emit_heredoc_reminders; end

    def symbol_name; end

    def write_to_buffer
      with_comments { dispatch }
      self
    end

  private

    def delimited(nodes, delimiter = ', ', &block)
      return if nodes.empty?

      emit_join(nodes, block || method(:visit), -> { write(delimiter) })
    end

    def emit_join(nodes, emit_node, emit_delimiter)
      return if nodes.empty?

      head, *tail = nodes
      emit_node.call(head)

      tail.each do |node|
        emit_delimiter.call
        emit_node.call(node)
      end
    end

    def nl
      emit_eol_comments
      buffer.nl
    end

    def with_comments
      emit_comments_before if buffer.fresh_line?
      yield
      comments.consume(node)
    end

    def ws
      write(' ')
    end

    def emit_eol_comments
      comments.take_eol_comments.each do |comment|
        write(' ', comment.text)
      end
    end

    def emit_eof_comments
      emit_eol_comments
      comments_left = comments.take_all
      return if comments_left.empty?

      buffer.nl
      emit_comments(comments_left)
    end

    def emit_comments_before(source_part = :expression)
      comments_before = comments.take_before(node, source_part)
      return if comments_before.empty?

      emit_comments(comments_before)
      buffer.nl
    end

    def emit_comments(comments)
      max = comments.size - 1
      comments.each_with_index do |comment, index|
        if comment.type.equal?(:document)
          buffer.append_without_prefix(comment.text.chomp)
        else
          write(comment.text)
        end
        buffer.nl if index < max
      end
    end

    def write(*strings)
      strings.each(&buffer.method(:append))
    end

    def k_end
      buffer.indent
      emit_comments_before(:end)
      buffer.unindent
      write('end')
    end

    def parentheses(open = '(', close = ')')
      write(open)
      yield
      write(close)
    end

    def indented
      buffer = buffer()
      buffer.indent
      nl
      yield
      nl
      buffer.unindent
    end

    def emit_optional_body(node, indent: true)
      if node
        emit_body(node, indent: indent)
      else
        nl
      end
    end

    def emit_body(node, indent: true)
      with_indent(indent: indent) do
        if n_begin?(node)
          if node.children.empty?
            write('()')
          elsif node.children.one?
            visit_deep(node)
          else
            emit_body_inner(node)
          end
        else
          visit_deep(node)
        end
      end
    end

    def with_indent(indent:)
      return yield unless indent

      buffer.indent
      nl
      yield
      buffer.unindent
      nl
    end

    def emit_body_inner(node)
      head, *tail = node.children
      emit_body_member(head)

      tail.each do |child|
        nl

        nl if EXTRA_NL.include?(child.type)

        emit_body_member(child)
      end
    end

    def emit_body_member(node)
      if n_rescue?(node)
        emit_rescue_postcontrol(node)
      else
        visit_deep(node)
      end
    end

    def emit_ensure(node)
      body, ensure_body = node.children

      if body
        emit_body_rescue(body)
      else
        nl
      end

      write('ensure')

      emit_optional_body(ensure_body)
    end

    def emit_body_rescue(node)
      if n_rescue?(node)
        emit_rescue_regular(node)
      else
        emit_body(node)
      end
    end

    def emit_optional_body_ensure_rescue(node)
      if node
        emit_body_ensure_rescue(node)
      else
        nl
      end
    end

    def emit_body_ensure_rescue(node)
      if n_ensure?(node)
        emit_ensure(node)
      elsif n_rescue?(node)
        emit_rescue_regular(node)
      else
        emit_body(node)
      end
    end

    def emit_rescue_postcontrol(node)
      writer = writer_with(Writer::Rescue, node)
      writer.emit_postcontrol
      writer.emit_heredoc_reminders
    end

    def emit_rescue_regular(node)
      writer_with(Writer::Rescue, node).emit_regular
    end

    def writer_with(klass, node)
      klass.new(to_h.merge(node: node))
    end

    def emitter(node)
      Emitter.emitter(**to_h.merge(node: node))
    end

    def visit(node)
      emitter(node).write_to_buffer
    end

    def visit_deep(node)
      emitter(node).tap do |emitter|
        emitter.write_to_buffer
        emitter.emit_heredoc_reminders
      end
    end

    def first_child
      children.first
    end

    def conditional_parentheses(flag, &block)
      if flag
        parentheses(&block)
      else
        block.call
      end
    end

    def children
      node.children
    end
  end # Generation
  # rubocop:enable Metrics/ModuleLength
end # Unparser