prism 0.29.0 → 1.1.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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -1
  3. data/CONTRIBUTING.md +0 -4
  4. data/README.md +4 -0
  5. data/config.yml +498 -145
  6. data/docs/fuzzing.md +1 -1
  7. data/docs/parsing_rules.md +4 -1
  8. data/docs/ripper_translation.md +22 -0
  9. data/docs/serialization.md +3 -0
  10. data/ext/prism/api_node.c +2858 -2082
  11. data/ext/prism/extconf.rb +1 -1
  12. data/ext/prism/extension.c +203 -421
  13. data/ext/prism/extension.h +2 -2
  14. data/include/prism/ast.h +1732 -453
  15. data/include/prism/defines.h +36 -0
  16. data/include/prism/diagnostic.h +23 -6
  17. data/include/prism/node.h +0 -21
  18. data/include/prism/options.h +94 -3
  19. data/include/prism/parser.h +57 -28
  20. data/include/prism/regexp.h +18 -8
  21. data/include/prism/static_literals.h +3 -2
  22. data/include/prism/util/pm_char.h +1 -2
  23. data/include/prism/util/pm_constant_pool.h +0 -8
  24. data/include/prism/util/pm_integer.h +22 -15
  25. data/include/prism/util/pm_newline_list.h +11 -0
  26. data/include/prism/util/pm_string.h +28 -12
  27. data/include/prism/version.h +3 -3
  28. data/include/prism.h +0 -11
  29. data/lib/prism/compiler.rb +3 -0
  30. data/lib/prism/desugar_compiler.rb +111 -74
  31. data/lib/prism/dispatcher.rb +16 -1
  32. data/lib/prism/dot_visitor.rb +45 -34
  33. data/lib/prism/dsl.rb +660 -468
  34. data/lib/prism/ffi.rb +64 -6
  35. data/lib/prism/inspect_visitor.rb +294 -64
  36. data/lib/prism/lex_compat.rb +1 -1
  37. data/lib/prism/mutation_compiler.rb +11 -6
  38. data/lib/prism/node.rb +2469 -4973
  39. data/lib/prism/node_ext.rb +91 -14
  40. data/lib/prism/parse_result/comments.rb +0 -7
  41. data/lib/prism/parse_result/errors.rb +65 -0
  42. data/lib/prism/parse_result/newlines.rb +101 -11
  43. data/lib/prism/parse_result.rb +43 -3
  44. data/lib/prism/reflection.rb +10 -8
  45. data/lib/prism/serialize.rb +484 -609
  46. data/lib/prism/translation/parser/compiler.rb +152 -132
  47. data/lib/prism/translation/parser/lexer.rb +26 -4
  48. data/lib/prism/translation/parser.rb +9 -4
  49. data/lib/prism/translation/ripper.rb +22 -20
  50. data/lib/prism/translation/ruby_parser.rb +73 -13
  51. data/lib/prism/visitor.rb +3 -0
  52. data/lib/prism.rb +0 -4
  53. data/prism.gemspec +3 -5
  54. data/rbi/prism/dsl.rbi +521 -0
  55. data/rbi/prism/node.rbi +744 -4837
  56. data/rbi/prism/visitor.rbi +3 -0
  57. data/rbi/prism.rbi +36 -30
  58. data/sig/prism/dsl.rbs +190 -303
  59. data/sig/prism/mutation_compiler.rbs +1 -0
  60. data/sig/prism/node.rbs +759 -628
  61. data/sig/prism/parse_result.rbs +2 -0
  62. data/sig/prism/visitor.rbs +1 -0
  63. data/sig/prism.rbs +103 -64
  64. data/src/diagnostic.c +62 -28
  65. data/src/node.c +499 -1754
  66. data/src/options.c +76 -27
  67. data/src/prettyprint.c +156 -112
  68. data/src/prism.c +2773 -2081
  69. data/src/regexp.c +202 -69
  70. data/src/serialize.c +170 -50
  71. data/src/static_literals.c +63 -84
  72. data/src/token_type.c +4 -4
  73. data/src/util/pm_constant_pool.c +0 -8
  74. data/src/util/pm_integer.c +53 -25
  75. data/src/util/pm_newline_list.c +29 -0
  76. data/src/util/pm_string.c +130 -80
  77. data/src/util/pm_strpbrk.c +32 -6
  78. metadata +4 -6
  79. data/include/prism/util/pm_string_list.h +0 -44
  80. data/lib/prism/debug.rb +0 -249
  81. data/lib/prism/translation/parser/rubocop.rb +0 -73
  82. data/src/util/pm_string_list.c +0 -28
@@ -1273,8 +1273,8 @@ module Prism
1273
1273
  def visit_case_node(node)
1274
1274
  predicate = visit(node.predicate)
1275
1275
  clauses =
1276
- node.conditions.reverse_each.inject(visit(node.consequent)) do |consequent, condition|
1277
- on_when(*visit(condition), consequent)
1276
+ node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
1277
+ on_when(*visit(condition), current)
1278
1278
  end
1279
1279
 
1280
1280
  bounds(node.location)
@@ -1286,8 +1286,8 @@ module Prism
1286
1286
  def visit_case_match_node(node)
1287
1287
  predicate = visit(node.predicate)
1288
1288
  clauses =
1289
- node.conditions.reverse_each.inject(visit(node.consequent)) do |consequent, condition|
1290
- on_in(*visit(condition), consequent)
1289
+ node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
1290
+ on_in(*visit(condition), current)
1291
1291
  end
1292
1292
 
1293
1293
  bounds(node.location)
@@ -1908,7 +1908,7 @@ module Prism
1908
1908
  if node.then_keyword == "?"
1909
1909
  predicate = visit(node.predicate)
1910
1910
  truthy = visit(node.statements.body.first)
1911
- falsy = visit(node.consequent.statements.body.first)
1911
+ falsy = visit(node.subsequent.statements.body.first)
1912
1912
 
1913
1913
  bounds(node.location)
1914
1914
  on_ifop(predicate, truthy, falsy)
@@ -1921,13 +1921,13 @@ module Prism
1921
1921
  else
1922
1922
  visit(node.statements)
1923
1923
  end
1924
- consequent = visit(node.consequent)
1924
+ subsequent = visit(node.subsequent)
1925
1925
 
1926
1926
  bounds(node.location)
1927
1927
  if node.if_keyword == "if"
1928
- on_if(predicate, statements, consequent)
1928
+ on_if(predicate, statements, subsequent)
1929
1929
  else
1930
- on_elsif(predicate, statements, consequent)
1930
+ on_elsif(predicate, statements, subsequent)
1931
1931
  end
1932
1932
  else
1933
1933
  statements = visit(node.statements.body.first)
@@ -1960,7 +1960,7 @@ module Prism
1960
1960
  # ^^^^^^^^^^^^^^^^^^^^^
1961
1961
  def visit_in_node(node)
1962
1962
  # This is a special case where we're not going to call on_in directly
1963
- # because we don't have access to the consequent. Instead, we'll return
1963
+ # because we don't have access to the subsequent. Instead, we'll return
1964
1964
  # the component parts and let the parent node handle it.
1965
1965
  pattern = visit_pattern_node(node.pattern)
1966
1966
  statements =
@@ -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
@@ -2806,10 +2808,10 @@ module Prism
2806
2808
  visit(node.statements)
2807
2809
  end
2808
2810
 
2809
- consequent = visit(node.consequent)
2811
+ subsequent = visit(node.subsequent)
2810
2812
 
2811
2813
  bounds(node.location)
2812
- on_rescue(exceptions, reference, statements, consequent)
2814
+ on_rescue(exceptions, reference, statements, subsequent)
2813
2815
  end
2814
2816
 
2815
2817
  # def foo(*bar); end
@@ -3130,10 +3132,10 @@ module Prism
3130
3132
  else
3131
3133
  visit(node.statements)
3132
3134
  end
3133
- consequent = visit(node.consequent)
3135
+ else_clause = visit(node.else_clause)
3134
3136
 
3135
3137
  bounds(node.location)
3136
- on_unless(predicate, statements, consequent)
3138
+ on_unless(predicate, statements, else_clause)
3137
3139
  else
3138
3140
  statements = visit(node.statements.body.first)
3139
3141
  predicate = visit(node.predicate)
@@ -3174,7 +3176,7 @@ module Prism
3174
3176
  # ^^^^^^^^^^^^^
3175
3177
  def visit_when_node(node)
3176
3178
  # This is a special case where we're not going to call on_when directly
3177
- # because we don't have access to the consequent. Instead, we'll return
3179
+ # because we don't have access to the subsequent. Instead, we'll return
3178
3180
  # the component parts and let the parent node handle it.
3179
3181
  conditions = visit_arguments(node.conditions)
3180
3182
  statements =
@@ -1,6 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ruby_parser"
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
@@ -50,7 +55,19 @@ module Prism
50
55
  # a and b
51
56
  # ^^^^^^^
52
57
  def visit_and_node(node)
53
- s(node, :and, visit(node.left), visit(node.right))
58
+ left = visit(node.left)
59
+
60
+ if left[0] == :and
61
+ # ruby_parser has the and keyword as right-associative as opposed to
62
+ # prism which has it as left-associative. We reverse that
63
+ # associativity here.
64
+ nest = left
65
+ nest = nest[2] while nest[2][0] == :and
66
+ nest[2] = s(node, :and, nest[2], visit(node.right))
67
+ left
68
+ else
69
+ s(node, :and, left, visit(node.right))
70
+ end
54
71
  end
55
72
 
56
73
  # []
@@ -130,7 +147,7 @@ module Prism
130
147
  end
131
148
 
132
149
  current = node.rescue_clause
133
- until (current = current.consequent).nil?
150
+ until (current = current.subsequent).nil?
134
151
  result << visit(current)
135
152
  end
136
153
  end
@@ -246,6 +263,11 @@ module Prism
246
263
  when RegularExpressionNode, InterpolatedRegularExpressionNode
247
264
  return s(node, :match2, visit(node.receiver), visit(node.arguments.arguments.first))
248
265
  end
266
+
267
+ case node.arguments.arguments.first
268
+ when RegularExpressionNode, InterpolatedRegularExpressionNode
269
+ return s(node, :match3, visit(node.arguments.arguments.first), visit(node.receiver))
270
+ end
249
271
  end
250
272
  end
251
273
 
@@ -325,13 +347,13 @@ module Prism
325
347
  # case foo; when bar; end
326
348
  # ^^^^^^^^^^^^^^^^^^^^^^^
327
349
  def visit_case_node(node)
328
- s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.consequent)
350
+ s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.else_clause)
329
351
  end
330
352
 
331
353
  # case foo; in bar; end
332
354
  # ^^^^^^^^^^^^^^^^^^^^^
333
355
  def visit_case_match_node(node)
334
- s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.consequent)
356
+ s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.else_clause)
335
357
  end
336
358
 
337
359
  # class Foo; end
@@ -480,9 +502,9 @@ module Prism
480
502
  def visit_constant_path_target_node(node)
481
503
  inner =
482
504
  if node.parent.nil?
483
- s(node, :colon3, node.child.name)
505
+ s(node, :colon3, node.name)
484
506
  else
485
- s(node, :colon2, visit(node.parent), node.child.name)
507
+ s(node, :colon2, visit(node.parent), node.name)
486
508
  end
487
509
 
488
510
  s(node, :const, inner)
@@ -678,7 +700,7 @@ module Prism
678
700
  # foo ? bar : baz
679
701
  # ^^^^^^^^^^^^^^^
680
702
  def visit_if_node(node)
681
- s(node, :if, visit(node.predicate), visit(node.statements), visit(node.consequent))
703
+ s(node, :if, visit(node.predicate), visit(node.statements), visit(node.subsequent))
682
704
  end
683
705
 
684
706
  # 1i
@@ -870,6 +892,15 @@ module Prism
870
892
  else
871
893
  visited << result
872
894
  end
895
+ elsif result[0] == :dstr
896
+ if !visited.empty? && part.parts[0].is_a?(StringNode)
897
+ # If we are in the middle of an implicitly concatenated string,
898
+ # we should not have a bare string as the first part. In this
899
+ # case we need to visit just that first part and then we can
900
+ # push the rest of the parts onto the visited array.
901
+ result[1] = visit(part.parts[0])
902
+ end
903
+ visited.concat(result[1..-1])
873
904
  else
874
905
  visited << result
875
906
  end
@@ -900,12 +931,23 @@ module Prism
900
931
  results << result
901
932
  state = :interpolated_content
902
933
  end
903
- else
904
- results << result
934
+ when :interpolated_content
935
+ if result.is_a?(Array) && result[0] == :str && results[-1][0] == :str && (results[-1].line_max == result.line)
936
+ results[-1][1] << result[1]
937
+ results[-1].line_max = result.line_max
938
+ else
939
+ results << result
940
+ end
905
941
  end
906
942
  end
907
943
  end
908
944
 
945
+ # -> { it }
946
+ # ^^
947
+ def visit_it_local_variable_read_node(node)
948
+ s(node, :call, nil, :it)
949
+ end
950
+
909
951
  # foo(bar: baz)
910
952
  # ^^^^^^^^
911
953
  def visit_keyword_hash_node(node)
@@ -1118,7 +1160,19 @@ module Prism
1118
1160
  # a or b
1119
1161
  # ^^^^^^
1120
1162
  def visit_or_node(node)
1121
- s(node, :or, visit(node.left), visit(node.right))
1163
+ left = visit(node.left)
1164
+
1165
+ if left[0] == :or
1166
+ # ruby_parser has the or keyword as right-associative as opposed to
1167
+ # prism which has it as left-associative. We reverse that
1168
+ # associativity here.
1169
+ nest = left
1170
+ nest = nest[2] while nest[2][0] == :or
1171
+ nest[2] = s(node, :or, nest[2], visit(node.right))
1172
+ left
1173
+ else
1174
+ s(node, :or, left, visit(node.right))
1175
+ end
1122
1176
  end
1123
1177
 
1124
1178
  # def foo(bar, *baz); end
@@ -1374,7 +1428,13 @@ module Prism
1374
1428
  # "foo"
1375
1429
  # ^^^^^
1376
1430
  def visit_string_node(node)
1377
- s(node, :str, node.unescaped)
1431
+ unescaped = node.unescaped
1432
+
1433
+ if node.forced_binary_encoding?
1434
+ unescaped.force_encoding(Encoding::BINARY)
1435
+ end
1436
+
1437
+ s(node, :str, unescaped)
1378
1438
  end
1379
1439
 
1380
1440
  # super(foo)
@@ -1416,7 +1476,7 @@ module Prism
1416
1476
  # bar unless foo
1417
1477
  # ^^^^^^^^^^^^^^
1418
1478
  def visit_unless_node(node)
1419
- s(node, :if, visit(node.predicate), visit(node.consequent), visit(node.statements))
1479
+ s(node, :if, visit(node.predicate), visit(node.else_clause), visit(node.statements))
1420
1480
  end
1421
1481
 
1422
1482
  # until foo; bar end
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.29.0"
5
+ spec.version = "1.1.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",
@@ -84,6 +82,7 @@ Gem::Specification.new do |spec|
84
82
  "lib/prism/pack.rb",
85
83
  "lib/prism/parse_result.rb",
86
84
  "lib/prism/parse_result/comments.rb",
85
+ "lib/prism/parse_result/errors.rb",
87
86
  "lib/prism/parse_result/newlines.rb",
88
87
  "lib/prism/pattern.rb",
89
88
  "lib/prism/polyfill/byteindex.rb",
@@ -96,7 +95,6 @@ Gem::Specification.new do |spec|
96
95
  "lib/prism/translation/parser34.rb",
97
96
  "lib/prism/translation/parser/compiler.rb",
98
97
  "lib/prism/translation/parser/lexer.rb",
99
- "lib/prism/translation/parser/rubocop.rb",
100
98
  "lib/prism/translation/ripper.rb",
101
99
  "lib/prism/translation/ripper/sexp.rb",
102
100
  "lib/prism/translation/ripper/shim.rb",
@@ -105,6 +103,7 @@ Gem::Specification.new do |spec|
105
103
  "prism.gemspec",
106
104
  "rbi/prism.rbi",
107
105
  "rbi/prism/compiler.rbi",
106
+ "rbi/prism/dsl.rbi",
108
107
  "rbi/prism/inspect_visitor.rbi",
109
108
  "rbi/prism/node_ext.rbi",
110
109
  "rbi/prism/node.rbi",
@@ -149,7 +148,6 @@ Gem::Specification.new do |spec|
149
148
  "src/util/pm_list.c",
150
149
  "src/util/pm_memchr.c",
151
150
  "src/util/pm_newline_list.c",
152
- "src/util/pm_string_list.c",
153
151
  "src/util/pm_string.c",
154
152
  "src/util/pm_strncasecmp.c",
155
153
  "src/util/pm_strpbrk.c"