prism 0.23.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1477,7 +1477,7 @@ module Prism
1477
1477
  # ^^^^^
1478
1478
  def visit_string_node(node)
1479
1479
  if node.opening&.start_with?("<<")
1480
- children, closing = visit_heredoc(InterpolatedStringNode.new(node.opening_loc, [node.copy(opening_loc: nil, closing_loc: nil, location: node.content_loc)], node.closing_loc, node.location))
1480
+ children, closing = visit_heredoc(InterpolatedStringNode.new(node.send(:source), node.opening_loc, [node.copy(opening_loc: nil, closing_loc: nil, location: node.content_loc)], node.closing_loc, node.location))
1481
1481
  builder.string_compose(token(node.opening_loc), children, closing)
1482
1482
  elsif node.opening == "?"
1483
1483
  builder.character([node.unescaped, srange(node.location)])
@@ -9,18 +9,26 @@ require "prism/translation/parser"
9
9
  module Prism
10
10
  module Translation
11
11
  class Parser
12
- # This is the special version number that should be used in rubocop
12
+ # This is the special version numbers that should be used in RuboCop
13
13
  # configuration files to trigger using prism.
14
+
15
+ # For Ruby 3.3
14
16
  VERSION_3_3 = 80_82_73_83_77.33
15
17
 
18
+ # For Ruby 3.4
19
+ VERSION_3_4 = 80_82_73_83_77.34
20
+
16
21
  # This module gets prepended into RuboCop::AST::ProcessedSource.
17
22
  module ProcessedSource
18
23
  # Redefine parser_class so that we can inject the prism parser into the
19
24
  # list of known parsers.
20
25
  def parser_class(ruby_version)
21
26
  if ruby_version == Prism::Translation::Parser::VERSION_3_3
22
- require "prism/translation/parser"
23
- Prism::Translation::Parser
27
+ require "prism/translation/parser33"
28
+ Prism::Translation::Parser33
29
+ elsif ruby_version == Prism::Translation::Parser::VERSION_3_4
30
+ require "prism/translation/parser34"
31
+ Prism::Translation::Parser34
24
32
  else
25
33
  super
26
34
  end
@@ -43,7 +43,7 @@ module Prism
43
43
  source = source_buffer.source
44
44
 
45
45
  offset_cache = build_offset_cache(source)
46
- result = unwrap(Prism.parse(source, filepath: source_buffer.name), offset_cache)
46
+ result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version)), offset_cache)
47
47
 
48
48
  build_ast(result.value, offset_cache)
49
49
  ensure
@@ -56,7 +56,7 @@ module Prism
56
56
  source = source_buffer.source
57
57
 
58
58
  offset_cache = build_offset_cache(source)
59
- result = unwrap(Prism.parse(source, filepath: source_buffer.name), offset_cache)
59
+ result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version)), offset_cache)
60
60
 
61
61
  [
62
62
  build_ast(result.value, offset_cache),
@@ -75,7 +75,7 @@ module Prism
75
75
  offset_cache = build_offset_cache(source)
76
76
  result =
77
77
  begin
78
- unwrap(Prism.parse_lex(source, filepath: source_buffer.name), offset_cache)
78
+ unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version)), offset_cache)
79
79
  rescue ::Parser::SyntaxError
80
80
  raise if !recover
81
81
  end
@@ -168,6 +168,18 @@ module Prism
168
168
  )
169
169
  end
170
170
 
171
+ # Converts the version format handled by Parser to the format handled by Prism.
172
+ def convert_for_prism(version)
173
+ case version
174
+ when 33
175
+ "3.3.0"
176
+ when 34
177
+ "3.4.0"
178
+ else
179
+ "latest"
180
+ end
181
+ end
182
+
171
183
  require_relative "parser/compiler"
172
184
  require_relative "parser/lexer"
173
185
 
@@ -0,0 +1,12 @@
1
+ require_relative "parser"
2
+
3
+ module Prism
4
+ module Translation
5
+ # This class is the entry-point for Ruby 3.3 of `Prism::Translation::Parser`.
6
+ class Parser33 < Parser
7
+ def version # :nodoc:
8
+ 33
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "parser"
2
+
3
+ module Prism
4
+ module Translation
5
+ # This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
6
+ class Parser34 < Parser
7
+ def version # :nodoc:
8
+ 34
9
+ end
10
+ end
11
+ end
12
+ end
@@ -222,6 +222,44 @@ module Prism
222
222
  on_break(on_args_add_block(args_val, false))
223
223
  end
224
224
 
225
+ # Visit an AliasMethodNode.
226
+ def visit_alias_method_node(node)
227
+ # For both the old and new name, if there is a colon in the symbol
228
+ # name (e.g. 'alias :foo :bar') then we do *not* emit the [:symbol] wrapper around
229
+ # the lexer token (e.g. :@ident) inside [:symbol_literal]. But if there
230
+ # is no colon (e.g. 'alias foo bar') then we *do* still emit the [:symbol] wrapper.
231
+
232
+ if node.new_name.is_a?(SymbolNode) && !node.new_name.opening
233
+ new_name_val = visit_symbol_literal_node(node.new_name, no_symbol_wrapper: true)
234
+ else
235
+ new_name_val = visit(node.new_name)
236
+ end
237
+ if node.old_name.is_a?(SymbolNode) && !node.old_name.opening
238
+ old_name_val = visit_symbol_literal_node(node.old_name, no_symbol_wrapper: true)
239
+ else
240
+ old_name_val = visit(node.old_name)
241
+ end
242
+
243
+ on_alias(new_name_val, old_name_val)
244
+ end
245
+
246
+ # Visit an AliasGlobalVariableNode.
247
+ def visit_alias_global_variable_node(node)
248
+ on_var_alias(visit(node.new_name), visit(node.old_name))
249
+ end
250
+
251
+ # Visit a GlobalVariableReadNode.
252
+ def visit_global_variable_read_node(node)
253
+ bounds(node.location)
254
+ on_gvar(node.name.to_s)
255
+ end
256
+
257
+ # Visit a BackReferenceReadNode.
258
+ def visit_back_reference_read_node(node)
259
+ bounds(node.location)
260
+ on_backref(node.name.to_s)
261
+ end
262
+
225
263
  # Visit an AndNode.
226
264
  def visit_and_node(node)
227
265
  visit_binary_operator(node)
@@ -326,23 +364,7 @@ module Prism
326
364
 
327
365
  # Visit an InterpolatedStringNode node.
328
366
  def visit_interpolated_string_node(node)
329
- parts = node.parts.map do |part|
330
- case part
331
- when StringNode
332
- bounds(part.content_loc)
333
- on_tstring_content(part.content)
334
- when EmbeddedStatementsNode
335
- on_string_embexpr(visit(part))
336
- else
337
- raise NotImplementedError, "Unexpected node type in InterpolatedStringNode"
338
- end
339
- end
340
-
341
- string_list = parts.inject(on_string_content) do |items, item|
342
- on_string_add(items, item)
343
- end
344
-
345
- on_string_literal(string_list)
367
+ on_string_literal(visit_enumerated_node(node))
346
368
  end
347
369
 
348
370
  # Visit an EmbeddedStatementsNode node.
@@ -352,15 +374,12 @@ module Prism
352
374
 
353
375
  # Visit a SymbolNode node.
354
376
  def visit_symbol_node(node)
355
- if (opening = node.opening) && (['"', "'"].include?(opening[-1]) || opening.start_with?("%s"))
356
- bounds(node.value_loc)
357
- tstring_val = on_tstring_content(node.value.to_s)
358
- return on_dyna_symbol(on_string_add(on_string_content, tstring_val))
359
- end
377
+ visit_symbol_literal_node(node)
378
+ end
360
379
 
361
- bounds(node.value_loc)
362
- ident_val = on_ident(node.value.to_s)
363
- on_symbol_literal(on_symbol(ident_val))
380
+ # Visit an InterpolatedSymbolNode node.
381
+ def visit_interpolated_symbol_node(node)
382
+ on_dyna_symbol(visit_enumerated_node(node))
364
383
  end
365
384
 
366
385
  # Visit a StatementsNode node.
@@ -459,6 +478,25 @@ module Prism
459
478
  end
460
479
  end
461
480
 
481
+ # Visit an InterpolatedStringNode or an InterpolatedSymbolNode node.
482
+ def visit_enumerated_node(node)
483
+ parts = node.parts.map do |part|
484
+ case part
485
+ when StringNode
486
+ bounds(part.content_loc)
487
+ on_tstring_content(part.content)
488
+ when EmbeddedStatementsNode
489
+ on_string_embexpr(visit(part))
490
+ else
491
+ raise NotImplementedError, "Unexpected node type in visit_enumerated_node"
492
+ end
493
+ end
494
+
495
+ parts.inject(on_string_content) do |items, item|
496
+ on_string_add(items, item)
497
+ end
498
+ end
499
+
462
500
  # Visit an operation-and-assign node, such as +=.
463
501
  def visit_binary_op_assign(node, operator: node.operator)
464
502
  bounds(node.name_loc)
@@ -487,6 +525,87 @@ module Prism
487
525
  on_assign(on_aref_field(visit(node.receiver), args_val), assign_val)
488
526
  end
489
527
 
528
+ # In an alias statement Ripper will emit @kw instead of @ident if the object
529
+ # being aliased is a Ruby keyword. For instance, in the line "alias :foo :if",
530
+ # the :if is treated as a lexer keyword. So we need to know what symbols are
531
+ # also keywords.
532
+ RUBY_KEYWORDS = [
533
+ "alias",
534
+ "and",
535
+ "begin",
536
+ "BEGIN",
537
+ "break",
538
+ "case",
539
+ "class",
540
+ "def",
541
+ "defined?",
542
+ "do",
543
+ "else",
544
+ "elsif",
545
+ "end",
546
+ "END",
547
+ "ensure",
548
+ "false",
549
+ "for",
550
+ "if",
551
+ "in",
552
+ "module",
553
+ "next",
554
+ "nil",
555
+ "not",
556
+ "or",
557
+ "redo",
558
+ "rescue",
559
+ "retry",
560
+ "return",
561
+ "self",
562
+ "super",
563
+ "then",
564
+ "true",
565
+ "undef",
566
+ "unless",
567
+ "until",
568
+ "when",
569
+ "while",
570
+ "yield",
571
+ "__ENCODING__",
572
+ "__FILE__",
573
+ "__LINE__",
574
+ ]
575
+
576
+ # Ripper has several methods of emitting a symbol literal. Inside an alias
577
+ # sometimes it suppresses the [:symbol] wrapper around ident. If the symbol
578
+ # is also the name of a keyword (e.g. :if) it will emit a :@kw wrapper, not
579
+ # an :@ident wrapper, with similar treatment for constants and operators.
580
+ def visit_symbol_literal_node(node, no_symbol_wrapper: false)
581
+ if (opening = node.opening) && (['"', "'"].include?(opening[-1]) || opening.start_with?("%s"))
582
+ bounds(node.value_loc)
583
+ str_val = node.value.to_s
584
+ if str_val == ""
585
+ return on_dyna_symbol(on_string_content)
586
+ else
587
+ tstring_val = on_tstring_content(str_val)
588
+ return on_dyna_symbol(on_string_add(on_string_content, tstring_val))
589
+ end
590
+ end
591
+
592
+ bounds(node.value_loc)
593
+ node_name = node.value.to_s
594
+ if RUBY_KEYWORDS.include?(node_name)
595
+ token_val = on_kw(node_name)
596
+ elsif node_name.length == 0
597
+ raise NotImplementedError
598
+ elsif /[[:upper:]]/.match(node_name[0])
599
+ token_val = on_const(node_name)
600
+ elsif /[[:punct:]]/.match(node_name[0])
601
+ token_val = on_op(node_name)
602
+ else
603
+ token_val = on_ident(node_name)
604
+ end
605
+ sym_val = no_symbol_wrapper ? token_val : on_symbol(token_val)
606
+ on_symbol_literal(sym_val)
607
+ end
608
+
490
609
  # Visit a node that represents a number. We need to explicitly handle the
491
610
  # unary - operator.
492
611
  def visit_number(node)
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.23.0"
5
+ spec.version = "0.24.0"
6
6
  spec.authors = ["Shopify"]
7
7
  spec.email = ["ruby@shopify.com"]
8
8
 
@@ -87,6 +87,8 @@ Gem::Specification.new do |spec|
87
87
  "lib/prism/serialize.rb",
88
88
  "lib/prism/translation.rb",
89
89
  "lib/prism/translation/parser.rb",
90
+ "lib/prism/translation/parser33.rb",
91
+ "lib/prism/translation/parser34.rb",
90
92
  "lib/prism/translation/parser/compiler.rb",
91
93
  "lib/prism/translation/parser/lexer.rb",
92
94
  "lib/prism/translation/parser/rubocop.rb",
data/src/prettyprint.c CHANGED
@@ -44,9 +44,9 @@ prettyprint_source(pm_buffer_t *output_buffer, const uint8_t *source, size_t len
44
44
 
45
45
  static inline void
46
46
  prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) {
47
- pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start);
48
- pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end);
49
- pm_buffer_append_format(output_buffer, "(%lu,%lu)-(%lu,%lu)", (unsigned long) start.line, (unsigned long) start.column, (unsigned long) end.line, (unsigned long) end.column);
47
+ pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start, parser->start_line);
48
+ pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end, parser->start_line);
49
+ pm_buffer_append_format(output_buffer, "(%" PRIi32 ",%" PRIu32 ")-(%" PRIi32 ",%" PRIu32 ")", start.line, start.column, end.line, end.column);
50
50
  }
51
51
 
52
52
  static inline void
data/src/prism.c CHANGED
@@ -51,6 +51,7 @@ debug_context(pm_context_t context) {
51
51
  case PM_CONTEXT_IF: return "IF";
52
52
  case PM_CONTEXT_MAIN: return "MAIN";
53
53
  case PM_CONTEXT_MODULE: return "MODULE";
54
+ case PM_CONTEXT_NONE: return "NONE";
54
55
  case PM_CONTEXT_PARENS: return "PARENS";
55
56
  case PM_CONTEXT_POSTEXE: return "POSTEXE";
56
57
  case PM_CONTEXT_PREDICATE: return "PREDICATE";
@@ -14205,7 +14206,6 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
14205
14206
  // If we get here, then we have an end of a label immediately
14206
14207
  // after a start. In that case we'll create an empty symbol
14207
14208
  // node.
14208
- pm_token_t opening = not_provided(parser);
14209
14209
  pm_token_t content = parse_strings_empty_content(parser->previous.start);
14210
14210
  pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &content, &parser->previous);
14211
14211
 
@@ -16769,7 +16769,18 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
16769
16769
  if (is_single_value && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
16770
16770
  pm_token_t rescue = parser->current;
16771
16771
  parser_lex(parser);
16772
- pm_node_t *right = parse_expression(parser, binding_power, false, PM_ERR_RESCUE_MODIFIER_VALUE);
16772
+
16773
+ bool accepts_command_call_inner = false;
16774
+
16775
+ // RHS can accept command call iff the value is a call with arguments but without paranthesis.
16776
+ if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
16777
+ pm_call_node_t *call_node = (pm_call_node_t *)value;
16778
+ if ((call_node->arguments != NULL) && (call_node->opening_loc.start == NULL)) {
16779
+ accepts_command_call_inner = true;
16780
+ }
16781
+ }
16782
+
16783
+ pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner, PM_ERR_RESCUE_MODIFIER_VALUE);
16773
16784
 
16774
16785
  return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
16775
16786
  }
@@ -18115,7 +18126,7 @@ typedef struct {
18115
18126
  pm_diagnostic_t *error;
18116
18127
 
18117
18128
  /** The start line of the diagnostic message. */
18118
- uint32_t line;
18129
+ int32_t line;
18119
18130
 
18120
18131
  /** The column start of the diagnostic message. */
18121
18132
  uint32_t column_start;
@@ -18147,12 +18158,13 @@ typedef struct {
18147
18158
  #define PM_COLOR_RESET "\033[0m"
18148
18159
 
18149
18160
  static inline pm_error_t *
18150
- pm_parser_errors_format_sort(const pm_list_t *error_list, const pm_newline_list_t *newline_list) {
18161
+ pm_parser_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_list, const pm_newline_list_t *newline_list) {
18151
18162
  pm_error_t *errors = calloc(error_list->size, sizeof(pm_error_t));
18163
+ int32_t start_line = parser->start_line;
18152
18164
 
18153
18165
  for (pm_diagnostic_t *error = (pm_diagnostic_t *) error_list->head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
18154
- pm_line_column_t start = pm_newline_list_line_column(newline_list, error->location.start);
18155
- pm_line_column_t end = pm_newline_list_line_column(newline_list, error->location.end);
18166
+ pm_line_column_t start = pm_newline_list_line_column(newline_list, error->location.start, start_line);
18167
+ pm_line_column_t end = pm_newline_list_line_column(newline_list, error->location.end, start_line);
18156
18168
 
18157
18169
  // We're going to insert this error into the array in sorted order. We
18158
18170
  // do this by finding the first error that has a line number greater
@@ -18163,8 +18175,8 @@ pm_parser_errors_format_sort(const pm_list_t *error_list, const pm_newline_list_
18163
18175
  (index < error_list->size) &&
18164
18176
  (errors[index].error != NULL) &&
18165
18177
  (
18166
- (errors[index].line < ((uint32_t) start.line)) ||
18167
- (errors[index].line == ((uint32_t) start.line) && errors[index].column_start < ((uint32_t) start.column))
18178
+ (errors[index].line < start.line) ||
18179
+ ((errors[index].line == start.line) && (errors[index].column_start < start.column))
18168
18180
  )
18169
18181
  ) index++;
18170
18182
 
@@ -18177,18 +18189,18 @@ pm_parser_errors_format_sort(const pm_list_t *error_list, const pm_newline_list_
18177
18189
  // Finally, we'll insert the error into the array.
18178
18190
  uint32_t column_end;
18179
18191
  if (start.line == end.line) {
18180
- column_end = (uint32_t) end.column;
18192
+ column_end = end.column;
18181
18193
  } else {
18182
- column_end = (uint32_t) (newline_list->offsets[start.line] - newline_list->offsets[start.line - 1] - 1);
18194
+ column_end = (uint32_t) (newline_list->offsets[start.line - start_line + 1] - newline_list->offsets[start.line - start_line] - 1);
18183
18195
  }
18184
18196
 
18185
18197
  // Ensure we have at least one column of error.
18186
- if (((uint32_t) start.column) == column_end) column_end++;
18198
+ if (start.column == column_end) column_end++;
18187
18199
 
18188
18200
  errors[index] = (pm_error_t) {
18189
18201
  .error = error,
18190
- .line = (uint32_t) start.line,
18191
- .column_start = (uint32_t) start.column,
18202
+ .line = start.line,
18203
+ .column_start = start.column,
18192
18204
  .column_end = column_end
18193
18205
  };
18194
18206
  }
@@ -18197,17 +18209,19 @@ pm_parser_errors_format_sort(const pm_list_t *error_list, const pm_newline_list_
18197
18209
  }
18198
18210
 
18199
18211
  static inline void
18200
- pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, size_t line, pm_buffer_t *buffer) {
18201
- const uint8_t *start = &parser->start[newline_list->offsets[line - 1]];
18212
+ pm_parser_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, int32_t line, pm_buffer_t *buffer) {
18213
+ size_t index = (size_t) (line - parser->start_line);
18214
+
18215
+ const uint8_t *start = &parser->start[newline_list->offsets[index]];
18202
18216
  const uint8_t *end;
18203
18217
 
18204
- if (line >= newline_list->size) {
18218
+ if (index >= newline_list->size - 1) {
18205
18219
  end = parser->end;
18206
18220
  } else {
18207
- end = &parser->start[newline_list->offsets[line]];
18221
+ end = &parser->start[newline_list->offsets[index + 1]];
18208
18222
  }
18209
18223
 
18210
- pm_buffer_append_format(buffer, number_prefix, (uint32_t) line);
18224
+ pm_buffer_append_format(buffer, number_prefix, line);
18211
18225
  pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
18212
18226
 
18213
18227
  if (end == parser->end && end[-1] != '\n') {
@@ -18225,25 +18239,26 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18225
18239
 
18226
18240
  // First, we're going to sort all of the errors by line number using an
18227
18241
  // insertion sort into a newly allocated array.
18242
+ const int32_t start_line = parser->start_line;
18228
18243
  const pm_newline_list_t *newline_list = &parser->newline_list;
18229
- pm_error_t *errors = pm_parser_errors_format_sort(error_list, newline_list);
18244
+ pm_error_t *errors = pm_parser_errors_format_sort(parser, error_list, newline_list);
18230
18245
 
18231
18246
  // Now we're going to determine how we're going to format line numbers and
18232
18247
  // blank lines based on the maximum number of digits in the line numbers
18233
18248
  // that are going to be displayed.
18234
18249
  pm_error_format_t error_format;
18235
- size_t max_line_number = errors[error_list->size - 1].line;
18250
+ int32_t max_line_number = errors[error_list->size - 1].line - start_line;
18236
18251
 
18237
18252
  if (max_line_number < 10) {
18238
18253
  if (colorize) {
18239
18254
  error_format = (pm_error_format_t) {
18240
- .number_prefix = PM_COLOR_GRAY "%1" PRIu32 " | " PM_COLOR_RESET,
18255
+ .number_prefix = PM_COLOR_GRAY "%1" PRIi32 " | " PM_COLOR_RESET,
18241
18256
  .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
18242
18257
  .divider = PM_COLOR_GRAY " ~~~~~" PM_COLOR_RESET "\n"
18243
18258
  };
18244
18259
  } else {
18245
18260
  error_format = (pm_error_format_t) {
18246
- .number_prefix = "%1" PRIu32 " | ",
18261
+ .number_prefix = "%1" PRIi32 " | ",
18247
18262
  .blank_prefix = " | ",
18248
18263
  .divider = " ~~~~~\n"
18249
18264
  };
@@ -18251,13 +18266,13 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18251
18266
  } else if (max_line_number < 100) {
18252
18267
  if (colorize) {
18253
18268
  error_format = (pm_error_format_t) {
18254
- .number_prefix = PM_COLOR_GRAY "%2" PRIu32 " | " PM_COLOR_RESET,
18269
+ .number_prefix = PM_COLOR_GRAY "%2" PRIi32 " | " PM_COLOR_RESET,
18255
18270
  .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
18256
18271
  .divider = PM_COLOR_GRAY " ~~~~~~" PM_COLOR_RESET "\n"
18257
18272
  };
18258
18273
  } else {
18259
18274
  error_format = (pm_error_format_t) {
18260
- .number_prefix = "%2" PRIu32 " | ",
18275
+ .number_prefix = "%2" PRIi32 " | ",
18261
18276
  .blank_prefix = " | ",
18262
18277
  .divider = " ~~~~~~\n"
18263
18278
  };
@@ -18265,13 +18280,13 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18265
18280
  } else if (max_line_number < 1000) {
18266
18281
  if (colorize) {
18267
18282
  error_format = (pm_error_format_t) {
18268
- .number_prefix = PM_COLOR_GRAY "%3" PRIu32 " | " PM_COLOR_RESET,
18283
+ .number_prefix = PM_COLOR_GRAY "%3" PRIi32 " | " PM_COLOR_RESET,
18269
18284
  .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
18270
18285
  .divider = PM_COLOR_GRAY " ~~~~~~~" PM_COLOR_RESET "\n"
18271
18286
  };
18272
18287
  } else {
18273
18288
  error_format = (pm_error_format_t) {
18274
- .number_prefix = "%3" PRIu32 " | ",
18289
+ .number_prefix = "%3" PRIi32 " | ",
18275
18290
  .blank_prefix = " | ",
18276
18291
  .divider = " ~~~~~~~\n"
18277
18292
  };
@@ -18279,13 +18294,13 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18279
18294
  } else if (max_line_number < 10000) {
18280
18295
  if (colorize) {
18281
18296
  error_format = (pm_error_format_t) {
18282
- .number_prefix = PM_COLOR_GRAY "%4" PRIu32 " | " PM_COLOR_RESET,
18297
+ .number_prefix = PM_COLOR_GRAY "%4" PRIi32 " | " PM_COLOR_RESET,
18283
18298
  .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
18284
18299
  .divider = PM_COLOR_GRAY " ~~~~~~~~" PM_COLOR_RESET "\n"
18285
18300
  };
18286
18301
  } else {
18287
18302
  error_format = (pm_error_format_t) {
18288
- .number_prefix = "%4" PRIu32 " | ",
18303
+ .number_prefix = "%4" PRIi32 " | ",
18289
18304
  .blank_prefix = " | ",
18290
18305
  .divider = " ~~~~~~~~\n"
18291
18306
  };
@@ -18293,13 +18308,13 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18293
18308
  } else {
18294
18309
  if (colorize) {
18295
18310
  error_format = (pm_error_format_t) {
18296
- .number_prefix = PM_COLOR_GRAY "%5" PRIu32 " | " PM_COLOR_RESET,
18311
+ .number_prefix = PM_COLOR_GRAY "%5" PRIi32 " | " PM_COLOR_RESET,
18297
18312
  .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
18298
18313
  .divider = PM_COLOR_GRAY " ~~~~~~~~" PM_COLOR_RESET "\n"
18299
18314
  };
18300
18315
  } else {
18301
18316
  error_format = (pm_error_format_t) {
18302
- .number_prefix = "%5" PRIu32 " | ",
18317
+ .number_prefix = "%5" PRIi32 " | ",
18303
18318
  .blank_prefix = " | ",
18304
18319
  .divider = " ~~~~~~~~\n"
18305
18320
  };
@@ -18314,7 +18329,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18314
18329
  // the source before the error to give some context. We'll be careful not to
18315
18330
  // display the same line twice in case the errors are close enough in the
18316
18331
  // source.
18317
- uint32_t last_line = 0;
18332
+ int32_t last_line = 0;
18318
18333
  const pm_encoding_t *encoding = parser->encoding;
18319
18334
 
18320
18335
  for (size_t index = 0; index < error_list->size; index++) {
@@ -18360,7 +18375,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18360
18375
  pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length);
18361
18376
 
18362
18377
  size_t column = 0;
18363
- const uint8_t *start = &parser->start[newline_list->offsets[error->line - 1]];
18378
+ const uint8_t *start = &parser->start[newline_list->offsets[error->line - start_line]];
18364
18379
 
18365
18380
  while (column < error->column_end) {
18366
18381
  if (column < error->column_start) {
@@ -18384,7 +18399,7 @@ pm_parser_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, bool col
18384
18399
  // Here we determine how many lines of padding to display after the
18385
18400
  // error, depending on where the next error is in source.
18386
18401
  last_line = error->line;
18387
- size_t next_line = (index == error_list->size - 1) ? newline_list->size : errors[index + 1].line;
18402
+ int32_t next_line = (index == error_list->size - 1) ? ((int32_t) newline_list->size) : errors[index + 1].line;
18388
18403
 
18389
18404
  if (next_line - last_line > 1) {
18390
18405
  pm_buffer_append_string(buffer, " ", 2);
@@ -51,7 +51,7 @@ pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor) {
51
51
  * are returned.
52
52
  */
53
53
  pm_line_column_t
54
- pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor) {
54
+ pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
55
55
  assert(cursor >= list->start);
56
56
  size_t offset = (size_t) (cursor - list->start);
57
57
 
@@ -62,7 +62,7 @@ pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor
62
62
  size_t mid = left + (right - left) / 2;
63
63
 
64
64
  if (list->offsets[mid] == offset) {
65
- return ((pm_line_column_t) { mid + 1, 0 });
65
+ return ((pm_line_column_t) { ((int32_t) mid) + start_line, 0 });
66
66
  }
67
67
 
68
68
  if (list->offsets[mid] < offset) {
@@ -72,7 +72,10 @@ pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor
72
72
  }
73
73
  }
74
74
 
75
- return ((pm_line_column_t) { left, offset - list->offsets[left - 1] });
75
+ return ((pm_line_column_t) {
76
+ .line = ((int32_t) left) + start_line - 1,
77
+ .column = (uint32_t) (offset - list->offsets[left - 1])
78
+ });
76
79
  }
77
80
 
78
81
  /**
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prism
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0
4
+ version: 0.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-14 00:00:00.000000000 Z
11
+ date: 2024-02-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -95,6 +95,8 @@ files:
95
95
  - lib/prism/translation/parser/compiler.rb
96
96
  - lib/prism/translation/parser/lexer.rb
97
97
  - lib/prism/translation/parser/rubocop.rb
98
+ - lib/prism/translation/parser33.rb
99
+ - lib/prism/translation/parser34.rb
98
100
  - lib/prism/translation/ripper.rb
99
101
  - lib/prism/translation/ruby_parser.rb
100
102
  - lib/prism/visitor.rb