prism 1.5.1 → 1.9.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -1
  3. data/Makefile +12 -5
  4. data/README.md +2 -1
  5. data/config.yml +34 -8
  6. data/docs/build_system.md +2 -2
  7. data/docs/cruby_compilation.md +1 -1
  8. data/docs/design.md +2 -2
  9. data/docs/parser_translation.md +1 -1
  10. data/docs/releasing.md +4 -25
  11. data/docs/ripper_translation.md +8 -17
  12. data/docs/ruby_api.md +1 -0
  13. data/ext/prism/api_node.c +7 -3
  14. data/ext/prism/extconf.rb +1 -1
  15. data/ext/prism/extension.c +10 -2
  16. data/ext/prism/extension.h +1 -1
  17. data/include/prism/ast.h +89 -25
  18. data/include/prism/diagnostic.h +3 -0
  19. data/include/prism/options.h +8 -2
  20. data/include/prism/parser.h +3 -0
  21. data/include/prism/version.h +3 -3
  22. data/include/prism.h +1 -1
  23. data/lib/prism/compiler.rb +152 -152
  24. data/lib/prism/dot_visitor.rb +5 -0
  25. data/lib/prism/dsl.rb +2 -2
  26. data/lib/prism/ffi.rb +11 -3
  27. data/lib/prism/inspect_visitor.rb +1 -0
  28. data/lib/prism/lex_compat.rb +133 -150
  29. data/lib/prism/node.rb +1184 -34
  30. data/lib/prism/parse_result.rb +11 -15
  31. data/lib/prism/polyfill/scan_byte.rb +1 -1
  32. data/lib/prism/polyfill/warn.rb +16 -22
  33. data/lib/prism/reflection.rb +1 -1
  34. data/lib/prism/serialize.rb +8 -5
  35. data/lib/prism/translation/parser/compiler.rb +16 -16
  36. data/lib/prism/translation/parser.rb +12 -3
  37. data/lib/prism/translation/parser_current.rb +5 -3
  38. data/lib/prism/translation/parser_versions.rb +36 -0
  39. data/lib/prism/translation/ripper/filter.rb +53 -0
  40. data/lib/prism/translation/ripper/lexer.rb +135 -0
  41. data/lib/prism/translation/ripper.rb +86 -40
  42. data/lib/prism/translation/ruby_parser.rb +55 -20
  43. data/lib/prism/translation.rb +5 -3
  44. data/lib/prism/visitor.rb +152 -152
  45. data/lib/prism.rb +21 -14
  46. data/prism.gemspec +5 -7
  47. data/rbi/prism/dsl.rbi +3 -3
  48. data/rbi/prism/node.rbi +24 -8
  49. data/rbi/prism/translation/parser_versions.rbi +23 -0
  50. data/rbi/prism.rbi +0 -3
  51. data/sig/prism/dsl.rbs +2 -2
  52. data/sig/prism/node.rbs +22 -8
  53. data/sig/prism/parse_result.rbs +1 -0
  54. data/sig/prism.rbs +58 -40
  55. data/src/diagnostic.c +7 -1
  56. data/src/encoding.c +172 -67
  57. data/src/node.c +9 -0
  58. data/src/options.c +17 -7
  59. data/src/prettyprint.c +16 -0
  60. data/src/prism.c +1335 -1958
  61. data/src/serialize.c +7 -1
  62. data/src/token_type.c +2 -2
  63. data/src/util/pm_constant_pool.c +1 -1
  64. data/src/util/pm_string.c +6 -8
  65. metadata +7 -9
  66. data/lib/prism/translation/parser33.rb +0 -13
  67. data/lib/prism/translation/parser34.rb +0 -13
  68. data/lib/prism/translation/parser35.rb +0 -13
  69. data/rbi/prism/translation/parser33.rbi +0 -6
  70. data/rbi/prism/translation/parser34.rbi +0 -6
  71. data/rbi/prism/translation/parser35.rbi +0 -6
@@ -76,6 +76,15 @@ module Prism
76
76
  source.byteslice(byte_offset, length) or raise
77
77
  end
78
78
 
79
+ # Converts the line number and column in bytes to a byte offset.
80
+ def byte_offset(line, column)
81
+ normal = line - @start_line
82
+ raise IndexError if normal < 0
83
+ offsets.fetch(normal) + column
84
+ rescue IndexError
85
+ raise ArgumentError, "line #{line} is out of range"
86
+ end
87
+
79
88
  # Binary search through the offsets to find the line number for the given
80
89
  # byte offset.
81
90
  def line(byte_offset)
@@ -155,21 +164,8 @@ module Prism
155
164
  # Binary search through the offsets to find the line number for the given
156
165
  # byte offset.
157
166
  def find_line(byte_offset)
158
- left = 0
159
- right = offsets.length - 1
160
-
161
- while left <= right
162
- mid = left + (right - left) / 2
163
- return mid if (offset = offsets[mid]) == byte_offset
164
-
165
- if offset < byte_offset
166
- left = mid + 1
167
- else
168
- right = mid - 1
169
- end
170
- end
171
-
172
- left - 1
167
+ index = offsets.bsearch_index { |offset| offset > byte_offset } || offsets.length
168
+ index - 1
173
169
  end
174
170
  end
175
171
 
@@ -3,7 +3,7 @@
3
3
  require "strscan"
4
4
 
5
5
  # Polyfill for StringScanner#scan_byte, which didn't exist until Ruby 3.4.
6
- if !(StringScanner.instance_methods.include?(:scan_byte))
6
+ if !(StringScanner.method_defined?(:scan_byte))
7
7
  StringScanner.include(
8
8
  Module.new {
9
9
  def scan_byte # :nodoc:
@@ -7,17 +7,14 @@ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.pa
7
7
  Kernel.prepend(
8
8
  Module.new {
9
9
  def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
10
- uplevel =
11
- case uplevel
12
- when nil
13
- 1
14
- when Integer
15
- uplevel + 1
16
- else
17
- uplevel.to_int + 1
18
- end
19
-
20
- super(*msgs, uplevel: uplevel)
10
+ case uplevel
11
+ when nil
12
+ super(*msgs)
13
+ when Integer
14
+ super(*msgs, uplevel: uplevel + 1)
15
+ else
16
+ super(*msgs, uplevel: uplevel.to_int + 1)
17
+ end
21
18
  end
22
19
  }
23
20
  )
@@ -25,17 +22,14 @@ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.pa
25
22
  Object.prepend(
26
23
  Module.new {
27
24
  def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
28
- uplevel =
29
- case uplevel
30
- when nil
31
- 1
32
- when Integer
33
- uplevel + 1
34
- else
35
- uplevel.to_int + 1
36
- end
37
-
38
- super(*msgs, uplevel: uplevel)
25
+ case uplevel
26
+ when nil
27
+ super(*msgs)
28
+ when Integer
29
+ super(*msgs, uplevel: uplevel + 1)
30
+ else
31
+ super(*msgs, uplevel: uplevel.to_int + 1)
32
+ end
39
33
  end
40
34
  }
41
35
  )
@@ -143,7 +143,7 @@ module Prism
143
143
  when :call_and_write_node
144
144
  [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), OptionalLocationField.new(:message_loc), ConstantField.new(:read_name), ConstantField.new(:write_name), LocationField.new(:operator_loc), NodeField.new(:value)]
145
145
  when :call_node
146
- [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), ConstantField.new(:name), OptionalLocationField.new(:message_loc), OptionalLocationField.new(:opening_loc), OptionalNodeField.new(:arguments), OptionalLocationField.new(:closing_loc), OptionalNodeField.new(:block)]
146
+ [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), ConstantField.new(:name), OptionalLocationField.new(:message_loc), OptionalLocationField.new(:opening_loc), OptionalNodeField.new(:arguments), OptionalLocationField.new(:closing_loc), OptionalLocationField.new(:equal_loc), OptionalNodeField.new(:block)]
147
147
  when :call_operator_write_node
148
148
  [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), OptionalLocationField.new(:message_loc), ConstantField.new(:read_name), ConstantField.new(:write_name), ConstantField.new(:binary_operator), LocationField.new(:binary_operator_loc), NodeField.new(:value)]
149
149
  when :call_or_write_node
@@ -21,11 +21,11 @@ module Prism
21
21
 
22
22
  # The minor version of prism that we are expecting to find in the serialized
23
23
  # strings.
24
- MINOR_VERSION = 5
24
+ MINOR_VERSION = 9
25
25
 
26
26
  # The patch version of prism that we are expecting to find in the serialized
27
27
  # strings.
28
- PATCH_VERSION = 1
28
+ PATCH_VERSION = 0
29
29
 
30
30
  # Deserialize the dumped output from a request to parse or parse_file.
31
31
  #
@@ -397,6 +397,7 @@ module Prism
397
397
  :conditional_while_predicate,
398
398
  :constant_path_colon_colon_constant,
399
399
  :def_endless,
400
+ :def_endless_parameters,
400
401
  :def_endless_setter,
401
402
  :def_name,
402
403
  :def_params_term,
@@ -555,6 +556,7 @@ module Prism
555
556
  :parameter_wild_loose_comma,
556
557
  :pattern_array_multiple_rests,
557
558
  :pattern_capture_duplicate,
559
+ :pattern_capture_in_alternative,
558
560
  :pattern_expression_after_bracket,
559
561
  :pattern_expression_after_comma,
560
562
  :pattern_expression_after_hrocket,
@@ -616,6 +618,7 @@ module Prism
616
618
  :unexpected_index_keywords,
617
619
  :unexpected_label,
618
620
  :unexpected_multi_write,
621
+ :unexpected_parameter_default_value,
619
622
  :unexpected_range_operator,
620
623
  :unexpected_safe_navigation,
621
624
  :unexpected_token_close_context,
@@ -878,7 +881,7 @@ module Prism
878
881
  when 18 then
879
882
  CallAndWriteNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_constant(constant_pool, encoding), load_location(freeze), load_node(constant_pool, encoding, freeze))
880
883
  when 19 then
881
- CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
884
+ CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
882
885
  when 20 then
883
886
  CallOperatorWriteNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_constant(constant_pool, encoding), load_constant(constant_pool, encoding), load_location(freeze), load_node(constant_pool, encoding, freeze))
884
887
  when 21 then
@@ -1286,7 +1289,7 @@ module Prism
1286
1289
  -> (constant_pool, encoding, freeze) {
1287
1290
  node_id = load_varuint
1288
1291
  location = load_location(freeze)
1289
- value = CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
1292
+ value = CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
1290
1293
  value.freeze if freeze
1291
1294
  value
1292
1295
  },
@@ -2238,6 +2241,7 @@ module Prism
2238
2241
  :KEYWORD_WHEN,
2239
2242
  :NEWLINE,
2240
2243
  :PARENTHESIS_RIGHT,
2244
+ :PIPE,
2241
2245
  :SEMICOLON,
2242
2246
  :AMPERSAND,
2243
2247
  :AMPERSAND_AMPERSAND,
@@ -2354,7 +2358,6 @@ module Prism
2354
2358
  :PERCENT_LOWER_X,
2355
2359
  :PERCENT_UPPER_I,
2356
2360
  :PERCENT_UPPER_W,
2357
- :PIPE,
2358
2361
  :PIPE_EQUAL,
2359
2362
  :PIPE_PIPE,
2360
2363
  :PIPE_PIPE_EQUAL,
@@ -217,7 +217,7 @@ module Prism
217
217
  rescue_clause.exceptions.any? ? builder.array(nil, visit_all(rescue_clause.exceptions), nil) : nil,
218
218
  token(rescue_clause.operator_loc),
219
219
  visit(rescue_clause.reference),
220
- srange_find(find_start_offset, find_end_offset, ";"),
220
+ srange_semicolon(find_start_offset, find_end_offset),
221
221
  visit(rescue_clause.statements)
222
222
  )
223
223
  end until (rescue_clause = rescue_clause.subsequent).nil?
@@ -323,7 +323,7 @@ module Prism
323
323
  visit_all(arguments),
324
324
  token(node.closing_loc),
325
325
  ),
326
- srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, "="),
326
+ token(node.equal_loc),
327
327
  visit(node.arguments.arguments.last)
328
328
  ),
329
329
  block
@@ -340,7 +340,7 @@ module Prism
340
340
  if name.end_with?("=") && !message_loc.slice.end_with?("=") && node.arguments && block.nil?
341
341
  builder.assign(
342
342
  builder.attr_asgn(visit(node.receiver), call_operator, token(message_loc)),
343
- srange_find(message_loc.end_offset, node.arguments.location.start_offset, "="),
343
+ token(node.equal_loc),
344
344
  visit(node.arguments.arguments.last)
345
345
  )
346
346
  else
@@ -789,7 +789,7 @@ module Prism
789
789
  if (do_keyword_loc = node.do_keyword_loc)
790
790
  token(do_keyword_loc)
791
791
  else
792
- srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, ";")
792
+ srange_semicolon(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset)
793
793
  end,
794
794
  visit(node.statements),
795
795
  token(node.end_keyword_loc)
@@ -921,7 +921,7 @@ module Prism
921
921
  if (then_keyword_loc = node.then_keyword_loc)
922
922
  token(then_keyword_loc)
923
923
  else
924
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, ";")
924
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset)
925
925
  end,
926
926
  visit(node.statements),
927
927
  case node.subsequent
@@ -987,7 +987,7 @@ module Prism
987
987
  if (then_loc = node.then_loc)
988
988
  token(then_loc)
989
989
  else
990
- srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, ";")
990
+ srange_semicolon(node.pattern.location.end_offset, node.statements&.location&.start_offset)
991
991
  end,
992
992
  visit(node.statements)
993
993
  )
@@ -1808,7 +1808,7 @@ module Prism
1808
1808
  if (then_keyword_loc = node.then_keyword_loc)
1809
1809
  token(then_keyword_loc)
1810
1810
  else
1811
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, ";")
1811
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset)
1812
1812
  end,
1813
1813
  visit(node.else_clause),
1814
1814
  token(node.else_clause&.else_keyword_loc),
@@ -1839,7 +1839,7 @@ module Prism
1839
1839
  if (do_keyword_loc = node.do_keyword_loc)
1840
1840
  token(do_keyword_loc)
1841
1841
  else
1842
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
1842
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
1843
1843
  end,
1844
1844
  visit(node.statements),
1845
1845
  token(node.closing_loc)
@@ -1863,7 +1863,7 @@ module Prism
1863
1863
  if (then_keyword_loc = node.then_keyword_loc)
1864
1864
  token(then_keyword_loc)
1865
1865
  else
1866
- srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, ";")
1866
+ srange_semicolon(node.conditions.last.location.end_offset, node.statements&.location&.start_offset)
1867
1867
  end,
1868
1868
  visit(node.statements)
1869
1869
  )
@@ -1883,7 +1883,7 @@ module Prism
1883
1883
  if (do_keyword_loc = node.do_keyword_loc)
1884
1884
  token(do_keyword_loc)
1885
1885
  else
1886
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
1886
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
1887
1887
  end,
1888
1888
  visit(node.statements),
1889
1889
  token(node.closing_loc)
@@ -2012,16 +2012,16 @@ module Prism
2012
2012
  Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])
2013
2013
  end
2014
2014
 
2015
- # Constructs a new source range by finding the given character between
2016
- # the given start offset and end offset. If the needle is not found, it
2017
- # returns nil. Importantly it does not search past newlines or comments.
2015
+ # Constructs a new source range by finding a semicolon between the given
2016
+ # start offset and end offset. If the semicolon is not found, it returns
2017
+ # nil. Importantly it does not search past newlines or comments.
2018
2018
  #
2019
2019
  # Note that end_offset is allowed to be nil, in which case this will
2020
2020
  # search until the end of the string.
2021
- def srange_find(start_offset, end_offset, character)
2022
- if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*#{character}/])
2021
+ def srange_semicolon(start_offset, end_offset)
2022
+ if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*;/])
2023
2023
  final_offset = start_offset + match.bytesize
2024
- [character, Range.new(source_buffer, offset_cache[final_offset - character.bytesize], offset_cache[final_offset])]
2024
+ [";", Range.new(source_buffer, offset_cache[final_offset - 1], offset_cache[final_offset])]
2025
2025
  end
2026
2026
  end
2027
2027
 
@@ -19,6 +19,13 @@ module Prism
19
19
  # whitequark/parser gem's syntax tree. It inherits from the base parser for
20
20
  # the parser gem, and overrides the parse* methods to parse with prism and
21
21
  # then translate.
22
+ #
23
+ # Note that this version of the parser always parses using the latest
24
+ # version of Ruby syntax supported by Prism. If you want specific version
25
+ # support, use one of the version-specific subclasses, such as
26
+ # `Prism::Translation::Parser34`. If you want to parse using the same
27
+ # version of Ruby syntax as the currently running version of Ruby, use
28
+ # `Prism::Translation::ParserCurrent`.
22
29
  class Parser < ::Parser::Base
23
30
  Diagnostic = ::Parser::Diagnostic # :nodoc:
24
31
  private_constant :Diagnostic
@@ -77,7 +84,7 @@ module Prism
77
84
  end
78
85
 
79
86
  def version # :nodoc:
80
- 34
87
+ 41
81
88
  end
82
89
 
83
90
  # The default encoding for Ruby files is UTF-8.
@@ -349,8 +356,10 @@ module Prism
349
356
  "3.3.1"
350
357
  when 34
351
358
  "3.4.0"
352
- when 35
353
- "3.5.0"
359
+ when 35, 40
360
+ "4.0.0"
361
+ when 41
362
+ "4.1.0"
354
363
  else
355
364
  "latest"
356
365
  end
@@ -10,11 +10,13 @@ module Prism
10
10
  ParserCurrent = Parser33
11
11
  when /^3\.4\./
12
12
  ParserCurrent = Parser34
13
- when /^3\.5\./
14
- ParserCurrent = Parser35
13
+ when /^3\.5\./, /^4\.0\./
14
+ ParserCurrent = Parser40
15
+ when /^4\.1\./
16
+ ParserCurrent = Parser41
15
17
  else
16
18
  # Keep this in sync with released Ruby.
17
- parser = Parser34
19
+ parser = Parser40
18
20
  major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments
19
21
  warn "warning: `Prism::Translation::Current` is loading #{parser.name}, " \
20
22
  "but you are running #{major}.#{minor}."
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ # :markup: markdown
3
+
4
+ module Prism
5
+ module Translation
6
+ # This class is the entry-point for Ruby 3.3 of `Prism::Translation::Parser`.
7
+ class Parser33 < Parser
8
+ def version # :nodoc:
9
+ 33
10
+ end
11
+ end
12
+
13
+ # This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
14
+ class Parser34 < Parser
15
+ def version # :nodoc:
16
+ 34
17
+ end
18
+ end
19
+
20
+ # This class is the entry-point for Ruby 4.0 of `Prism::Translation::Parser`.
21
+ class Parser40 < Parser
22
+ def version # :nodoc:
23
+ 40
24
+ end
25
+ end
26
+
27
+ Parser35 = Parser40 # :nodoc:
28
+
29
+ # This class is the entry-point for Ruby 4.1 of `Prism::Translation::Parser`.
30
+ class Parser41 < Parser
31
+ def version # :nodoc:
32
+ 41
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Prism
4
+ module Translation
5
+ class Ripper
6
+ class Filter # :nodoc:
7
+ # :stopdoc:
8
+ def initialize(src, filename = '-', lineno = 1)
9
+ @__lexer = Lexer.new(src, filename, lineno)
10
+ @__line = nil
11
+ @__col = nil
12
+ @__state = nil
13
+ end
14
+
15
+ def filename
16
+ @__lexer.filename
17
+ end
18
+
19
+ def lineno
20
+ @__line
21
+ end
22
+
23
+ def column
24
+ @__col
25
+ end
26
+
27
+ def state
28
+ @__state
29
+ end
30
+
31
+ def parse(init = nil)
32
+ data = init
33
+ @__lexer.lex.each do |pos, event, tok, state|
34
+ @__line, @__col = *pos
35
+ @__state = state
36
+ data = if respond_to?(event, true)
37
+ then __send__(event, tok, data)
38
+ else on_default(event, tok, data)
39
+ end
40
+ end
41
+ data
42
+ end
43
+
44
+ private
45
+
46
+ def on_default(event, token, data)
47
+ data
48
+ end
49
+ # :startdoc:
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+ # :markup: markdown
3
+
4
+ require_relative "../ripper"
5
+
6
+ module Prism
7
+ module Translation
8
+ class Ripper
9
+ class Lexer < Ripper # :nodoc:
10
+ # :stopdoc:
11
+ class State
12
+
13
+ attr_reader :to_int, :to_s
14
+
15
+ def initialize(i)
16
+ @to_int = i
17
+ @to_s = Ripper.lex_state_name(i)
18
+ freeze
19
+ end
20
+
21
+ def [](index)
22
+ case index
23
+ when 0, :to_int
24
+ @to_int
25
+ when 1, :to_s
26
+ @to_s
27
+ else
28
+ nil
29
+ end
30
+ end
31
+
32
+ alias to_i to_int
33
+ alias inspect to_s
34
+ def pretty_print(q) q.text(to_s) end
35
+ def ==(i) super or to_int == i end
36
+ def &(i) self.class.new(to_int & i) end
37
+ def |(i) self.class.new(to_int | i) end
38
+ def allbits?(i) to_int.allbits?(i) end
39
+ def anybits?(i) to_int.anybits?(i) end
40
+ def nobits?(i) to_int.nobits?(i) end
41
+
42
+ # Instances are frozen and there are only a handful of them so we cache them here.
43
+ STATES = Hash.new { |h,k| h[k] = State.new(k) }
44
+
45
+ def self.cached(i)
46
+ STATES[i]
47
+ end
48
+ end
49
+
50
+ class Elem
51
+ attr_accessor :pos, :event, :tok, :state, :message
52
+
53
+ def initialize(pos, event, tok, state, message = nil)
54
+ @pos = pos
55
+ @event = event
56
+ @tok = tok
57
+ @state = State.cached(state)
58
+ @message = message
59
+ end
60
+
61
+ def [](index)
62
+ case index
63
+ when 0, :pos
64
+ @pos
65
+ when 1, :event
66
+ @event
67
+ when 2, :tok
68
+ @tok
69
+ when 3, :state
70
+ @state
71
+ when 4, :message
72
+ @message
73
+ else
74
+ nil
75
+ end
76
+ end
77
+
78
+ def inspect
79
+ "#<#{self.class}: #{event}@#{pos[0]}:#{pos[1]}:#{state}: #{tok.inspect}#{": " if message}#{message}>"
80
+ end
81
+
82
+ alias to_s inspect
83
+
84
+ def pretty_print(q)
85
+ q.group(2, "#<#{self.class}:", ">") {
86
+ q.breakable
87
+ q.text("#{event}@#{pos[0]}:#{pos[1]}")
88
+ q.breakable
89
+ state.pretty_print(q)
90
+ q.breakable
91
+ q.text("token: ")
92
+ tok.pretty_print(q)
93
+ if message
94
+ q.breakable
95
+ q.text("message: ")
96
+ q.text(message)
97
+ end
98
+ }
99
+ end
100
+
101
+ def to_a
102
+ if @message
103
+ [@pos, @event, @tok, @state, @message]
104
+ else
105
+ [@pos, @event, @tok, @state]
106
+ end
107
+ end
108
+ end
109
+
110
+ # Pretty much just the same as Prism.lex_compat.
111
+ def lex(raise_errors: false)
112
+ Ripper.lex(@source, filename, lineno, raise_errors: raise_errors)
113
+ end
114
+
115
+ # Returns the lex_compat result wrapped in `Elem`. Errors are omitted.
116
+ # Since ripper is a streaming parser, tokens are expected to be emitted in the order
117
+ # that the parser encounters them. This is not implemented.
118
+ def parse(...)
119
+ lex(...).map do |position, event, token, state|
120
+ Elem.new(position, event, token, state.to_int)
121
+ end
122
+ end
123
+
124
+ # Similar to parse but ripper sorts the elements by position in the source. Also
125
+ # includes errors. Since prism does error recovery, in cases of syntax errors
126
+ # the result may differ greatly compared to ripper.
127
+ def scan(...)
128
+ parse(...)
129
+ end
130
+
131
+ # :startdoc:
132
+ end
133
+ end
134
+ end
135
+ end