herb 0.11.1 → 0.11.2

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -2
  3. data/config.yml +6 -0
  4. data/ext/herb/extconf.rb +8 -31
  5. data/ext/herb/nodes.c +75 -75
  6. data/ext/herb/parser_options_helpers.c +26 -0
  7. data/lib/herb/analysis/partial_index.rb +1 -1
  8. data/lib/herb/analysis/partial_resolution.rb +27 -0
  9. data/lib/herb/ast/helpers.rb +1 -1
  10. data/lib/herb/configuration.rb +11 -1
  11. data/lib/herb/dev/classifier.rb +1 -1
  12. data/lib/herb/engine/compiler.rb +5 -8
  13. data/lib/herb/engine/slots/dynamics_compiler.rb +53 -14
  14. data/lib/herb/engine/slots/subtree_compiler.rb +1 -1
  15. data/lib/herb/engine/slots/visitor.rb +32 -4
  16. data/lib/herb/engine/visitors/instrumentation_visitor.rb +18 -6
  17. data/lib/herb/parser_options.rb +6 -3
  18. data/lib/herb/project.rb +19 -8
  19. data/lib/herb/version.rb +1 -1
  20. data/lib/herb.rb +1 -1
  21. data/sig/herb/analysis/partial_resolution.rbs +8 -0
  22. data/sig/herb/configuration.rbs +3 -0
  23. data/sig/herb/engine/slots/dynamics_compiler.rbs +24 -7
  24. data/sig/herb/engine/slots/visitor.rbs +14 -0
  25. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +5 -1
  26. data/sig/herb/parser_options.rbs +6 -4
  27. data/sig/herb.rbs +2 -2
  28. data/src/analyze/action_view/attribute_extraction_helpers.c +40 -21
  29. data/src/analyze/action_view/generated_handlers.c +36 -36
  30. data/src/analyze/action_view/image_tag.c +7 -3
  31. data/src/analyze/action_view/javascript_include_tag.c +6 -3
  32. data/src/analyze/action_view/link_to.c +23 -23
  33. data/src/analyze/action_view/registry.c +7 -3
  34. data/src/analyze/action_view/tag_helper_node_builders.c +6 -13
  35. data/src/analyze/action_view/tag_helpers.c +139 -90
  36. data/src/analyze/action_view/turbo_frame_tag.c +5 -4
  37. data/src/analyze/analyze.c +35 -19
  38. data/src/analyze/analyze_helpers.c +161 -188
  39. data/src/analyze/analyzed_ruby.c +8 -7
  40. data/src/analyze/control_type.c +29 -22
  41. data/src/analyze/herb_directives.c +16 -20
  42. data/src/analyze/iteration_nodes.c +69 -24
  43. data/src/analyze/parse_errors.c +32 -22
  44. data/src/analyze/postfix_conditionals.c +23 -13
  45. data/src/analyze/prism_annotate.c +29 -28
  46. data/src/analyze/render_nodes.c +51 -41
  47. data/src/analyze/strict_locals.c +14 -15
  48. data/src/analyze/ternary_conditionals.c +14 -10
  49. data/src/herb.c +10 -8
  50. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  51. data/src/include/analyze/action_view/tag_helper_node_builders.h +1 -0
  52. data/src/include/analyze/action_view/tag_helpers.h +1 -1
  53. data/src/include/analyze/analyze.h +3 -2
  54. data/src/include/analyze/analyzed_ruby.h +4 -2
  55. data/src/include/analyze/helpers.h +6 -6
  56. data/src/include/herb.h +3 -2
  57. data/src/include/parser/parser_options.h +5 -0
  58. data/src/include/prism/prism_context.h +12 -12
  59. data/src/include/prism/prism_helpers.h +30 -0
  60. data/src/include/prism_version.h +11 -0
  61. data/src/include/version.h +1 -1
  62. data/src/parser/parser_helpers.c +1 -2
  63. data/src/parser.c +6 -7
  64. data/src/parser_options_defaults.c +1 -0
  65. data/src/prism/prism_helpers.c +84 -50
  66. data/src/prism/ruby_parser.c +20 -20
  67. data/templates/ext/herb/nodes.c.erb +5 -5
  68. data/templates/ext/herb/parser_options_helpers.c.erb +33 -0
  69. data/templates/java/nodes.c.erb +6 -6
  70. data/templates/java/parser_options_helpers.c.erb +41 -2
  71. data/templates/java/parser_options_helpers.h.erb +2 -1
  72. data/templates/javascript/packages/node/extension/nodes.cpp.erb +5 -5
  73. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +34 -2
  74. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +1 -1
  75. data/templates/lib/herb/parser_options.rb.erb +1 -1
  76. data/templates/rust/src/prism/generated_deserialize.rs.erb +90 -44
  77. data/templates/rust/src/prism/generated_prettyprint.rs.erb +18 -27
  78. data/templates/src/analyze/action_view/generated_handlers.c.erb +23 -22
  79. data/templates/src/include/parser/parser_options.h.erb +10 -0
  80. data/templates/src/include/prism_version.h.erb +17 -0
  81. data/templates/src/parser_options_defaults.c.erb +1 -1
  82. data/templates/template.rb +17 -2
  83. data/templates/wasm/nodes.cpp.erb +5 -5
  84. data/templates/wasm/parser_options_helpers.cpp.erb +24 -0
  85. data/vendor/prism/Rakefile +76 -7
  86. data/vendor/prism/config.yml +174 -161
  87. data/vendor/prism/include/prism/arena.h +45 -0
  88. data/vendor/prism/include/prism/arena.hpp +42 -0
  89. data/vendor/prism/include/prism/ast.h +2738 -611
  90. data/vendor/prism/include/prism/ast.hpp +641 -0
  91. data/vendor/prism/include/prism/buffer.h +60 -0
  92. data/vendor/prism/include/prism/buffer.hpp +55 -0
  93. data/vendor/prism/include/prism/comments.h +72 -0
  94. data/vendor/prism/include/prism/compiler/accel.h +26 -0
  95. data/vendor/prism/include/prism/compiler/align.h +36 -0
  96. data/vendor/prism/include/prism/compiler/assume.h +25 -0
  97. data/vendor/prism/include/prism/compiler/branch.h +26 -0
  98. data/vendor/prism/include/prism/compiler/bswap.h +46 -0
  99. data/vendor/prism/include/prism/compiler/cplusplus.hpp +16 -0
  100. data/vendor/prism/include/prism/compiler/endianness.h +34 -0
  101. data/vendor/prism/include/prism/compiler/exceptions.hpp +17 -0
  102. data/vendor/prism/include/prism/compiler/exported.h +24 -0
  103. data/vendor/prism/include/prism/compiler/fallthrough.h +22 -0
  104. data/vendor/prism/include/prism/compiler/filesystem.h +32 -0
  105. data/vendor/prism/include/prism/compiler/flex_array.h +19 -0
  106. data/vendor/prism/include/prism/compiler/force_inline.h +21 -0
  107. data/vendor/prism/include/prism/compiler/format.h +27 -0
  108. data/vendor/prism/include/prism/compiler/inline.h +17 -0
  109. data/vendor/prism/include/prism/compiler/lifetimebound.hpp +25 -0
  110. data/vendor/prism/include/prism/compiler/nodiscard.h +22 -0
  111. data/vendor/prism/include/prism/compiler/nonnull.h +18 -0
  112. data/vendor/prism/include/prism/compiler/unused.h +18 -0
  113. data/vendor/prism/include/prism/constant_pool.h +106 -0
  114. data/vendor/prism/include/prism/diagnostic.h +55 -402
  115. data/vendor/prism/include/prism/errors_format.h +61 -0
  116. data/vendor/prism/include/prism/excludes.h +29 -0
  117. data/vendor/prism/include/prism/integer.h +41 -0
  118. data/vendor/prism/include/prism/internal/allocator.h +68 -0
  119. data/vendor/prism/include/prism/internal/allocator_debug.h +88 -0
  120. data/vendor/prism/include/prism/internal/arena.h +108 -0
  121. data/vendor/prism/include/prism/internal/bit.h +42 -0
  122. data/vendor/prism/include/prism/internal/buffer.h +94 -0
  123. data/vendor/prism/include/prism/internal/char.h +145 -0
  124. data/vendor/prism/include/prism/internal/comments.h +54 -0
  125. data/vendor/prism/include/prism/internal/constant_pool.h +152 -0
  126. data/vendor/prism/include/prism/internal/diagnostic.h +389 -0
  127. data/vendor/prism/include/prism/{encoding.h → internal/encoding.h} +27 -68
  128. data/vendor/prism/include/prism/internal/integer.h +68 -0
  129. data/vendor/prism/include/prism/internal/isinf.h +16 -0
  130. data/vendor/prism/include/prism/internal/line_offset_list.h +34 -0
  131. data/vendor/prism/include/prism/{util/pm_list.h → internal/list.h} +11 -52
  132. data/vendor/prism/include/prism/internal/magic_comments.h +23 -0
  133. data/vendor/prism/include/prism/internal/memchr.h +15 -0
  134. data/vendor/prism/include/prism/internal/node.h +42 -0
  135. data/vendor/prism/include/prism/internal/options.h +232 -0
  136. data/vendor/prism/include/prism/internal/parser.h +1015 -0
  137. data/vendor/prism/include/prism/internal/regexp.h +26 -0
  138. data/vendor/prism/include/prism/internal/serialize.h +39 -0
  139. data/vendor/prism/include/prism/internal/source.h +72 -0
  140. data/vendor/prism/include/prism/internal/static_literals.h +60 -0
  141. data/vendor/prism/include/prism/internal/stringy.h +30 -0
  142. data/vendor/prism/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
  143. data/vendor/prism/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
  144. data/vendor/prism/include/prism/internal/tokens.h +11 -0
  145. data/vendor/prism/include/prism/internal/xxh3.h +16 -0
  146. data/vendor/prism/include/prism/json.h +40 -0
  147. data/vendor/prism/include/prism/line_offset_list.h +69 -0
  148. data/vendor/prism/include/prism/magic_comments.h +53 -0
  149. data/vendor/prism/include/prism/node.h +59 -49
  150. data/vendor/prism/include/prism/node.hpp +272 -0
  151. data/vendor/prism/include/prism/node_type.hpp +38 -0
  152. data/vendor/prism/include/prism/options.h +154 -279
  153. data/vendor/prism/include/prism/options.hpp +43 -0
  154. data/vendor/prism/include/prism/parser.h +367 -870
  155. data/vendor/prism/include/prism/parser.hpp +274 -0
  156. data/vendor/prism/include/prism/prettyprint.h +14 -9
  157. data/vendor/prism/include/prism/serialize.h +123 -0
  158. data/vendor/prism/include/prism/source.h +163 -0
  159. data/vendor/prism/include/prism/stream.h +36 -0
  160. data/vendor/prism/include/prism/string_query.h +82 -0
  161. data/vendor/prism/include/prism/stringy.h +61 -0
  162. data/vendor/prism/include/prism/stringy.hpp +31 -0
  163. data/vendor/prism/include/prism/version.h +20 -3
  164. data/vendor/prism/include/prism.h +35 -320
  165. data/vendor/prism/include/prism.hpp +24 -0
  166. data/vendor/prism/src/arena.c +122 -0
  167. data/vendor/prism/src/{util/pm_buffer.c → buffer.c} +53 -21
  168. data/vendor/prism/src/{util/pm_char.c → char.c} +28 -57
  169. data/vendor/prism/src/comments.c +455 -0
  170. data/vendor/prism/src/constant_pool.c +406 -0
  171. data/vendor/prism/src/diagnostic.c +120 -68
  172. data/vendor/prism/src/encoding.c +8 -3
  173. data/vendor/prism/src/errors_format.c +519 -0
  174. data/vendor/prism/src/{util/pm_integer.c → integer.c} +38 -22
  175. data/vendor/prism/src/json.c +5733 -0
  176. data/vendor/prism/src/line_offset_list.c +100 -0
  177. data/vendor/prism/src/list.c +24 -0
  178. data/vendor/prism/src/{util/pm_memchr.c → memchr.c} +8 -6
  179. data/vendor/prism/src/node.c +3465 -7787
  180. data/vendor/prism/src/options.c +161 -54
  181. data/vendor/prism/src/parser.c +371 -0
  182. data/vendor/prism/src/prettyprint.c +421 -354
  183. data/vendor/prism/src/prism.c +8522 -7280
  184. data/vendor/prism/src/regexp.c +960 -45
  185. data/vendor/prism/src/serialize.c +2434 -2048
  186. data/vendor/prism/src/source.c +524 -0
  187. data/vendor/prism/src/static_literals.c +303 -360
  188. data/vendor/prism/src/string_query.c +180 -0
  189. data/vendor/prism/src/stringy.c +61 -0
  190. data/vendor/prism/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
  191. data/vendor/prism/src/strpbrk.c +447 -0
  192. data/vendor/prism/src/{token_type.c → tokens.c} +39 -18
  193. data/vendor/prism/src/xxh3.c +292 -0
  194. data/vendor/prism/templates/ext/prism/api_node.c.erb +58 -44
  195. data/vendor/prism/templates/include/prism/ast.h.erb +67 -17
  196. data/vendor/prism/templates/include/prism/ast.hpp.erb +31 -0
  197. data/vendor/prism/templates/include/prism/internal/diagnostic.h.erb +60 -0
  198. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/AbstractNodeVisitor.java.erb +1 -1
  199. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Loader.java.erb +232 -133
  200. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Nodes.java.erb +62 -23
  201. data/vendor/prism/templates/javascript/src/deserialize.js.erb +153 -146
  202. data/vendor/prism/templates/javascript/src/nodes.js.erb +4 -9
  203. data/vendor/prism/templates/lib/prism/compiler.rb.erb +14 -5
  204. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +20 -12
  205. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +37 -11
  206. data/vendor/prism/templates/lib/prism/dsl.rb.erb +43 -4
  207. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +26 -10
  208. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +5 -2
  209. data/vendor/prism/templates/lib/prism/node.rb.erb +283 -105
  210. data/vendor/prism/templates/lib/prism/reflection.rb.erb +11 -2
  211. data/vendor/prism/templates/lib/prism/serialize.rb.erb +291 -134
  212. data/vendor/prism/templates/lib/prism/visitor.rb.erb +18 -0
  213. data/vendor/prism/templates/src/diagnostic.c.erb +114 -63
  214. data/vendor/prism/templates/src/json.c.erb +130 -0
  215. data/vendor/prism/templates/src/node.c.erb +79 -236
  216. data/vendor/prism/templates/src/prettyprint.c.erb +24 -13
  217. data/vendor/prism/templates/src/serialize.c.erb +369 -183
  218. data/vendor/prism/templates/src/{token_type.c.erb → tokens.c.erb} +22 -11
  219. data/vendor/prism/templates/template.rb +193 -91
  220. metadata +100 -42
  221. data/vendor/prism/include/prism/defines.h +0 -260
  222. data/vendor/prism/include/prism/pack.h +0 -163
  223. data/vendor/prism/include/prism/regexp.h +0 -43
  224. data/vendor/prism/include/prism/static_literals.h +0 -121
  225. data/vendor/prism/include/prism/util/pm_buffer.h +0 -236
  226. data/vendor/prism/include/prism/util/pm_char.h +0 -204
  227. data/vendor/prism/include/prism/util/pm_constant_pool.h +0 -218
  228. data/vendor/prism/include/prism/util/pm_integer.h +0 -130
  229. data/vendor/prism/include/prism/util/pm_memchr.h +0 -29
  230. data/vendor/prism/include/prism/util/pm_newline_list.h +0 -113
  231. data/vendor/prism/include/prism/util/pm_string.h +0 -200
  232. data/vendor/prism/src/pack.c +0 -509
  233. data/vendor/prism/src/util/pm_constant_pool.c +0 -342
  234. data/vendor/prism/src/util/pm_list.c +0 -49
  235. data/vendor/prism/src/util/pm_newline_list.c +0 -125
  236. data/vendor/prism/src/util/pm_string.c +0 -381
  237. data/vendor/prism/src/util/pm_strpbrk.c +0 -206
  238. data/vendor/prism/templates/include/prism/diagnostic.h.erb +0 -130
  239. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +0 -68
  240. data/vendor/prism/templates/rbi/prism/node.rbi.erb +0 -167
  241. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +0 -18
  242. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +0 -45
  243. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +0 -31
  244. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +0 -7
  245. data/vendor/prism/templates/sig/prism/node.rbs.erb +0 -136
  246. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +0 -17
  247. data/vendor/prism/templates/sig/prism.rbs.erb +0 -92
@@ -18,6 +18,8 @@
18
18
  #include "../../include/util/util.h"
19
19
  #include "../../include/visitor.h"
20
20
 
21
+ #include "../../include/prism/prism_helpers.h"
22
+
21
23
  #include <prism.h>
22
24
  #include <stdbool.h>
23
25
  #include <stdlib.h>
@@ -42,7 +44,9 @@ extern char* wrap_in_stylesheet_path(const char*, size_t, const char*, hb_alloca
42
44
  extern bool stylesheet_link_tag_source_is_url(const char*, size_t);
43
45
 
44
46
  typedef struct {
45
- pm_parser_t parser;
47
+ pm_arena_t* arena;
48
+ pm_parser_t* parser;
49
+ pm_options_t* options;
46
50
  pm_node_t* root;
47
51
  const uint8_t* prism_source;
48
52
  char* content_string;
@@ -60,46 +64,42 @@ typedef struct {
60
64
  } local_read_search_T;
61
65
 
62
66
  static void append_local_read_constant(local_read_search_T* search, pm_constant_id_t constant_id) {
63
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&search->scope->parser.constant_pool, constant_id);
67
+ const pm_constant_t* constant = pm_parser_constant(search->scope->parser, constant_id);
68
+
69
+ if (!constant || pm_constant_length(constant) == 0) { return; }
64
70
 
65
- if (!constant || constant->length == 0) { return; }
71
+ size_t length = pm_constant_length(constant);
66
72
 
67
73
  for (size_t index = 0; index < hb_array_size(search->constants); index++) {
68
- pm_constant_t* existing = hb_array_get(search->constants, index);
74
+ const pm_constant_t* existing = hb_array_get(search->constants, index);
69
75
 
70
- if (existing && existing->length == constant->length
71
- && memcmp(existing->start, constant->start, constant->length) == 0) {
76
+ if (existing && pm_constant_length(existing) == length
77
+ && memcmp(pm_constant_start(existing), pm_constant_start(constant), length) == 0) {
72
78
  return;
73
79
  }
74
80
  }
75
81
 
76
- hb_array_append(search->constants, constant);
82
+ hb_array_append(search->constants, (void*) constant);
77
83
  }
78
84
 
79
- static bool search_local_variable_reads(const pm_node_t* node, void* data) {
85
+ static pm_visit_result_t search_local_variable_reads(const pm_node_t* node, void* data) {
80
86
  local_read_search_T* search = (local_read_search_T*) data;
81
- const uint8_t* base = (const uint8_t*) search->scope->buffer.value;
82
87
 
83
- size_t start = (size_t) (node->location.start - base);
84
- size_t end = (size_t) (node->location.end - base);
88
+ size_t start = node->location.start;
89
+ size_t end = herb_prism_location_end(node->location);
85
90
 
86
- if (end <= search->from || start >= search->to) { return false; }
91
+ if (end <= search->from || start >= search->to) { return PM_VISIT_SKIP; }
87
92
 
88
93
  if (PM_NODE_TYPE(node) == PM_LOCAL_VARIABLE_READ_NODE && start >= search->from && end <= search->to) {
89
94
  append_local_read_constant(search, ((pm_local_variable_read_node_t*) node)->name);
90
95
  }
91
96
 
92
- return true;
97
+ return PM_VISIT_DESCEND;
93
98
  }
94
99
 
95
- static bool build_scope_options_from_context(
96
- analyze_ruby_context_T* context,
97
- pm_options_t* options,
98
- size_t from,
99
- size_t to
100
- ) {
101
- if (!context || !context->tag_helper_scope || !context->tag_helper_scope->root) { return false; }
102
- if (to <= from) { return false; }
100
+ static pm_options_t* build_scope_options_from_context(analyze_ruby_context_T* context, size_t from, size_t to) {
101
+ if (!context || !context->tag_helper_scope || !context->tag_helper_scope->root) { return NULL; }
102
+ if (to <= from) { return NULL; }
103
103
 
104
104
  local_read_search_T search = { .scope = context->tag_helper_scope,
105
105
  .constants = hb_array_init(4, context->allocator),
@@ -109,27 +109,34 @@ static bool build_scope_options_from_context(
109
109
  pm_visit_node(context->tag_helper_scope->root, search_local_variable_reads, &search);
110
110
 
111
111
  size_t locals_count = hb_array_size(search.constants);
112
- bool built = false;
112
+ pm_options_t* options = NULL;
113
+
114
+ if (locals_count > 0) {
115
+ options = pm_options_new();
116
+ herb_prism_options_set_ruby_version(options, context->options);
113
117
 
114
- if (locals_count > 0 && pm_options_scopes_init(options, 1)) {
115
- pm_options_scope_t* scope = &options->scopes[0];
118
+ if (pm_options_scopes_init(options, 1)) {
119
+ pm_options_scope_t* scope = pm_options_scope_mut(options, 0);
120
+ pm_options_scope_init(scope, locals_count);
116
121
 
117
- if (pm_options_scope_init(scope, locals_count)) {
118
122
  for (size_t index = 0; index < locals_count; index++) {
119
- pm_constant_t* constant = hb_array_get(search.constants, index);
123
+ const pm_constant_t* constant = hb_array_get(search.constants, index);
120
124
 
121
- pm_string_constant_init(&scope->locals[index], (const char*) constant->start, constant->length);
125
+ pm_string_init(
126
+ pm_options_scope_local_mut(scope, index),
127
+ pm_constant_start(constant),
128
+ pm_constant_length(constant)
129
+ );
122
130
  }
123
-
124
- built = true;
125
131
  } else {
126
132
  pm_options_free(options);
133
+ options = NULL;
127
134
  }
128
135
  }
129
136
 
130
137
  hb_array_free(&search.constants);
131
138
 
132
- return built;
139
+ return options;
133
140
  }
134
141
 
135
142
  static bool symbol_node_equals(pm_node_t* node, const char* name) {
@@ -195,22 +202,27 @@ static tag_helper_parse_context_T* parse_tag_helper_content(
195
202
 
196
203
  size_t content_length = strlen(parse_context->content_string);
197
204
 
198
- pm_options_t options = { 0 };
199
- bool has_scope_options =
200
- build_scope_options_from_context(context, &options, erb_content_offset, erb_content_offset + content_length);
201
-
202
- pm_parser_init(
203
- &parse_context->parser,
204
- parse_context->prism_source,
205
- content_length,
206
- has_scope_options ? &options : NULL
207
- );
208
- parse_context->root = pm_parse(&parse_context->parser);
205
+ parse_context->options =
206
+ build_scope_options_from_context(context, erb_content_offset, erb_content_offset + content_length);
209
207
 
210
- if (has_scope_options) { pm_options_free(&options); }
208
+ parse_context->arena = pm_arena_new();
209
+ if (parse_context->options) {
210
+ parse_context->parser =
211
+ pm_parser_new(parse_context->arena, parse_context->prism_source, content_length, parse_context->options);
212
+ } else {
213
+ parse_context->parser = herb_prism_parser_new(
214
+ parse_context->arena,
215
+ parse_context->prism_source,
216
+ content_length,
217
+ context ? context->options : NULL
218
+ );
219
+ }
220
+ parse_context->root = pm_parse(parse_context->parser);
211
221
 
212
222
  if (!parse_context->root) {
213
- pm_parser_free(&parse_context->parser);
223
+ pm_parser_free(parse_context->parser);
224
+ pm_arena_free(parse_context->arena);
225
+ if (parse_context->options) { pm_options_free(parse_context->options); }
214
226
  hb_allocator_dealloc(allocator, parse_context->content_string);
215
227
  hb_allocator_dealloc(allocator, parse_context);
216
228
  return NULL;
@@ -220,7 +232,7 @@ static tag_helper_parse_context_T* parse_tag_helper_content(
220
232
 
221
233
  tag_helper_search_data_T search = { .tag_helper_node = NULL,
222
234
  .source = parse_context->prism_source,
223
- .parser = &parse_context->parser,
235
+ .parser = parse_context->parser,
224
236
  .info = parse_context->info,
225
237
  .found = false };
226
238
  pm_visit_node(parse_context->root, search_tag_helper_node, &search);
@@ -228,8 +240,9 @@ static tag_helper_parse_context_T* parse_tag_helper_content(
228
240
  if (!search.found
229
241
  || asset_tag_resolves_at_render_time(parse_context->info->call_node, search.matched_handler->name)) {
230
242
  tag_helper_info_free(&parse_context->info);
231
- pm_node_destroy(&parse_context->parser, parse_context->root);
232
- pm_parser_free(&parse_context->parser);
243
+ pm_parser_free(parse_context->parser);
244
+ pm_arena_free(parse_context->arena);
245
+ if (parse_context->options) { pm_options_free(parse_context->options); }
233
246
  hb_allocator_dealloc(allocator, parse_context->content_string);
234
247
  hb_allocator_dealloc(allocator, parse_context);
235
248
  return NULL;
@@ -245,8 +258,9 @@ static void free_tag_helper_parse_context(tag_helper_parse_context_T* parse_cont
245
258
  hb_allocator_T* allocator = parse_context->info ? parse_context->info->allocator : NULL;
246
259
 
247
260
  tag_helper_info_free(&parse_context->info);
248
- pm_node_destroy(&parse_context->parser, parse_context->root);
249
- pm_parser_free(&parse_context->parser);
261
+ pm_parser_free(parse_context->parser);
262
+ pm_arena_free(parse_context->arena);
263
+ if (parse_context->options) { pm_options_free(parse_context->options); }
250
264
 
251
265
  if (allocator) {
252
266
  hb_allocator_dealloc(allocator, parse_context->content_string);
@@ -254,7 +268,7 @@ static void free_tag_helper_parse_context(tag_helper_parse_context_T* parse_cont
254
268
  }
255
269
  }
256
270
 
257
- bool search_tag_helper_node(const pm_node_t* node, void* data) {
271
+ pm_visit_result_t search_tag_helper_node(const pm_node_t* node, void* data) {
258
272
  tag_helper_search_data_T* search_data = (tag_helper_search_data_T*) data;
259
273
 
260
274
  if (node->type == PM_CALL_NODE) {
@@ -280,16 +294,16 @@ bool search_tag_helper_node(const pm_node_t* node, void* data) {
280
294
  search_data->info->has_block = handlers[i]->supports_block();
281
295
  }
282
296
 
283
- return false;
297
+ return PM_VISIT_SKIP;
284
298
  }
285
299
  }
286
300
 
287
- return false;
301
+ return PM_VISIT_SKIP;
288
302
  }
289
303
 
290
304
  pm_visit_child_nodes(node, search_tag_helper_node, search_data);
291
305
 
292
- return search_data->found;
306
+ return search_data->found ? PM_VISIT_DESCEND : PM_VISIT_SKIP;
293
307
  }
294
308
 
295
309
  position_T byte_offset_to_position(const char* source, size_t offset) {
@@ -321,9 +335,11 @@ position_T prism_location_to_position_with_offset(
321
335
  ) {
322
336
  position_T default_position = { .line = 1, .column = 1 };
323
337
 
324
- if (!pm_location || !pm_location->start || !original_source || !erb_content_source) { return default_position; }
338
+ if (!pm_location || !herb_prism_location_assigned(*pm_location) || !original_source || !erb_content_source) {
339
+ return default_position;
340
+ }
325
341
 
326
- size_t offset_in_erb = (size_t) (pm_location->start - erb_content_source);
342
+ size_t offset_in_erb = pm_location->start;
327
343
  size_t total_offset = erb_content_offset + offset_in_erb;
328
344
 
329
345
  if (strnlen(original_source, total_offset) < total_offset) {
@@ -375,7 +391,7 @@ static void prism_node_location_to_positions(
375
391
  parse_context->prism_source
376
392
  );
377
393
 
378
- pm_location_t end_location = { .start = location->end, .end = location->end };
394
+ pm_location_t end_location = { .start = herb_prism_location_end(*location), .length = 0 };
379
395
  *out_end = prism_location_to_position_with_offset(
380
396
  &end_location,
381
397
  parse_context->original_source,
@@ -394,7 +410,7 @@ static void calculate_tag_name_positions(
394
410
  *out_start = default_start;
395
411
  *out_end = default_end;
396
412
 
397
- if (parse_context->info->call_node && parse_context->info->call_node->message_loc.start) {
413
+ if (parse_context->info->call_node && herb_prism_location_assigned(parse_context->info->call_node->message_loc)) {
398
414
  prism_node_location_to_positions(&parse_context->info->call_node->message_loc, parse_context, out_start, out_end);
399
415
  }
400
416
  }
@@ -405,6 +421,7 @@ static const char* IMAGE_TAG_PATH_OPTIONS[] = { "skip_pipeline", NULL };
405
421
 
406
422
  static char* extract_path_options_from_keyword_hash(
407
423
  pm_call_node_t* call_node,
424
+ const uint8_t* source,
408
425
  const char** option_names,
409
426
  hb_allocator_T* allocator
410
427
  ) {
@@ -449,12 +466,18 @@ static char* extract_path_options_from_keyword_hash(
449
466
  if (!first) { hb_buffer_append(&buffer, ", "); }
450
467
  first = false;
451
468
 
452
- size_t key_source_length = assoc->key->location.end - assoc->key->location.start;
453
- hb_buffer_append_with_length(&buffer, (const char*) assoc->key->location.start, key_source_length);
469
+ hb_buffer_append_with_length(
470
+ &buffer,
471
+ (const char*) (source + assoc->key->location.start),
472
+ assoc->key->location.length
473
+ );
454
474
  hb_buffer_append(&buffer, " ");
455
475
 
456
- size_t value_source_length = assoc->value->location.end - assoc->value->location.start;
457
- hb_buffer_append_with_length(&buffer, (const char*) assoc->value->location.start, value_source_length);
476
+ hb_buffer_append_with_length(
477
+ &buffer,
478
+ (const char*) (source + assoc->value->location.start),
479
+ assoc->value->location.length
480
+ );
458
481
  }
459
482
 
460
483
  if (first) {
@@ -512,8 +535,11 @@ static hb_array_T* prepend_stylesheet_link_tag_attributes(
512
535
  size_t length = pm_string_length(&string_node->unescaped);
513
536
  source_value = hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
514
537
  } else {
515
- size_t length = source_argument->location.end - source_argument->location.start;
516
- source_value = hb_allocator_strndup(allocator, (const char*) source_argument->location.start, length);
538
+ source_value = hb_allocator_strndup(
539
+ allocator,
540
+ (const char*) (parse_context->prism_source + source_argument->location.start),
541
+ source_argument->location.length
542
+ );
517
543
  }
518
544
 
519
545
  if (!source_value) { return attributes; }
@@ -523,7 +549,7 @@ static hb_array_T* prepend_stylesheet_link_tag_attributes(
523
549
 
524
550
  size_t source_length = strlen(source_value);
525
551
  bool is_url = stylesheet_link_tag_source_is_url(source_value, source_length);
526
- bool source_is_path_helper = is_route_helper_node(source_argument, &parse_context->parser);
552
+ bool source_is_path_helper = is_route_helper_node(source_argument, parse_context->parser);
527
553
 
528
554
  char* href_value = source_value;
529
555
 
@@ -603,6 +629,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
603
629
  if (attributes && handler->name && strcmp(handler->name, "javascript_include_tag") == 0) {
604
630
  path_options = extract_path_options_from_keyword_hash(
605
631
  parse_context->info->call_node,
632
+ parse_context->prism_source,
606
633
  JAVASCRIPT_INCLUDE_TAG_PATH_OPTIONS,
607
634
  allocator
608
635
  );
@@ -616,6 +643,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
616
643
  if (attributes && handler->name && strcmp(handler->name, "stylesheet_link_tag") == 0) {
617
644
  path_options = extract_path_options_from_keyword_hash(
618
645
  parse_context->info->call_node,
646
+ parse_context->prism_source,
619
647
  STYLESHEET_LINK_TAG_PATH_OPTIONS,
620
648
  allocator
621
649
  );
@@ -627,8 +655,12 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
627
655
  }
628
656
 
629
657
  if (attributes && handler->name && strcmp(handler->name, "image_tag") == 0) {
630
- path_options =
631
- extract_path_options_from_keyword_hash(parse_context->info->call_node, IMAGE_TAG_PATH_OPTIONS, allocator);
658
+ path_options = extract_path_options_from_keyword_hash(
659
+ parse_context->info->call_node,
660
+ parse_context->prism_source,
661
+ IMAGE_TAG_PATH_OPTIONS,
662
+ allocator
663
+ );
632
664
  discard_attribute_by_name(attributes, "skip-pipeline", allocator);
633
665
 
634
666
  AST_NODE_T* size_node = remove_attribute_by_name(attributes, "size");
@@ -722,7 +754,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
722
754
  bool content_is_ruby_expression = false;
723
755
 
724
756
  if (parse_context->info->call_node && handler->extract_content) {
725
- helper_content = handler->extract_content(parse_context->info->call_node, &parse_context->parser, allocator);
757
+ helper_content = handler->extract_content(parse_context->info->call_node, parse_context->parser, allocator);
726
758
 
727
759
  if (helper_content) {
728
760
  pm_call_node_t* call = parse_context->info->call_node;
@@ -751,8 +783,8 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
751
783
  }
752
784
  }
753
785
 
754
- if (detect_turbo_frame_tag(parse_context->info->call_node, &parse_context->parser)) {
755
- char* id_value = extract_turbo_frame_tag_id(parse_context->info->call_node, &parse_context->parser, allocator);
786
+ if (detect_turbo_frame_tag(parse_context->info->call_node, parse_context->parser)) {
787
+ char* id_value = extract_turbo_frame_tag_id(parse_context->info->call_node, parse_context->parser, allocator);
756
788
 
757
789
  if (id_value) {
758
790
  if (!attributes) { attributes = hb_array_init(4, allocator); }
@@ -780,10 +812,10 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
780
812
  }
781
813
  }
782
814
 
783
- if (detect_javascript_include_tag(parse_context->info->call_node, &parse_context->parser)
815
+ if (detect_javascript_include_tag(parse_context->info->call_node, parse_context->parser)
784
816
  && parse_context->info->call_node->arguments && parse_context->info->call_node->arguments->arguments.size >= 1) {
785
817
  char* source_value =
786
- extract_javascript_include_tag_src(parse_context->info->call_node, &parse_context->parser, allocator);
818
+ extract_javascript_include_tag_src(parse_context->info->call_node, parse_context->parser, allocator);
787
819
 
788
820
  if (source_value) {
789
821
  if (!attributes) { attributes = hb_array_init(4, allocator); }
@@ -821,9 +853,9 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
821
853
  }
822
854
  }
823
855
 
824
- if (detect_image_tag(parse_context->info->call_node, &parse_context->parser)
856
+ if (detect_image_tag(parse_context->info->call_node, parse_context->parser)
825
857
  && parse_context->info->call_node->arguments && parse_context->info->call_node->arguments->arguments.size >= 1) {
826
- char* source_value = extract_image_tag_src(parse_context->info->call_node, &parse_context->parser, allocator);
858
+ char* source_value = extract_image_tag_src(parse_context->info->call_node, parse_context->parser, allocator);
827
859
 
828
860
  if (source_value) {
829
861
  if (!attributes) { attributes = hb_array_init(4, allocator); }
@@ -832,7 +864,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
832
864
  position_T source_start, source_end;
833
865
  prism_node_location_to_positions(&first_argument->location, parse_context, &source_start, &source_end);
834
866
  bool source_is_string = (first_argument->type == PM_STRING_NODE);
835
- bool source_is_path_helper = is_route_helper_node(first_argument, &parse_context->parser);
867
+ bool source_is_path_helper = is_route_helper_node(first_argument, parse_context->parser);
836
868
 
837
869
  size_t source_length = strlen(source_value);
838
870
  bool is_url = image_tag_source_is_url(source_value, source_length);
@@ -865,7 +897,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
865
897
  }
866
898
  }
867
899
 
868
- if (detect_stylesheet_link_tag(parse_context->info->call_node, &parse_context->parser)
900
+ if (detect_stylesheet_link_tag(parse_context->info->call_node, parse_context->parser)
869
901
  && parse_context->info->call_node->arguments && parse_context->info->call_node->arguments->arguments.size >= 1) {
870
902
  pm_node_t* first_argument = parse_context->info->call_node->arguments->arguments.nodes[0];
871
903
 
@@ -1056,8 +1088,11 @@ static AST_NODE_T* create_javascript_include_tag_element(
1056
1088
  size_t length = pm_string_length(&string_node->unescaped);
1057
1089
  source_value = hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
1058
1090
  } else {
1059
- size_t source_length = source_argument->location.end - source_argument->location.start;
1060
- source_value = hb_allocator_strndup(allocator, (const char*) source_argument->location.start, source_length);
1091
+ source_value = hb_allocator_strndup(
1092
+ allocator,
1093
+ (const char*) (parse_context->prism_source + source_argument->location.start),
1094
+ source_argument->location.length
1095
+ );
1061
1096
  }
1062
1097
 
1063
1098
  position_T source_start, source_end;
@@ -1164,8 +1199,12 @@ static hb_array_T* transform_javascript_include_tag_multi_source(
1164
1199
 
1165
1200
  if (source_count == 0) { return NULL; }
1166
1201
 
1167
- char* path_options =
1168
- extract_path_options_from_keyword_hash(call_node, JAVASCRIPT_INCLUDE_TAG_PATH_OPTIONS, allocator);
1202
+ char* path_options = extract_path_options_from_keyword_hash(
1203
+ call_node,
1204
+ parse_context->prism_source,
1205
+ JAVASCRIPT_INCLUDE_TAG_PATH_OPTIONS,
1206
+ allocator
1207
+ );
1169
1208
  hb_array_T* elements = hb_array_init(source_count * 2, allocator);
1170
1209
 
1171
1210
  for (size_t i = 0; i < source_count; i++) {
@@ -1264,7 +1303,12 @@ static hb_array_T* transform_stylesheet_link_tag_multi_source(
1264
1303
 
1265
1304
  if (source_count == 0) { return NULL; }
1266
1305
 
1267
- char* path_options = extract_path_options_from_keyword_hash(call_node, STYLESHEET_LINK_TAG_PATH_OPTIONS, allocator);
1306
+ char* path_options = extract_path_options_from_keyword_hash(
1307
+ call_node,
1308
+ parse_context->prism_source,
1309
+ STYLESHEET_LINK_TAG_PATH_OPTIONS,
1310
+ allocator
1311
+ );
1268
1312
  hb_array_T* elements = hb_array_init(source_count * 2, allocator);
1269
1313
 
1270
1314
  for (size_t i = 0; i < source_count; i++) {
@@ -1371,16 +1415,17 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
1371
1415
  resolve_nonce_attribute(attributes, allocator);
1372
1416
  }
1373
1417
 
1374
- if (detect_link_to(parse_context->info->call_node, &parse_context->parser)
1375
- && parse_context->info->call_node->arguments && parse_context->info->call_node->arguments->arguments.size >= 1) {
1418
+ if (detect_link_to(parse_context->info->call_node, parse_context->parser) && parse_context->info->call_node->arguments
1419
+ && parse_context->info->call_node->arguments->arguments.size >= 1) {
1376
1420
  pm_node_t* first_argument = parse_context->info->call_node->arguments->arguments.nodes[0];
1377
- size_t source_length = first_argument->location.end - first_argument->location.start;
1421
+ size_t source_length = first_argument->location.length;
1422
+ const char* first_argument_source = (const char*) (parse_context->prism_source + first_argument->location.start);
1378
1423
  char* href = NULL;
1379
1424
 
1380
- if (first_argument->type != PM_STRING_NODE && !is_route_helper_node(first_argument, &parse_context->parser)) {
1381
- href = wrap_in_url_for((const char*) first_argument->location.start, source_length, allocator);
1425
+ if (first_argument->type != PM_STRING_NODE && !is_route_helper_node(first_argument, parse_context->parser)) {
1426
+ href = wrap_in_url_for(first_argument_source, source_length, allocator);
1382
1427
  } else {
1383
- href = hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
1428
+ href = hb_allocator_strndup(allocator, first_argument_source, source_length);
1384
1429
  }
1385
1430
 
1386
1431
  if (href) {
@@ -1406,8 +1451,8 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
1406
1451
  }
1407
1452
  }
1408
1453
 
1409
- if (detect_turbo_frame_tag(parse_context->info->call_node, &parse_context->parser)) {
1410
- char* id_value = extract_turbo_frame_tag_id(parse_context->info->call_node, &parse_context->parser, allocator);
1454
+ if (detect_turbo_frame_tag(parse_context->info->call_node, parse_context->parser)) {
1455
+ char* id_value = extract_turbo_frame_tag_id(parse_context->info->call_node, parse_context->parser, allocator);
1411
1456
 
1412
1457
  if (id_value) {
1413
1458
  if (!attributes) { attributes = hb_array_init(4, allocator); }
@@ -1575,7 +1620,7 @@ static AST_NODE_T* transform_link_to_helper(
1575
1620
  hb_allocator_T* allocator = context->allocator;
1576
1621
  tag_helper_info_T* info = parse_context->info;
1577
1622
 
1578
- char* href = extract_link_to_href(info->call_node, &parse_context->parser, allocator);
1623
+ char* href = extract_link_to_href(info->call_node, parse_context->parser, allocator);
1579
1624
 
1580
1625
  hb_array_T* attributes = NULL;
1581
1626
  pm_arguments_node_t* link_arguments = info->call_node->arguments;
@@ -1603,8 +1648,12 @@ static AST_NODE_T* transform_link_to_helper(
1603
1648
 
1604
1649
  if (second_arg->type != PM_KEYWORD_HASH_NODE && second_arg->type != PM_HASH_NODE
1605
1650
  && second_arg->type != PM_STRING_NODE && second_arg->type != PM_SYMBOL_NODE) {
1606
- size_t source_length = second_arg->location.end - second_arg->location.start;
1607
- char* content = hb_allocator_strndup(allocator, (const char*) second_arg->location.start, source_length);
1651
+ size_t source_length = second_arg->location.length;
1652
+ char* content = hb_allocator_strndup(
1653
+ allocator,
1654
+ (const char*) (parse_context->prism_source + second_arg->location.start),
1655
+ source_length
1656
+ );
1608
1657
 
1609
1658
  if (content) {
1610
1659
  hb_buffer_T wrapped;
@@ -24,14 +24,15 @@ char* extract_turbo_frame_tag_id(pm_call_node_t* call_node, pm_parser_t* parser,
24
24
  return hb_allocator_strndup(allocator, (const char*) pm_string_source(&symbol_node->unescaped), length);
25
25
  }
26
26
 
27
- size_t source_length = first_argument->location.end - first_argument->location.start;
28
- const char* source = (const char*) first_argument->location.start;
27
+ size_t source_length = first_argument->location.length;
28
+ const char* source = (const char*) (pm_parser_start(parser) + first_argument->location.start);
29
29
 
30
30
  if (first_argument->type == PM_CALL_NODE) {
31
31
  pm_call_node_t* call = (pm_call_node_t*) first_argument;
32
- pm_constant_t* call_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call->name);
32
+ const pm_constant_t* call_constant = pm_parser_constant(parser, call->name);
33
33
 
34
- if (call_constant && call_constant->length == 6 && strncmp((const char*) call_constant->start, "dom_id", 6) == 0) {
34
+ if (call_constant && pm_constant_length(call_constant) == 6
35
+ && strncmp((const char*) pm_constant_start(call_constant), "dom_id", 6) == 0) {
35
36
  return hb_allocator_strndup(allocator, source, source_length);
36
37
  }
37
38
  }
@@ -26,6 +26,7 @@
26
26
  #include "../include/location/location.h"
27
27
  #include "../include/location/position.h"
28
28
  #include "../include/parser/parser.h"
29
+ #include "../include/prism/prism_helpers.h"
29
30
  #include "../include/visitor.h"
30
31
 
31
32
  #include <prism.h>
@@ -34,8 +35,8 @@
34
35
  #include <stdlib.h>
35
36
  #include <string.h>
36
37
 
37
- static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source) {
38
- analyzed_ruby_T* analyzed = init_analyzed_ruby(source);
38
+ static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source, const parser_options_T* options) {
39
+ analyzed_ruby_T* analyzed = init_analyzed_ruby(source, options);
39
40
 
40
41
  if (analyzed->valid) { return analyzed; }
41
42
 
@@ -62,7 +63,7 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
62
63
  hb_string_T opening = erb_content_node->tag_opening->value;
63
64
 
64
65
  if (!erb_opening_is_custom(opening)) {
65
- analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value);
66
+ analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value, options);
66
67
 
67
68
  erb_content_node->parsed = true;
68
69
  erb_content_node->valid = analyzed->valid;
@@ -1002,9 +1003,10 @@ static AST_ERB_CONTENT_NODE_T* erb_content_part_node(
1002
1003
  token_T* tag_opening,
1003
1004
  token_T* content,
1004
1005
  token_T* tag_closing,
1006
+ const parser_options_T* options,
1005
1007
  hb_allocator_T* allocator
1006
1008
  ) {
1007
- analyzed_ruby_T* analyzed = herb_analyze_ruby(content->value);
1009
+ analyzed_ruby_T* analyzed = herb_analyze_ruby(content->value, options);
1008
1010
 
1009
1011
  position_T start_position = tag_opening ? tag_opening->location.start : content->location.start;
1010
1012
  position_T end_position = tag_closing ? tag_closing->location.end : content->location.end;
@@ -1024,13 +1026,18 @@ static AST_ERB_CONTENT_NODE_T* erb_content_part_node(
1024
1026
  );
1025
1027
  }
1026
1028
 
1027
- static void append_control_role_parts(AST_ERB_CONTENT_NODE_T* erb_node, hb_array_T* output, hb_allocator_T* allocator) {
1029
+ static void append_control_role_parts(
1030
+ AST_ERB_CONTENT_NODE_T* erb_node,
1031
+ hb_array_T* output,
1032
+ const parser_options_T* options,
1033
+ hb_allocator_T* allocator
1034
+ ) {
1028
1035
  token_T* tag_opening = token_copy(erb_node->tag_opening, allocator);
1029
1036
  token_T* content = erb_node->content;
1030
1037
  bool split_content = false;
1031
1038
 
1032
1039
  while (true) {
1033
- analyzed_ruby_T* analyzed = split_content ? herb_analyze_ruby(content->value) : erb_node->analyzed_ruby;
1040
+ analyzed_ruby_T* analyzed = split_content ? herb_analyze_ruby(content->value, options) : erb_node->analyzed_ruby;
1034
1041
  uint32_t offset = 0;
1035
1042
  bool split = control_role_split_offset(analyzed, &offset);
1036
1043
 
@@ -1042,7 +1049,7 @@ static void append_control_role_parts(AST_ERB_CONTENT_NODE_T* erb_node, hb_array
1042
1049
 
1043
1050
  if (!token_split(content, offset, allocator, &head, &tail)) { break; }
1044
1051
 
1045
- hb_array_append(output, (AST_NODE_T*) erb_content_part_node(tag_opening, head, NULL, allocator));
1052
+ hb_array_append(output, (AST_NODE_T*) erb_content_part_node(tag_opening, head, NULL, options, allocator));
1046
1053
 
1047
1054
  if (split_content) { token_free(content, allocator); }
1048
1055
 
@@ -1056,7 +1063,7 @@ static void append_control_role_parts(AST_ERB_CONTENT_NODE_T* erb_node, hb_array
1056
1063
  hb_array_append(
1057
1064
  output,
1058
1065
  (AST_NODE_T*)
1059
- erb_content_part_node(tag_opening, last_content, token_copy(erb_node->tag_closing, allocator), allocator)
1066
+ erb_content_part_node(tag_opening, last_content, token_copy(erb_node->tag_closing, allocator), options, allocator)
1060
1067
  );
1061
1068
  }
1062
1069
 
@@ -1101,7 +1108,7 @@ static hb_array_T* split_control_role_tags(hb_array_T* array, analyze_ruby_conte
1101
1108
 
1102
1109
  AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) item;
1103
1110
 
1104
- append_control_role_parts(erb_node, split, allocator);
1111
+ append_control_role_parts(erb_node, split, context->options, allocator);
1105
1112
  ast_node_free(item, allocator);
1106
1113
  }
1107
1114
 
@@ -1159,7 +1166,11 @@ hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby
1159
1166
  return new_array;
1160
1167
  }
1161
1168
 
1162
- static tag_helper_scope_T* tag_helper_scope_init(const char* source, hb_allocator_T* allocator) {
1169
+ static tag_helper_scope_T* tag_helper_scope_init(
1170
+ const char* source,
1171
+ const parser_options_T* options,
1172
+ hb_allocator_T* allocator
1173
+ ) {
1163
1174
  if (!source) { return NULL; }
1164
1175
 
1165
1176
  tag_helper_scope_T* scope = hb_allocator_alloc(allocator, sizeof(tag_helper_scope_T));
@@ -1189,14 +1200,19 @@ static tag_helper_scope_T* tag_helper_scope_init(const char* source, hb_allocato
1189
1200
  return NULL;
1190
1201
  }
1191
1202
 
1192
- pm_options_partial_script_set(&scope->options, true);
1193
- pm_parser_init(&scope->parser, (const uint8_t*) scope->buffer.value, scope->buffer.length, &scope->options);
1203
+ scope->arena = pm_arena_new();
1204
+ scope->options = pm_options_new();
1205
+ pm_options_partial_script_set(scope->options, true);
1206
+ herb_prism_options_set_ruby_version(scope->options, options);
1207
+ scope->parser =
1208
+ pm_parser_new(scope->arena, (const uint8_t*) scope->buffer.value, scope->buffer.length, scope->options);
1194
1209
 
1195
- scope->root = pm_parse(&scope->parser);
1210
+ scope->root = pm_parse(scope->parser);
1196
1211
 
1197
1212
  if (!scope->root) {
1198
- pm_parser_free(&scope->parser);
1199
- pm_options_free(&scope->options);
1213
+ pm_parser_free(scope->parser);
1214
+ pm_arena_free(scope->arena);
1215
+ pm_options_free(scope->options);
1200
1216
  hb_buffer_free(&scope->buffer);
1201
1217
  hb_allocator_dealloc(allocator, scope);
1202
1218
 
@@ -1209,9 +1225,9 @@ static tag_helper_scope_T* tag_helper_scope_init(const char* source, hb_allocato
1209
1225
  static void tag_helper_scope_free(tag_helper_scope_T* scope, hb_allocator_T* allocator) {
1210
1226
  if (!scope) { return; }
1211
1227
 
1212
- pm_node_destroy(&scope->parser, scope->root);
1213
- pm_parser_free(&scope->parser);
1214
- pm_options_free(&scope->options);
1228
+ pm_parser_free(scope->parser);
1229
+ pm_arena_free(scope->arena);
1230
+ pm_options_free(scope->options);
1215
1231
  hb_buffer_free(&scope->buffer);
1216
1232
  hb_allocator_dealloc(allocator, scope);
1217
1233
  }
@@ -1256,7 +1272,7 @@ void herb_analyze_parse_tree(
1256
1272
  }
1257
1273
 
1258
1274
  if (options && options->action_view_helpers) {
1259
- context.tag_helper_scope = tag_helper_scope_init(source, allocator);
1275
+ context.tag_helper_scope = tag_helper_scope_init(source, options, allocator);
1260
1276
 
1261
1277
  herb_visit_node((AST_NODE_T*) document, transform_tag_helper_nodes, &context);
1262
1278