1# frozen_string_literal: true
2#
3# dummyparser.rb
4#
5
6require 'ripper'
7
8class Node
9  def initialize(name, *nodes)
10    @name = name
11    @children = nodes
12  end
13
14  attr_reader :name, :children
15
16  def to_s
17    "#{@name}(#{Node.trim_nil(@children).map {|n| n.to_s }.join(',')})"
18  end
19
20  def self.trim_nil(list)
21    if !list.empty? and list.last.nil?
22      list = list[0...-1]
23      list.pop while !list.empty? and list.last.nil?
24    end
25    list
26  end
27
28  class Sym < self
29    def initialize(name)
30      @name = name
31    end
32
33    def to_s
34      ":#{@name}"
35    end
36  end
37end
38
39class NodeList
40  def initialize(list = [])
41    @list = list
42  end
43
44  attr_reader :list
45
46  def push(item)
47    @list.push item
48    self
49  end
50
51  def concat(item)
52    @list.concat item
53    self
54  end
55
56  def prepend(items)
57    @list.unshift items
58  end
59
60  def to_s
61    "[#{@list.join(',')}]"
62  end
63end
64
65class DummyParser < Ripper
66  def hook(*names)
67    class << self; self; end.class_eval do
68      names.each do |name|
69        define_method(name) do |*a, &b|
70          result = super(*a, &b)
71          yield(name, *a)
72          result
73        end
74      end
75    end
76    self
77  end
78
79  def on_program(stmts)
80    stmts
81  end
82
83  def on_stmts_new
84    NodeList.new
85  end
86
87  def on_stmts_add(stmts, st)
88    stmts.push st
89    stmts
90  end
91
92  def on_void_stmt
93    Node.new('void')
94  end
95
96  def on_var_ref(name)
97    Node.new('ref', name)
98  end
99
100  def on_var_alias(a, b)
101    Node.new('valias', a, b)
102  end
103
104  def on_alias_error(a)
105    Node.new('aliaserr', a)
106  end
107
108  def on_arg_paren(args)
109    args
110  end
111
112  def on_args_new
113    NodeList.new
114  end
115
116  def on_args_add(list, arg)
117    list.push(arg)
118  end
119
120  def on_args_add_block(list, blk)
121    if blk
122      list.push('&' + blk.to_s)
123    else
124      list
125    end
126  end
127
128  def on_args_add_star(list, arg)
129    list.push('*' + arg.to_s)
130  end
131
132  def on_args_prepend(list, args)
133    list.prepend args
134    list
135  end
136
137  def on_method_add_arg(m, arg)
138    if arg == nil
139      arg = on_args_new
140    end
141    m.children.push arg
142    m
143  end
144
145  def on_method_add_block(m, b)
146    on_args_add_block(m.children, b)
147    m
148  end
149
150  def on_paren(params)
151    params
152  end
153
154  def on_brace_block(params, code)
155    Node.new('block', params, code)
156  end
157
158  def on_block_var(params, shadow)
159    params
160  end
161
162  def on_rest_param(var)
163    "*#{var}"
164  end
165
166  def on_kwrest_param(var)
167    "**#{var}"
168  end
169
170  def on_blockarg(var)
171    "&#{var}"
172  end
173
174  def on_params(required, optional, rest, more, keyword, keyword_rest, block)
175    args = NodeList.new
176
177    required.each do |req|
178      args.push(req)
179    end if required
180
181    optional.each do |var, val|
182      args.push("#{var}=#{val}")
183    end if optional
184
185    args.push(rest) if rest
186
187    more.each do |m|
188      args.push(m)
189    end if more
190
191    args.push(block) if block
192    args
193  end
194
195  def on_assoc_new(a, b)
196    Node.new('assoc', a, b)
197  end
198
199  def on_bare_assoc_hash(assoc_list)
200    Node.new('assocs', *assoc_list)
201  end
202
203  def on_assoclist_from_args(a)
204    Node.new('assocs', *a)
205  end
206
207  def on_word_new
208    "".dup
209  end
210
211  def on_word_add(word, w)
212    word << w
213  end
214
215  def on_words_new
216    NodeList.new
217  end
218
219  def on_words_add(words, word)
220    words.push word
221  end
222
223  def on_qwords_new
224    NodeList.new
225  end
226
227  def on_qwords_add(words, word)
228    words.push word
229  end
230
231  def on_symbols_new
232    NodeList.new
233  end
234
235  def on_symbols_add(symbols, symbol)
236    symbols.push Node::Sym.new(symbol)
237  end
238
239  def on_qsymbols_new
240    NodeList.new
241  end
242
243  def on_qsymbols_add(symbols, symbol)
244    symbols.push Node::Sym.new(symbol)
245  end
246
247  def on_mlhs_new
248    NodeList.new
249  end
250
251  def on_mlhs_paren(list)
252    Node.new(:mlhs, list)
253  end
254
255  def on_mlhs_add(list, node)
256    list.push node
257  end
258
259  def on_mlhs_add_block(list, blk)
260    if blk
261      list.push('&' + blk.to_s)
262    else
263      list
264    end
265  end
266
267  def on_mlhs_add_star(list, arg)
268    list.push('*' + arg.to_s)
269  end
270
271  def on_mlhs_add_post(list, post)
272    list.concat(post.list)
273  end
274
275  def on_rescue(exc, *rest)
276    Node.new('rescue', (exc && NodeList.new(exc)), *rest)
277  end
278
279  (Ripper::PARSER_EVENTS.map(&:to_s) - instance_methods(false).map {|n|n.to_s.sub(/^on_/, '')}).each do |event|
280    define_method(:"on_#{event}") do |*args|
281      Node.new(event, *args)
282    end
283  end
284end
285