prism 1.9.0 → 2.0.0.rc2

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 (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/LICENSE.md +1 -1
  5. data/Makefile +41 -12
  6. data/README.md +35 -97
  7. data/config.yml +174 -161
  8. data/docs/build_system.md +2 -2
  9. data/docs/configuration.md +5 -4
  10. data/docs/encoding.md +2 -2
  11. data/docs/fuzzing.md +4 -11
  12. data/docs/javascript.md +19 -4
  13. data/docs/mapping.md +1 -1
  14. data/docs/releasing.md +77 -5
  15. data/docs/relocation.md +2 -4
  16. data/docs/serialization.md +22 -24
  17. data/docs/testing.md +46 -29
  18. data/ext/prism/api_node.c +1461 -1401
  19. data/ext/prism/extconf.rb +3 -4
  20. data/ext/prism/extension.c +796 -422
  21. data/ext/prism/extension.h +3 -3
  22. data/include/prism/arena.h +37 -0
  23. data/include/prism/ast.h +2727 -610
  24. data/include/prism/buffer.h +52 -0
  25. data/include/prism/comments.h +55 -0
  26. data/include/prism/compiler/accel.h +26 -0
  27. data/include/prism/compiler/align.h +36 -0
  28. data/include/prism/compiler/assume.h +25 -0
  29. data/include/prism/compiler/bswap.h +46 -0
  30. data/include/prism/compiler/endianness.h +34 -0
  31. data/include/prism/compiler/exported.h +24 -0
  32. data/include/prism/compiler/fallthrough.h +22 -0
  33. data/include/prism/compiler/filesystem.h +32 -0
  34. data/include/prism/compiler/flex_array.h +19 -0
  35. data/include/prism/compiler/force_inline.h +21 -0
  36. data/include/prism/compiler/format.h +25 -0
  37. data/include/prism/compiler/inline.h +17 -0
  38. data/include/prism/compiler/nodiscard.h +22 -0
  39. data/include/prism/compiler/nonnull.h +18 -0
  40. data/include/prism/compiler/unused.h +18 -0
  41. data/include/prism/constant_pool.h +81 -0
  42. data/include/prism/diagnostic.h +38 -403
  43. data/include/prism/errors_format.h +53 -0
  44. data/include/prism/excludes.h +29 -0
  45. data/include/prism/integer.h +41 -0
  46. data/include/prism/internal/allocator.h +68 -0
  47. data/include/prism/internal/allocator_debug.h +88 -0
  48. data/include/prism/internal/arena.h +108 -0
  49. data/include/prism/internal/bit.h +42 -0
  50. data/include/prism/internal/buffer.h +94 -0
  51. data/include/prism/internal/char.h +145 -0
  52. data/include/prism/internal/comments.h +53 -0
  53. data/include/prism/internal/constant_pool.h +152 -0
  54. data/include/prism/internal/diagnostic.h +389 -0
  55. data/include/prism/{encoding.h → internal/encoding.h} +27 -68
  56. data/include/prism/internal/integer.h +68 -0
  57. data/include/prism/internal/isinf.h +16 -0
  58. data/include/prism/internal/line_offset_list.h +34 -0
  59. data/include/prism/{util/pm_list.h → internal/list.h} +11 -52
  60. data/include/prism/internal/magic_comments.h +23 -0
  61. data/include/prism/internal/memchr.h +15 -0
  62. data/include/prism/internal/node.h +38 -0
  63. data/include/prism/internal/options.h +232 -0
  64. data/include/prism/internal/parser.h +1004 -0
  65. data/include/prism/internal/regexp.h +26 -0
  66. data/include/prism/internal/serialize.h +39 -0
  67. data/include/prism/internal/source.h +72 -0
  68. data/include/prism/{static_literals.h → internal/static_literals.h} +26 -47
  69. data/include/prism/internal/stringy.h +35 -0
  70. data/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
  71. data/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
  72. data/include/prism/internal/tokens.h +11 -0
  73. data/include/prism/internal/xxh3.h +16 -0
  74. data/include/prism/json.h +32 -0
  75. data/include/prism/line_offset_list.h +61 -0
  76. data/include/prism/magic_comments.h +35 -0
  77. data/include/prism/node.h +18 -53
  78. data/include/prism/options.h +146 -280
  79. data/include/prism/parser.h +356 -867
  80. data/include/prism/prettyprint.h +6 -9
  81. data/include/prism/serialize.h +115 -0
  82. data/include/prism/source.h +155 -0
  83. data/include/prism/stream.h +28 -0
  84. data/include/prism/string_query.h +74 -0
  85. data/include/prism/stringy.h +72 -0
  86. data/include/prism/version.h +12 -3
  87. data/include/prism.h +43 -320
  88. data/lib/prism/compiler.rb +319 -305
  89. data/lib/prism/desugar_compiler.rb +105 -34
  90. data/lib/prism/dispatcher.rb +646 -473
  91. data/lib/prism/dot_visitor.rb +592 -511
  92. data/lib/prism/dsl.rb +391 -25
  93. data/lib/prism/ffi.rb +258 -90
  94. data/lib/prism/inspect_visitor.rb +357 -325
  95. data/lib/prism/lex_compat.rb +254 -212
  96. data/lib/prism/mutation_compiler.rb +313 -305
  97. data/lib/prism/node.rb +20966 -6992
  98. data/lib/prism/node_ext.rb +180 -187
  99. data/lib/prism/node_find.rb +215 -0
  100. data/lib/prism/parse_result/errors.rb +7 -1
  101. data/lib/prism/parse_result/newlines.rb +276 -8
  102. data/lib/prism/parse_result.rb +468 -139
  103. data/lib/prism/pattern.rb +65 -20
  104. data/lib/prism/reflection.rb +23 -12
  105. data/lib/prism/relocation.rb +149 -87
  106. data/lib/prism/serialize.rb +3460 -539
  107. data/lib/prism/string_query.rb +24 -1
  108. data/lib/prism/translation/parser/builder.rb +10 -2
  109. data/lib/prism/translation/parser/compiler.rb +44 -52
  110. data/lib/prism/translation/parser/lexer.rb +41 -92
  111. data/lib/prism/translation/parser.rb +1 -1
  112. data/lib/prism/translation/parser_current.rb +1 -1
  113. data/lib/prism/translation/ripper/lexer.rb +8 -10
  114. data/lib/prism/translation/ripper/sexp.rb +2 -10
  115. data/lib/prism/translation/ripper/shim.rb +2 -0
  116. data/lib/prism/translation/ripper.rb +967 -209
  117. data/lib/prism/translation/ruby_parser.rb +73 -316
  118. data/lib/prism/translation.rb +2 -0
  119. data/lib/prism/visitor.rb +632 -5
  120. data/lib/prism.rb +79 -9
  121. data/prism.gemspec +128 -62
  122. data/rbi/generated/prism/compiler.rbi +489 -0
  123. data/rbi/generated/prism/desugar_compiler.rbi +306 -0
  124. data/rbi/generated/prism/dispatcher.rbi +1138 -0
  125. data/rbi/generated/prism/dot_visitor.rbi +618 -0
  126. data/rbi/generated/prism/dsl.rbi +751 -0
  127. data/rbi/generated/prism/inspect_visitor.rbi +503 -0
  128. data/rbi/generated/prism/lex_compat.rbi +162 -0
  129. data/rbi/generated/prism/mutation_compiler.rbi +464 -0
  130. data/rbi/generated/prism/node.rbi +14407 -0
  131. data/rbi/generated/prism/node_ext.rbi +259 -0
  132. data/rbi/generated/prism/node_find.rbi +79 -0
  133. data/rbi/generated/prism/parse_result/errors.rbi +21 -0
  134. data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
  135. data/rbi/generated/prism/parse_result.rbi +776 -0
  136. data/rbi/generated/prism/pattern.rbi +134 -0
  137. data/rbi/generated/prism/reflection.rbi +89 -0
  138. data/rbi/generated/prism/relocation.rbi +329 -0
  139. data/rbi/generated/prism/serialize.rbi +184 -0
  140. data/rbi/generated/prism/string_query.rbi +43 -0
  141. data/rbi/generated/prism/translation.rbi +7 -0
  142. data/rbi/generated/prism/visitor.rbi +650 -0
  143. data/rbi/generated/prism.rbi +86 -0
  144. data/rbi/prism/translation/parser_versions.rbi +5 -0
  145. data/rbi/rubyvm/node_find.rbi +14 -0
  146. data/sig/generated/prism/compiler.rbs +492 -0
  147. data/sig/generated/prism/desugar_compiler.rbs +305 -0
  148. data/sig/generated/prism/dispatcher.rbs +1292 -0
  149. data/sig/generated/prism/dot_visitor.rbs +635 -0
  150. data/sig/generated/prism/dsl.rbs +928 -0
  151. data/sig/generated/prism/inspect_visitor.rbs +509 -0
  152. data/sig/generated/prism/lex_compat.rbs +166 -0
  153. data/sig/{prism → generated/prism}/mutation_compiler.rbs +309 -4
  154. data/sig/generated/prism/node.rbs +20896 -0
  155. data/sig/generated/prism/node_ext.rbs +290 -0
  156. data/sig/generated/prism/node_find.rbs +90 -0
  157. data/sig/generated/prism/parse_result/errors.rbs +22 -0
  158. data/sig/generated/prism/parse_result/newlines.rbs +223 -0
  159. data/sig/generated/prism/parse_result.rbs +871 -0
  160. data/sig/generated/prism/pattern.rbs +156 -0
  161. data/sig/generated/prism/reflection.rbs +101 -0
  162. data/sig/generated/prism/relocation.rbs +428 -0
  163. data/sig/generated/prism/serialize.rbs +198 -0
  164. data/sig/generated/prism/string_query.rbs +43 -0
  165. data/sig/generated/prism/translation.rbs +8 -0
  166. data/sig/generated/prism/visitor.rbs +1111 -0
  167. data/sig/generated/prism.rbs +84 -0
  168. data/sig/manifest.yaml +2 -0
  169. data/src/arena.c +117 -0
  170. data/src/{util/pm_buffer.c → buffer.c} +53 -21
  171. data/src/{util/pm_char.c → char.c} +28 -57
  172. data/src/comments.c +454 -0
  173. data/src/constant_pool.c +406 -0
  174. data/src/diagnostic.c +97 -65
  175. data/src/encoding.c +8 -3
  176. data/src/errors_format.c +519 -0
  177. data/src/{util/pm_integer.c → integer.c} +33 -22
  178. data/src/json.c +5733 -0
  179. data/src/line_offset_list.c +100 -0
  180. data/src/list.c +24 -0
  181. data/src/{util/pm_memchr.c → memchr.c} +8 -6
  182. data/src/node.c +3504 -7674
  183. data/src/options.c +162 -49
  184. data/src/parser.c +367 -0
  185. data/src/prettyprint.c +421 -354
  186. data/src/prism.c +8402 -7161
  187. data/src/regexp.c +961 -45
  188. data/src/serialize.c +460 -424
  189. data/src/source.c +518 -0
  190. data/src/static_literals.c +111 -43
  191. data/src/string_query.c +180 -0
  192. data/src/stringy.c +91 -0
  193. data/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
  194. data/src/strpbrk.c +447 -0
  195. data/src/{token_type.c → tokens.c} +39 -18
  196. data/src/xxh3.c +292 -0
  197. metadata +128 -63
  198. data/ext/prism/api_pack.c +0 -276
  199. data/include/prism/defines.h +0 -260
  200. data/include/prism/pack.h +0 -163
  201. data/include/prism/regexp.h +0 -43
  202. data/include/prism/util/pm_buffer.h +0 -236
  203. data/include/prism/util/pm_char.h +0 -204
  204. data/include/prism/util/pm_constant_pool.h +0 -218
  205. data/include/prism/util/pm_integer.h +0 -130
  206. data/include/prism/util/pm_memchr.h +0 -29
  207. data/include/prism/util/pm_newline_list.h +0 -113
  208. data/include/prism/util/pm_string.h +0 -200
  209. data/lib/prism/pack.rb +0 -230
  210. data/lib/prism/parse_result/comments.rb +0 -188
  211. data/rbi/prism/compiler.rbi +0 -12
  212. data/rbi/prism/dsl.rbi +0 -524
  213. data/rbi/prism/inspect_visitor.rbi +0 -12
  214. data/rbi/prism/node.rbi +0 -8750
  215. data/rbi/prism/node_ext.rbi +0 -107
  216. data/rbi/prism/parse_result.rbi +0 -404
  217. data/rbi/prism/reflection.rbi +0 -58
  218. data/rbi/prism/string_query.rbi +0 -12
  219. data/rbi/prism/visitor.rbi +0 -473
  220. data/rbi/prism.rbi +0 -63
  221. data/sig/prism/compiler.rbs +0 -9
  222. data/sig/prism/dispatcher.rbs +0 -19
  223. data/sig/prism/dot_visitor.rbs +0 -6
  224. data/sig/prism/dsl.rbs +0 -351
  225. data/sig/prism/inspect_visitor.rbs +0 -22
  226. data/sig/prism/lex_compat.rbs +0 -10
  227. data/sig/prism/node.rbs +0 -4042
  228. data/sig/prism/node_ext.rbs +0 -149
  229. data/sig/prism/pack.rbs +0 -43
  230. data/sig/prism/parse_result/comments.rbs +0 -38
  231. data/sig/prism/parse_result.rbs +0 -197
  232. data/sig/prism/pattern.rbs +0 -13
  233. data/sig/prism/reflection.rbs +0 -50
  234. data/sig/prism/relocation.rbs +0 -185
  235. data/sig/prism/serialize.rbs +0 -8
  236. data/sig/prism/string_query.rbs +0 -11
  237. data/sig/prism/visitor.rbs +0 -169
  238. data/sig/prism.rbs +0 -272
  239. data/src/pack.c +0 -509
  240. data/src/util/pm_constant_pool.c +0 -342
  241. data/src/util/pm_list.c +0 -49
  242. data/src/util/pm_newline_list.c +0 -125
  243. data/src/util/pm_string.c +0 -381
  244. data/src/util/pm_strpbrk.c +0 -206
@@ -1,31 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
  # :markup: markdown
3
+ #--
4
+ # rbs_inline: enabled
3
5
 
4
6
  module Prism
5
7
  # Query methods that allow categorizing strings based on their context for
6
8
  # where they could be valid in a Ruby syntax tree.
7
9
  class StringQuery
10
+ # @rbs!
11
+ # def self.local?: (String string) -> bool
12
+ # def self.constant?: (String string) -> bool
13
+ # def self.method_name?: (String string) -> bool
14
+ # def self.keyword?: (String string) -> bool
15
+
8
16
  # The string that this query is wrapping.
9
- attr_reader :string
17
+ attr_reader :string #: String
10
18
 
11
19
  # Initialize a new query with the given string.
20
+ #
21
+ #: (String string) -> void
12
22
  def initialize(string)
13
23
  @string = string
14
24
  end
15
25
 
16
26
  # Whether or not this string is a valid local variable name.
27
+ #
28
+ #: () -> bool
17
29
  def local?
18
30
  StringQuery.local?(string)
19
31
  end
20
32
 
21
33
  # Whether or not this string is a valid constant name.
34
+ #
35
+ #: () -> bool
22
36
  def constant?
23
37
  StringQuery.constant?(string)
24
38
  end
25
39
 
26
40
  # Whether or not this string is a valid method name.
41
+ #
42
+ #: () -> bool
27
43
  def method_name?
28
44
  StringQuery.method_name?(string)
29
45
  end
46
+
47
+ # Whether or not this string is a valid keyword.
48
+ #
49
+ #: () -> bool
50
+ def keyword?
51
+ StringQuery.keyword?(string)
52
+ end
30
53
  end
31
54
  end
@@ -7,12 +7,14 @@ module Prism
7
7
  # A builder that knows how to convert more modern Ruby syntax
8
8
  # into whitequark/parser gem's syntax tree.
9
9
  class Builder < ::Parser::Builders::Default
10
- # It represents the `it` block argument, which is not yet implemented in the Parser gem.
10
+ # It represents the `it` block argument, which is not yet implemented in
11
+ # the Parser gem.
11
12
  def itarg
12
13
  n(:itarg, [:it], nil)
13
14
  end
14
15
 
15
- # The following three lines have been added to support the `it` block parameter syntax in the source code below.
16
+ # The following three lines have been added to support the `it` block
17
+ # parameter syntax in the source code below.
16
18
  #
17
19
  # if args.type == :itarg
18
20
  # block_type = :itblock
@@ -56,6 +58,12 @@ module Prism
56
58
  method_call.loc.with_expression(join_exprs(method_call, block)))
57
59
  end
58
60
  end
61
+
62
+ # def foo(&nil); end
63
+ # ^^^^
64
+ def blocknilarg(amper_t, nil_t)
65
+ n0(:blocknilarg, arg_prefix_map(amper_t, nil_t))
66
+ end
59
67
  end
60
68
  end
61
69
  end
@@ -6,9 +6,9 @@ module Prism
6
6
  class Parser
7
7
  # A visitor that knows how to convert a prism syntax tree into the
8
8
  # whitequark/parser gem's syntax tree.
9
- class Compiler < ::Prism::Compiler
9
+ class Compiler < ::Prism::Compiler # :nodoc:
10
10
  # Raised when the tree is malformed or there is a bug in the compiler.
11
- class CompilationError < StandardError
11
+ class CompilationError < StandardError # :nodoc:
12
12
  end
13
13
 
14
14
  # The Parser::Base instance that is being used to build the AST.
@@ -140,7 +140,7 @@ module Prism
140
140
  if key.opening.nil?
141
141
  builder.match_hash_var([key.unescaped, srange(key.location)])
142
142
  else
143
- builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc))
143
+ builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.content_loc)])], token(key.closing_loc))
144
144
  end
145
145
  else
146
146
  builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc))
@@ -151,9 +151,9 @@ module Prism
151
151
  implicit_value = if value.is_a?(CallNode)
152
152
  builder.call_method(nil, nil, [value.name, srange(value.message_loc)])
153
153
  elsif value.is_a?(ConstantReadNode)
154
- builder.const([value.name, srange(key.value_loc)])
154
+ builder.const([value.name, srange(key.content_loc)])
155
155
  else
156
- builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
156
+ builder.ident([value.name, srange(key.content_loc)]).updated(:lvar)
157
157
  end
158
158
 
159
159
  builder.pair_keyword([key.unescaped, srange(key)], implicit_value)
@@ -165,7 +165,14 @@ module Prism
165
165
  else
166
166
  parts =
167
167
  if key.is_a?(SymbolNode)
168
- [builder.string_internal([key.unescaped, srange(key.value_loc)])]
168
+ content = key.content
169
+ if content == ""
170
+ []
171
+ elsif content.include?("\n")
172
+ string_nodes_from_line_continuations(key.unescaped, content, key.content_loc.start_offset, key.opening)
173
+ else
174
+ [builder.string_internal([key.unescaped, srange(key.content_loc)])]
175
+ end
169
176
  else
170
177
  visit_all(key.parts)
171
178
  end
@@ -297,11 +304,6 @@ module Prism
297
304
 
298
305
  if node.call_operator_loc.nil?
299
306
  case name
300
- when :-@
301
- case (receiver = node.receiver).type
302
- when :integer_node, :float_node, :rational_node, :imaginary_node
303
- return visit(numeric_negate(node.message_loc, receiver))
304
- end
305
307
  when :!
306
308
  return visit_block(builder.not_op(token(node.message_loc), token(node.opening_loc), visit(node.receiver), token(node.closing_loc)), block)
307
309
  when :=~
@@ -975,17 +977,17 @@ module Prism
975
977
  guard = builder.if_guard(token(node.pattern.if_keyword_loc), visit(node.pattern.predicate))
976
978
  when UnlessNode
977
979
  pattern = within_pattern { |compiler| node.pattern.statements.accept(compiler) }
978
- guard = builder.unless_guard(token(node.pattern.keyword_loc), visit(node.pattern.predicate))
980
+ guard = builder.unless_guard(token(node.pattern.unless_keyword_loc), visit(node.pattern.predicate))
979
981
  else
980
982
  pattern = within_pattern { |compiler| node.pattern.accept(compiler) }
981
983
  end
982
984
 
983
985
  builder.in_pattern(
984
- token(node.in_loc),
986
+ token(node.in_keyword_loc),
985
987
  pattern,
986
988
  guard,
987
- if (then_loc = node.then_loc)
988
- token(then_loc)
989
+ if (then_keyword_loc = node.then_keyword_loc)
990
+ token(then_keyword_loc)
989
991
  else
990
992
  srange_semicolon(node.pattern.location.end_offset, node.statements&.location&.start_offset)
991
993
  end,
@@ -1296,7 +1298,7 @@ module Prism
1296
1298
  def visit_match_predicate_node(node)
1297
1299
  builder.match_pattern_p(
1298
1300
  visit(node.value),
1299
- token(node.operator_loc),
1301
+ token(node.keyword_loc),
1300
1302
  within_pattern { |compiler| node.pattern.accept(compiler) }
1301
1303
  )
1302
1304
  end
@@ -1324,7 +1326,7 @@ module Prism
1324
1326
  # A node that is missing from the syntax tree. This is only used in the
1325
1327
  # case of a syntax error. The parser gem doesn't have such a concept, so
1326
1328
  # we invent our own here.
1327
- def visit_missing_node(node)
1329
+ def visit_error_recovery_node(node)
1328
1330
  ::AST::Node.new(:missing, [], location: ::Parser::Source::Map.new(srange(node.location)))
1329
1331
  end
1330
1332
 
@@ -1390,6 +1392,12 @@ module Prism
1390
1392
  builder.nil(token(node.location))
1391
1393
  end
1392
1394
 
1395
+ # def foo(&nil); end
1396
+ # ^^^^
1397
+ def visit_no_block_parameter_node(node)
1398
+ builder.blocknilarg(token(node.operator_loc), token(node.keyword_loc))
1399
+ end
1400
+
1393
1401
  # def foo(**nil); end
1394
1402
  # ^^^^^
1395
1403
  def visit_no_keywords_parameter_node(node)
@@ -1767,12 +1775,12 @@ module Prism
1767
1775
  end
1768
1776
  else
1769
1777
  parts =
1770
- if node.value == ""
1778
+ if node.content == ""
1771
1779
  []
1772
- elsif node.value.include?("\n")
1773
- string_nodes_from_line_continuations(node.unescaped, node.value, node.value_loc.start_offset, node.opening)
1780
+ elsif node.content.include?("\n")
1781
+ string_nodes_from_line_continuations(node.unescaped, node.content, node.content_loc.start_offset, node.opening)
1774
1782
  else
1775
- [builder.string_internal([node.unescaped, srange(node.value_loc)])]
1783
+ [builder.string_internal([node.unescaped, srange(node.content_loc)])]
1776
1784
  end
1777
1785
 
1778
1786
  builder.symbol_compose(
@@ -1801,9 +1809,9 @@ module Prism
1801
1809
  # bar unless foo
1802
1810
  # ^^^^^^^^^^^^^^
1803
1811
  def visit_unless_node(node)
1804
- if node.keyword_loc.start_offset == node.location.start_offset
1812
+ if node.unless_keyword_loc.start_offset == node.location.start_offset
1805
1813
  builder.condition(
1806
- token(node.keyword_loc),
1814
+ token(node.unless_keyword_loc),
1807
1815
  visit(node.predicate),
1808
1816
  if (then_keyword_loc = node.then_keyword_loc)
1809
1817
  token(then_keyword_loc)
@@ -1819,7 +1827,7 @@ module Prism
1819
1827
  builder.condition_mod(
1820
1828
  visit(node.else_clause),
1821
1829
  visit(node.statements),
1822
- token(node.keyword_loc),
1830
+ token(node.unless_keyword_loc),
1823
1831
  visit(node.predicate)
1824
1832
  )
1825
1833
  end
@@ -1831,24 +1839,24 @@ module Prism
1831
1839
  # bar until foo
1832
1840
  # ^^^^^^^^^^^^^
1833
1841
  def visit_until_node(node)
1834
- if node.location.start_offset == node.keyword_loc.start_offset
1842
+ if node.location.start_offset == node.until_keyword_loc.start_offset
1835
1843
  builder.loop(
1836
1844
  :until,
1837
- token(node.keyword_loc),
1845
+ token(node.until_keyword_loc),
1838
1846
  visit(node.predicate),
1839
1847
  if (do_keyword_loc = node.do_keyword_loc)
1840
1848
  token(do_keyword_loc)
1841
1849
  else
1842
- srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
1850
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset)
1843
1851
  end,
1844
1852
  visit(node.statements),
1845
- token(node.closing_loc)
1853
+ token(node.end_keyword_loc)
1846
1854
  )
1847
1855
  else
1848
1856
  builder.loop_mod(
1849
1857
  :until,
1850
1858
  visit(node.statements),
1851
- token(node.keyword_loc),
1859
+ token(node.until_keyword_loc),
1852
1860
  visit(node.predicate)
1853
1861
  )
1854
1862
  end
@@ -1858,7 +1866,7 @@ module Prism
1858
1866
  # ^^^^^^^^^^^^^
1859
1867
  def visit_when_node(node)
1860
1868
  builder.when(
1861
- token(node.keyword_loc),
1869
+ token(node.when_keyword_loc),
1862
1870
  visit_all(node.conditions),
1863
1871
  if (then_keyword_loc = node.then_keyword_loc)
1864
1872
  token(then_keyword_loc)
@@ -1875,24 +1883,24 @@ module Prism
1875
1883
  # bar while foo
1876
1884
  # ^^^^^^^^^^^^^
1877
1885
  def visit_while_node(node)
1878
- if node.location.start_offset == node.keyword_loc.start_offset
1886
+ if node.location.start_offset == node.while_keyword_loc.start_offset
1879
1887
  builder.loop(
1880
1888
  :while,
1881
- token(node.keyword_loc),
1889
+ token(node.while_keyword_loc),
1882
1890
  visit(node.predicate),
1883
1891
  if (do_keyword_loc = node.do_keyword_loc)
1884
1892
  token(do_keyword_loc)
1885
1893
  else
1886
- srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
1894
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset)
1887
1895
  end,
1888
1896
  visit(node.statements),
1889
- token(node.closing_loc)
1897
+ token(node.end_keyword_loc)
1890
1898
  )
1891
1899
  else
1892
1900
  builder.loop_mod(
1893
1901
  :while,
1894
1902
  visit(node.statements),
1895
- token(node.keyword_loc),
1903
+ token(node.while_keyword_loc),
1896
1904
  visit(node.predicate)
1897
1905
  )
1898
1906
  end
@@ -1967,22 +1975,6 @@ module Prism
1967
1975
  elements
1968
1976
  end
1969
1977
 
1970
- # Negate the value of a numeric node. This is a special case where you
1971
- # have a negative sign on one line and then a number on the next line.
1972
- # In normal Ruby, this will always be a method call. The parser gem,
1973
- # however, marks this as a numeric literal. We have to massage the tree
1974
- # here to get it into the correct form.
1975
- def numeric_negate(message_loc, receiver)
1976
- case receiver.type
1977
- when :integer_node, :float_node
1978
- receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
1979
- when :rational_node
1980
- receiver.copy(numerator: -receiver.numerator, location: message_loc.join(receiver.location))
1981
- when :imaginary_node
1982
- receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
1983
- end
1984
- end
1985
-
1986
1978
  # Blocks can have a special set of parameters that automatically expand
1987
1979
  # when given arrays if they have a single required parameter and no
1988
1980
  # other parameters.
@@ -2193,7 +2185,7 @@ module Prism
2193
2185
  else
2194
2186
  lines.sum do |line|
2195
2187
  count = line.scan(/(\\*)n/).count { |(backslashes)| backslashes&.length&.odd? }
2196
- count -= 1 if !line.end_with?("\n") && count > 0
2188
+ count -= 1 if line.match?(/(?:\A|[^\\])(?:\\\\)*\\n\z/) && count > 0
2197
2189
  count
2198
2190
  end
2199
2191
  end
@@ -10,7 +10,7 @@ module Prism
10
10
  class Parser
11
11
  # Accepts a list of prism tokens and converts them into the expected
12
12
  # format for the parser gem.
13
- class Lexer
13
+ class Lexer # :nodoc:
14
14
  # These tokens are always skipped
15
15
  TYPES_ALWAYS_SKIP = Set.new(%i[IGNORED_NEWLINE __END__ EOF])
16
16
  private_constant :TYPES_ALWAYS_SKIP
@@ -18,8 +18,6 @@ module Prism
18
18
  # The direct translating of types between the two lexers.
19
19
  TYPES = {
20
20
  # These tokens should never appear in the output of the lexer.
21
- MISSING: nil,
22
- NOT_PROVIDED: nil,
23
21
  EMBDOC_END: nil,
24
22
  EMBDOC_LINE: nil,
25
23
 
@@ -30,11 +28,13 @@ module Prism
30
28
  AMPERSAND_DOT: :tANDDOT,
31
29
  AMPERSAND_EQUAL: :tOP_ASGN,
32
30
  BACK_REFERENCE: :tBACK_REF,
33
- BACKTICK: :tXSTRING_BEG,
31
+ BACKTICK: :tBACK_REF2,
34
32
  BANG: :tBANG,
35
33
  BANG_EQUAL: :tNEQ,
36
34
  BANG_TILDE: :tNMATCH,
37
35
  BRACE_LEFT: :tLCURLY,
36
+ BRACE_LEFT_ARGUMENT: :tLBRACE_ARG,
37
+ BRACE_LEFT_HASH: :tLBRACE,
38
38
  BRACE_RIGHT: :tRCURLY,
39
39
  BRACKET_LEFT: :tLBRACK2,
40
40
  BRACKET_LEFT_ARRAY: :tLBRACK,
@@ -89,6 +89,8 @@ module Prism
89
89
  KEYWORD_DEF: :kDEF,
90
90
  KEYWORD_DEFINED: :kDEFINED,
91
91
  KEYWORD_DO: :kDO,
92
+ KEYWORD_DO_BLOCK: :kDO_BLOCK,
93
+ KEYWORD_DO_LAMBDA: :kDO_LAMBDA,
92
94
  KEYWORD_DO_LOOP: :kDO_COND,
93
95
  KEYWORD_END: :kEND,
94
96
  KEYWORD_END_UPCASE: :klEND,
@@ -139,8 +141,10 @@ module Prism
139
141
  MINUS_EQUAL: :tOP_ASGN,
140
142
  MINUS_GREATER: :tLAMBDA,
141
143
  NEWLINE: :tNL,
144
+ NEWLINE_TERMINATOR: :tNL,
142
145
  NUMBERED_REFERENCE: :tNTH_REF,
143
146
  PARENTHESIS_LEFT: :tLPAREN2,
147
+ PARENTHESIS_LEFT_GROUPING: :tLPAREN,
144
148
  PARENTHESIS_LEFT_PARENTHESES: :tLPAREN_ARG,
145
149
  PARENTHESIS_RIGHT: :tRPAREN,
146
150
  PERCENT: :tPERCENT,
@@ -180,41 +184,15 @@ module Prism
180
184
  UPLUS: :tUPLUS,
181
185
  USTAR: :tSTAR,
182
186
  USTAR_STAR: :tDSTAR,
183
- WORDS_SEP: :tSPACE
187
+ WORDS_SEP: :tSPACE,
188
+ WORDS_SEP_IMPLICIT: :tSPACE,
189
+ XSTRING_BEGIN: :tXSTRING_BEG
184
190
  }
185
191
 
186
- # These constants represent flags in our lex state. We really, really
187
- # don't want to be using them and we really, really don't want to be
188
- # exposing them as part of our public API. Unfortunately, we don't have
189
- # another way of matching the exact tokens that the parser gem expects
190
- # without them. We should find another way to do this, but in the
191
- # meantime we'll hide them from the documentation and mark them as
192
- # private constants.
193
- EXPR_BEG = 0x1 # :nodoc:
194
- EXPR_LABEL = 0x400 # :nodoc:
195
-
196
- # It is used to determine whether `do` is of the token type `kDO` or `kDO_LAMBDA`.
197
- #
198
- # NOTE: In edge cases like `-> (foo = -> (bar) {}) do end`, please note that `kDO` is still returned
199
- # instead of `kDO_LAMBDA`, which is expected: https://github.com/ruby/prism/pull/3046
200
- LAMBDA_TOKEN_TYPES = Set.new([:kDO_LAMBDA, :tLAMBDA, :tLAMBEG])
201
-
202
- # The `PARENTHESIS_LEFT` token in Prism is classified as either `tLPAREN` or `tLPAREN2` in the Parser gem.
203
- # The following token types are listed as those classified as `tLPAREN`.
204
- LPAREN_CONVERSION_TOKEN_TYPES = Set.new([
205
- :kBREAK, :tCARET, :kCASE, :tDIVIDE, :kFOR, :kIF, :kNEXT, :kRETURN, :kUNTIL, :kWHILE, :tAMPER, :tANDOP, :tBANG, :tCOMMA, :tDOT2, :tDOT3,
206
- :tEQL, :tLPAREN, :tLPAREN2, :tLPAREN_ARG, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS, :tLCURLY
207
- ])
208
-
209
- # Types of tokens that are allowed to continue a method call with comments in-between.
210
- # For these, the parser gem doesn't emit a newline token after the last comment.
211
- COMMENT_CONTINUATION_TYPES = Set.new([:COMMENT, :AMPERSAND_DOT, :DOT])
212
- private_constant :COMMENT_CONTINUATION_TYPES
213
-
214
192
  # Heredocs are complex and require us to keep track of a bit of info to refer to later
215
193
  HeredocData = Struct.new(:identifier, :common_whitespace, keyword_init: true)
216
194
 
217
- private_constant :TYPES, :EXPR_BEG, :EXPR_LABEL, :LAMBDA_TOKEN_TYPES, :LPAREN_CONVERSION_TOKEN_TYPES, :HeredocData
195
+ private_constant :TYPES, :HeredocData
218
196
 
219
197
  # The Parser::Source::Buffer that the tokens were lexed from.
220
198
  attr_reader :source_buffer
@@ -234,7 +212,7 @@ module Prism
234
212
  @offset_cache = offset_cache
235
213
  end
236
214
 
237
- Range = ::Parser::Source::Range # :nodoc:
215
+ Range = ::Parser::Source::Range
238
216
  private_constant :Range
239
217
 
240
218
  # Convert the prism tokens into the expected format for the parser gem.
@@ -253,7 +231,7 @@ module Prism
253
231
  comment_newline_location = nil
254
232
 
255
233
  while index < length
256
- token, state = lexed[index]
234
+ token = lexed[index]
257
235
  index += 1
258
236
  next if TYPES_ALWAYS_SKIP.include?(token.type)
259
237
 
@@ -261,15 +239,14 @@ module Prism
261
239
  value = token.value
262
240
  location = range(token.location.start_offset, token.location.end_offset)
263
241
 
264
- case type
265
- when :kDO
266
- nearest_lambda_token = tokens.reverse_each.find do |token|
267
- LAMBDA_TOKEN_TYPES.include?(token.first)
268
- end
242
+ # A newline deferred past a run of comments is emitted before the
243
+ # token that follows the last comment.
244
+ if comment_newline_location && type != :tCOMMENT
245
+ tokens << [:tNL, [nil, comment_newline_location]]
246
+ comment_newline_location = nil
247
+ end
269
248
 
270
- if nearest_lambda_token&.first == :tLAMBDA
271
- type = :kDO_LAMBDA
272
- end
249
+ case type
273
250
  when :tCHARACTER
274
251
  value.delete_prefix!("?")
275
252
  # Character literals behave similar to double-quoted strings. We can use the same escaping mechanism.
@@ -277,7 +254,7 @@ module Prism
277
254
  when :tCOMMENT
278
255
  if token.type == :EMBDOC_BEGIN
279
256
 
280
- while !((next_token = lexed[index]&.first) && next_token.type == :EMBDOC_END) && (index < length - 1)
257
+ while !((next_token = lexed[index]) && next_token.type == :EMBDOC_END) && (index < length - 1)
281
258
  value += next_token.value
282
259
  index += 1
283
260
  end
@@ -286,30 +263,12 @@ module Prism
286
263
  location = range(token.location.start_offset, next_token.location.end_offset)
287
264
  index += 1
288
265
  else
289
- is_at_eol = value.chomp!.nil?
290
- location = range(token.location.start_offset, token.location.end_offset + (is_at_eol ? 0 : -1))
291
-
292
- prev_token, _ = lexed[index - 2] if index - 2 >= 0
293
- next_token, _ = lexed[index]
294
-
295
- is_inline_comment = prev_token&.location&.start_line == token.location.start_line
296
- if is_inline_comment && !is_at_eol && !COMMENT_CONTINUATION_TYPES.include?(next_token&.type)
297
- tokens << [:tCOMMENT, [value, location]]
298
-
299
- nl_location = range(token.location.end_offset - 1, token.location.end_offset)
300
- tokens << [:tNL, [nil, nl_location]]
301
- next
302
- elsif is_inline_comment && next_token&.type == :COMMENT
303
- comment_newline_location = range(token.location.end_offset - 1, token.location.end_offset)
304
- elsif comment_newline_location && !COMMENT_CONTINUATION_TYPES.include?(next_token&.type)
305
- tokens << [:tCOMMENT, [value, location]]
306
- tokens << [:tNL, [nil, comment_newline_location]]
307
- comment_newline_location = nil
308
- next
309
- end
266
+ # A carriage return before the terminating newline is part of
267
+ # the comment token but not of the comment's value.
268
+ location = range(token.location.start_offset, token.location.end_offset - 1) if value.chomp!
310
269
  end
311
270
  when :tNL
312
- next_token, _ = lexed[index]
271
+ next_token = lexed[index]
313
272
  # Newlines after comments are emitted out of order.
314
273
  if next_token&.type == :COMMENT
315
274
  comment_newline_location = location
@@ -332,10 +291,6 @@ module Prism
332
291
  value.chomp!(":")
333
292
  when :tLABEL_END
334
293
  value.chomp!(":")
335
- when :tLCURLY
336
- type = :tLBRACE if state == EXPR_BEG | EXPR_LABEL
337
- when :tLPAREN2
338
- type = :tLPAREN if tokens.empty? || LPAREN_CONVERSION_TOKEN_TYPES.include?(tokens.dig(-1, 0))
339
294
  when :tNTH_REF
340
295
  value = parse_integer(value.delete_prefix("$"))
341
296
  when :tOP_ASGN
@@ -346,8 +301,8 @@ module Prism
346
301
  location = range(token.location.start_offset, token.location.start_offset + percent_array_leading_whitespace(value))
347
302
  value = nil
348
303
  when :tSTRING_BEG
349
- next_token, _ = lexed[index]
350
- next_next_token, _ = lexed[index + 1]
304
+ next_token = lexed[index]
305
+ next_next_token = lexed[index + 1]
351
306
  basic_quotes = value == '"' || value == "'"
352
307
 
353
308
  if basic_quotes && next_token&.type == :STRING_END
@@ -415,7 +370,7 @@ module Prism
415
370
  while token.type == :STRING_CONTENT
416
371
  current_length += token.value.bytesize
417
372
  # Heredoc interpolation can have multiple STRING_CONTENT nodes on the same line.
418
- prev_token, _ = lexed[index - 2] if index - 2 >= 0
373
+ prev_token = lexed[index - 2] if index - 2 >= 0
419
374
  is_first_token_on_line = prev_token && token.location.start_line != prev_token.location.start_line
420
375
  # The parser gem only removes indentation when the heredoc is not nested
421
376
  not_nested = heredoc_stack.size == 1
@@ -435,7 +390,7 @@ module Prism
435
390
  tokens << [:tSTRING_CONTENT, [current_string, range(start_offset, start_offset + current_length)]]
436
391
  break
437
392
  end
438
- token, _ = lexed[index]
393
+ token = lexed[index]
439
394
  index += 1
440
395
  end
441
396
  else
@@ -489,17 +444,9 @@ module Prism
489
444
  location = range(token.location.start_offset, token.location.start_offset + 1)
490
445
  end
491
446
 
492
- if percent_array?(quote_stack.pop)
493
- prev_token, _ = lexed[index - 2] if index - 2 >= 0
494
- empty = %i[PERCENT_LOWER_I PERCENT_LOWER_W PERCENT_UPPER_I PERCENT_UPPER_W].include?(prev_token&.type)
495
- ends_with_whitespace = prev_token&.type == :WORDS_SEP
496
- # parser always emits a space token after content in a percent array, even if no actual whitespace is present.
497
- if !empty && !ends_with_whitespace
498
- tokens << [:tSPACE, [nil, range(token.location.start_offset, token.location.start_offset)]]
499
- end
500
- end
447
+ quote_stack.pop
501
448
  when :tSYMBEG
502
- if (next_token = lexed[index]&.first) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
449
+ if (next_token = lexed[index]) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
503
450
  next_location = token.location.join(next_token.location)
504
451
  type = :tSYMBOL
505
452
  value = next_token.value
@@ -514,13 +461,11 @@ module Prism
514
461
  type = :tIDENTIFIER
515
462
  end
516
463
  when :tXSTRING_BEG
517
- if (next_token = lexed[index]&.first) && !%i[STRING_CONTENT STRING_END EMBEXPR_BEGIN].include?(next_token.type)
518
- # self.`()
519
- type = :tBACK_REF2
520
- end
521
464
  quote_stack.push(value)
522
465
  when :tSYMBOLS_BEG, :tQSYMBOLS_BEG, :tWORDS_BEG, :tQWORDS_BEG
523
- if (next_token = lexed[index]&.first) && next_token.type == :WORDS_SEP
466
+ # The separator that delimits the opener from the first word is
467
+ # part of the opener for parser, so it is not emitted separately.
468
+ if (next_token = lexed[index]) && %i[WORDS_SEP WORDS_SEP_IMPLICIT].include?(next_token.type)
524
469
  index += 1
525
470
  end
526
471
 
@@ -536,6 +481,10 @@ module Prism
536
481
  end
537
482
  end
538
483
 
484
+ if comment_newline_location
485
+ tokens << [:tNL, [nil, comment_newline_location]]
486
+ end
487
+
539
488
  tokens
540
489
  end
541
490
 
@@ -596,9 +545,9 @@ module Prism
596
545
  previous_line = -1
597
546
  result = Float::MAX
598
547
 
599
- while (next_token = lexed[next_token_index]&.first)
548
+ while (next_token = lexed[next_token_index])
600
549
  next_token_index += 1
601
- next_next_token, _ = lexed[next_token_index]
550
+ next_next_token = lexed[next_token_index]
602
551
  first_token_on_line = next_token.location.start_column == 0
603
552
 
604
553
  # String content inside nested heredocs and interpolation is ignored
@@ -33,7 +33,7 @@ module Prism
33
33
  # The parser gem has a list of diagnostics with a hard-coded set of error
34
34
  # messages. We create our own diagnostic class in order to set our own
35
35
  # error messages.
36
- class PrismDiagnostic < Diagnostic
36
+ class PrismDiagnostic < Diagnostic # :nodoc:
37
37
  # This is the cached message coming from prism.
38
38
  attr_reader :message
39
39
 
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  # :markup: markdown
3
+ #--
3
4
  # typed: ignore
4
5
 
5
- #
6
6
  module Prism
7
7
  module Translation
8
8
  case RUBY_VERSION