prism 0.21.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
data/src/prism.c CHANGED
@@ -492,7 +492,8 @@ pm_parser_err(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_
492
492
  /**
493
493
  * Append an error to the list of errors on the parser using a format string.
494
494
  */
495
- #define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
495
+ #define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
496
+ pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
496
497
 
497
498
  /**
498
499
  * Append an error to the list of errors on the parser using the location of the
@@ -507,7 +508,8 @@ pm_parser_err_current(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
507
508
  * Append an error to the list of errors on the parser using the given location
508
509
  * using a format string.
509
510
  */
510
- #define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, (location)->start, (location)->end, diag_id, __VA_ARGS__)
511
+ #define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
512
+ PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
511
513
 
512
514
  /**
513
515
  * Append an error to the list of errors on the parser using the location of the
@@ -522,7 +524,15 @@ pm_parser_err_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_
522
524
  * Append an error to the list of errors on the parser using the location of the
523
525
  * given node and a format string.
524
526
  */
525
- #define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, node->location.start, node->location.end, diag_id, __VA_ARGS__)
527
+ #define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
528
+ PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
529
+
530
+ /**
531
+ * Append an error to the list of errors on the parser using the location of the
532
+ * given node and a format string, and add on the content of the node.
533
+ */
534
+ #define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
535
+ PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
526
536
 
527
537
  /**
528
538
  * Append an error to the list of errors on the parser using the location of the
@@ -546,7 +556,15 @@ pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_
546
556
  * Append an error to the list of errors on the parser using the location of the
547
557
  * given token and a format string.
548
558
  */
549
- #define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) pm_diagnostic_list_append_format(&parser->error_list, (token).start, (token).end, diag_id, __VA_ARGS__)
559
+ #define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
560
+ PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
561
+
562
+ /**
563
+ * Append an error to the list of errors on the parser using the location of the
564
+ * given token and a format string, and add on the content of the token.
565
+ */
566
+ #define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
567
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
550
568
 
551
569
  /**
552
570
  * Append a warning to the list of warnings on the parser.
@@ -2890,7 +2908,8 @@ pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
2890
2908
  static pm_def_node_t *
2891
2909
  pm_def_node_create(
2892
2910
  pm_parser_t *parser,
2893
- const pm_token_t *name,
2911
+ pm_constant_id_t name,
2912
+ const pm_token_t *name_loc,
2894
2913
  pm_node_t *receiver,
2895
2914
  pm_parameters_node_t *parameters,
2896
2915
  pm_node_t *body,
@@ -2920,8 +2939,8 @@ pm_def_node_create(
2920
2939
  .type = PM_DEF_NODE,
2921
2940
  .location = { .start = def_keyword->start, .end = end },
2922
2941
  },
2923
- .name = pm_parser_constant_id_token(parser, name),
2924
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
2942
+ .name = name,
2943
+ .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
2925
2944
  .receiver = receiver,
2926
2945
  .parameters = parameters,
2927
2946
  .body = body,
@@ -4642,13 +4661,20 @@ pm_multi_target_node_create(pm_parser_t *parser) {
4642
4661
  */
4643
4662
  static void
4644
4663
  pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
4645
- if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE) || PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
4664
+ if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
4646
4665
  if (node->rest == NULL) {
4647
4666
  node->rest = target;
4648
4667
  } else {
4649
4668
  pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
4650
4669
  pm_node_list_append(&node->rights, target);
4651
4670
  }
4671
+ } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
4672
+ if (node->rest == NULL) {
4673
+ node->rest = target;
4674
+ } else {
4675
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
4676
+ pm_node_list_append(&node->rights, target);
4677
+ }
4652
4678
  } else if (node->rest == NULL) {
4653
4679
  pm_node_list_append(&node->lefts, target);
4654
4680
  } else {
@@ -7172,7 +7198,7 @@ lex_numeric(pm_parser_t *parser) {
7172
7198
  static pm_token_type_t
7173
7199
  lex_global_variable(pm_parser_t *parser) {
7174
7200
  if (parser->current.end >= parser->end) {
7175
- pm_parser_err_current(parser, PM_ERR_INVALID_VARIABLE_GLOBAL);
7201
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_INVALID_VARIABLE_GLOBAL);
7176
7202
  return PM_TOKEN_GLOBAL_VARIABLE;
7177
7203
  }
7178
7204
 
@@ -7213,7 +7239,7 @@ lex_global_variable(pm_parser_t *parser) {
7213
7239
  } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
7214
7240
 
7215
7241
  // $0 isn't allowed to be followed by anything.
7216
- pm_parser_err_current(parser, PM_ERR_INVALID_VARIABLE_GLOBAL);
7242
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_INVALID_VARIABLE_GLOBAL);
7217
7243
  }
7218
7244
 
7219
7245
  return PM_TOKEN_GLOBAL_VARIABLE;
@@ -7244,7 +7270,7 @@ lex_global_variable(pm_parser_t *parser) {
7244
7270
  } else {
7245
7271
  // If we get here, then we have a $ followed by something that isn't
7246
7272
  // recognized as a global variable.
7247
- pm_parser_err_current(parser, PM_ERR_INVALID_VARIABLE_GLOBAL);
7273
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_INVALID_VARIABLE_GLOBAL);
7248
7274
  }
7249
7275
 
7250
7276
  return PM_TOKEN_GLOBAL_VARIABLE;
@@ -8148,10 +8174,10 @@ lex_at_variable(pm_parser_t *parser) {
8148
8174
  while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0) {
8149
8175
  parser->current.end += width;
8150
8176
  }
8151
- } else if (type == PM_TOKEN_CLASS_VARIABLE) {
8152
- pm_parser_err_current(parser, PM_ERR_INCOMPLETE_VARIABLE_CLASS);
8153
8177
  } else {
8154
- pm_parser_err_current(parser, PM_ERR_INCOMPLETE_VARIABLE_INSTANCE);
8178
+ pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
8179
+ size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8180
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, (int) ((parser->current.end + width) - parser->current.start), (const char *) parser->current.start);
8155
8181
  }
8156
8182
 
8157
8183
  // If we're lexing an embedded variable, then we need to pop back into the
@@ -9590,11 +9616,21 @@ parser_lex(pm_parser_t *parser) {
9590
9616
  if (*parser->current.start != '_') {
9591
9617
  size_t width = char_is_identifier_start(parser, parser->current.start);
9592
9618
 
9593
- // If this isn't the beginning of an identifier, then it's an invalid
9594
- // token as we've exhausted all of the other options. We'll skip past
9595
- // it and return the next token.
9619
+ // If this isn't the beginning of an identifier, then
9620
+ // it's an invalid token as we've exhausted all of the
9621
+ // other options. We'll skip past it and return the next
9622
+ // token after adding an appropriate error message.
9596
9623
  if (!width) {
9597
- pm_parser_err_current(parser, PM_ERR_INVALID_TOKEN);
9624
+ pm_diagnostic_id_t diag_id;
9625
+ if (*parser->current.start >= 0x80) {
9626
+ diag_id = PM_ERR_INVALID_MULTIBYTE_CHARACTER;
9627
+ } else if (char_is_ascii_printable(*parser->current.start) || (*parser->current.start == '\\')) {
9628
+ diag_id = PM_ERR_INVALID_PRINTABLE_CHARACTER;
9629
+ } else {
9630
+ diag_id = PM_ERR_INVALID_CHARACTER;
9631
+ }
9632
+
9633
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, *parser->current.start);
9598
9634
  goto lex_next_token;
9599
9635
  }
9600
9636
 
@@ -9701,7 +9737,7 @@ parser_lex(pm_parser_t *parser) {
9701
9737
  // and then find the first one.
9702
9738
  pm_lex_mode_t *lex_mode = parser->lex_modes.current;
9703
9739
  const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
9704
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9740
+ const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
9705
9741
 
9706
9742
  // If we haven't found an escape yet, then this buffer will be
9707
9743
  // unallocated since we can refer directly to the source string.
@@ -9710,7 +9746,7 @@ parser_lex(pm_parser_t *parser) {
9710
9746
  while (breakpoint != NULL) {
9711
9747
  // If we hit a null byte, skip directly past it.
9712
9748
  if (*breakpoint == '\0') {
9713
- breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1));
9749
+ breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1), true);
9714
9750
  continue;
9715
9751
  }
9716
9752
 
@@ -9729,7 +9765,7 @@ parser_lex(pm_parser_t *parser) {
9729
9765
  // we need to continue on past it.
9730
9766
  if (lex_mode->as.list.nesting > 0) {
9731
9767
  parser->current.end = breakpoint + 1;
9732
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9768
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
9733
9769
  lex_mode->as.list.nesting--;
9734
9770
  continue;
9735
9771
  }
@@ -9814,7 +9850,7 @@ parser_lex(pm_parser_t *parser) {
9814
9850
  }
9815
9851
 
9816
9852
  token_buffer.cursor = parser->current.end;
9817
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9853
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
9818
9854
  continue;
9819
9855
  }
9820
9856
 
@@ -9827,7 +9863,7 @@ parser_lex(pm_parser_t *parser) {
9827
9863
  // that looked like an interpolated class or instance variable
9828
9864
  // like "#@" but wasn't actually. In this case we'll just skip
9829
9865
  // to the next breakpoint.
9830
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9866
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
9831
9867
  continue;
9832
9868
  }
9833
9869
 
@@ -9842,7 +9878,7 @@ parser_lex(pm_parser_t *parser) {
9842
9878
  // and find the next breakpoint.
9843
9879
  assert(*breakpoint == lex_mode->as.list.incrementor);
9844
9880
  parser->current.end = breakpoint + 1;
9845
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9881
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
9846
9882
  lex_mode->as.list.nesting++;
9847
9883
  continue;
9848
9884
  }
@@ -9881,14 +9917,14 @@ parser_lex(pm_parser_t *parser) {
9881
9917
  // regular expression. We'll use strpbrk to find the first of these
9882
9918
  // characters.
9883
9919
  const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
9884
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9920
+ const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
9885
9921
  pm_token_buffer_t token_buffer = { { 0 }, 0 };
9886
9922
 
9887
9923
  while (breakpoint != NULL) {
9888
9924
  // If we hit a null byte, skip directly past it.
9889
9925
  if (*breakpoint == '\0') {
9890
9926
  parser->current.end = breakpoint + 1;
9891
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9927
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
9892
9928
  continue;
9893
9929
  }
9894
9930
 
@@ -9910,7 +9946,7 @@ parser_lex(pm_parser_t *parser) {
9910
9946
  // If the terminator is not a newline, then we can set
9911
9947
  // the next breakpoint and continue.
9912
9948
  parser->current.end = breakpoint + 1;
9913
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9949
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
9914
9950
  continue;
9915
9951
  }
9916
9952
  }
@@ -9920,7 +9956,7 @@ parser_lex(pm_parser_t *parser) {
9920
9956
  if (*breakpoint == lex_mode->as.regexp.terminator) {
9921
9957
  if (lex_mode->as.regexp.nesting > 0) {
9922
9958
  parser->current.end = breakpoint + 1;
9923
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
9959
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
9924
9960
  lex_mode->as.regexp.nesting--;
9925
9961
  continue;
9926
9962
  }
@@ -10019,7 +10055,7 @@ parser_lex(pm_parser_t *parser) {
10019
10055
  }
10020
10056
 
10021
10057
  token_buffer.cursor = parser->current.end;
10022
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10058
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
10023
10059
  continue;
10024
10060
  }
10025
10061
 
@@ -10032,7 +10068,7 @@ parser_lex(pm_parser_t *parser) {
10032
10068
  // something that looked like an interpolated class or
10033
10069
  // instance variable like "#@" but wasn't actually. In
10034
10070
  // this case we'll just skip to the next breakpoint.
10035
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10071
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
10036
10072
  continue;
10037
10073
  }
10038
10074
 
@@ -10047,7 +10083,7 @@ parser_lex(pm_parser_t *parser) {
10047
10083
  // and find the next breakpoint.
10048
10084
  assert(*breakpoint == lex_mode->as.regexp.incrementor);
10049
10085
  parser->current.end = breakpoint + 1;
10050
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10086
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
10051
10087
  lex_mode->as.regexp.nesting++;
10052
10088
  continue;
10053
10089
  }
@@ -10083,7 +10119,7 @@ parser_lex(pm_parser_t *parser) {
10083
10119
  // string. We'll use strpbrk to find the first of these characters.
10084
10120
  pm_lex_mode_t *lex_mode = parser->lex_modes.current;
10085
10121
  const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
10086
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10122
+ const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10087
10123
 
10088
10124
  // If we haven't found an escape yet, then this buffer will be
10089
10125
  // unallocated since we can refer directly to the source string.
@@ -10095,7 +10131,7 @@ parser_lex(pm_parser_t *parser) {
10095
10131
  if (lex_mode->as.string.incrementor != '\0' && *breakpoint == lex_mode->as.string.incrementor) {
10096
10132
  lex_mode->as.string.nesting++;
10097
10133
  parser->current.end = breakpoint + 1;
10098
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10134
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10099
10135
  continue;
10100
10136
  }
10101
10137
 
@@ -10107,7 +10143,7 @@ parser_lex(pm_parser_t *parser) {
10107
10143
  // to continue on past it.
10108
10144
  if (lex_mode->as.string.nesting > 0) {
10109
10145
  parser->current.end = breakpoint + 1;
10110
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10146
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10111
10147
  lex_mode->as.string.nesting--;
10112
10148
  continue;
10113
10149
  }
@@ -10149,7 +10185,7 @@ parser_lex(pm_parser_t *parser) {
10149
10185
  if (parser->heredoc_end == NULL) {
10150
10186
  pm_newline_list_append(&parser->newline_list, breakpoint);
10151
10187
  parser->current.end = breakpoint + 1;
10152
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10188
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10153
10189
  continue;
10154
10190
  } else {
10155
10191
  parser->current.end = breakpoint + 1;
@@ -10163,7 +10199,7 @@ parser_lex(pm_parser_t *parser) {
10163
10199
  case '\0':
10164
10200
  // Skip directly past the null character.
10165
10201
  parser->current.end = breakpoint + 1;
10166
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10202
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10167
10203
  break;
10168
10204
  case '\\': {
10169
10205
  // Here we hit escapes.
@@ -10232,7 +10268,7 @@ parser_lex(pm_parser_t *parser) {
10232
10268
  }
10233
10269
 
10234
10270
  token_buffer.cursor = parser->current.end;
10235
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10271
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10236
10272
  break;
10237
10273
  }
10238
10274
  case '#': {
@@ -10243,7 +10279,7 @@ parser_lex(pm_parser_t *parser) {
10243
10279
  // looked like an interpolated class or instance variable like "#@"
10244
10280
  // but wasn't actually. In this case we'll just skip to the next
10245
10281
  // breakpoint.
10246
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10282
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10247
10283
  break;
10248
10284
  }
10249
10285
 
@@ -10371,7 +10407,7 @@ parser_lex(pm_parser_t *parser) {
10371
10407
  breakpoints[2] = '\0';
10372
10408
  }
10373
10409
 
10374
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10410
+ const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10375
10411
  pm_token_buffer_t token_buffer = { { 0 }, 0 };
10376
10412
  bool was_escaped_newline = false;
10377
10413
 
@@ -10380,7 +10416,7 @@ parser_lex(pm_parser_t *parser) {
10380
10416
  case '\0':
10381
10417
  // Skip directly past the null character.
10382
10418
  parser->current.end = breakpoint + 1;
10383
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10419
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10384
10420
  break;
10385
10421
  case '\n': {
10386
10422
  if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
@@ -10455,7 +10491,7 @@ parser_lex(pm_parser_t *parser) {
10455
10491
  // Otherwise we hit a newline and it wasn't followed by
10456
10492
  // a terminator, so we can continue parsing.
10457
10493
  parser->current.end = breakpoint + 1;
10458
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10494
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10459
10495
  break;
10460
10496
  }
10461
10497
  case '\\': {
@@ -10519,7 +10555,7 @@ parser_lex(pm_parser_t *parser) {
10519
10555
  }
10520
10556
 
10521
10557
  token_buffer.cursor = parser->current.end;
10522
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10558
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10523
10559
  break;
10524
10560
  }
10525
10561
  case '#': {
@@ -10531,7 +10567,7 @@ parser_lex(pm_parser_t *parser) {
10531
10567
  // or instance variable like "#@" but wasn't
10532
10568
  // actually. In this case we'll just skip to the
10533
10569
  // next breakpoint.
10534
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
10570
+ breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
10535
10571
  break;
10536
10572
  }
10537
10573
 
@@ -11044,7 +11080,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
11044
11080
  return target;
11045
11081
  case PM_BACK_REFERENCE_READ_NODE:
11046
11082
  case PM_NUMBERED_REFERENCE_READ_NODE:
11047
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_READONLY);
11083
+ PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
11048
11084
  return target;
11049
11085
  case PM_GLOBAL_VARIABLE_READ_NODE:
11050
11086
  assert(sizeof(pm_global_variable_target_node_t) == sizeof(pm_global_variable_read_node_t));
@@ -11182,7 +11218,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
11182
11218
  }
11183
11219
  case PM_BACK_REFERENCE_READ_NODE:
11184
11220
  case PM_NUMBERED_REFERENCE_READ_NODE:
11185
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_READONLY);
11221
+ PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
11186
11222
  /* fallthrough */
11187
11223
  case PM_GLOBAL_VARIABLE_READ_NODE: {
11188
11224
  pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target, operator, value);
@@ -11357,7 +11393,7 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
11357
11393
  pm_multi_target_node_targets_append(parser, result, target);
11358
11394
  } else if (!match1(parser, PM_TOKEN_EOF)) {
11359
11395
  // If we get here, then we have a trailing , in a multi target node.
11360
- // We'll set the implicit rest flag to indicate this.
11396
+ // We'll add an implicit rest node to represent this.
11361
11397
  pm_node_t *rest = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
11362
11398
  pm_multi_target_node_targets_append(parser, result, rest);
11363
11399
  break;
@@ -11447,8 +11483,13 @@ parse_statements(pm_parser_t *parser, pm_context_t context) {
11447
11483
 
11448
11484
  while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
11449
11485
  if (context_terminator(context, &parser->current)) break;
11450
- } else {
11451
- expect1(parser, PM_TOKEN_NEWLINE, PM_ERR_EXPECT_EOL_AFTER_STATEMENT);
11486
+ } else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
11487
+ // This is an inlined version of accept1 because the error that we
11488
+ // want to add has varargs. If this happens again, we should
11489
+ // probably extract a helper function.
11490
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
11491
+ parser->previous.start = parser->previous.end;
11492
+ parser->previous.type = PM_TOKEN_MISSING;
11452
11493
  }
11453
11494
  }
11454
11495
 
@@ -12377,25 +12418,10 @@ parse_rescues(pm_parser_t *parser, pm_begin_node_t *parent_node, bool def_p) {
12377
12418
  }
12378
12419
 
12379
12420
  static inline pm_begin_node_t *
12380
- parse_rescues_as_begin(pm_parser_t *parser, pm_statements_node_t *statements, bool def_p) {
12421
+ parse_rescues_as_begin(pm_parser_t *parser, const uint8_t *start, pm_statements_node_t *statements, bool def_p) {
12381
12422
  pm_token_t no_begin_token = not_provided(parser);
12382
12423
  pm_begin_node_t *begin_node = pm_begin_node_create(parser, &no_begin_token, statements);
12383
12424
  parse_rescues(parser, begin_node, def_p);
12384
-
12385
- // All nodes within a begin node are optional, so we look
12386
- // for the earliest possible node that we can use to set
12387
- // the BeginNode's start location
12388
- const uint8_t *start = begin_node->base.location.start;
12389
- if (begin_node->statements) {
12390
- start = begin_node->statements->base.location.start;
12391
- } else if (begin_node->rescue_clause) {
12392
- start = begin_node->rescue_clause->base.location.start;
12393
- } else if (begin_node->else_clause) {
12394
- start = begin_node->else_clause->base.location.start;
12395
- } else if (begin_node->ensure_clause) {
12396
- start = begin_node->ensure_clause->base.location.start;
12397
- }
12398
-
12399
12425
  begin_node->base.location.start = start;
12400
12426
  return begin_node;
12401
12427
  }
@@ -12490,7 +12516,7 @@ parse_block(pm_parser_t *parser) {
12490
12516
 
12491
12517
  if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
12492
12518
  assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
12493
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
12519
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, opening.start, (pm_statements_node_t *) statements, false);
12494
12520
  }
12495
12521
  }
12496
12522
 
@@ -13857,7 +13883,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
13857
13883
  pm_constant_id_t name_id = pm_parser_constant_id_constant(parser, "0it", 3);
13858
13884
  variable = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0);
13859
13885
  } else {
13860
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE, (int) (parser->previous.end - parser->previous.start), parser->previous.start);
13886
+ PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
13861
13887
  variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0);
13862
13888
  }
13863
13889
  }
@@ -14166,7 +14192,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
14166
14192
  parser_lex(parser);
14167
14193
 
14168
14194
  if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
14169
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
14195
+ expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
14170
14196
  // If we get here, then we have an end immediately after a
14171
14197
  // start. In that case we'll create an empty content token and
14172
14198
  // return an uninterpolated string.
@@ -14223,15 +14249,19 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
14223
14249
  parser_lex(parser);
14224
14250
  } while (match1(parser, PM_TOKEN_STRING_CONTENT));
14225
14251
 
14226
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
14252
+ expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
14227
14253
  node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
14228
14254
  } else if (accept1(parser, PM_TOKEN_LABEL_END) && !state_is_arg_labeled) {
14229
14255
  node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &unescaped));
14230
14256
  } else if (match1(parser, PM_TOKEN_EOF)) {
14231
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_TERM);
14257
+ pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
14232
14258
  node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
14259
+ } else if (accept1(parser, PM_TOKEN_STRING_END)) {
14260
+ node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
14233
14261
  } else {
14234
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
14262
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_type_human(parser->previous.type));
14263
+ parser->previous.start = parser->previous.end;
14264
+ parser->previous.type = PM_TOKEN_MISSING;
14235
14265
  node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
14236
14266
  }
14237
14267
  } else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
@@ -14246,7 +14276,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
14246
14276
  if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
14247
14277
  node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
14248
14278
  pm_node_flag_set(node, parse_unescaped_encoding(parser));
14249
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_TERM);
14279
+ expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
14250
14280
  } else if (accept1(parser, PM_TOKEN_LABEL_END)) {
14251
14281
  node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &unescaped));
14252
14282
  } else {
@@ -14337,6 +14367,29 @@ parse_strings(pm_parser_t *parser, pm_node_t *current) {
14337
14367
  return current;
14338
14368
  }
14339
14369
 
14370
+ /**
14371
+ * Append an error to the error list on the parser using the given diagnostic
14372
+ * ID. This function is a specialization that handles formatting the specific
14373
+ * kind of error that is being appended.
14374
+ */
14375
+ static void
14376
+ pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
14377
+ switch (diag_id) {
14378
+ case PM_ERR_HASH_KEY: {
14379
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, pm_token_type_human(parser->previous.type));
14380
+ break;
14381
+ }
14382
+ case PM_ERR_UNARY_RECEIVER: {
14383
+ const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_type_human(parser->current.type));
14384
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, human, parser->previous.start[0]);
14385
+ break;
14386
+ }
14387
+ default:
14388
+ pm_parser_err_previous(parser, diag_id);
14389
+ break;
14390
+ }
14391
+ }
14392
+
14340
14393
  /**
14341
14394
  * Parse an expression that begins with the previous node that we just lexed.
14342
14395
  */
@@ -14521,7 +14574,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
14521
14574
  // If we didn't find a terminator and we didn't find a right
14522
14575
  // parenthesis, then this is a syntax error.
14523
14576
  if (!terminator_found) {
14524
- pm_parser_err(parser, parser->current.start, parser->current.start, PM_ERR_EXPECT_EOL_AFTER_STATEMENT);
14577
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
14525
14578
  }
14526
14579
 
14527
14580
  // Parse each statement within the parentheses.
@@ -14550,7 +14603,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
14550
14603
  } else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14551
14604
  break;
14552
14605
  } else {
14553
- pm_parser_err(parser, parser->current.start, parser->current.start, PM_ERR_EXPECT_EOL_AFTER_STATEMENT);
14606
+ PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
14554
14607
  }
14555
14608
  }
14556
14609
 
@@ -15290,7 +15343,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
15290
15343
 
15291
15344
  if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15292
15345
  assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15293
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
15346
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, class_keyword.start, (pm_statements_node_t *) statements, false);
15294
15347
  }
15295
15348
 
15296
15349
  expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
@@ -15343,7 +15396,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
15343
15396
 
15344
15397
  if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15345
15398
  assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15346
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
15399
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, class_keyword.start, (pm_statements_node_t *) statements, false);
15347
15400
  }
15348
15401
 
15349
15402
  expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
@@ -15612,7 +15665,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
15612
15665
 
15613
15666
  if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15614
15667
  assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15615
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, true);
15668
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, def_keyword.start, (pm_statements_node_t *) statements, true);
15616
15669
  }
15617
15670
 
15618
15671
  pm_accepts_block_stack_pop(parser);
@@ -15631,10 +15684,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
15631
15684
  * methods to override the unary operators, we should ignore
15632
15685
  * the @ in the same way we do for symbols.
15633
15686
  */
15634
- name.end = parse_operator_symbol_name(&name);
15687
+ pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
15635
15688
 
15636
15689
  return (pm_node_t *) pm_def_node_create(
15637
15690
  parser,
15691
+ name_id,
15638
15692
  &name,
15639
15693
  receiver,
15640
15694
  params,
@@ -15872,7 +15926,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
15872
15926
 
15873
15927
  if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15874
15928
  assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15875
- statements = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) statements, false);
15929
+ statements = (pm_node_t *) parse_rescues_as_begin(parser, module_keyword.start, (pm_statements_node_t *) statements, false);
15876
15930
  }
15877
15931
 
15878
15932
  pm_constant_id_list_t locals = parser->current_scope->locals;
@@ -16463,7 +16517,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16463
16517
  // context of a multiple assignment. We enforce that here. We'll
16464
16518
  // still lex past it though and create a missing node place.
16465
16519
  if (binding_power != PM_BINDING_POWER_STATEMENT) {
16466
- pm_parser_err_previous(parser, diag_id);
16520
+ pm_parser_err_prefix(parser, diag_id);
16467
16521
  return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
16468
16522
  }
16469
16523
 
@@ -16486,7 +16540,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16486
16540
  parser_lex(parser);
16487
16541
 
16488
16542
  pm_token_t operator = parser->previous;
16489
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, PM_ERR_UNARY_RECEIVER_BANG);
16543
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, PM_ERR_UNARY_RECEIVER);
16490
16544
  pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!");
16491
16545
 
16492
16546
  pm_conditional_predicate(receiver);
@@ -16496,7 +16550,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16496
16550
  parser_lex(parser);
16497
16551
 
16498
16552
  pm_token_t operator = parser->previous;
16499
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_TILDE);
16553
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
16500
16554
  pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~");
16501
16555
 
16502
16556
  return (pm_node_t *) node;
@@ -16505,7 +16559,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16505
16559
  parser_lex(parser);
16506
16560
 
16507
16561
  pm_token_t operator = parser->previous;
16508
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_MINUS);
16562
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
16509
16563
  pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@");
16510
16564
 
16511
16565
  return (pm_node_t *) node;
@@ -16514,7 +16568,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16514
16568
  parser_lex(parser);
16515
16569
 
16516
16570
  pm_token_t operator = parser->previous;
16517
- pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_MINUS);
16571
+ pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
16518
16572
 
16519
16573
  if (accept1(parser, PM_TOKEN_STAR_STAR)) {
16520
16574
  pm_token_t exponent_operator = parser->previous;
@@ -16605,7 +16659,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16605
16659
 
16606
16660
  if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
16607
16661
  assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
16608
- body = (pm_node_t *) parse_rescues_as_begin(parser, (pm_statements_node_t *) body, false);
16662
+ body = (pm_node_t *) parse_rescues_as_begin(parser, opening.start, (pm_statements_node_t *) body, false);
16609
16663
  }
16610
16664
 
16611
16665
  expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
@@ -16630,7 +16684,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16630
16684
  parser_lex(parser);
16631
16685
 
16632
16686
  pm_token_t operator = parser->previous;
16633
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER_PLUS);
16687
+ pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, PM_ERR_UNARY_RECEIVER);
16634
16688
  pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@");
16635
16689
 
16636
16690
  return (pm_node_t *) node;
@@ -16653,7 +16707,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16653
16707
  // here because it will provide more context in addition to the
16654
16708
  // recoverable error that we will also add.
16655
16709
  if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
16656
- pm_parser_err_previous(parser, diag_id);
16710
+ pm_parser_err_prefix(parser, diag_id);
16657
16711
  }
16658
16712
 
16659
16713
  // If we get here, then we are assuming this token is closing a
@@ -16666,7 +16720,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
16666
16720
  // have an unexpected token.
16667
16721
  PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_type_human(parser->current.type));
16668
16722
  } else {
16669
- pm_parser_err_previous(parser, diag_id);
16723
+ pm_parser_err_prefix(parser, diag_id);
16670
16724
  }
16671
16725
 
16672
16726
  return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
@@ -16900,7 +16954,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
16900
16954
  switch (PM_NODE_TYPE(node)) {
16901
16955
  case PM_BACK_REFERENCE_READ_NODE:
16902
16956
  case PM_NUMBERED_REFERENCE_READ_NODE:
16903
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_READONLY);
16957
+ PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
16904
16958
  /* fallthrough */
16905
16959
  case PM_GLOBAL_VARIABLE_READ_NODE: {
16906
16960
  parser_lex(parser);
@@ -17011,7 +17065,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
17011
17065
  switch (PM_NODE_TYPE(node)) {
17012
17066
  case PM_BACK_REFERENCE_READ_NODE:
17013
17067
  case PM_NUMBERED_REFERENCE_READ_NODE:
17014
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_READONLY);
17068
+ PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
17015
17069
  /* fallthrough */
17016
17070
  case PM_GLOBAL_VARIABLE_READ_NODE: {
17017
17071
  parser_lex(parser);
@@ -17132,7 +17186,7 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
17132
17186
  switch (PM_NODE_TYPE(node)) {
17133
17187
  case PM_BACK_REFERENCE_READ_NODE:
17134
17188
  case PM_NUMBERED_REFERENCE_READ_NODE:
17135
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_READONLY);
17189
+ PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
17136
17190
  /* fallthrough */
17137
17191
  case PM_GLOBAL_VARIABLE_READ_NODE: {
17138
17192
  parser_lex(parser);
@@ -17796,6 +17850,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
17796
17850
  .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
17797
17851
  .next_start = NULL,
17798
17852
  .heredoc_end = NULL,
17853
+ .data_loc = { .start = NULL, .end = NULL },
17799
17854
  .comment_list = { 0 },
17800
17855
  .magic_comment_list = { 0 },
17801
17856
  .warning_list = { 0 },