@@ -222,6 +222,44 @@ def visit_break_node(node)
222
222
on_break ( on_args_add_block ( args_val , false ) )
223
223
end
224
224
225
+ # Visit an AliasMethodNode.
226
+ def visit_alias_method_node ( node )
227
+ # For both the old and new name, if there is a colon in the symbol
228
+ # name (e.g. 'alias :foo :bar') then we do *not* emit the [:symbol] wrapper around
229
+ # the lexer token (e.g. :@ident) inside [:symbol_literal]. But if there
230
+ # is no colon (e.g. 'alias foo bar') then we *do* still emit the [:symbol] wrapper.
231
+
232
+ if node . new_name . is_a? ( SymbolNode ) && !node . new_name . opening
233
+ new_name_val = visit_symbol_literal_node ( node . new_name , no_symbol_wrapper : true )
234
+ else
235
+ new_name_val = visit ( node . new_name )
236
+ end
237
+ if node . old_name . is_a? ( SymbolNode ) && !node . old_name . opening
238
+ old_name_val = visit_symbol_literal_node ( node . old_name , no_symbol_wrapper : true )
239
+ else
240
+ old_name_val = visit ( node . old_name )
241
+ end
242
+
243
+ on_alias ( new_name_val , old_name_val )
244
+ end
245
+
246
+ # Visit an AliasGlobalVariableNode.
247
+ def visit_alias_global_variable_node ( node )
248
+ on_var_alias ( visit ( node . new_name ) , visit ( node . old_name ) )
249
+ end
250
+
251
+ # Visit a GlobalVariableReadNode.
252
+ def visit_global_variable_read_node ( node )
253
+ bounds ( node . location )
254
+ on_gvar ( node . name . to_s )
255
+ end
256
+
257
+ # Visit a BackReferenceReadNode.
258
+ def visit_back_reference_read_node ( node )
259
+ bounds ( node . location )
260
+ on_backref ( node . name . to_s )
261
+ end
262
+
225
263
# Visit an AndNode.
226
264
def visit_and_node ( node )
227
265
visit_binary_operator ( node )
@@ -326,23 +364,7 @@ def visit_x_string_node(node)
326
364
327
365
# Visit an InterpolatedStringNode node.
328
366
def visit_interpolated_string_node ( node )
329
- parts = node . parts . map do |part |
330
- case part
331
- when StringNode
332
- bounds ( part . content_loc )
333
- on_tstring_content ( part . content )
334
- when EmbeddedStatementsNode
335
- on_string_embexpr ( visit ( part ) )
336
- else
337
- raise NotImplementedError , "Unexpected node type in InterpolatedStringNode"
338
- end
339
- end
340
-
341
- string_list = parts . inject ( on_string_content ) do |items , item |
342
- on_string_add ( items , item )
343
- end
344
-
345
- on_string_literal ( string_list )
367
+ on_string_literal ( visit_enumerated_node ( node ) )
346
368
end
347
369
348
370
# Visit an EmbeddedStatementsNode node.
@@ -352,15 +374,12 @@ def visit_embedded_statements_node(node)
352
374
353
375
# Visit a SymbolNode node.
354
376
def visit_symbol_node ( node )
355
- if ( opening = node . opening ) && ( [ '"' , "'" ] . include? ( opening [ -1 ] ) || opening . start_with? ( "%s" ) )
356
- bounds ( node . value_loc )
357
- tstring_val = on_tstring_content ( node . value . to_s )
358
- return on_dyna_symbol ( on_string_add ( on_string_content , tstring_val ) )
359
- end
377
+ visit_symbol_literal_node ( node )
378
+ end
360
379
361
- bounds ( node . value_loc )
362
- ident_val = on_ident ( node . value . to_s )
363
- on_symbol_literal ( on_symbol ( ident_val ) )
380
+ # Visit an InterpolatedSymbolNode node.
381
+ def visit_interpolated_symbol_node ( node )
382
+ on_dyna_symbol ( visit_enumerated_node ( node ) )
364
383
end
365
384
366
385
# Visit a StatementsNode node.
@@ -459,6 +478,25 @@ def visit_elements(elements)
459
478
end
460
479
end
461
480
481
+ # Visit an InterpolatedStringNode or an InterpolatedSymbolNode node.
482
+ def visit_enumerated_node ( node )
483
+ parts = node . parts . map do |part |
484
+ case part
485
+ when StringNode
486
+ bounds ( part . content_loc )
487
+ on_tstring_content ( part . content )
488
+ when EmbeddedStatementsNode
489
+ on_string_embexpr ( visit ( part ) )
490
+ else
491
+ raise NotImplementedError , "Unexpected node type in visit_enumerated_node"
492
+ end
493
+ end
494
+
495
+ parts . inject ( on_string_content ) do |items , item |
496
+ on_string_add ( items , item )
497
+ end
498
+ end
499
+
462
500
# Visit an operation-and-assign node, such as +=.
463
501
def visit_binary_op_assign ( node , operator : node . operator )
464
502
bounds ( node . name_loc )
@@ -487,6 +525,87 @@ def visit_aref_field_node(node)
487
525
on_assign ( on_aref_field ( visit ( node . receiver ) , args_val ) , assign_val )
488
526
end
489
527
528
+ # In an alias statement Ripper will emit @kw instead of @ident if the object
529
+ # being aliased is a Ruby keyword. For instance, in the line "alias :foo :if",
530
+ # the :if is treated as a lexer keyword. So we need to know what symbols are
531
+ # also keywords.
532
+ RUBY_KEYWORDS = [
533
+ "alias" ,
534
+ "and" ,
535
+ "begin" ,
536
+ "BEGIN" ,
537
+ "break" ,
538
+ "case" ,
539
+ "class" ,
540
+ "def" ,
541
+ "defined?" ,
542
+ "do" ,
543
+ "else" ,
544
+ "elsif" ,
545
+ "end" ,
546
+ "END" ,
547
+ "ensure" ,
548
+ "false" ,
549
+ "for" ,
550
+ "if" ,
551
+ "in" ,
552
+ "module" ,
553
+ "next" ,
554
+ "nil" ,
555
+ "not" ,
556
+ "or" ,
557
+ "redo" ,
558
+ "rescue" ,
559
+ "retry" ,
560
+ "return" ,
561
+ "self" ,
562
+ "super" ,
563
+ "then" ,
564
+ "true" ,
565
+ "undef" ,
566
+ "unless" ,
567
+ "until" ,
568
+ "when" ,
569
+ "while" ,
570
+ "yield" ,
571
+ "__ENCODING__" ,
572
+ "__FILE__" ,
573
+ "__LINE__" ,
574
+ ]
575
+
576
+ # Ripper has several methods of emitting a symbol literal. Inside an alias
577
+ # sometimes it suppresses the [:symbol] wrapper around ident. If the symbol
578
+ # is also the name of a keyword (e.g. :if) it will emit a :@kw wrapper, not
579
+ # an :@ident wrapper, with similar treatment for constants and operators.
580
+ def visit_symbol_literal_node ( node , no_symbol_wrapper : false )
581
+ if ( opening = node . opening ) && ( [ '"' , "'" ] . include? ( opening [ -1 ] ) || opening . start_with? ( "%s" ) )
582
+ bounds ( node . value_loc )
583
+ str_val = node . value . to_s
584
+ if str_val == ""
585
+ return on_dyna_symbol ( on_string_content )
586
+ else
587
+ tstring_val = on_tstring_content ( str_val )
588
+ return on_dyna_symbol ( on_string_add ( on_string_content , tstring_val ) )
589
+ end
590
+ end
591
+
592
+ bounds ( node . value_loc )
593
+ node_name = node . value . to_s
594
+ if RUBY_KEYWORDS . include? ( node_name )
595
+ token_val = on_kw ( node_name )
596
+ elsif node_name . length == 0
597
+ raise NotImplementedError
598
+ elsif /[[:upper:]]/ . match ( node_name [ 0 ] )
599
+ token_val = on_const ( node_name )
600
+ elsif /[[:punct:]]/ . match ( node_name [ 0 ] )
601
+ token_val = on_op ( node_name )
602
+ else
603
+ token_val = on_ident ( node_name )
604
+ end
605
+ sym_val = no_symbol_wrapper ? token_val : on_symbol ( token_val )
606
+ on_symbol_literal ( sym_val )
607
+ end
608
+
490
609
# Visit a node that represents a number. We need to explicitly handle the
491
610
# unary - operator.
492
611
def visit_number ( node )
0 commit comments