prism 2.0.0.rc2-x86_64-linux-gnu → 2.0.0-x86_64-linux-gnu

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -2
  3. data/docs/serialization.md +19 -6
  4. data/ext/prism/api_node.c +80 -80
  5. data/ext/prism/extension.c +34 -67
  6. data/ext/prism/extension.h +1 -1
  7. data/include/prism/arena.h +8 -0
  8. data/include/prism/arena.hpp +42 -0
  9. data/include/prism/ast.h +11 -1
  10. data/include/prism/ast.hpp +641 -0
  11. data/include/prism/buffer.h +8 -0
  12. data/include/prism/buffer.hpp +55 -0
  13. data/include/prism/comments.h +17 -0
  14. data/include/prism/compiler/branch.h +26 -0
  15. data/include/prism/compiler/cplusplus.hpp +16 -0
  16. data/include/prism/compiler/exceptions.hpp +17 -0
  17. data/include/prism/compiler/format.h +2 -0
  18. data/include/prism/compiler/lifetimebound.hpp +25 -0
  19. data/include/prism/constant_pool.h +25 -0
  20. data/include/prism/diagnostic.h +18 -0
  21. data/include/prism/errors_format.h +8 -0
  22. data/include/prism/internal/node.h +8 -4
  23. data/include/prism/internal/stringy.h +1 -6
  24. data/include/prism/json.h +8 -0
  25. data/include/prism/line_offset_list.h +8 -0
  26. data/include/prism/magic_comments.h +18 -0
  27. data/include/prism/node.h +55 -10
  28. data/include/prism/node.hpp +272 -0
  29. data/include/prism/node_type.hpp +38 -0
  30. data/include/prism/options.h +10 -1
  31. data/include/prism/options.hpp +43 -0
  32. data/include/prism/parser.h +72 -64
  33. data/include/prism/parser.hpp +274 -0
  34. data/include/prism/prettyprint.h +8 -0
  35. data/include/prism/serialize.h +8 -0
  36. data/include/prism/source.h +8 -0
  37. data/include/prism/stream.h +8 -0
  38. data/include/prism/string_query.h +8 -0
  39. data/include/prism/stringy.h +16 -27
  40. data/include/prism/stringy.hpp +31 -0
  41. data/include/prism/version.h +9 -1
  42. data/include/prism.h +0 -8
  43. data/include/prism.hpp +24 -0
  44. data/lib/prism/3.3/prism.so +0 -0
  45. data/lib/prism/3.4/prism.so +0 -0
  46. data/lib/prism/4.0/prism.so +0 -0
  47. data/lib/prism/serialize.rb +2549 -3281
  48. data/prism.gemspec +14 -1
  49. data/rbi/generated/prism/node.rbi +736 -0
  50. data/rbi/generated/prism/serialize.rbi +6 -5
  51. data/sig/generated/prism/node.rbs +736 -0
  52. data/sig/generated/prism/serialize.rbs +7 -5
  53. data/src/comments.c +2 -2
  54. data/src/diagnostic.c +8 -0
  55. data/src/node.c +216 -368
  56. data/src/options.c +7 -13
  57. data/src/parser.c +52 -48
  58. data/src/prism.c +175 -194
  59. data/src/regexp.c +0 -1
  60. data/src/serialize.c +2300 -1950
  61. data/src/source.c +8 -2
  62. data/src/stringy.c +3 -33
  63. metadata +14 -1
data/src/prism.c CHANGED
@@ -1,4 +1,5 @@
1
1
  #include "prism/compiler/accel.h"
2
+ #include "prism/compiler/branch.h"
2
3
  #include "prism/compiler/fallthrough.h"
3
4
  #include "prism/compiler/unused.h"
4
5
 
@@ -68,24 +69,6 @@
68
69
  # define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
69
70
  #endif
70
71
 
71
- /**
72
- * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its
73
- * branch predication.
74
- */
75
- #if defined(__GNUC__) || defined(__clang__)
76
- /** The compiler should predicate that this branch will be taken. */
77
- #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
78
-
79
- /** The compiler should predicate that this branch will not be taken. */
80
- #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
81
- #else
82
- /** Void because this platform does not support branch prediction hints. */
83
- #define PRISM_LIKELY(x) (x)
84
-
85
- /** Void because this platform does not support branch prediction hints. */
86
- #define PRISM_UNLIKELY(x) (x)
87
- #endif
88
-
89
72
  /**
90
73
  * The prism version and the serialization format.
91
74
  */
@@ -2452,7 +2435,7 @@ pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node,
2452
2435
  PM_NODE_LENGTH_SET_NODE(node, argument);
2453
2436
  }
2454
2437
 
2455
- pm_node_list_append(arena, &node->arguments, argument);
2438
+ pm_node_list_append_inline(arena, &node->arguments, argument);
2456
2439
 
2457
2440
  if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2458
2441
  if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
@@ -2500,7 +2483,7 @@ pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_
2500
2483
  PM_NODE_START_SET_NODE(node, element);
2501
2484
  }
2502
2485
 
2503
- pm_node_list_append(arena, &node->elements, element);
2486
+ pm_node_list_append_inline(arena, &node->elements, element);
2504
2487
  PM_NODE_LENGTH_SET_NODE(node, element);
2505
2488
 
2506
2489
  // If the element is not a static literal, then the array is not a static
@@ -2553,9 +2536,9 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *node
2553
2536
  node->rest = child;
2554
2537
  found_rest = true;
2555
2538
  } else if (found_rest) {
2556
- pm_node_list_append(parser->arena, &node->posts, child);
2539
+ pm_node_list_append_inline(parser->arena, &node->posts, child);
2557
2540
  } else {
2558
- pm_node_list_append(parser->arena, &node->requireds, child);
2541
+ pm_node_list_append_inline(parser->arena, &node->requireds, child);
2559
2542
  }
2560
2543
  }
2561
2544
 
@@ -2623,7 +2606,7 @@ pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *openin
2623
2606
 
2624
2607
  static PRISM_INLINE void
2625
2608
  pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2626
- pm_node_list_append(arena, &node->requireds, inner);
2609
+ pm_node_list_append_inline(arena, &node->requireds, inner);
2627
2610
  }
2628
2611
 
2629
2612
  /**
@@ -2887,7 +2870,7 @@ pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name)
2887
2870
  */
2888
2871
  static void
2889
2872
  pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2890
- pm_node_list_append(arena, &node->locals, UP(local));
2873
+ pm_node_list_append_inline(arena, &node->locals, UP(local));
2891
2874
 
2892
2875
  if (PM_NODE_LENGTH(node) == 0) {
2893
2876
  PM_NODE_START_SET_NODE(node, local);
@@ -3540,7 +3523,7 @@ static void
3540
3523
  pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3541
3524
  assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3542
3525
 
3543
- pm_node_list_append(arena, &node->conditions, condition);
3526
+ pm_node_list_append_inline(arena, &node->conditions, condition);
3544
3527
  PM_NODE_LENGTH_SET_NODE(node, condition);
3545
3528
  }
3546
3529
 
@@ -3587,7 +3570,7 @@ static void
3587
3570
  pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3588
3571
  assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3589
3572
 
3590
- pm_node_list_append(arena, &node->conditions, condition);
3573
+ pm_node_list_append_inline(arena, &node->conditions, condition);
3591
3574
  PM_NODE_LENGTH_SET_NODE(node, condition);
3592
3575
  }
3593
3576
 
@@ -4127,7 +4110,7 @@ pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4127
4110
  // much more efficient, as we could instead resize the node list to only point
4128
4111
  // to 1...-1.
4129
4112
  for (size_t index = 1; index < nodes->size - 1; index++) {
4130
- pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
4113
+ pm_node_list_append_inline(parser->arena, &node->requireds, nodes->nodes[index]);
4131
4114
  }
4132
4115
 
4133
4116
  return node;
@@ -4624,7 +4607,7 @@ pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4624
4607
  */
4625
4608
  static PRISM_INLINE void
4626
4609
  pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4627
- pm_node_list_append(arena, &hash->elements, element);
4610
+ pm_node_list_append_inline(arena, &hash->elements, element);
4628
4611
 
4629
4612
  bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4630
4613
  if (static_literal) {
@@ -5049,7 +5032,7 @@ pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *
5049
5032
  break;
5050
5033
  }
5051
5034
 
5052
- pm_node_list_append(arena, parts, part);
5035
+ pm_node_list_append_inline(arena, parts, part);
5053
5036
  }
5054
5037
 
5055
5038
  /**
@@ -5191,7 +5174,7 @@ pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_n
5191
5174
  // These will only happen in error cases. But we want to handle it
5192
5175
  // here so that we don't fail the assertion.
5193
5176
  CLEAR_FLAGS(node);
5194
- pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5177
+ pm_node_list_append_inline(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5195
5178
  return;
5196
5179
  case PM_ERROR_RECOVERY_NODE:
5197
5180
  CLEAR_FLAGS(node);
@@ -5201,7 +5184,7 @@ pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_n
5201
5184
  break;
5202
5185
  }
5203
5186
 
5204
- pm_node_list_append(arena, &node->parts, part);
5187
+ pm_node_list_append_inline(arena, &node->parts, part);
5205
5188
 
5206
5189
  #undef CLEAR_FLAGS
5207
5190
  #undef MUTABLE_FLAGS
@@ -5381,7 +5364,7 @@ pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *
5381
5364
  pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5382
5365
  }
5383
5366
 
5384
- pm_node_list_append(arena, &hash->elements, element);
5367
+ pm_node_list_append_inline(arena, &hash->elements, element);
5385
5368
  if (PM_NODE_LENGTH(hash) == 0) {
5386
5369
  PM_NODE_START_SET_NODE(hash, element);
5387
5370
  }
@@ -5729,19 +5712,19 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t
5729
5712
  node->rest = target;
5730
5713
  } else {
5731
5714
  pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5732
- pm_node_list_append(parser->arena, &node->rights, target);
5715
+ pm_node_list_append_inline(parser->arena, &node->rights, target);
5733
5716
  }
5734
5717
  } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5735
5718
  if (node->rest == NULL) {
5736
5719
  node->rest = target;
5737
5720
  } else {
5738
5721
  PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5739
- pm_node_list_append(parser->arena, &node->rights, target);
5722
+ pm_node_list_append_inline(parser->arena, &node->rights, target);
5740
5723
  }
5741
5724
  } else if (node->rest == NULL) {
5742
- pm_node_list_append(parser->arena, &node->lefts, target);
5725
+ pm_node_list_append_inline(parser->arena, &node->lefts, target);
5743
5726
  } else {
5744
- pm_node_list_append(parser->arena, &node->rights, target);
5727
+ pm_node_list_append_inline(parser->arena, &node->rights, target);
5745
5728
  }
5746
5729
 
5747
5730
  if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
@@ -6016,7 +5999,7 @@ pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param)
6016
5999
  static void
6017
6000
  pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6018
6001
  pm_parameters_node_location_set(params, param);
6019
- pm_node_list_append(arena, &params->requireds, param);
6002
+ pm_node_list_append_inline(arena, &params->requireds, param);
6020
6003
  }
6021
6004
 
6022
6005
  /**
@@ -6025,7 +6008,7 @@ pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *par
6025
6008
  static void
6026
6009
  pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6027
6010
  pm_parameters_node_location_set(params, UP(param));
6028
- pm_node_list_append(arena, &params->optionals, UP(param));
6011
+ pm_node_list_append_inline(arena, &params->optionals, UP(param));
6029
6012
  }
6030
6013
 
6031
6014
  /**
@@ -6034,7 +6017,7 @@ pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *par
6034
6017
  static void
6035
6018
  pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6036
6019
  pm_parameters_node_location_set(params, param);
6037
- pm_node_list_append(arena, &params->posts, param);
6020
+ pm_node_list_append_inline(arena, &params->posts, param);
6038
6021
  }
6039
6022
 
6040
6023
  /**
@@ -6052,7 +6035,7 @@ pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6052
6035
  static void
6053
6036
  pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6054
6037
  pm_parameters_node_location_set(params, param);
6055
- pm_node_list_append(arena, &params->keywords, param);
6038
+ pm_node_list_append_inline(arena, &params->keywords, param);
6056
6039
  }
6057
6040
 
6058
6041
  /**
@@ -6340,7 +6323,7 @@ pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subseque
6340
6323
  */
6341
6324
  static void
6342
6325
  pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6343
- pm_node_list_append(arena, &node->exceptions, exception);
6326
+ pm_node_list_append_inline(arena, &node->exceptions, exception);
6344
6327
  PM_NODE_LENGTH_SET_NODE(node, exception);
6345
6328
  }
6346
6329
 
@@ -6573,7 +6556,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
6573
6556
  }
6574
6557
  }
6575
6558
 
6576
- pm_node_list_append(parser->arena, &node->body, statement);
6559
+ pm_node_list_append_inline(parser->arena, &node->body, statement);
6577
6560
  if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6578
6561
  }
6579
6562
 
@@ -6820,7 +6803,7 @@ pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6820
6803
  ((pm_string_t) { 0 })
6821
6804
  );
6822
6805
 
6823
- pm_string_constant_init(&node->unescaped, content, strlen(content));
6806
+ pm_string_init(&node->unescaped, (const uint8_t *) content, strlen(content));
6824
6807
  return node;
6825
6808
  }
6826
6809
 
@@ -6963,7 +6946,7 @@ pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6963
6946
  static void
6964
6947
  pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6965
6948
  PM_NODE_LENGTH_SET_NODE(node, name);
6966
- pm_node_list_append(arena, &node->names, name);
6949
+ pm_node_list_append_inline(arena, &node->names, name);
6967
6950
  }
6968
6951
 
6969
6952
  /**
@@ -7105,7 +7088,7 @@ pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7105
7088
  static void
7106
7089
  pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7107
7090
  PM_NODE_LENGTH_SET_NODE(node, condition);
7108
- pm_node_list_append(arena, &node->conditions, condition);
7091
+ pm_node_list_append_inline(arena, &node->conditions, condition);
7109
7092
  }
7110
7093
 
7111
7094
  /**
@@ -7692,6 +7675,27 @@ parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor
7692
7675
  return NULL;
7693
7676
  }
7694
7677
 
7678
+ /**
7679
+ * Returns true if the given magic comment key matches the given name, which is
7680
+ * written in lowercase with underscores and is the same length as the key.
7681
+ * Keys match case-insensitively, and a dash in the key matches an underscore in
7682
+ * the name. Every byte of a name is ASCII, so a byte of a multibyte character
7683
+ * in the key never matches one.
7684
+ */
7685
+ static bool
7686
+ parser_magic_comment_key_p(const uint8_t *key, size_t key_length, const char *name) {
7687
+ assert(name[key_length] == '\0');
7688
+
7689
+ for (size_t index = 0; index < key_length; index++) {
7690
+ uint8_t byte = key[index];
7691
+ if (byte == '-') byte = '_';
7692
+ if ('A' <= byte && byte <= 'Z') byte |= 0x20;
7693
+ if (byte != (uint8_t) name[index]) return false;
7694
+ }
7695
+
7696
+ return true;
7697
+ }
7698
+
7695
7699
  /**
7696
7700
  * Parse the current token on the parser to see if it's a magic comment and
7697
7701
  * potentially perform some action based on that. A regular expression that this
@@ -7783,73 +7787,34 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
7783
7787
  if (cursor != end) return false;
7784
7788
  }
7785
7789
 
7786
- // Here, we need to do some processing on the key to swap out dashes for
7787
- // underscores. We only need to do this if there _is_ a dash in the key.
7788
- pm_string_t key;
7790
+ /* Finally, we can start checking the key against the list of known
7791
+ * magic comment keys, and potentially change state based on that. */
7789
7792
  const size_t key_length = (size_t) (key_end - key_start);
7790
- const uint8_t *dash = pm_memchr(key_start, '-', key_length, parser->encoding_changed, parser->encoding);
7791
-
7792
- if (dash == NULL) {
7793
- pm_string_shared_init(&key, key_start, key_end);
7794
- } else {
7795
- uint8_t *buffer = xmalloc(key_length);
7796
- if (buffer == NULL) break;
7797
-
7798
- memcpy(buffer, key_start, key_length);
7799
- buffer[dash - key_start] = '_';
7800
-
7801
- while ((dash = pm_memchr(dash + 1, '-', (size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7802
- buffer[dash - key_start] = '_';
7803
- }
7804
-
7805
- pm_string_owned_init(&key, buffer, key_length);
7806
- }
7807
-
7808
- // Finally, we can start checking the key against the list of known
7809
- // magic comment keys, and potentially change state based on that.
7810
- const uint8_t *key_source = pm_string_source(&key);
7811
7793
  uint32_t value_length = (uint32_t) (value_end - value_start);
7812
7794
 
7813
- // We only want to attempt to compare against encoding comments if it's
7814
- // the first line in the file (or the second in the case of a shebang).
7815
- if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7816
- if (
7817
- (key_length == 8 && pm_strncasecmp(key_source, (const uint8_t *) "encoding", 8) == 0) ||
7818
- (key_length == 6 && pm_strncasecmp(key_source, (const uint8_t *) "coding", 6) == 0)
7819
- ) {
7820
- result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7821
- }
7822
- }
7823
-
7824
- if (key_length == 11) {
7825
- if (pm_strncasecmp(key_source, (const uint8_t *) "warn_indent", 11) == 0) {
7826
- switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7827
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7828
- PM_PARSER_WARN_TOKEN_FORMAT(
7829
- parser,
7830
- &parser->current,
7831
- PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7832
- (int) key_length,
7833
- (const char *) key_source,
7834
- (int) value_length,
7835
- (const char *) value_start
7836
- );
7837
- break;
7838
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7839
- parser->warn_mismatched_indentation = false;
7840
- break;
7841
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7842
- parser->warn_mismatched_indentation = true;
7843
- break;
7795
+ switch (key_length) {
7796
+ case 6:
7797
+ /* We only want to attempt to compare against encoding comments
7798
+ * if it is the first line in the file (or the second in the
7799
+ * case of a shebang). */
7800
+ if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7801
+ if (parser_magic_comment_key_p(key_start, key_length, "coding")) {
7802
+ result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7803
+ }
7844
7804
  }
7845
- }
7846
- } else if (key_length == 21) {
7847
- if (pm_strncasecmp(key_source, (const uint8_t *) "frozen_string_literal", 21) == 0) {
7848
- // We only want to handle frozen string literal comments if it's
7849
- // before any semantic tokens have been seen.
7850
- if (semantic_token_seen) {
7851
- pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7852
- } else {
7805
+ break;
7806
+ case 8:
7807
+ /* We only want to attempt to compare against encoding comments
7808
+ * if it is the first line in the file (or the second in the
7809
+ * case of a shebang). */
7810
+ if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7811
+ if (parser_magic_comment_key_p(key_start, key_length, "encoding")) {
7812
+ result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7813
+ }
7814
+ }
7815
+ break;
7816
+ case 11:
7817
+ if (parser_magic_comment_key_p(key_start, key_length, "warn_indent")) {
7853
7818
  switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7854
7819
  case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7855
7820
  PM_PARSER_WARN_TOKEN_FORMAT(
@@ -7857,53 +7822,79 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
7857
7822
  &parser->current,
7858
7823
  PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7859
7824
  (int) key_length,
7860
- (const char *) key_source,
7825
+ "warn_indent",
7861
7826
  (int) value_length,
7862
7827
  (const char *) value_start
7863
7828
  );
7864
7829
  break;
7865
7830
  case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7866
- parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
7831
+ parser->warn_mismatched_indentation = false;
7867
7832
  break;
7868
7833
  case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7869
- parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED;
7834
+ parser->warn_mismatched_indentation = true;
7870
7835
  break;
7871
7836
  }
7872
7837
  }
7873
- }
7874
- } else if (key_length == 24) {
7875
- if (pm_strncasecmp(key_source, (const uint8_t *) "shareable_constant_value", 24) == 0) {
7876
- const uint8_t *cursor = parser->current.start;
7877
- while ((cursor > parser->start) && ((cursor[-1] == ' ') || (cursor[-1] == '\t'))) cursor--;
7878
-
7879
- if (!((cursor == parser->start) || (cursor[-1] == '\n'))) {
7880
- pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7881
- } else if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
7882
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7883
- } else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
7884
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7885
- } else if (value_length == 23 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_everything", 23) == 0) {
7886
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7887
- } else if (value_length == 17 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_copy", 17) == 0) {
7888
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7889
- } else {
7890
- PM_PARSER_WARN_TOKEN_FORMAT(
7891
- parser,
7892
- &parser->current,
7893
- PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7894
- (int) key_length,
7895
- (const char *) key_source,
7896
- (int) value_length,
7897
- (const char *) value_start
7898
- );
7838
+ break;
7839
+ case 21:
7840
+ if (parser_magic_comment_key_p(key_start, key_length, "frozen_string_literal")) {
7841
+ /* We only want to handle frozen string literal comments if
7842
+ * it is before any semantic tokens have been seen. */
7843
+ if (semantic_token_seen) {
7844
+ pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7845
+ } else {
7846
+ switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7847
+ case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7848
+ PM_PARSER_WARN_TOKEN_FORMAT(
7849
+ parser,
7850
+ &parser->current,
7851
+ PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7852
+ (int) key_length,
7853
+ "frozen_string_literal",
7854
+ (int) value_length,
7855
+ (const char *) value_start
7856
+ );
7857
+ break;
7858
+ case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7859
+ parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
7860
+ break;
7861
+ case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7862
+ parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED;
7863
+ break;
7864
+ }
7865
+ }
7899
7866
  }
7900
- }
7867
+ break;
7868
+ case 24:
7869
+ if (parser_magic_comment_key_p(key_start, key_length, "shareable_constant_value")) {
7870
+ const uint8_t *cursor = parser->current.start;
7871
+ while ((cursor > parser->start) && ((cursor[-1] == ' ') || (cursor[-1] == '\t'))) cursor--;
7872
+
7873
+ if (!((cursor == parser->start) || (cursor[-1] == '\n'))) {
7874
+ pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7875
+ } else if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
7876
+ pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7877
+ } else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
7878
+ pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7879
+ } else if (value_length == 23 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_everything", 23) == 0) {
7880
+ pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7881
+ } else if (value_length == 17 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_copy", 17) == 0) {
7882
+ pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7883
+ } else {
7884
+ PM_PARSER_WARN_TOKEN_FORMAT(
7885
+ parser,
7886
+ &parser->current,
7887
+ PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7888
+ (int) key_length,
7889
+ "shareable_constant_value",
7890
+ (int) value_length,
7891
+ (const char *) value_start
7892
+ );
7893
+ }
7894
+ }
7895
+ break;
7901
7896
  }
7902
7897
 
7903
- // When we're done, we want to free the string in case we had to
7904
- // allocate memory for it.
7905
- pm_string_cleanup(&key);
7906
-
7907
7898
  // Allocate a new magic comment node to append to the parser's list.
7908
7899
  pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_magic_comment_t), PRISM_ALIGNOF(pm_magic_comment_t));
7909
7900
  magic_comment->node.next = NULL;
@@ -9650,7 +9641,7 @@ lex_question_mark(pm_parser_t *parser) {
9650
9641
 
9651
9642
  // Copy buffer data into the arena and free the heap buffer.
9652
9643
  void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length, PRISM_ALIGNOF(uint8_t));
9653
- pm_string_constant_init(&parser->current_string, (const char *) arena_data, buffer.length);
9644
+ pm_string_init(&parser->current_string, (const uint8_t *) arena_data, buffer.length);
9654
9645
  pm_buffer_cleanup(&buffer);
9655
9646
 
9656
9647
  return PM_TOKEN_CHARACTER_LITERAL;
@@ -9974,7 +9965,7 @@ pm_token_buffer_copy(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
9974
9965
  // Copy buffer data into the arena and free the heap buffer.
9975
9966
  size_t len = pm_buffer_length(&token_buffer->buffer);
9976
9967
  void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->buffer), len, PRISM_ALIGNOF(uint8_t));
9977
- pm_string_constant_init(&parser->current_string, (const char *) arena_data, len);
9968
+ pm_string_init(&parser->current_string, (const uint8_t *) arena_data, len);
9978
9969
  pm_buffer_cleanup(&token_buffer->buffer);
9979
9970
  }
9980
9971
 
@@ -13187,7 +13178,7 @@ parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power,
13187
13178
  return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13188
13179
  }
13189
13180
 
13190
- static bool
13181
+ static pm_visit_result_t
13191
13182
  pm_node_unreference_each(const pm_node_t *node, void *data) {
13192
13183
  switch (PM_NODE_TYPE(node)) {
13193
13184
  /* When we are about to destroy a set of nodes that could potentially
@@ -13213,15 +13204,15 @@ pm_node_unreference_each(const pm_node_t *node, void *data) {
13213
13204
  }
13214
13205
  parser->current_block_exits->size--;
13215
13206
 
13216
- /* Note returning true here because these nodes could have
13207
+ /* Note descending here because these nodes could have
13217
13208
  * arguments that are themselves block exits. */
13218
- return true;
13209
+ return PM_VISIT_DESCEND;
13219
13210
  }
13220
13211
 
13221
13212
  index++;
13222
13213
  }
13223
13214
 
13224
- return true;
13215
+ return PM_VISIT_DESCEND;
13225
13216
  }
13226
13217
  /* When an implicit local variable is written to or targeted, it becomes
13227
13218
  * a regular, named local variable. This branch removes it from the list
@@ -13245,10 +13236,10 @@ pm_node_unreference_each(const pm_node_t *node, void *data) {
13245
13236
  }
13246
13237
  }
13247
13238
 
13248
- return false;
13239
+ return PM_VISIT_SKIP;
13249
13240
  }
13250
13241
  default:
13251
- return true;
13242
+ return PM_VISIT_DESCEND;
13252
13243
  }
13253
13244
  }
13254
13245
 
@@ -15990,7 +15981,7 @@ ensure_valid_jump(pm_parser_t *parser, pm_node_t *node) {
15990
15981
  // block exit to the list of exits for the expression, and
15991
15982
  // the node parsing will handle validating it instead.
15992
15983
  assert(parser->current_block_exits != NULL);
15993
- pm_node_list_append(parser->arena, parser->current_block_exits, node);
15984
+ pm_node_list_append_inline(parser->arena, parser->current_block_exits, node);
15994
15985
  return;
15995
15986
  case PM_CONTEXT_BEGIN_ELSE:
15996
15987
  case PM_CONTEXT_BEGIN_ENSURE:
@@ -16728,12 +16719,12 @@ parse_variable(pm_parser_t *parser) {
16728
16719
  }
16729
16720
 
16730
16721
  pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false));
16731
- pm_node_list_append(parser->arena, &current_scope->implicit_parameters, node);
16722
+ pm_node_list_append_inline(parser->arena, &current_scope->implicit_parameters, node);
16732
16723
 
16733
16724
  return node;
16734
16725
  } else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
16735
16726
  pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16736
- pm_node_list_append(parser->arena, &current_scope->implicit_parameters, node);
16727
+ pm_node_list_append_inline(parser->arena, &current_scope->implicit_parameters, node);
16737
16728
 
16738
16729
  return node;
16739
16730
  }
@@ -16790,18 +16781,13 @@ parse_method_definition_name(pm_parser_t *parser) {
16790
16781
 
16791
16782
  static void
16792
16783
  parse_heredoc_dedent_string(pm_arena_t *arena, pm_string_t *string, size_t common_whitespace) {
16793
- // Make a writable copy in the arena if the string isn't already writable.
16794
- // We keep a mutable pointer to the arena memory so we can memmove into it
16795
- // below without casting away const from the string's source field.
16796
- uint8_t *writable;
16797
-
16798
- if (string->type != PM_STRING_OWNED) {
16799
- size_t length = pm_string_length(string);
16800
- writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(string), length, PRISM_ALIGNOF(uint8_t));
16801
- pm_string_constant_init(string, (const char *) writable, length);
16802
- } else {
16803
- writable = (uint8_t *) string->source;
16804
- }
16784
+ // Make a writable copy of the string in the arena, since strings only view
16785
+ // their bytes. We keep a mutable pointer to the arena memory so we can
16786
+ // memmove into it below without casting away const from the string's
16787
+ // source field.
16788
+ size_t length = pm_string_length(string);
16789
+ uint8_t *writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(string), length, PRISM_ALIGNOF(uint8_t));
16790
+ pm_string_init(string, writable, length);
16805
16791
 
16806
16792
  // Now get the bounds of the existing string. We'll use this as a
16807
16793
  // destination to move bytes into. We'll also use it for bounds checking
@@ -16966,11 +16952,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
16966
16952
  if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16967
16953
  pm_node_list_t parts = { 0 };
16968
16954
  pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16969
- pm_node_list_append(parser->arena, &parts, part);
16955
+ pm_node_list_append_inline(parser->arena, &parts, part);
16970
16956
 
16971
16957
  do {
16972
16958
  part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16973
- pm_node_list_append(parser->arena, &parts, part);
16959
+ pm_node_list_append_inline(parser->arena, &parts, part);
16974
16960
  parser_lex(parser);
16975
16961
  } while (match1(parser, PM_TOKEN_STRING_CONTENT));
16976
16962
 
@@ -17025,11 +17011,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
17025
17011
  pm_node_list_t parts = { 0 };
17026
17012
  pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
17027
17013
  pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
17028
- pm_node_list_append(parser->arena, &parts, part);
17014
+ pm_node_list_append_inline(parser->arena, &parts, part);
17029
17015
 
17030
17016
  while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
17031
17017
  if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
17032
- pm_node_list_append(parser->arena, &parts, part);
17018
+ pm_node_list_append_inline(parser->arena, &parts, part);
17033
17019
  }
17034
17020
  }
17035
17021
 
@@ -17053,7 +17039,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
17053
17039
 
17054
17040
  while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
17055
17041
  if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
17056
- pm_node_list_append(parser->arena, &parts, part);
17042
+ pm_node_list_append_inline(parser->arena, &parts, part);
17057
17043
  }
17058
17044
  }
17059
17045
 
@@ -17439,7 +17425,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
17439
17425
  }
17440
17426
 
17441
17427
  pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17442
- pm_node_list_append(parser->arena, &assocs, assoc);
17428
+ pm_node_list_append_inline(parser->arena, &assocs, assoc);
17443
17429
  break;
17444
17430
  }
17445
17431
  }
@@ -17454,7 +17440,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
17454
17440
  pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17455
17441
  pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17456
17442
 
17457
- pm_node_list_append(parser->arena, &assocs, assoc);
17443
+ pm_node_list_append_inline(parser->arena, &assocs, assoc);
17458
17444
  break;
17459
17445
  }
17460
17446
  }
@@ -17482,7 +17468,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
17482
17468
  rest = assoc;
17483
17469
  } else {
17484
17470
  pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17485
- pm_node_list_append(parser->arena, &assocs, assoc);
17471
+ pm_node_list_append_inline(parser->arena, &assocs, assoc);
17486
17472
  }
17487
17473
  } else {
17488
17474
  pm_node_t *key;
@@ -17528,7 +17514,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
17528
17514
  pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17529
17515
  }
17530
17516
 
17531
- pm_node_list_append(parser->arena, &assocs, assoc);
17517
+ pm_node_list_append_inline(parser->arena, &assocs, assoc);
17532
17518
  }
17533
17519
  }
17534
17520
 
@@ -17808,7 +17794,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_
17808
17794
  * are not captures of this pattern. A nested alternation is not visited
17809
17795
  * either: its operands were already checked when it was parsed.
17810
17796
  */
17811
- static bool
17797
+ static pm_visit_result_t
17812
17798
  parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
17813
17799
  pm_parser_t *parser = (pm_parser_t *) data;
17814
17800
 
@@ -17819,7 +17805,7 @@ parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
17819
17805
  if (peek_at(parser, parser->start + PM_NODE_START(node)) != '_') {
17820
17806
  pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17821
17807
  }
17822
- return false;
17808
+ return PM_VISIT_SKIP;
17823
17809
  case PM_ARRAY_PATTERN_NODE:
17824
17810
  case PM_ASSOC_NODE:
17825
17811
  case PM_ASSOC_SPLAT_NODE:
@@ -17829,9 +17815,9 @@ parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
17829
17815
  case PM_IMPLICIT_NODE:
17830
17816
  case PM_PARENTHESES_NODE:
17831
17817
  case PM_SPLAT_NODE:
17832
- return true;
17818
+ return PM_VISIT_DESCEND;
17833
17819
  default:
17834
- return false;
17820
+ return PM_VISIT_SKIP;
17835
17821
  }
17836
17822
  }
17837
17823
 
@@ -18027,7 +18013,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_set_t *captures, uint8_t flags
18027
18013
  // or a find pattern. We need to parse all of the patterns, put them
18028
18014
  // into a big list, and then determine which type of node we have.
18029
18015
  pm_node_list_t nodes = { 0 };
18030
- pm_node_list_append(parser->arena, &nodes, node);
18016
+ pm_node_list_append_inline(parser->arena, &nodes, node);
18031
18017
 
18032
18018
  // Gather up all of the patterns into the list.
18033
18019
  while (accept1(parser, PM_TOKEN_COMMA)) {
@@ -18046,7 +18032,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_set_t *captures, uint8_t flags
18046
18032
  }
18047
18033
 
18048
18034
  node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
18049
- pm_node_list_append(parser->arena, &nodes, node);
18035
+ pm_node_list_append_inline(parser->arena, &nodes, node);
18050
18036
  trailing_rest = true;
18051
18037
  break;
18052
18038
  }
@@ -18066,7 +18052,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_set_t *captures, uint8_t flags
18066
18052
  node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
18067
18053
  }
18068
18054
 
18069
- pm_node_list_append(parser->arena, &nodes, node);
18055
+ pm_node_list_append_inline(parser->arena, &nodes, node);
18070
18056
  }
18071
18057
 
18072
18058
  // If the first pattern and the last pattern are rest patterns, then we
@@ -19572,11 +19558,11 @@ parse_heredoc(pm_parser_t *parser, uint16_t depth) {
19572
19558
  // so we'll need to create an interpolated string node to hold
19573
19559
  // them all.
19574
19560
  pm_node_list_t parts = { 0 };
19575
- pm_node_list_append(parser->arena, &parts, part);
19561
+ pm_node_list_append_inline(parser->arena, &parts, part);
19576
19562
 
19577
19563
  while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19578
19564
  if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19579
- pm_node_list_append(parser->arena, &parts, part);
19565
+ pm_node_list_append_inline(parser->arena, &parts, part);
19580
19566
  }
19581
19567
  }
19582
19568
 
@@ -21845,7 +21831,7 @@ parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *c
21845
21831
  pm_token_t token = { .type = 0, .start = start, .end = end };
21846
21832
  pm_location_t token_loc = TOK2LOC(parser, &token);
21847
21833
  pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21848
- pm_node_list_append(parser->arena, &name_data->match->targets, target);
21834
+ pm_node_list_append_inline(parser->arena, &name_data->match->targets, target);
21849
21835
  }
21850
21836
 
21851
21837
  pm_buffer_cleanup(&unescaped);
@@ -22014,9 +22000,7 @@ parse_match(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t binding_pow
22014
22000
  }
22015
22001
 
22016
22002
  if (!interpolated && total_length > 0) {
22017
- void *memory = xmalloc(total_length);
22018
- if (!memory) abort();
22019
-
22003
+ uint8_t *memory = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, total_length, PRISM_ALIGNOF(uint8_t));
22020
22004
  uint8_t *cursor = memory;
22021
22005
  PM_NODE_LIST_FOREACH(parts, index, part) {
22022
22006
  pm_string_t *unescaped = &((pm_string_node_t *) part)->unescaped;
@@ -22026,11 +22010,9 @@ parse_match(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t binding_pow
22026
22010
  cursor += length;
22027
22011
  }
22028
22012
 
22029
- pm_string_t owned;
22030
- pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
22031
-
22032
- result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22033
- pm_string_cleanup(&owned);
22013
+ pm_string_t content;
22014
+ pm_string_init(&content, memory, total_length);
22015
+ result = parse_interpolated_regular_expression_named_captures(parser, &content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22034
22016
  }
22035
22017
  } else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
22036
22018
  /* If we have a regular expression node, then we can parse the named
@@ -22040,7 +22022,7 @@ parse_match(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t binding_pow
22040
22022
  .call = call,
22041
22023
  .match = NULL,
22042
22024
  .names = { 0 },
22043
- .shared = regexp->unescaped.type == PM_STRING_SHARED,
22025
+ .shared = pm_string_source(&regexp->unescaped) == parser->start + regexp->content_loc.start,
22044
22026
  };
22045
22027
 
22046
22028
  pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
@@ -23566,7 +23548,6 @@ pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_op
23566
23548
  */
23567
23549
  void
23568
23550
  pm_parser_cleanup(pm_parser_t *parser) {
23569
- pm_string_cleanup(&parser->filepath);
23570
23551
  pm_arena_cleanup(&parser->metadata_arena);
23571
23552
 
23572
23553
  while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {