prism 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -1
- data/CONTRIBUTING.md +0 -4
- data/README.md +1 -0
- data/config.yml +95 -26
- data/docs/fuzzing.md +1 -1
- data/docs/ripper_translation.md +22 -0
- data/ext/prism/api_node.c +70 -52
- data/ext/prism/extconf.rb +27 -23
- data/ext/prism/extension.c +107 -372
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +170 -102
- data/include/prism/diagnostic.h +18 -3
- data/include/prism/node.h +0 -21
- data/include/prism/parser.h +23 -25
- data/include/prism/regexp.h +17 -8
- data/include/prism/static_literals.h +3 -2
- data/include/prism/util/pm_char.h +1 -2
- data/include/prism/util/pm_constant_pool.h +0 -8
- data/include/prism/util/pm_integer.h +16 -9
- data/include/prism/util/pm_string.h +0 -8
- data/include/prism/version.h +2 -2
- data/include/prism.h +0 -11
- data/lib/prism/compiler.rb +3 -0
- data/lib/prism/desugar_compiler.rb +4 -4
- data/lib/prism/dispatcher.rb +14 -0
- data/lib/prism/dot_visitor.rb +54 -35
- data/lib/prism/dsl.rb +23 -18
- data/lib/prism/ffi.rb +25 -4
- data/lib/prism/inspect_visitor.rb +26 -24
- data/lib/prism/mutation_compiler.rb +6 -1
- data/lib/prism/node.rb +314 -389
- data/lib/prism/node_ext.rb +175 -17
- data/lib/prism/parse_result/comments.rb +1 -8
- data/lib/prism/parse_result/newlines.rb +102 -12
- data/lib/prism/parse_result.rb +17 -0
- data/lib/prism/reflection.rb +11 -9
- data/lib/prism/serialize.rb +91 -68
- data/lib/prism/translation/parser/compiler.rb +288 -138
- data/lib/prism/translation/parser.rb +7 -2
- data/lib/prism/translation/ripper.rb +24 -22
- data/lib/prism/translation/ruby_parser.rb +32 -14
- data/lib/prism/visitor.rb +3 -0
- data/lib/prism.rb +0 -4
- data/prism.gemspec +2 -4
- data/rbi/prism/node.rbi +114 -57
- data/rbi/prism/node_ext.rbi +5 -0
- data/rbi/prism/parse_result.rbi +1 -1
- data/rbi/prism/visitor.rbi +3 -0
- data/rbi/prism.rbi +6 -0
- data/sig/prism/dsl.rbs +13 -10
- data/sig/prism/lex_compat.rbs +10 -0
- data/sig/prism/mutation_compiler.rbs +1 -0
- data/sig/prism/node.rbs +72 -48
- data/sig/prism/node_ext.rbs +4 -0
- data/sig/prism/visitor.rbs +1 -0
- data/sig/prism.rbs +21 -0
- data/src/diagnostic.c +56 -27
- data/src/node.c +432 -1690
- data/src/prettyprint.c +97 -54
- data/src/prism.c +1286 -1196
- data/src/regexp.c +133 -68
- data/src/serialize.c +22 -17
- data/src/static_literals.c +63 -84
- data/src/token_type.c +4 -4
- data/src/util/pm_constant_pool.c +0 -8
- data/src/util/pm_integer.c +39 -11
- data/src/util/pm_string.c +0 -12
- data/src/util/pm_strpbrk.c +32 -6
- metadata +3 -5
- data/include/prism/util/pm_string_list.h +0 -44
- data/lib/prism/debug.rb +0 -249
- data/src/util/pm_string_list.c +0 -28
@@ -90,7 +90,11 @@ module Prism
|
|
90
90
|
end
|
91
91
|
|
92
92
|
if node.constant
|
93
|
-
|
93
|
+
if visited.empty?
|
94
|
+
builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc)), token(node.closing_loc))
|
95
|
+
else
|
96
|
+
builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(nil, visited, nil), token(node.closing_loc))
|
97
|
+
end
|
94
98
|
else
|
95
99
|
builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc))
|
96
100
|
end
|
@@ -105,38 +109,46 @@ module Prism
|
|
105
109
|
# { a: 1 }
|
106
110
|
# ^^^^
|
107
111
|
def visit_assoc_node(node)
|
112
|
+
key = node.key
|
113
|
+
|
108
114
|
if in_pattern
|
109
115
|
if node.value.is_a?(ImplicitNode)
|
110
|
-
if
|
111
|
-
|
116
|
+
if key.is_a?(SymbolNode)
|
117
|
+
if key.opening.nil?
|
118
|
+
builder.match_hash_var([key.unescaped, srange(key.location)])
|
119
|
+
else
|
120
|
+
builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc))
|
121
|
+
end
|
112
122
|
else
|
113
|
-
builder.match_hash_var_from_str(token(
|
123
|
+
builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc))
|
114
124
|
end
|
125
|
+
elsif key.opening.nil?
|
126
|
+
builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
|
115
127
|
else
|
116
|
-
builder.
|
128
|
+
builder.pair_quoted(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc), visit(node.value))
|
117
129
|
end
|
118
130
|
elsif node.value.is_a?(ImplicitNode)
|
119
131
|
if (value = node.value.value).is_a?(LocalVariableReadNode)
|
120
132
|
builder.pair_keyword(
|
121
|
-
[
|
122
|
-
builder.ident([value.name, srange(
|
133
|
+
[key.unescaped, srange(key)],
|
134
|
+
builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
|
123
135
|
)
|
124
136
|
else
|
125
|
-
builder.pair_label([
|
137
|
+
builder.pair_label([key.unescaped, srange(key.location)])
|
126
138
|
end
|
127
139
|
elsif node.operator_loc
|
128
|
-
builder.pair(visit(
|
129
|
-
elsif
|
130
|
-
builder.pair_keyword([
|
140
|
+
builder.pair(visit(key), token(node.operator_loc), visit(node.value))
|
141
|
+
elsif key.is_a?(SymbolNode) && key.opening_loc.nil?
|
142
|
+
builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
|
131
143
|
else
|
132
144
|
parts =
|
133
|
-
if
|
134
|
-
[builder.string_internal([
|
145
|
+
if key.is_a?(SymbolNode)
|
146
|
+
[builder.string_internal([key.unescaped, srange(key.value_loc)])]
|
135
147
|
else
|
136
|
-
visit_all(
|
148
|
+
visit_all(key.parts)
|
137
149
|
end
|
138
150
|
|
139
|
-
builder.pair_quoted(token(
|
151
|
+
builder.pair_quoted(token(key.opening_loc), parts, token(key.closing_loc), visit(node.value))
|
140
152
|
end
|
141
153
|
end
|
142
154
|
|
@@ -146,7 +158,9 @@ module Prism
|
|
146
158
|
# { **foo }
|
147
159
|
# ^^^^^
|
148
160
|
def visit_assoc_splat_node(node)
|
149
|
-
if
|
161
|
+
if in_pattern
|
162
|
+
builder.match_rest(token(node.operator_loc), token(node.value&.location))
|
163
|
+
elsif node.value.nil? && forwarding.include?(:**)
|
150
164
|
builder.forwarded_kwrestarg(token(node.operator_loc))
|
151
165
|
else
|
152
166
|
builder.kwsplat(token(node.operator_loc), visit(node.value))
|
@@ -328,18 +342,48 @@ module Prism
|
|
328
342
|
[],
|
329
343
|
nil
|
330
344
|
),
|
331
|
-
[node.
|
345
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
332
346
|
visit(node.value)
|
333
347
|
)
|
334
348
|
end
|
335
349
|
|
336
350
|
# foo.bar &&= baz
|
337
351
|
# ^^^^^^^^^^^^^^^
|
338
|
-
|
352
|
+
def visit_call_and_write_node(node)
|
353
|
+
call_operator_loc = node.call_operator_loc
|
354
|
+
|
355
|
+
builder.op_assign(
|
356
|
+
builder.call_method(
|
357
|
+
visit(node.receiver),
|
358
|
+
call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
|
359
|
+
node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
|
360
|
+
nil,
|
361
|
+
[],
|
362
|
+
nil
|
363
|
+
),
|
364
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
365
|
+
visit(node.value)
|
366
|
+
)
|
367
|
+
end
|
339
368
|
|
340
369
|
# foo.bar ||= baz
|
341
370
|
# ^^^^^^^^^^^^^^^
|
342
|
-
|
371
|
+
def visit_call_or_write_node(node)
|
372
|
+
call_operator_loc = node.call_operator_loc
|
373
|
+
|
374
|
+
builder.op_assign(
|
375
|
+
builder.call_method(
|
376
|
+
visit(node.receiver),
|
377
|
+
call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
|
378
|
+
node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
|
379
|
+
nil,
|
380
|
+
[],
|
381
|
+
nil
|
382
|
+
),
|
383
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
384
|
+
visit(node.value)
|
385
|
+
)
|
386
|
+
end
|
343
387
|
|
344
388
|
# foo.bar, = 1
|
345
389
|
# ^^^^^^^
|
@@ -419,18 +463,30 @@ module Prism
|
|
419
463
|
def visit_class_variable_operator_write_node(node)
|
420
464
|
builder.op_assign(
|
421
465
|
builder.assignable(builder.cvar(token(node.name_loc))),
|
422
|
-
[node.
|
466
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
423
467
|
visit(node.value)
|
424
468
|
)
|
425
469
|
end
|
426
470
|
|
427
471
|
# @@foo &&= bar
|
428
472
|
# ^^^^^^^^^^^^^
|
429
|
-
|
473
|
+
def visit_class_variable_and_write_node(node)
|
474
|
+
builder.op_assign(
|
475
|
+
builder.assignable(builder.cvar(token(node.name_loc))),
|
476
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
477
|
+
visit(node.value)
|
478
|
+
)
|
479
|
+
end
|
430
480
|
|
431
481
|
# @@foo ||= bar
|
432
482
|
# ^^^^^^^^^^^^^
|
433
|
-
|
483
|
+
def visit_class_variable_or_write_node(node)
|
484
|
+
builder.op_assign(
|
485
|
+
builder.assignable(builder.cvar(token(node.name_loc))),
|
486
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
487
|
+
visit(node.value)
|
488
|
+
)
|
489
|
+
end
|
434
490
|
|
435
491
|
# @@foo, = bar
|
436
492
|
# ^^^^^
|
@@ -458,18 +514,30 @@ module Prism
|
|
458
514
|
def visit_constant_operator_write_node(node)
|
459
515
|
builder.op_assign(
|
460
516
|
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
|
461
|
-
[node.
|
517
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
462
518
|
visit(node.value)
|
463
519
|
)
|
464
520
|
end
|
465
521
|
|
466
522
|
# Foo &&= bar
|
467
523
|
# ^^^^^^^^^^^^
|
468
|
-
|
524
|
+
def visit_constant_and_write_node(node)
|
525
|
+
builder.op_assign(
|
526
|
+
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
|
527
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
528
|
+
visit(node.value)
|
529
|
+
)
|
530
|
+
end
|
469
531
|
|
470
532
|
# Foo ||= bar
|
471
533
|
# ^^^^^^^^^^^^
|
472
|
-
|
534
|
+
def visit_constant_or_write_node(node)
|
535
|
+
builder.op_assign(
|
536
|
+
builder.assignable(builder.const([node.name, srange(node.name_loc)])),
|
537
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
538
|
+
visit(node.value)
|
539
|
+
)
|
540
|
+
end
|
473
541
|
|
474
542
|
# Foo, = bar
|
475
543
|
# ^^^
|
@@ -512,18 +580,30 @@ module Prism
|
|
512
580
|
def visit_constant_path_operator_write_node(node)
|
513
581
|
builder.op_assign(
|
514
582
|
builder.assignable(visit(node.target)),
|
515
|
-
[node.
|
583
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
516
584
|
visit(node.value)
|
517
585
|
)
|
518
586
|
end
|
519
587
|
|
520
588
|
# Foo::Bar &&= baz
|
521
589
|
# ^^^^^^^^^^^^^^^^
|
522
|
-
|
590
|
+
def visit_constant_path_and_write_node(node)
|
591
|
+
builder.op_assign(
|
592
|
+
builder.assignable(visit(node.target)),
|
593
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
594
|
+
visit(node.value)
|
595
|
+
)
|
596
|
+
end
|
523
597
|
|
524
598
|
# Foo::Bar ||= baz
|
525
599
|
# ^^^^^^^^^^^^^^^^
|
526
|
-
|
600
|
+
def visit_constant_path_or_write_node(node)
|
601
|
+
builder.op_assign(
|
602
|
+
builder.assignable(visit(node.target)),
|
603
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
604
|
+
visit(node.value)
|
605
|
+
)
|
606
|
+
end
|
527
607
|
|
528
608
|
# Foo::Bar, = baz
|
529
609
|
# ^^^^^^^^
|
@@ -711,18 +791,30 @@ module Prism
|
|
711
791
|
def visit_global_variable_operator_write_node(node)
|
712
792
|
builder.op_assign(
|
713
793
|
builder.assignable(builder.gvar(token(node.name_loc))),
|
714
|
-
[node.
|
794
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
715
795
|
visit(node.value)
|
716
796
|
)
|
717
797
|
end
|
718
798
|
|
719
799
|
# $foo &&= bar
|
720
800
|
# ^^^^^^^^^^^^
|
721
|
-
|
801
|
+
def visit_global_variable_and_write_node(node)
|
802
|
+
builder.op_assign(
|
803
|
+
builder.assignable(builder.gvar(token(node.name_loc))),
|
804
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
805
|
+
visit(node.value)
|
806
|
+
)
|
807
|
+
end
|
722
808
|
|
723
809
|
# $foo ||= bar
|
724
810
|
# ^^^^^^^^^^^^
|
725
|
-
|
811
|
+
def visit_global_variable_or_write_node(node)
|
812
|
+
builder.op_assign(
|
813
|
+
builder.assignable(builder.gvar(token(node.name_loc))),
|
814
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
815
|
+
visit(node.value)
|
816
|
+
)
|
817
|
+
end
|
726
818
|
|
727
819
|
# $foo, = bar
|
728
820
|
# ^^^^
|
@@ -803,7 +895,7 @@ module Prism
|
|
803
895
|
# 1i
|
804
896
|
# ^^
|
805
897
|
def visit_imaginary_node(node)
|
806
|
-
visit_numeric(node, builder.complex([
|
898
|
+
visit_numeric(node, builder.complex([Complex(0, node.numeric.value), srange(node.location)]))
|
807
899
|
end
|
808
900
|
|
809
901
|
# { foo: }
|
@@ -857,18 +949,46 @@ module Prism
|
|
857
949
|
visit_all(arguments),
|
858
950
|
token(node.closing_loc)
|
859
951
|
),
|
860
|
-
[node.
|
952
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
861
953
|
visit(node.value)
|
862
954
|
)
|
863
955
|
end
|
864
956
|
|
865
957
|
# foo[bar] &&= baz
|
866
958
|
# ^^^^^^^^^^^^^^^^
|
867
|
-
|
959
|
+
def visit_index_and_write_node(node)
|
960
|
+
arguments = node.arguments&.arguments || []
|
961
|
+
arguments << node.block if node.block
|
962
|
+
|
963
|
+
builder.op_assign(
|
964
|
+
builder.index(
|
965
|
+
visit(node.receiver),
|
966
|
+
token(node.opening_loc),
|
967
|
+
visit_all(arguments),
|
968
|
+
token(node.closing_loc)
|
969
|
+
),
|
970
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
971
|
+
visit(node.value)
|
972
|
+
)
|
973
|
+
end
|
868
974
|
|
869
975
|
# foo[bar] ||= baz
|
870
976
|
# ^^^^^^^^^^^^^^^^
|
871
|
-
|
977
|
+
def visit_index_or_write_node(node)
|
978
|
+
arguments = node.arguments&.arguments || []
|
979
|
+
arguments << node.block if node.block
|
980
|
+
|
981
|
+
builder.op_assign(
|
982
|
+
builder.index(
|
983
|
+
visit(node.receiver),
|
984
|
+
token(node.opening_loc),
|
985
|
+
visit_all(arguments),
|
986
|
+
token(node.closing_loc)
|
987
|
+
),
|
988
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
989
|
+
visit(node.value)
|
990
|
+
)
|
991
|
+
end
|
872
992
|
|
873
993
|
# foo[bar], = 1
|
874
994
|
# ^^^^^^^^
|
@@ -902,18 +1022,30 @@ module Prism
|
|
902
1022
|
def visit_instance_variable_operator_write_node(node)
|
903
1023
|
builder.op_assign(
|
904
1024
|
builder.assignable(builder.ivar(token(node.name_loc))),
|
905
|
-
[node.
|
1025
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
906
1026
|
visit(node.value)
|
907
1027
|
)
|
908
1028
|
end
|
909
1029
|
|
910
1030
|
# @foo &&= bar
|
911
1031
|
# ^^^^^^^^^^^^
|
912
|
-
|
1032
|
+
def visit_instance_variable_and_write_node(node)
|
1033
|
+
builder.op_assign(
|
1034
|
+
builder.assignable(builder.ivar(token(node.name_loc))),
|
1035
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
1036
|
+
visit(node.value)
|
1037
|
+
)
|
1038
|
+
end
|
913
1039
|
|
914
1040
|
# @foo ||= bar
|
915
1041
|
# ^^^^^^^^^^^^
|
916
|
-
|
1042
|
+
def visit_instance_variable_or_write_node(node)
|
1043
|
+
builder.op_assign(
|
1044
|
+
builder.assignable(builder.ivar(token(node.name_loc))),
|
1045
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
1046
|
+
visit(node.value)
|
1047
|
+
)
|
1048
|
+
end
|
917
1049
|
|
918
1050
|
# @foo, = bar
|
919
1051
|
# ^^^^
|
@@ -946,36 +1078,7 @@ module Prism
|
|
946
1078
|
# ^^^^^^^^^^^^
|
947
1079
|
def visit_interpolated_string_node(node)
|
948
1080
|
if node.heredoc?
|
949
|
-
children, closing
|
950
|
-
opening = token(node.opening_loc)
|
951
|
-
|
952
|
-
start_offset = node.opening_loc.end_offset + 1
|
953
|
-
end_offset = node.parts.first.location.start_offset
|
954
|
-
|
955
|
-
# In the below case, the offsets should be the same:
|
956
|
-
#
|
957
|
-
# <<~HEREDOC
|
958
|
-
# a #{b}
|
959
|
-
# HEREDOC
|
960
|
-
#
|
961
|
-
# But in this case, the end_offset would be greater than the start_offset:
|
962
|
-
#
|
963
|
-
# <<~HEREDOC
|
964
|
-
# #{b}
|
965
|
-
# HEREDOC
|
966
|
-
#
|
967
|
-
# So we need to make sure the result node's heredoc range is correct, without updating the children
|
968
|
-
result = if start_offset < end_offset
|
969
|
-
# We need to add a padding string to ensure that the heredoc has correct range for its body
|
970
|
-
padding_string_node = builder.string_internal(["", srange_offsets(start_offset, end_offset)])
|
971
|
-
node_with_correct_location = builder.string_compose(opening, [padding_string_node, *children], closing)
|
972
|
-
# But the padding string should not be included in the final AST, so we need to update the result's children
|
973
|
-
node_with_correct_location.updated(:dstr, children)
|
974
|
-
else
|
975
|
-
builder.string_compose(opening, children, closing)
|
976
|
-
end
|
977
|
-
|
978
|
-
return result
|
1081
|
+
return visit_heredoc(node) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
|
979
1082
|
end
|
980
1083
|
|
981
1084
|
parts = if node.parts.one? { |part| part.type == :string_node }
|
@@ -1019,8 +1122,7 @@ module Prism
|
|
1019
1122
|
# ^^^^^^^^^^^^
|
1020
1123
|
def visit_interpolated_x_string_node(node)
|
1021
1124
|
if node.heredoc?
|
1022
|
-
children, closing
|
1023
|
-
builder.xstring_compose(token(node.opening_loc), children, closing)
|
1125
|
+
visit_heredoc(node) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
|
1024
1126
|
else
|
1025
1127
|
builder.xstring_compose(
|
1026
1128
|
token(node.opening_loc),
|
@@ -1030,6 +1132,12 @@ module Prism
|
|
1030
1132
|
end
|
1031
1133
|
end
|
1032
1134
|
|
1135
|
+
# -> { it }
|
1136
|
+
# ^^
|
1137
|
+
def visit_it_local_variable_read_node(node)
|
1138
|
+
builder.ident([:it, srange(node.location)]).updated(:lvar)
|
1139
|
+
end
|
1140
|
+
|
1033
1141
|
# -> { it }
|
1034
1142
|
# ^^^^^^^^^
|
1035
1143
|
def visit_it_parameters_node(node)
|
@@ -1083,14 +1191,7 @@ module Prism
|
|
1083
1191
|
# foo
|
1084
1192
|
# ^^^
|
1085
1193
|
def visit_local_variable_read_node(node)
|
1086
|
-
name
|
1087
|
-
|
1088
|
-
# This is just a guess. parser doesn't have support for the implicit
|
1089
|
-
# `it` variable yet, so we'll probably have to visit this once it
|
1090
|
-
# does.
|
1091
|
-
name = :it if name == :"0it"
|
1092
|
-
|
1093
|
-
builder.ident([name, srange(node.location)]).updated(:lvar)
|
1194
|
+
builder.ident([node.name, srange(node.location)]).updated(:lvar)
|
1094
1195
|
end
|
1095
1196
|
|
1096
1197
|
# foo = 1
|
@@ -1108,18 +1209,30 @@ module Prism
|
|
1108
1209
|
def visit_local_variable_operator_write_node(node)
|
1109
1210
|
builder.op_assign(
|
1110
1211
|
builder.assignable(builder.ident(token(node.name_loc))),
|
1111
|
-
[node.
|
1212
|
+
[node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
|
1112
1213
|
visit(node.value)
|
1113
1214
|
)
|
1114
1215
|
end
|
1115
1216
|
|
1116
1217
|
# foo &&= bar
|
1117
1218
|
# ^^^^^^^^^^^
|
1118
|
-
|
1219
|
+
def visit_local_variable_and_write_node(node)
|
1220
|
+
builder.op_assign(
|
1221
|
+
builder.assignable(builder.ident(token(node.name_loc))),
|
1222
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
1223
|
+
visit(node.value)
|
1224
|
+
)
|
1225
|
+
end
|
1119
1226
|
|
1120
1227
|
# foo ||= bar
|
1121
1228
|
# ^^^^^^^^^^^
|
1122
|
-
|
1229
|
+
def visit_local_variable_or_write_node(node)
|
1230
|
+
builder.op_assign(
|
1231
|
+
builder.assignable(builder.ident(token(node.name_loc))),
|
1232
|
+
[node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
|
1233
|
+
visit(node.value)
|
1234
|
+
)
|
1235
|
+
end
|
1123
1236
|
|
1124
1237
|
# foo, = bar
|
1125
1238
|
# ^^^
|
@@ -1182,13 +1295,9 @@ module Prism
|
|
1182
1295
|
# foo, bar = baz
|
1183
1296
|
# ^^^^^^^^
|
1184
1297
|
def visit_multi_target_node(node)
|
1185
|
-
elements = [*node.lefts]
|
1186
|
-
elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
|
1187
|
-
elements.concat(node.rights)
|
1188
|
-
|
1189
1298
|
builder.multi_lhs(
|
1190
1299
|
token(node.lparen_loc),
|
1191
|
-
visit_all(
|
1300
|
+
visit_all(multi_target_elements(node)),
|
1192
1301
|
token(node.rparen_loc)
|
1193
1302
|
)
|
1194
1303
|
end
|
@@ -1196,9 +1305,11 @@ module Prism
|
|
1196
1305
|
# foo, bar = baz
|
1197
1306
|
# ^^^^^^^^^^^^^^
|
1198
1307
|
def visit_multi_write_node(node)
|
1199
|
-
elements =
|
1200
|
-
|
1201
|
-
elements.
|
1308
|
+
elements = multi_target_elements(node)
|
1309
|
+
|
1310
|
+
if elements.length == 1 && elements.first.is_a?(MultiTargetNode)
|
1311
|
+
elements = multi_target_elements(elements.first)
|
1312
|
+
end
|
1202
1313
|
|
1203
1314
|
builder.multi_assign(
|
1204
1315
|
builder.multi_lhs(
|
@@ -1279,12 +1390,12 @@ module Prism
|
|
1279
1390
|
|
1280
1391
|
if node.requireds.any?
|
1281
1392
|
node.requireds.each do |required|
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1393
|
+
params <<
|
1394
|
+
if required.is_a?(RequiredParameterNode)
|
1395
|
+
visit(required)
|
1396
|
+
else
|
1397
|
+
required.accept(copy_compiler(in_destructure: true))
|
1398
|
+
end
|
1288
1399
|
end
|
1289
1400
|
end
|
1290
1401
|
|
@@ -1293,12 +1404,12 @@ module Prism
|
|
1293
1404
|
|
1294
1405
|
if node.posts.any?
|
1295
1406
|
node.posts.each do |post|
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1407
|
+
params <<
|
1408
|
+
if post.is_a?(RequiredParameterNode)
|
1409
|
+
visit(post)
|
1410
|
+
else
|
1411
|
+
post.accept(copy_compiler(in_destructure: true))
|
1412
|
+
end
|
1302
1413
|
end
|
1303
1414
|
end
|
1304
1415
|
|
@@ -1384,7 +1495,7 @@ module Prism
|
|
1384
1495
|
# 1r
|
1385
1496
|
# ^^
|
1386
1497
|
def visit_rational_node(node)
|
1387
|
-
visit_numeric(node, builder.rational([
|
1498
|
+
visit_numeric(node, builder.rational([node.value, srange(node.location)]))
|
1388
1499
|
end
|
1389
1500
|
|
1390
1501
|
# redo
|
@@ -1396,9 +1507,20 @@ module Prism
|
|
1396
1507
|
# /foo/
|
1397
1508
|
# ^^^^^
|
1398
1509
|
def visit_regular_expression_node(node)
|
1510
|
+
content = node.content
|
1511
|
+
parts =
|
1512
|
+
if content.include?("\n")
|
1513
|
+
offset = node.content_loc.start_offset
|
1514
|
+
content.lines.map do |line|
|
1515
|
+
builder.string_internal([line, srange_offsets(offset, offset += line.bytesize)])
|
1516
|
+
end
|
1517
|
+
else
|
1518
|
+
[builder.string_internal(token(node.content_loc))]
|
1519
|
+
end
|
1520
|
+
|
1399
1521
|
builder.regexp_compose(
|
1400
1522
|
token(node.opening_loc),
|
1401
|
-
|
1523
|
+
parts,
|
1402
1524
|
[node.closing[0], srange_offsets(node.closing_loc.start_offset, node.closing_loc.start_offset + 1)],
|
1403
1525
|
builder.regexp_options([node.closing[1..], srange_offsets(node.closing_loc.start_offset + 1, node.closing_loc.end_offset)])
|
1404
1526
|
)
|
@@ -1544,10 +1666,11 @@ module Prism
|
|
1544
1666
|
# ^^^^^
|
1545
1667
|
def visit_string_node(node)
|
1546
1668
|
if node.heredoc?
|
1547
|
-
children, closing
|
1548
|
-
builder.string_compose(token(node.opening_loc), children, closing)
|
1669
|
+
visit_heredoc(node.to_interpolated) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
|
1549
1670
|
elsif node.opening == "?"
|
1550
1671
|
builder.character([node.unescaped, srange(node.location)])
|
1672
|
+
elsif node.opening&.start_with?("%") && node.unescaped.empty?
|
1673
|
+
builder.string_compose(token(node.opening_loc), [], token(node.closing_loc))
|
1551
1674
|
else
|
1552
1675
|
content_lines = node.content.lines
|
1553
1676
|
unescaped_lines = node.unescaped.lines
|
@@ -1747,8 +1870,7 @@ module Prism
|
|
1747
1870
|
# ^^^^^
|
1748
1871
|
def visit_x_string_node(node)
|
1749
1872
|
if node.heredoc?
|
1750
|
-
children, closing
|
1751
|
-
builder.xstring_compose(token(node.opening_loc), children, closing)
|
1873
|
+
visit_heredoc(node.to_interpolated) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
|
1752
1874
|
else
|
1753
1875
|
parts = if node.unescaped.lines.one?
|
1754
1876
|
[builder.string_internal([node.unescaped, srange(node.content_loc)])]
|
@@ -1810,10 +1932,12 @@ module Prism
|
|
1810
1932
|
forwarding
|
1811
1933
|
end
|
1812
1934
|
|
1813
|
-
#
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1935
|
+
# Returns the set of targets for a MultiTargetNode or a MultiWriteNode.
|
1936
|
+
def multi_target_elements(node)
|
1937
|
+
elements = [*node.lefts]
|
1938
|
+
elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
|
1939
|
+
elements.concat(node.rights)
|
1940
|
+
elements
|
1817
1941
|
end
|
1818
1942
|
|
1819
1943
|
# Negate the value of a numeric node. This is a special case where you
|
@@ -1825,7 +1949,9 @@ module Prism
|
|
1825
1949
|
case receiver.type
|
1826
1950
|
when :integer_node, :float_node
|
1827
1951
|
receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
|
1828
|
-
when :rational_node
|
1952
|
+
when :rational_node
|
1953
|
+
receiver.copy(numerator: -receiver.numerator, location: message_loc.join(receiver.location))
|
1954
|
+
when :imaginary_node
|
1829
1955
|
receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
|
1830
1956
|
end
|
1831
1957
|
end
|
@@ -1844,16 +1970,6 @@ module Prism
|
|
1844
1970
|
parameters.block.nil?
|
1845
1971
|
end
|
1846
1972
|
|
1847
|
-
# Because we have mutated the AST to allow for newlines in the middle of
|
1848
|
-
# a rational, we need to manually handle the value here.
|
1849
|
-
def rational_value(node)
|
1850
|
-
if node.numeric.is_a?(IntegerNode)
|
1851
|
-
Rational(node.numeric.value)
|
1852
|
-
else
|
1853
|
-
Rational(node.slice.gsub(/\s/, "").chomp("r"))
|
1854
|
-
end
|
1855
|
-
end
|
1856
|
-
|
1857
1973
|
# Locations in the parser gem AST are generated using this class. We
|
1858
1974
|
# store a reference to its constant to make it slightly faster to look
|
1859
1975
|
# up.
|
@@ -1876,7 +1992,7 @@ module Prism
|
|
1876
1992
|
# Note that end_offset is allowed to be nil, in which case this will
|
1877
1993
|
# search until the end of the string.
|
1878
1994
|
def srange_find(start_offset, end_offset, tokens)
|
1879
|
-
if (match = source_buffer.source.byteslice(start_offset...end_offset).match(
|
1995
|
+
if (match = source_buffer.source.byteslice(start_offset...end_offset).match(/\A(\s*)(#{tokens.join("|")})/))
|
1880
1996
|
_, whitespace, token = *match
|
1881
1997
|
token_offset = start_offset + whitespace.bytesize
|
1882
1998
|
|
@@ -1907,7 +2023,8 @@ module Prism
|
|
1907
2023
|
token(parameters.opening_loc),
|
1908
2024
|
if procarg0?(parameters.parameters)
|
1909
2025
|
parameter = parameters.parameters.requireds.first
|
1910
|
-
|
2026
|
+
visited = parameter.is_a?(RequiredParameterNode) ? visit(parameter) : parameter.accept(copy_compiler(in_destructure: true))
|
2027
|
+
[builder.procarg0(visited)].concat(visit_all(parameters.locals))
|
1911
2028
|
else
|
1912
2029
|
visit(parameters)
|
1913
2030
|
end,
|
@@ -1923,29 +2040,55 @@ module Prism
|
|
1923
2040
|
end
|
1924
2041
|
end
|
1925
2042
|
|
2043
|
+
# The parser gem automatically converts \r\n to \n, meaning our offsets
|
2044
|
+
# need to be adjusted to always subtract 1 from the length.
|
2045
|
+
def chomped_bytesize(line)
|
2046
|
+
chomped = line.chomp
|
2047
|
+
chomped.bytesize + (chomped == line ? 0 : 1)
|
2048
|
+
end
|
2049
|
+
|
1926
2050
|
# Visit a heredoc that can be either a string or an xstring.
|
1927
2051
|
def visit_heredoc(node)
|
1928
2052
|
children = Array.new
|
2053
|
+
indented = false
|
2054
|
+
|
2055
|
+
# If this is a dedenting heredoc, then we need to insert the opening
|
2056
|
+
# content into the children as well.
|
2057
|
+
if node.opening.start_with?("<<~") && node.parts.length > 0 && !node.parts.first.is_a?(StringNode)
|
2058
|
+
location = node.parts.first.location
|
2059
|
+
location = location.copy(start_offset: location.start_offset - location.start_line_slice.bytesize)
|
2060
|
+
children << builder.string_internal(token(location))
|
2061
|
+
indented = true
|
2062
|
+
end
|
2063
|
+
|
1929
2064
|
node.parts.each do |part|
|
1930
2065
|
pushing =
|
1931
2066
|
if part.is_a?(StringNode) && part.unescaped.include?("\n")
|
1932
|
-
unescaped = part.unescaped.lines
|
1933
|
-
escaped = part.content.lines
|
2067
|
+
unescaped = part.unescaped.lines
|
2068
|
+
escaped = part.content.lines
|
1934
2069
|
|
1935
|
-
escaped_lengths =
|
1936
|
-
|
1937
|
-
|
1938
|
-
|
1939
|
-
|
2070
|
+
escaped_lengths = []
|
2071
|
+
normalized_lengths = []
|
2072
|
+
|
2073
|
+
if node.opening.end_with?("'")
|
2074
|
+
escaped.each do |line|
|
2075
|
+
escaped_lengths << line.bytesize
|
2076
|
+
normalized_lengths << chomped_bytesize(line)
|
1940
2077
|
end
|
2078
|
+
else
|
2079
|
+
escaped
|
2080
|
+
.chunk_while { |before, after| before.match?(/(?<!\\)\\\r?\n$/) }
|
2081
|
+
.each do |lines|
|
2082
|
+
escaped_lengths << lines.sum(&:bytesize)
|
2083
|
+
normalized_lengths << lines.sum { |line| chomped_bytesize(line) }
|
2084
|
+
end
|
2085
|
+
end
|
1941
2086
|
|
1942
2087
|
start_offset = part.location.start_offset
|
1943
|
-
end_offset = nil
|
1944
2088
|
|
1945
|
-
unescaped.
|
1946
|
-
|
1947
|
-
|
1948
|
-
start_offset = end_offset
|
2089
|
+
unescaped.map.with_index do |unescaped_line, index|
|
2090
|
+
inner_part = builder.string_internal([unescaped_line, srange_offsets(start_offset, start_offset + normalized_lengths.fetch(index, 0))])
|
2091
|
+
start_offset += escaped_lengths.fetch(index, 0)
|
1949
2092
|
inner_part
|
1950
2093
|
end
|
1951
2094
|
else
|
@@ -1956,7 +2099,12 @@ module Prism
|
|
1956
2099
|
if child.type == :str && child.children.last == ""
|
1957
2100
|
# nothing
|
1958
2101
|
elsif child.type == :str && children.last && children.last.type == :str && !children.last.children.first.end_with?("\n")
|
1959
|
-
|
2102
|
+
appendee = children[-1]
|
2103
|
+
|
2104
|
+
location = appendee.loc
|
2105
|
+
location = location.with_expression(location.expression.join(child.loc.expression))
|
2106
|
+
|
2107
|
+
children[-1] = appendee.updated(:str, [appendee.children.first << child.children.first], location: location)
|
1960
2108
|
else
|
1961
2109
|
children << child
|
1962
2110
|
end
|
@@ -1965,8 +2113,10 @@ module Prism
|
|
1965
2113
|
|
1966
2114
|
closing = node.closing
|
1967
2115
|
closing_t = [closing.chomp, srange_offsets(node.closing_loc.start_offset, node.closing_loc.end_offset - (closing[/\s+$/]&.length || 0))]
|
2116
|
+
composed = yield children, closing_t
|
1968
2117
|
|
1969
|
-
|
2118
|
+
composed = composed.updated(nil, children[1..-1]) if indented
|
2119
|
+
composed
|
1970
2120
|
end
|
1971
2121
|
|
1972
2122
|
# Visit a numeric node and account for the optional sign.
|