prism 0.29.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 +22 -1
- data/CONTRIBUTING.md +0 -4
- data/README.md +1 -0
- data/config.yml +66 -9
- data/docs/fuzzing.md +1 -1
- data/docs/ripper_translation.md +22 -0
- data/ext/prism/api_node.c +30 -12
- data/ext/prism/extension.c +107 -372
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +138 -70
- data/include/prism/diagnostic.h +7 -2
- 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/dispatcher.rb +14 -0
- data/lib/prism/dot_visitor.rb +22 -3
- data/lib/prism/dsl.rb +7 -2
- data/lib/prism/ffi.rb +24 -3
- data/lib/prism/inspect_visitor.rb +10 -8
- data/lib/prism/mutation_compiler.rb +6 -1
- data/lib/prism/node.rb +166 -241
- data/lib/prism/node_ext.rb +21 -5
- data/lib/prism/parse_result/comments.rb +0 -7
- data/lib/prism/parse_result/newlines.rb +101 -11
- data/lib/prism/parse_result.rb +17 -0
- data/lib/prism/reflection.rb +3 -1
- data/lib/prism/serialize.rb +80 -67
- data/lib/prism/translation/parser/compiler.rb +134 -114
- data/lib/prism/translation/parser.rb +6 -1
- data/lib/prism/translation/ripper.rb +8 -6
- data/lib/prism/translation/ruby_parser.rb +23 -5
- data/lib/prism/visitor.rb +3 -0
- data/lib/prism.rb +0 -4
- data/prism.gemspec +1 -4
- data/rbi/prism/node.rbi +63 -6
- data/rbi/prism/visitor.rbi +3 -0
- data/rbi/prism.rbi +6 -0
- data/sig/prism/dsl.rbs +4 -1
- data/sig/prism/mutation_compiler.rbs +1 -0
- data/sig/prism/node.rbs +28 -4
- data/sig/prism/visitor.rbs +1 -0
- data/sig/prism.rbs +21 -0
- data/src/diagnostic.c +27 -17
- data/src/node.c +408 -1666
- data/src/prettyprint.c +49 -6
- data/src/prism.c +958 -991
- data/src/regexp.c +133 -68
- data/src/serialize.c +6 -1
- data/src/static_literals.c +63 -84
- data/src/token_type.c +2 -2
- 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 +2 -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))
|
@@ -881,7 +895,7 @@ module Prism
|
|
881
895
|
# 1i
|
882
896
|
# ^^
|
883
897
|
def visit_imaginary_node(node)
|
884
|
-
visit_numeric(node, builder.complex([
|
898
|
+
visit_numeric(node, builder.complex([Complex(0, node.numeric.value), srange(node.location)]))
|
885
899
|
end
|
886
900
|
|
887
901
|
# { foo: }
|
@@ -1064,36 +1078,7 @@ module Prism
|
|
1064
1078
|
# ^^^^^^^^^^^^
|
1065
1079
|
def visit_interpolated_string_node(node)
|
1066
1080
|
if node.heredoc?
|
1067
|
-
children, closing
|
1068
|
-
opening = token(node.opening_loc)
|
1069
|
-
|
1070
|
-
start_offset = node.opening_loc.end_offset + 1
|
1071
|
-
end_offset = node.parts.first.location.start_offset
|
1072
|
-
|
1073
|
-
# In the below case, the offsets should be the same:
|
1074
|
-
#
|
1075
|
-
# <<~HEREDOC
|
1076
|
-
# a #{b}
|
1077
|
-
# HEREDOC
|
1078
|
-
#
|
1079
|
-
# But in this case, the end_offset would be greater than the start_offset:
|
1080
|
-
#
|
1081
|
-
# <<~HEREDOC
|
1082
|
-
# #{b}
|
1083
|
-
# HEREDOC
|
1084
|
-
#
|
1085
|
-
# So we need to make sure the result node's heredoc range is correct, without updating the children
|
1086
|
-
result = if start_offset < end_offset
|
1087
|
-
# We need to add a padding string to ensure that the heredoc has correct range for its body
|
1088
|
-
padding_string_node = builder.string_internal(["", srange_offsets(start_offset, end_offset)])
|
1089
|
-
node_with_correct_location = builder.string_compose(opening, [padding_string_node, *children], closing)
|
1090
|
-
# But the padding string should not be included in the final AST, so we need to update the result's children
|
1091
|
-
node_with_correct_location.updated(:dstr, children)
|
1092
|
-
else
|
1093
|
-
builder.string_compose(opening, children, closing)
|
1094
|
-
end
|
1095
|
-
|
1096
|
-
return result
|
1081
|
+
return visit_heredoc(node) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
|
1097
1082
|
end
|
1098
1083
|
|
1099
1084
|
parts = if node.parts.one? { |part| part.type == :string_node }
|
@@ -1137,8 +1122,7 @@ module Prism
|
|
1137
1122
|
# ^^^^^^^^^^^^
|
1138
1123
|
def visit_interpolated_x_string_node(node)
|
1139
1124
|
if node.heredoc?
|
1140
|
-
children, closing
|
1141
|
-
builder.xstring_compose(token(node.opening_loc), children, closing)
|
1125
|
+
visit_heredoc(node) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
|
1142
1126
|
else
|
1143
1127
|
builder.xstring_compose(
|
1144
1128
|
token(node.opening_loc),
|
@@ -1148,6 +1132,12 @@ module Prism
|
|
1148
1132
|
end
|
1149
1133
|
end
|
1150
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
|
+
|
1151
1141
|
# -> { it }
|
1152
1142
|
# ^^^^^^^^^
|
1153
1143
|
def visit_it_parameters_node(node)
|
@@ -1201,14 +1191,7 @@ module Prism
|
|
1201
1191
|
# foo
|
1202
1192
|
# ^^^
|
1203
1193
|
def visit_local_variable_read_node(node)
|
1204
|
-
name
|
1205
|
-
|
1206
|
-
# This is just a guess. parser doesn't have support for the implicit
|
1207
|
-
# `it` variable yet, so we'll probably have to visit this once it
|
1208
|
-
# does.
|
1209
|
-
name = :it if name == :"0it"
|
1210
|
-
|
1211
|
-
builder.ident([name, srange(node.location)]).updated(:lvar)
|
1194
|
+
builder.ident([node.name, srange(node.location)]).updated(:lvar)
|
1212
1195
|
end
|
1213
1196
|
|
1214
1197
|
# foo = 1
|
@@ -1312,13 +1295,9 @@ module Prism
|
|
1312
1295
|
# foo, bar = baz
|
1313
1296
|
# ^^^^^^^^
|
1314
1297
|
def visit_multi_target_node(node)
|
1315
|
-
elements = [*node.lefts]
|
1316
|
-
elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
|
1317
|
-
elements.concat(node.rights)
|
1318
|
-
|
1319
1298
|
builder.multi_lhs(
|
1320
1299
|
token(node.lparen_loc),
|
1321
|
-
visit_all(
|
1300
|
+
visit_all(multi_target_elements(node)),
|
1322
1301
|
token(node.rparen_loc)
|
1323
1302
|
)
|
1324
1303
|
end
|
@@ -1326,9 +1305,11 @@ module Prism
|
|
1326
1305
|
# foo, bar = baz
|
1327
1306
|
# ^^^^^^^^^^^^^^
|
1328
1307
|
def visit_multi_write_node(node)
|
1329
|
-
elements =
|
1330
|
-
|
1331
|
-
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
|
1332
1313
|
|
1333
1314
|
builder.multi_assign(
|
1334
1315
|
builder.multi_lhs(
|
@@ -1409,12 +1390,12 @@ module Prism
|
|
1409
1390
|
|
1410
1391
|
if node.requireds.any?
|
1411
1392
|
node.requireds.each do |required|
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1393
|
+
params <<
|
1394
|
+
if required.is_a?(RequiredParameterNode)
|
1395
|
+
visit(required)
|
1396
|
+
else
|
1397
|
+
required.accept(copy_compiler(in_destructure: true))
|
1398
|
+
end
|
1418
1399
|
end
|
1419
1400
|
end
|
1420
1401
|
|
@@ -1423,12 +1404,12 @@ module Prism
|
|
1423
1404
|
|
1424
1405
|
if node.posts.any?
|
1425
1406
|
node.posts.each do |post|
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1407
|
+
params <<
|
1408
|
+
if post.is_a?(RequiredParameterNode)
|
1409
|
+
visit(post)
|
1410
|
+
else
|
1411
|
+
post.accept(copy_compiler(in_destructure: true))
|
1412
|
+
end
|
1432
1413
|
end
|
1433
1414
|
end
|
1434
1415
|
|
@@ -1514,7 +1495,7 @@ module Prism
|
|
1514
1495
|
# 1r
|
1515
1496
|
# ^^
|
1516
1497
|
def visit_rational_node(node)
|
1517
|
-
visit_numeric(node, builder.rational([
|
1498
|
+
visit_numeric(node, builder.rational([node.value, srange(node.location)]))
|
1518
1499
|
end
|
1519
1500
|
|
1520
1501
|
# redo
|
@@ -1526,9 +1507,20 @@ module Prism
|
|
1526
1507
|
# /foo/
|
1527
1508
|
# ^^^^^
|
1528
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
|
+
|
1529
1521
|
builder.regexp_compose(
|
1530
1522
|
token(node.opening_loc),
|
1531
|
-
|
1523
|
+
parts,
|
1532
1524
|
[node.closing[0], srange_offsets(node.closing_loc.start_offset, node.closing_loc.start_offset + 1)],
|
1533
1525
|
builder.regexp_options([node.closing[1..], srange_offsets(node.closing_loc.start_offset + 1, node.closing_loc.end_offset)])
|
1534
1526
|
)
|
@@ -1674,10 +1666,11 @@ module Prism
|
|
1674
1666
|
# ^^^^^
|
1675
1667
|
def visit_string_node(node)
|
1676
1668
|
if node.heredoc?
|
1677
|
-
children, closing
|
1678
|
-
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) }
|
1679
1670
|
elsif node.opening == "?"
|
1680
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))
|
1681
1674
|
else
|
1682
1675
|
content_lines = node.content.lines
|
1683
1676
|
unescaped_lines = node.unescaped.lines
|
@@ -1877,8 +1870,7 @@ module Prism
|
|
1877
1870
|
# ^^^^^
|
1878
1871
|
def visit_x_string_node(node)
|
1879
1872
|
if node.heredoc?
|
1880
|
-
children, closing
|
1881
|
-
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) }
|
1882
1874
|
else
|
1883
1875
|
parts = if node.unescaped.lines.one?
|
1884
1876
|
[builder.string_internal([node.unescaped, srange(node.content_loc)])]
|
@@ -1940,10 +1932,12 @@ module Prism
|
|
1940
1932
|
forwarding
|
1941
1933
|
end
|
1942
1934
|
|
1943
|
-
#
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
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
|
1947
1941
|
end
|
1948
1942
|
|
1949
1943
|
# Negate the value of a numeric node. This is a special case where you
|
@@ -1955,7 +1949,9 @@ module Prism
|
|
1955
1949
|
case receiver.type
|
1956
1950
|
when :integer_node, :float_node
|
1957
1951
|
receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
|
1958
|
-
when :rational_node
|
1952
|
+
when :rational_node
|
1953
|
+
receiver.copy(numerator: -receiver.numerator, location: message_loc.join(receiver.location))
|
1954
|
+
when :imaginary_node
|
1959
1955
|
receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
|
1960
1956
|
end
|
1961
1957
|
end
|
@@ -1974,16 +1970,6 @@ module Prism
|
|
1974
1970
|
parameters.block.nil?
|
1975
1971
|
end
|
1976
1972
|
|
1977
|
-
# Because we have mutated the AST to allow for newlines in the middle of
|
1978
|
-
# a rational, we need to manually handle the value here.
|
1979
|
-
def rational_value(node)
|
1980
|
-
if node.numeric.is_a?(IntegerNode)
|
1981
|
-
Rational(node.numeric.value)
|
1982
|
-
else
|
1983
|
-
Rational(node.slice.gsub(/\s/, "").chomp("r"))
|
1984
|
-
end
|
1985
|
-
end
|
1986
|
-
|
1987
1973
|
# Locations in the parser gem AST are generated using this class. We
|
1988
1974
|
# store a reference to its constant to make it slightly faster to look
|
1989
1975
|
# up.
|
@@ -2006,7 +1992,7 @@ module Prism
|
|
2006
1992
|
# Note that end_offset is allowed to be nil, in which case this will
|
2007
1993
|
# search until the end of the string.
|
2008
1994
|
def srange_find(start_offset, end_offset, tokens)
|
2009
|
-
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("|")})/))
|
2010
1996
|
_, whitespace, token = *match
|
2011
1997
|
token_offset = start_offset + whitespace.bytesize
|
2012
1998
|
|
@@ -2037,7 +2023,8 @@ module Prism
|
|
2037
2023
|
token(parameters.opening_loc),
|
2038
2024
|
if procarg0?(parameters.parameters)
|
2039
2025
|
parameter = parameters.parameters.requireds.first
|
2040
|
-
|
2026
|
+
visited = parameter.is_a?(RequiredParameterNode) ? visit(parameter) : parameter.accept(copy_compiler(in_destructure: true))
|
2027
|
+
[builder.procarg0(visited)].concat(visit_all(parameters.locals))
|
2041
2028
|
else
|
2042
2029
|
visit(parameters)
|
2043
2030
|
end,
|
@@ -2053,29 +2040,55 @@ module Prism
|
|
2053
2040
|
end
|
2054
2041
|
end
|
2055
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
|
+
|
2056
2050
|
# Visit a heredoc that can be either a string or an xstring.
|
2057
2051
|
def visit_heredoc(node)
|
2058
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
|
+
|
2059
2064
|
node.parts.each do |part|
|
2060
2065
|
pushing =
|
2061
2066
|
if part.is_a?(StringNode) && part.unescaped.include?("\n")
|
2062
|
-
unescaped = part.unescaped.lines
|
2063
|
-
escaped = part.content.lines
|
2067
|
+
unescaped = part.unescaped.lines
|
2068
|
+
escaped = part.content.lines
|
2064
2069
|
|
2065
|
-
escaped_lengths =
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
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)
|
2070
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
|
2071
2086
|
|
2072
2087
|
start_offset = part.location.start_offset
|
2073
|
-
end_offset = nil
|
2074
2088
|
|
2075
|
-
unescaped.
|
2076
|
-
|
2077
|
-
|
2078
|
-
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)
|
2079
2092
|
inner_part
|
2080
2093
|
end
|
2081
2094
|
else
|
@@ -2086,7 +2099,12 @@ module Prism
|
|
2086
2099
|
if child.type == :str && child.children.last == ""
|
2087
2100
|
# nothing
|
2088
2101
|
elsif child.type == :str && children.last && children.last.type == :str && !children.last.children.first.end_with?("\n")
|
2089
|
-
|
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)
|
2090
2108
|
else
|
2091
2109
|
children << child
|
2092
2110
|
end
|
@@ -2095,8 +2113,10 @@ module Prism
|
|
2095
2113
|
|
2096
2114
|
closing = node.closing
|
2097
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
|
2098
2117
|
|
2099
|
-
|
2118
|
+
composed = composed.updated(nil, children[1..-1]) if indented
|
2119
|
+
composed
|
2100
2120
|
end
|
2101
2121
|
|
2102
2122
|
# Visit a numeric node and account for the optional sign.
|
@@ -2217,6 +2217,13 @@ module Prism
|
|
2217
2217
|
end
|
2218
2218
|
end
|
2219
2219
|
|
2220
|
+
# -> { it }
|
2221
|
+
# ^^
|
2222
|
+
def visit_it_local_variable_read_node(node)
|
2223
|
+
bounds(node.location)
|
2224
|
+
on_vcall(on_ident(node.slice))
|
2225
|
+
end
|
2226
|
+
|
2220
2227
|
# -> { it }
|
2221
2228
|
# ^^^^^^^^^
|
2222
2229
|
def visit_it_parameters_node(node)
|
@@ -2312,12 +2319,7 @@ module Prism
|
|
2312
2319
|
# ^^^
|
2313
2320
|
def visit_local_variable_read_node(node)
|
2314
2321
|
bounds(node.location)
|
2315
|
-
|
2316
|
-
if node.name == :"0it"
|
2317
|
-
on_vcall(on_ident(node.slice))
|
2318
|
-
else
|
2319
|
-
on_var_ref(on_ident(node.slice))
|
2320
|
-
end
|
2322
|
+
on_var_ref(on_ident(node.slice))
|
2321
2323
|
end
|
2322
2324
|
|
2323
2325
|
# foo = 1
|
@@ -1,6 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
begin
|
4
|
+
require "ruby_parser"
|
5
|
+
rescue LoadError
|
6
|
+
warn(%q{Error: Unable to load ruby_parser. Add `gem "ruby_parser"` to your Gemfile.})
|
7
|
+
exit(1)
|
8
|
+
end
|
4
9
|
|
5
10
|
module Prism
|
6
11
|
module Translation
|
@@ -480,9 +485,9 @@ module Prism
|
|
480
485
|
def visit_constant_path_target_node(node)
|
481
486
|
inner =
|
482
487
|
if node.parent.nil?
|
483
|
-
s(node, :colon3, node.
|
488
|
+
s(node, :colon3, node.name)
|
484
489
|
else
|
485
|
-
s(node, :colon2, visit(node.parent), node.
|
490
|
+
s(node, :colon2, visit(node.parent), node.name)
|
486
491
|
end
|
487
492
|
|
488
493
|
s(node, :const, inner)
|
@@ -870,6 +875,8 @@ module Prism
|
|
870
875
|
else
|
871
876
|
visited << result
|
872
877
|
end
|
878
|
+
elsif result[0] == :dstr
|
879
|
+
visited.concat(result[1..-1])
|
873
880
|
else
|
874
881
|
visited << result
|
875
882
|
end
|
@@ -900,12 +907,23 @@ module Prism
|
|
900
907
|
results << result
|
901
908
|
state = :interpolated_content
|
902
909
|
end
|
903
|
-
|
904
|
-
results
|
910
|
+
when :interpolated_content
|
911
|
+
if result.is_a?(Array) && result[0] == :str && results[-1][0] == :str && (results[-1].line_max == result.line)
|
912
|
+
results[-1][1] << result[1]
|
913
|
+
results[-1].line_max = result.line_max
|
914
|
+
else
|
915
|
+
results << result
|
916
|
+
end
|
905
917
|
end
|
906
918
|
end
|
907
919
|
end
|
908
920
|
|
921
|
+
# -> { it }
|
922
|
+
# ^^
|
923
|
+
def visit_it_local_variable_read_node(node)
|
924
|
+
s(node, :call, nil, :it)
|
925
|
+
end
|
926
|
+
|
909
927
|
# foo(bar: baz)
|
910
928
|
# ^^^^^^^^
|
911
929
|
def visit_keyword_hash_node(node)
|
data/lib/prism/visitor.rb
CHANGED
@@ -313,6 +313,9 @@ module Prism
|
|
313
313
|
# Visit a InterpolatedXStringNode node
|
314
314
|
alias visit_interpolated_x_string_node visit_child_nodes
|
315
315
|
|
316
|
+
# Visit a ItLocalVariableReadNode node
|
317
|
+
alias visit_it_local_variable_read_node visit_child_nodes
|
318
|
+
|
316
319
|
# Visit a ItParametersNode node
|
317
320
|
alias visit_it_parameters_node visit_child_nodes
|
318
321
|
|
data/lib/prism.rb
CHANGED
@@ -13,7 +13,6 @@ module Prism
|
|
13
13
|
|
14
14
|
autoload :BasicVisitor, "prism/visitor"
|
15
15
|
autoload :Compiler, "prism/compiler"
|
16
|
-
autoload :Debug, "prism/debug"
|
17
16
|
autoload :DesugarCompiler, "prism/desugar_compiler"
|
18
17
|
autoload :Dispatcher, "prism/dispatcher"
|
19
18
|
autoload :DotVisitor, "prism/dot_visitor"
|
@@ -32,7 +31,6 @@ module Prism
|
|
32
31
|
# Some of these constants are not meant to be exposed, so marking them as
|
33
32
|
# private here.
|
34
33
|
|
35
|
-
private_constant :Debug
|
36
34
|
private_constant :LexCompat
|
37
35
|
private_constant :LexRipper
|
38
36
|
|
@@ -71,8 +69,6 @@ require_relative "prism/polyfill/byteindex"
|
|
71
69
|
require_relative "prism/node"
|
72
70
|
require_relative "prism/node_ext"
|
73
71
|
require_relative "prism/parse_result"
|
74
|
-
require_relative "prism/parse_result/comments"
|
75
|
-
require_relative "prism/parse_result/newlines"
|
76
72
|
|
77
73
|
# This is a Ruby implementation of the prism parser. If we're running on CRuby
|
78
74
|
# and we haven't explicitly set the PRISM_FFI_BACKEND environment variable, then
|
data/prism.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "prism"
|
5
|
-
spec.version = "0.
|
5
|
+
spec.version = "0.30.0"
|
6
6
|
spec.authors = ["Shopify"]
|
7
7
|
spec.email = ["ruby@shopify.com"]
|
8
8
|
|
@@ -65,12 +65,10 @@ Gem::Specification.new do |spec|
|
|
65
65
|
"include/prism/util/pm_newline_list.h",
|
66
66
|
"include/prism/util/pm_strncasecmp.h",
|
67
67
|
"include/prism/util/pm_string.h",
|
68
|
-
"include/prism/util/pm_string_list.h",
|
69
68
|
"include/prism/util/pm_strpbrk.h",
|
70
69
|
"include/prism/version.h",
|
71
70
|
"lib/prism.rb",
|
72
71
|
"lib/prism/compiler.rb",
|
73
|
-
"lib/prism/debug.rb",
|
74
72
|
"lib/prism/desugar_compiler.rb",
|
75
73
|
"lib/prism/dispatcher.rb",
|
76
74
|
"lib/prism/dot_visitor.rb",
|
@@ -149,7 +147,6 @@ Gem::Specification.new do |spec|
|
|
149
147
|
"src/util/pm_list.c",
|
150
148
|
"src/util/pm_memchr.c",
|
151
149
|
"src/util/pm_newline_list.c",
|
152
|
-
"src/util/pm_string_list.c",
|
153
150
|
"src/util/pm_string.c",
|
154
151
|
"src/util/pm_strncasecmp.c",
|
155
152
|
"src/util/pm_strpbrk.c"
|