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
@@ -1,18 +1,20 @@
1
1
  #include "../include/analyze/analyzed_ruby.h"
2
2
  #include "../include/lib/hb_string.h"
3
+ #include "../include/prism/prism_helpers.h"
3
4
 
4
5
  #include <prism.h>
5
6
  #include <string.h>
6
7
 
7
- analyzed_ruby_T* init_analyzed_ruby(hb_string_T source) {
8
+ analyzed_ruby_T* init_analyzed_ruby(hb_string_T source, const parser_options_T* options) {
8
9
  analyzed_ruby_T* analyzed = malloc(sizeof(analyzed_ruby_T));
9
10
 
10
11
  if (!analyzed) { return NULL; }
11
12
 
12
- pm_parser_init(&analyzed->parser, (const uint8_t*) source.data, source.length, NULL);
13
+ analyzed->arena = pm_arena_new();
14
+ analyzed->parser = herb_prism_parser_new(analyzed->arena, (const uint8_t*) source.data, source.length, options);
13
15
 
14
- analyzed->root = pm_parse(&analyzed->parser);
15
- analyzed->valid = (analyzed->parser.error_list.size == 0);
16
+ analyzed->root = pm_parse(analyzed->parser);
17
+ analyzed->valid = (pm_parser_errors_size(analyzed->parser) == 0);
16
18
  analyzed->parsed = true;
17
19
  analyzed->if_node_count = 0;
18
20
  analyzed->elsif_node_count = 0;
@@ -43,9 +45,8 @@ analyzed_ruby_T* init_analyzed_ruby(hb_string_T source) {
43
45
  void free_analyzed_ruby(analyzed_ruby_T* analyzed) {
44
46
  if (!analyzed) { return; }
45
47
 
46
- if (analyzed->parsed && analyzed->root != NULL) { pm_node_destroy(&analyzed->parser, analyzed->root); }
47
-
48
- pm_parser_free(&analyzed->parser);
48
+ pm_parser_free(analyzed->parser);
49
+ pm_arena_free(analyzed->arena);
49
50
 
50
51
  free(analyzed);
51
52
  }
@@ -6,6 +6,8 @@
6
6
  #include "../include/errors.h"
7
7
  #include "../include/lib/hb_array.h"
8
8
 
9
+ #include "../include/prism/prism_helpers.h"
10
+
9
11
  #include <prism.h>
10
12
  #include <stdbool.h>
11
13
  #include <stdint.h>
@@ -29,8 +31,8 @@ static bool control_type_is_yield(control_type_t type) {
29
31
  return type == CONTROL_TYPE_YIELD;
30
32
  }
31
33
 
32
- static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* data) {
33
- if (!node) { return true; }
34
+ static pm_visit_result_t find_earliest_control_keyword_walker(const pm_node_t* node, void* data) {
35
+ if (!node) { return PM_VISIT_DESCEND; }
34
36
 
35
37
  location_walker_context_T* context = (location_walker_context_T*) data;
36
38
  earliest_control_keyword_T* result = context->result;
@@ -41,50 +43,52 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
41
43
  switch (node->type) {
42
44
  case PM_IF_NODE: {
43
45
  pm_if_node_t* if_node = (pm_if_node_t*) node;
46
+ if (!herb_prism_location_assigned(if_node->if_keyword_loc)) { break; }
47
+
44
48
  current_type = CONTROL_TYPE_IF;
45
- keyword_offset = (uint32_t) (if_node->if_keyword_loc.start - context->source_start);
49
+ keyword_offset = if_node->if_keyword_loc.start;
46
50
  break;
47
51
  }
48
52
 
49
53
  case PM_UNLESS_NODE: {
50
54
  pm_unless_node_t* unless_node = (pm_unless_node_t*) node;
51
55
  current_type = CONTROL_TYPE_UNLESS;
52
- keyword_offset = (uint32_t) (unless_node->keyword_loc.start - context->source_start);
56
+ keyword_offset = unless_node->unless_keyword_loc.start;
53
57
  break;
54
58
  }
55
59
 
56
60
  case PM_CASE_NODE: {
57
61
  pm_case_node_t* case_node = (pm_case_node_t*) node;
58
62
  current_type = CONTROL_TYPE_CASE;
59
- keyword_offset = (uint32_t) (case_node->case_keyword_loc.start - context->source_start);
63
+ keyword_offset = case_node->case_keyword_loc.start;
60
64
  break;
61
65
  }
62
66
 
63
67
  case PM_CASE_MATCH_NODE: {
64
68
  pm_case_match_node_t* case_match_node = (pm_case_match_node_t*) node;
65
69
  current_type = CONTROL_TYPE_CASE_MATCH;
66
- keyword_offset = (uint32_t) (case_match_node->case_keyword_loc.start - context->source_start);
70
+ keyword_offset = case_match_node->case_keyword_loc.start;
67
71
  break;
68
72
  }
69
73
 
70
74
  case PM_WHILE_NODE: {
71
75
  pm_while_node_t* while_node = (pm_while_node_t*) node;
72
76
  current_type = CONTROL_TYPE_WHILE;
73
- keyword_offset = (uint32_t) (while_node->keyword_loc.start - context->source_start);
77
+ keyword_offset = while_node->while_keyword_loc.start;
74
78
  break;
75
79
  }
76
80
 
77
81
  case PM_UNTIL_NODE: {
78
82
  pm_until_node_t* until_node = (pm_until_node_t*) node;
79
83
  current_type = CONTROL_TYPE_UNTIL;
80
- keyword_offset = (uint32_t) (until_node->keyword_loc.start - context->source_start);
84
+ keyword_offset = until_node->until_keyword_loc.start;
81
85
  break;
82
86
  }
83
87
 
84
88
  case PM_FOR_NODE: {
85
89
  pm_for_node_t* for_node = (pm_for_node_t*) node;
86
90
  current_type = CONTROL_TYPE_FOR;
87
- keyword_offset = (uint32_t) (for_node->for_keyword_loc.start - context->source_start);
91
+ keyword_offset = for_node->for_keyword_loc.start;
88
92
  break;
89
93
  }
90
94
 
@@ -92,17 +96,17 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
92
96
  pm_begin_node_t* begin_node = (pm_begin_node_t*) node;
93
97
  current_type = CONTROL_TYPE_BEGIN;
94
98
 
95
- if (begin_node->begin_keyword_loc.start != NULL) {
96
- keyword_offset = (uint32_t) (begin_node->begin_keyword_loc.start - context->source_start);
99
+ if (herb_prism_location_assigned(begin_node->begin_keyword_loc)) {
100
+ keyword_offset = begin_node->begin_keyword_loc.start;
97
101
  } else {
98
- keyword_offset = (uint32_t) (node->location.start - context->source_start);
102
+ keyword_offset = node->location.start;
99
103
  }
100
104
  break;
101
105
  }
102
106
 
103
107
  case PM_YIELD_NODE: {
104
108
  current_type = CONTROL_TYPE_YIELD;
105
- keyword_offset = (uint32_t) (node->location.start - context->source_start);
109
+ keyword_offset = node->location.start;
106
110
  break;
107
111
  }
108
112
 
@@ -112,12 +116,14 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
112
116
  if (call->block != NULL && call->block->type == PM_BLOCK_NODE) {
113
117
  pm_block_node_t* block_node = (pm_block_node_t*) call->block;
114
118
 
115
- bool has_opening = is_do_block(block_node->opening_loc) || is_brace_block(block_node->opening_loc);
116
- bool is_unclosed = !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc);
119
+ bool has_opening = is_do_block(context->source_start, block_node->opening_loc)
120
+ || is_brace_block(context->source_start, block_node->opening_loc);
121
+ bool is_unclosed =
122
+ !has_valid_block_closing(context->source_start, block_node->opening_loc, block_node->closing_loc);
117
123
 
118
124
  if (has_opening && is_unclosed) {
119
125
  current_type = CONTROL_TYPE_BLOCK;
120
- keyword_offset = (uint32_t) (node->location.start - context->source_start);
126
+ keyword_offset = node->location.start;
121
127
  }
122
128
  }
123
129
  break;
@@ -126,12 +132,13 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
126
132
  case PM_LAMBDA_NODE: {
127
133
  pm_lambda_node_t* lambda = (pm_lambda_node_t*) node;
128
134
 
129
- bool has_opening = is_do_block(lambda->opening_loc) || is_brace_block(lambda->opening_loc);
130
- bool is_unclosed = !has_valid_block_closing(lambda->opening_loc, lambda->closing_loc);
135
+ bool has_opening = is_do_block(context->source_start, lambda->opening_loc)
136
+ || is_brace_block(context->source_start, lambda->opening_loc);
137
+ bool is_unclosed = !has_valid_block_closing(context->source_start, lambda->opening_loc, lambda->closing_loc);
131
138
 
132
139
  if (has_opening && is_unclosed) {
133
140
  current_type = CONTROL_TYPE_BLOCK;
134
- keyword_offset = (uint32_t) (node->location.start - context->source_start);
141
+ keyword_offset = node->location.start;
135
142
  }
136
143
 
137
144
  break;
@@ -141,7 +148,7 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
141
148
  case PM_BREAK_NODE:
142
149
  case PM_RETURN_NODE: {
143
150
  current_type = CONTROL_TYPE_UNKNOWN;
144
- keyword_offset = (uint32_t) (node->location.start - context->source_start);
151
+ keyword_offset = node->location.start;
145
152
  break;
146
153
  }
147
154
 
@@ -166,7 +173,7 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
166
173
  }
167
174
  }
168
175
 
169
- return true;
176
+ return PM_VISIT_DESCEND;
170
177
  }
171
178
 
172
179
  static control_type_t find_earliest_control_keyword(pm_node_t* root, const uint8_t* source_start) {
@@ -210,7 +217,7 @@ static control_type_t detect_analyzed_control_type(analyzed_ruby_T* ruby) {
210
217
 
211
218
  if (ruby->unclosed_control_flow_count == 0 && !has_yield_node(ruby)) { return CONTROL_TYPE_UNKNOWN; }
212
219
 
213
- return find_earliest_control_keyword(root, ruby->parser.start);
220
+ return find_earliest_control_keyword(root, pm_parser_start(ruby->parser));
214
221
  }
215
222
 
216
223
  control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
@@ -17,6 +17,7 @@
17
17
  #include "../include/prism/prism_helpers.h"
18
18
 
19
19
  #include <prism.h>
20
+ #include <prism/internal/diagnostic.h>
20
21
  #include <stdbool.h>
21
22
  #include <string.h>
22
23
 
@@ -152,14 +153,11 @@ hb_string_T herb_directive_kind_for_prism_node(const pm_node_t* node) {
152
153
  }
153
154
 
154
155
  typedef struct {
155
- const uint8_t* synthetic_start;
156
156
  size_t signature_start;
157
157
  size_t prefix_length;
158
158
  } synthetic_mapping_T;
159
159
 
160
- static size_t synthetic_to_content_offset(const synthetic_mapping_T* mapping, const uint8_t* pointer) {
161
- size_t offset = (size_t) (pointer - mapping->synthetic_start);
162
-
160
+ static size_t synthetic_to_content_offset(const synthetic_mapping_T* mapping, uint32_t offset) {
163
161
  if (offset < mapping->prefix_length) { return mapping->signature_start; }
164
162
 
165
163
  return mapping->signature_start + offset - mapping->prefix_length;
@@ -172,7 +170,7 @@ static AST_RUBY_LITERAL_NODE_T* create_default_value_node(
172
170
  hb_allocator_T* allocator
173
171
  ) {
174
172
  size_t start = synthetic_to_content_offset(mapping, value->location.start);
175
- size_t end = synthetic_to_content_offset(mapping, value->location.end);
173
+ size_t end = synthetic_to_content_offset(mapping, herb_prism_location_end(value->location));
176
174
 
177
175
  char* source = hb_allocator_strndup(allocator, content->bytes + start, end - start);
178
176
 
@@ -212,12 +210,12 @@ static void append_state_declaration(
212
210
  }
213
211
 
214
212
  size_t name_start = synthetic_to_content_offset(mapping, name_location.start);
215
- size_t name_end = synthetic_to_content_offset(mapping, name_location.end);
213
+ size_t name_end = synthetic_to_content_offset(mapping, herb_prism_location_end(name_location));
216
214
 
217
215
  if (name_end > name_start && content->bytes[name_end - 1] == ':') { name_end--; }
218
216
 
219
217
  size_t declaration_start = synthetic_to_content_offset(mapping, keyword->location.start);
220
- size_t declaration_end = synthetic_to_content_offset(mapping, keyword->location.end);
218
+ size_t declaration_end = synthetic_to_content_offset(mapping, herb_prism_location_end(keyword->location));
221
219
 
222
220
  if (!value) {
223
221
  append_herb_state_invalid_parameter_error(
@@ -257,7 +255,7 @@ static void append_invalid_parameter_error(
257
255
  if (!parameter) { return; }
258
256
 
259
257
  size_t start = synthetic_to_content_offset(mapping, parameter->location.start);
260
- size_t end = synthetic_to_content_offset(mapping, parameter->location.end);
258
+ size_t end = synthetic_to_content_offset(mapping, herb_prism_location_end(parameter->location));
261
259
 
262
260
  append_herb_state_invalid_parameter_error(
263
261
  content_slice(content, start, end),
@@ -560,29 +558,28 @@ static AST_NODE_T* create_herb_state_directive_node(
560
558
  hb_buffer_append_with_length(&synthetic, content->bytes + signature_start, signature_length);
561
559
  hb_buffer_append(&synthetic, SYNTHETIC_SUFFIX);
562
560
 
563
- pm_parser_t parser;
564
- pm_options_t prism_options = { 0 };
565
-
566
- pm_parser_init(&parser, (const uint8_t*) hb_buffer_value(&synthetic), hb_buffer_length(&synthetic), &prism_options);
561
+ pm_arena_t* arena = pm_arena_new();
562
+ pm_parser_t* parser =
563
+ herb_prism_parser_new(arena, (const uint8_t*) hb_buffer_value(&synthetic), hb_buffer_length(&synthetic), options);
567
564
 
568
- pm_node_t* root = pm_parse(&parser);
565
+ pm_node_t* root = pm_parse(parser);
569
566
 
570
567
  synthetic_mapping_T mapping = {
571
- .synthetic_start = parser.start,
572
568
  .signature_start = signature_start,
573
569
  .prefix_length = strlen(SYNTHETIC_PREFIX),
574
570
  };
575
571
 
576
572
  bool parsed = true;
577
573
 
578
- for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head; error != NULL;
579
- error = (const pm_diagnostic_t*) error->node.next) {
574
+ for (const pm_diagnostic_t* error = pm_parser_errors_first(parser); error != NULL;
575
+ error = pm_diagnostic_next(error)) {
580
576
  if (error->diag_id == PM_ERR_DEF_TERM) { continue; }
581
577
 
582
578
  parsed = false;
583
579
 
584
580
  position_T error_start = content_position(content, synthetic_to_content_offset(&mapping, error->location.start));
585
- position_T error_end = content_position(content, synthetic_to_content_offset(&mapping, error->location.end));
581
+ position_T error_end =
582
+ content_position(content, synthetic_to_content_offset(&mapping, herb_prism_location_end(error->location)));
586
583
 
587
584
  hb_array_append(errors, ruby_parse_error_from_prism_error_with_positions(error, error_start, error_end, allocator));
588
585
  }
@@ -591,9 +588,8 @@ static AST_NODE_T* create_herb_state_directive_node(
591
588
  parsed ? extract_state_declarations(find_parameters_node(root), content, &mapping, &errors, allocator, options)
592
589
  : hb_array_init(0, allocator);
593
590
 
594
- pm_node_destroy(&parser, root);
595
- pm_parser_free(&parser);
596
- pm_options_free(&prism_options);
591
+ pm_parser_free(parser);
592
+ pm_arena_free(arena);
597
593
  hb_buffer_free(&synthetic);
598
594
 
599
595
  return (AST_NODE_T*) ast_herb_state_directive_node_init(
@@ -6,6 +6,7 @@
6
6
  #include "../include/lib/hb_allocator.h"
7
7
  #include "../include/lib/hb_array.h"
8
8
  #include "../include/lib/hb_string.h"
9
+ #include "../include/prism/prism_helpers.h"
9
10
  #include "../include/visitor.h"
10
11
 
11
12
  #include <prism.h>
@@ -20,14 +21,13 @@ static token_T* create_token_from_prism_location(
20
21
  const uint8_t* erb_content_source,
21
22
  hb_allocator_T* allocator
22
23
  ) {
23
- if (location.start == NULL || location.end == NULL) { return NULL; }
24
+ if (!herb_prism_location_assigned(location)) { return NULL; }
24
25
  if (!source || !erb_content_source) { return NULL; }
25
26
 
26
- size_t length = (size_t) (location.end - location.start);
27
- char* value = hb_allocator_strndup(allocator, (const char*) location.start, length);
27
+ char* value = hb_allocator_strndup(allocator, (const char*) (erb_content_source + location.start), location.length);
28
28
 
29
- size_t total_start = erb_content_offset + (size_t) (location.start - erb_content_source);
30
- size_t total_end = erb_content_offset + (size_t) (location.end - erb_content_source);
29
+ size_t total_start = erb_content_offset + location.start;
30
+ size_t total_end = erb_content_offset + herb_prism_location_end(location);
31
31
 
32
32
  position_T start = byte_offset_to_position(source, total_start);
33
33
  position_T end = byte_offset_to_position(source, total_end);
@@ -59,15 +59,18 @@ static hb_array_T* extract_call_arguments(
59
59
  const pm_node_t* argument = call->arguments->arguments.nodes[index];
60
60
  if (!argument) { continue; }
61
61
 
62
- size_t length = (size_t) (argument->location.end - argument->location.start);
63
- char* value = hb_allocator_strndup(allocator, (const char*) argument->location.start, length);
62
+ char* value = hb_allocator_strndup(
63
+ allocator,
64
+ (const char*) (erb_content_source + argument->location.start),
65
+ argument->location.length
66
+ );
64
67
 
65
68
  position_T start = { .line = 1, .column = 1 };
66
69
  position_T end = { .line = 1, .column = 1 };
67
70
 
68
71
  if (source && erb_content_source) {
69
- size_t total_start = erb_content_offset + (size_t) (argument->location.start - erb_content_source);
70
- size_t total_end = erb_content_offset + (size_t) (argument->location.end - erb_content_source);
72
+ size_t total_start = erb_content_offset + argument->location.start;
73
+ size_t total_end = erb_content_offset + herb_prism_location_end(argument->location);
71
74
 
72
75
  start = byte_offset_to_position(source, total_start);
73
76
  end = byte_offset_to_position(source, total_end);
@@ -106,30 +109,72 @@ static const char* ITERATION_METHODS[] = {
106
109
  "cycle",
107
110
  };
108
111
 
109
- static bool is_iteration_method(const pm_constant_t* constant) {
110
- size_t count = sizeof(ITERATION_METHODS) / sizeof(ITERATION_METHODS[0]);
112
+ static const char* ARGUMENTLESS_ITERATION_METHODS[] = {
113
+ "times", "each_pair", "map", "flat_map", "select", "filter", "reject", "filter_map",
114
+ };
111
115
 
116
+ static const char* TAG_BUILDER_ELEMENTS[] = {
117
+ "map",
118
+ "select",
119
+ "filter",
120
+ };
121
+
122
+ static bool constant_matches_any(const pm_constant_t* constant, const char** names, size_t count) {
112
123
  for (size_t index = 0; index < count; index++) {
113
- const char* name = ITERATION_METHODS[index];
124
+ const char* name = names[index];
114
125
  size_t length = strlen(name);
115
126
 
116
- if (constant->length == length && memcmp(constant->start, name, length) == 0) { return true; }
127
+ if (pm_constant_length(constant) == length && memcmp(pm_constant_start(constant), name, length) == 0) {
128
+ return true;
129
+ }
117
130
  }
118
131
 
119
132
  return false;
120
133
  }
121
134
 
135
+ static bool is_iteration_method(const pm_constant_t* constant) {
136
+ return constant_matches_any(constant, ITERATION_METHODS, sizeof(ITERATION_METHODS) / sizeof(ITERATION_METHODS[0]));
137
+ }
138
+
139
+ static bool rejects_call_arguments(const pm_constant_t* constant) {
140
+ return constant_matches_any(
141
+ constant,
142
+ ARGUMENTLESS_ITERATION_METHODS,
143
+ sizeof(ARGUMENTLESS_ITERATION_METHODS) / sizeof(ARGUMENTLESS_ITERATION_METHODS[0])
144
+ );
145
+ }
146
+
147
+ static bool is_tag_builder_element(const pm_constant_t* constant) {
148
+ return constant_matches_any(
149
+ constant,
150
+ TAG_BUILDER_ELEMENTS,
151
+ sizeof(TAG_BUILDER_ELEMENTS) / sizeof(TAG_BUILDER_ELEMENTS[0])
152
+ );
153
+ }
154
+
155
+ static bool has_tag_builder_receiver(const pm_call_node_t* call, const pm_parser_t* parser) {
156
+ if (call->receiver->type != PM_CALL_NODE) { return false; }
157
+
158
+ const pm_call_node_t* receiver = (const pm_call_node_t*) call->receiver;
159
+ const pm_constant_t* constant = pm_parser_constant(parser, receiver->name);
160
+
161
+ return constant && pm_constant_length(constant) == 3 && memcmp(pm_constant_start(constant), "tag", 3) == 0;
162
+ }
163
+
122
164
  static bool is_iteration_call(const pm_call_node_t* call, const pm_parser_t* parser) {
123
165
  if (!call) { return false; }
124
166
  if (call->receiver == NULL) { return false; }
125
167
  if (call->block == NULL || call->block->type != PM_BLOCK_NODE) { return false; }
126
168
 
127
169
  pm_constant_id_t name_id = call->name;
128
- const pm_constant_t* constant = pm_constant_pool_id_to_constant(&((pm_parser_t*) parser)->constant_pool, name_id);
170
+ const pm_constant_t* constant = pm_parser_constant(parser, name_id);
129
171
 
130
172
  if (!constant) { return false; }
173
+ if (!is_iteration_method(constant)) { return false; }
174
+ if (call->arguments != NULL && rejects_call_arguments(constant)) { return false; }
175
+ if (is_tag_builder_element(constant) && has_tag_builder_receiver(call, parser)) { return false; }
131
176
 
132
- return is_iteration_method(constant);
177
+ return true;
133
178
  }
134
179
 
135
180
  static pm_call_node_t* find_iteration_call(pm_node_t* node, const pm_parser_t* parser) {
@@ -173,15 +218,15 @@ static AST_ERB_ITERATION_BLOCK_NODE_T* try_transform_block_node(
173
218
  const char* ruby_source = block_node->content->value.data;
174
219
  size_t ruby_length = block_node->content->value.length;
175
220
 
176
- pm_parser_t parser;
177
- pm_parser_init(&parser, (const uint8_t*) ruby_source, ruby_length, NULL);
178
- pm_node_t* root = pm_parse(&parser);
221
+ pm_arena_t* arena = pm_arena_new();
222
+ pm_parser_t* parser = herb_prism_parser_new(arena, (const uint8_t*) ruby_source, ruby_length, context->options);
223
+ pm_node_t* root = pm_parse(parser);
179
224
 
180
- pm_call_node_t* iteration_call = find_iteration_call(root, &parser);
225
+ pm_call_node_t* iteration_call = find_iteration_call(root, parser);
181
226
 
182
227
  if (!iteration_call) {
183
- pm_node_destroy(&parser, root);
184
- pm_parser_free(&parser);
228
+ pm_parser_free(parser);
229
+ pm_arena_free(arena);
185
230
 
186
231
  return NULL;
187
232
  }
@@ -192,7 +237,7 @@ static AST_ERB_ITERATION_BLOCK_NODE_T* try_transform_block_node(
192
237
  erb_content_offset = calculate_byte_offset_from_position(context->source, block_node->content->location.start);
193
238
  }
194
239
 
195
- const uint8_t* erb_content_source = (const uint8_t*) parser.start;
240
+ const uint8_t* erb_content_source = pm_parser_start(parser);
196
241
 
197
242
  token_T* receiver = create_token_from_prism_location(
198
243
  iteration_call->receiver->location,
@@ -260,8 +305,8 @@ static AST_ERB_ITERATION_BLOCK_NODE_T* try_transform_block_node(
260
305
  allocator
261
306
  );
262
307
 
263
- pm_node_destroy(&parser, root);
264
- pm_parser_free(&parser);
308
+ pm_parser_free(parser);
309
+ pm_arena_free(arena);
265
310
 
266
311
  return iteration_block_node;
267
312
  }
@@ -9,6 +9,7 @@
9
9
  #include "../include/prism/prism_helpers.h"
10
10
 
11
11
  #include <prism.h>
12
+ #include <prism/internal/diagnostic.h>
12
13
  #include <stdlib.h>
13
14
  #include <string.h>
14
15
 
@@ -43,7 +44,12 @@ static bool should_skip_forwarding_error(
43
44
  return has_anonymous_keyword_rest;
44
45
  }
45
46
 
46
- static void parse_erb_content_errors(AST_NODE_T* erb_node, const char* source, hb_allocator_T* allocator) {
47
+ static void parse_erb_content_errors(
48
+ AST_NODE_T* erb_node,
49
+ const char* source,
50
+ const parser_options_T* parser_options,
51
+ hb_allocator_T* allocator
52
+ ) {
47
53
  if (!erb_node || erb_node->type != AST_ERB_CONTENT_NODE) { return; }
48
54
  AST_ERB_CONTENT_NODE_T* content_node = (AST_ERB_CONTENT_NODE_T*) erb_node;
49
55
 
@@ -52,13 +58,15 @@ static void parse_erb_content_errors(AST_NODE_T* erb_node, const char* source, h
52
58
  char* content = hb_string_to_c_string_using_malloc(content_node->content->value);
53
59
  if (!content) { return; }
54
60
 
55
- pm_parser_t parser;
56
- pm_options_t options = { 0, .partial_script = true };
57
- pm_parser_init(&parser, (const uint8_t*) content, strlen(content), &options);
61
+ pm_arena_t* arena = pm_arena_new();
62
+ pm_options_t* options = pm_options_new();
63
+ pm_options_partial_script_set(options, true);
64
+ herb_prism_options_set_ruby_version(options, parser_options);
65
+ pm_parser_t* parser = pm_parser_new(arena, (const uint8_t*) content, strlen(content), options);
58
66
 
59
- pm_node_t* root = pm_parse(&parser);
67
+ pm_parse(parser);
60
68
 
61
- const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head;
69
+ const pm_diagnostic_t* error = pm_parser_errors_first(parser);
62
70
 
63
71
  if (error != NULL) {
64
72
  RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error_with_positions(
@@ -71,9 +79,9 @@ static void parse_erb_content_errors(AST_NODE_T* erb_node, const char* source, h
71
79
  hb_array_append_lazy(&erb_node->errors, parse_error, allocator);
72
80
  }
73
81
 
74
- pm_node_destroy(&parser, root);
75
- pm_parser_free(&parser);
76
- pm_options_free(&options);
82
+ pm_parser_free(parser);
83
+ pm_arena_free(arena);
84
+ pm_options_free(options);
77
85
  free(content);
78
86
  }
79
87
 
@@ -95,24 +103,26 @@ void herb_analyze_parse_errors(
95
103
  bool strict_locals_enabled = parser_options && parser_options->strict_locals;
96
104
  bool has_anonymous_keyword_rest = strict_locals_enabled && document_has_anonymous_keyword_rest(document);
97
105
 
98
- pm_parser_t parser;
99
- pm_options_t options = { 0, .partial_script = true };
100
- pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
106
+ pm_arena_t* arena = pm_arena_new();
107
+ pm_options_t* options = pm_options_new();
108
+ pm_options_partial_script_set(options, true);
109
+ herb_prism_options_set_ruby_version(options, parser_options);
110
+ pm_parser_t* parser = pm_parser_new(arena, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), options);
101
111
 
102
- pm_node_t* root = pm_parse(&parser);
112
+ pm_parse(parser);
103
113
 
104
- for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head; error != NULL;
105
- error = (const pm_diagnostic_t*) error->node.next) {
114
+ for (const pm_diagnostic_t* error = pm_parser_errors_first(parser); error != NULL;
115
+ error = pm_diagnostic_next(error)) {
106
116
  if (should_skip_forwarding_error(error, strict_locals_enabled, has_anonymous_keyword_rest)) { continue; }
107
117
 
108
- size_t error_offset = (size_t) (error->location.start - parser.start);
118
+ size_t error_offset = error->location.start;
109
119
 
110
- if (strstr(error->message, "unexpected ';'") != NULL) {
120
+ if (strstr(pm_diagnostic_message(error), "unexpected ';'") != NULL) {
111
121
  if (error_offset < strlen(extracted_ruby) && extracted_ruby[error_offset] == ';') {
112
122
  if (error_offset >= strlen(source) || source[error_offset] != ';') {
113
123
  AST_NODE_T* erb_node = find_erb_content_at_offset(document, source, error_offset);
114
124
 
115
- if (erb_node) { parse_erb_content_errors(erb_node, source, allocator); }
125
+ if (erb_node) { parse_erb_content_errors(erb_node, source, parser_options, allocator); }
116
126
 
117
127
  continue;
118
128
  }
@@ -120,12 +130,12 @@ void herb_analyze_parse_errors(
120
130
  }
121
131
 
122
132
  RUBY_PARSE_ERROR_T* parse_error =
123
- ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser, allocator);
133
+ ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, parser, allocator);
124
134
  hb_array_append_lazy(&document->base.errors, parse_error, allocator);
125
135
  }
126
136
 
127
- pm_node_destroy(&parser, root);
128
- pm_parser_free(&parser);
129
- pm_options_free(&options);
137
+ pm_parser_free(parser);
138
+ pm_arena_free(arena);
139
+ pm_options_free(options);
130
140
  hb_allocator_dealloc(allocator, extracted_ruby);
131
141
  }