herb 0.11.0-x86_64-linux-gnu → 0.11.2-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 (273) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -2
  3. data/config.yml +9 -0
  4. data/ext/herb/extconf.rb +8 -31
  5. data/ext/herb/nodes.c +90 -73
  6. data/ext/herb/parser_options_helpers.c +26 -0
  7. data/lib/herb/3.2/herb.so +0 -0
  8. data/lib/herb/3.3/herb.so +0 -0
  9. data/lib/herb/3.4/herb.so +0 -0
  10. data/lib/herb/4.0/herb.so +0 -0
  11. data/lib/herb/analysis/partial_index.rb +1 -1
  12. data/lib/herb/analysis/partial_resolution.rb +27 -0
  13. data/lib/herb/ast/helpers.rb +1 -1
  14. data/lib/herb/ast/nodes.rb +32 -6
  15. data/lib/herb/bootstrap.rb +6 -2
  16. data/lib/herb/configuration.rb +11 -1
  17. data/lib/herb/dev/classifier.rb +1 -1
  18. data/lib/herb/dev/runner.rb +6 -1
  19. data/lib/herb/engine/compiler.rb +52 -19
  20. data/lib/herb/engine/slots/dynamics_compiler.rb +63 -14
  21. data/lib/herb/engine/slots/markers.rb +24 -0
  22. data/lib/herb/engine/slots/state_compiler.rb +1 -2
  23. data/lib/herb/engine/slots/subtree_compiler.rb +1 -1
  24. data/lib/herb/engine/slots/visitor.rb +71 -32
  25. data/lib/herb/engine/visitors/instrumentation_visitor.rb +18 -6
  26. data/lib/herb/engine.rb +0 -2
  27. data/lib/herb/parser_options.rb +6 -3
  28. data/lib/herb/project.rb +19 -8
  29. data/lib/herb/version.rb +1 -1
  30. data/lib/herb.rb +1 -1
  31. data/sig/herb/analysis/partial_resolution.rbs +8 -0
  32. data/sig/herb/ast/nodes.rbs +10 -4
  33. data/sig/herb/bootstrap.rbs +2 -0
  34. data/sig/herb/configuration.rbs +3 -0
  35. data/sig/herb/dev/runner.rbs +3 -0
  36. data/sig/herb/engine/compiler.rbs +14 -3
  37. data/sig/herb/engine/slots/dynamics_compiler.rbs +27 -7
  38. data/sig/herb/engine/slots/markers.rbs +14 -0
  39. data/sig/herb/engine/slots/visitor.rbs +31 -13
  40. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +5 -1
  41. data/sig/herb/parser_options.rbs +6 -4
  42. data/sig/herb.rbs +2 -2
  43. data/sig/serialized_ast_nodes.rbs +1 -0
  44. data/src/analyze/action_view/attribute_extraction_helpers.c +40 -21
  45. data/src/analyze/action_view/generated_handlers.c +36 -36
  46. data/src/analyze/action_view/image_tag.c +7 -3
  47. data/src/analyze/action_view/javascript_include_tag.c +6 -3
  48. data/src/analyze/action_view/link_to.c +23 -23
  49. data/src/analyze/action_view/registry.c +7 -3
  50. data/src/analyze/action_view/tag_helper_node_builders.c +12 -16
  51. data/src/analyze/action_view/tag_helpers.c +215 -110
  52. data/src/analyze/action_view/turbo_frame_tag.c +5 -4
  53. data/src/analyze/analyze.c +41 -45
  54. data/src/analyze/analyze_helpers.c +240 -405
  55. data/src/analyze/analyzed_ruby.c +10 -7
  56. data/src/analyze/builders.c +1 -0
  57. data/src/analyze/control_type.c +46 -29
  58. data/src/analyze/herb_directives.c +16 -20
  59. data/src/analyze/iteration_nodes.c +69 -24
  60. data/src/analyze/parse_errors.c +32 -22
  61. data/src/analyze/postfix_conditionals.c +23 -13
  62. data/src/analyze/prism_annotate.c +56 -32
  63. data/src/analyze/render_nodes.c +51 -41
  64. data/src/analyze/strict_locals.c +14 -15
  65. data/src/analyze/ternary_conditionals.c +14 -10
  66. data/src/ast/ast_nodes.c +3 -1
  67. data/src/ast/ast_pretty_print.c +5 -1
  68. data/src/extract.c +204 -143
  69. data/src/herb.c +10 -8
  70. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  71. data/src/include/analyze/action_view/tag_helper_node_builders.h +1 -0
  72. data/src/include/analyze/action_view/tag_helpers.h +1 -1
  73. data/src/include/analyze/analyze.h +3 -24
  74. data/src/include/analyze/analyzed_ruby.h +29 -2
  75. data/src/include/analyze/helpers.h +7 -27
  76. data/src/include/ast/ast_nodes.h +2 -1
  77. data/src/include/herb.h +3 -2
  78. data/src/include/lexer/lexer.h +1 -0
  79. data/src/include/parser/parser_options.h +5 -0
  80. data/src/include/prism/herb_prism_node.h +6 -1
  81. data/src/include/prism/prism_context.h +12 -12
  82. data/src/include/prism/prism_helpers.h +30 -0
  83. data/src/include/prism_version.h +11 -0
  84. data/src/include/version.h +1 -1
  85. data/src/lexer.c +32 -0
  86. data/src/parser/parser_helpers.c +1 -2
  87. data/src/parser.c +6 -7
  88. data/src/parser_options_defaults.c +1 -0
  89. data/src/prism/prism_helpers.c +167 -42
  90. data/src/prism/ruby_parser.c +20 -20
  91. data/templates/ext/herb/nodes.c.erb +5 -5
  92. data/templates/ext/herb/parser_options_helpers.c.erb +33 -0
  93. data/templates/java/nodes.c.erb +6 -6
  94. data/templates/java/parser_options_helpers.c.erb +41 -2
  95. data/templates/java/parser_options_helpers.h.erb +2 -1
  96. data/templates/javascript/packages/core/src/nodes.ts.erb +21 -1
  97. data/templates/javascript/packages/node/extension/nodes.cpp.erb +5 -5
  98. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +34 -2
  99. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +1 -1
  100. data/templates/lib/herb/parser_options.rb.erb +1 -1
  101. data/templates/rust/src/ast/nodes.rs.erb +1 -4
  102. data/templates/rust/src/prism/generated_deserialize.rs.erb +90 -44
  103. data/templates/rust/src/prism/generated_prettyprint.rs.erb +18 -27
  104. data/templates/src/analyze/action_view/generated_handlers.c.erb +23 -22
  105. data/templates/src/include/parser/parser_options.h.erb +10 -0
  106. data/templates/src/include/prism_version.h.erb +17 -0
  107. data/templates/src/parser_options_defaults.c.erb +1 -1
  108. data/templates/template.rb +17 -2
  109. data/templates/wasm/nodes.cpp.erb +8 -18
  110. data/templates/wasm/parser_options_helpers.cpp.erb +24 -0
  111. data/vendor/prism/Rakefile +76 -7
  112. data/vendor/prism/config.yml +174 -161
  113. data/vendor/prism/include/prism/arena.h +45 -0
  114. data/vendor/prism/include/prism/arena.hpp +42 -0
  115. data/vendor/prism/include/prism/ast.h +2738 -611
  116. data/vendor/prism/include/prism/ast.hpp +641 -0
  117. data/vendor/prism/include/prism/buffer.h +60 -0
  118. data/vendor/prism/include/prism/buffer.hpp +55 -0
  119. data/vendor/prism/include/prism/comments.h +72 -0
  120. data/vendor/prism/include/prism/compiler/accel.h +26 -0
  121. data/vendor/prism/include/prism/compiler/align.h +36 -0
  122. data/vendor/prism/include/prism/compiler/assume.h +25 -0
  123. data/vendor/prism/include/prism/compiler/branch.h +26 -0
  124. data/vendor/prism/include/prism/compiler/bswap.h +46 -0
  125. data/vendor/prism/include/prism/compiler/cplusplus.hpp +16 -0
  126. data/vendor/prism/include/prism/compiler/endianness.h +34 -0
  127. data/vendor/prism/include/prism/compiler/exceptions.hpp +17 -0
  128. data/vendor/prism/include/prism/compiler/exported.h +24 -0
  129. data/vendor/prism/include/prism/compiler/fallthrough.h +22 -0
  130. data/vendor/prism/include/prism/compiler/filesystem.h +32 -0
  131. data/vendor/prism/include/prism/compiler/flex_array.h +19 -0
  132. data/vendor/prism/include/prism/compiler/force_inline.h +21 -0
  133. data/vendor/prism/include/prism/compiler/format.h +27 -0
  134. data/vendor/prism/include/prism/compiler/inline.h +17 -0
  135. data/vendor/prism/include/prism/compiler/lifetimebound.hpp +25 -0
  136. data/vendor/prism/include/prism/compiler/nodiscard.h +22 -0
  137. data/vendor/prism/include/prism/compiler/nonnull.h +18 -0
  138. data/vendor/prism/include/prism/compiler/unused.h +18 -0
  139. data/vendor/prism/include/prism/constant_pool.h +106 -0
  140. data/vendor/prism/include/prism/diagnostic.h +55 -402
  141. data/vendor/prism/include/prism/errors_format.h +61 -0
  142. data/vendor/prism/include/prism/excludes.h +29 -0
  143. data/vendor/prism/include/prism/integer.h +41 -0
  144. data/vendor/prism/include/prism/internal/allocator.h +68 -0
  145. data/vendor/prism/include/prism/internal/allocator_debug.h +88 -0
  146. data/vendor/prism/include/prism/internal/arena.h +108 -0
  147. data/vendor/prism/include/prism/internal/bit.h +42 -0
  148. data/vendor/prism/include/prism/internal/buffer.h +94 -0
  149. data/vendor/prism/include/prism/internal/char.h +145 -0
  150. data/vendor/prism/include/prism/internal/comments.h +54 -0
  151. data/vendor/prism/include/prism/internal/constant_pool.h +152 -0
  152. data/vendor/prism/include/prism/internal/diagnostic.h +389 -0
  153. data/vendor/prism/include/prism/{encoding.h → internal/encoding.h} +27 -68
  154. data/vendor/prism/include/prism/internal/integer.h +68 -0
  155. data/vendor/prism/include/prism/internal/isinf.h +16 -0
  156. data/vendor/prism/include/prism/internal/line_offset_list.h +34 -0
  157. data/vendor/prism/include/prism/{util/pm_list.h → internal/list.h} +11 -52
  158. data/vendor/prism/include/prism/internal/magic_comments.h +23 -0
  159. data/vendor/prism/include/prism/internal/memchr.h +15 -0
  160. data/vendor/prism/include/prism/internal/node.h +42 -0
  161. data/vendor/prism/include/prism/internal/options.h +232 -0
  162. data/vendor/prism/include/prism/internal/parser.h +1015 -0
  163. data/vendor/prism/include/prism/internal/regexp.h +26 -0
  164. data/vendor/prism/include/prism/internal/serialize.h +39 -0
  165. data/vendor/prism/include/prism/internal/source.h +72 -0
  166. data/vendor/prism/include/prism/internal/static_literals.h +60 -0
  167. data/vendor/prism/include/prism/internal/stringy.h +30 -0
  168. data/vendor/prism/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
  169. data/vendor/prism/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
  170. data/vendor/prism/include/prism/internal/tokens.h +11 -0
  171. data/vendor/prism/include/prism/internal/xxh3.h +16 -0
  172. data/vendor/prism/include/prism/json.h +40 -0
  173. data/vendor/prism/include/prism/line_offset_list.h +69 -0
  174. data/vendor/prism/include/prism/magic_comments.h +53 -0
  175. data/vendor/prism/include/prism/node.h +59 -49
  176. data/vendor/prism/include/prism/node.hpp +272 -0
  177. data/vendor/prism/include/prism/node_type.hpp +38 -0
  178. data/vendor/prism/include/prism/options.h +154 -279
  179. data/vendor/prism/include/prism/options.hpp +43 -0
  180. data/vendor/prism/include/prism/parser.h +367 -870
  181. data/vendor/prism/include/prism/parser.hpp +274 -0
  182. data/vendor/prism/include/prism/prettyprint.h +14 -9
  183. data/vendor/prism/include/prism/serialize.h +123 -0
  184. data/vendor/prism/include/prism/source.h +163 -0
  185. data/vendor/prism/include/prism/stream.h +36 -0
  186. data/vendor/prism/include/prism/string_query.h +82 -0
  187. data/vendor/prism/include/prism/stringy.h +61 -0
  188. data/vendor/prism/include/prism/stringy.hpp +31 -0
  189. data/vendor/prism/include/prism/version.h +20 -3
  190. data/vendor/prism/include/prism.h +35 -320
  191. data/vendor/prism/include/prism.hpp +24 -0
  192. data/vendor/prism/src/arena.c +122 -0
  193. data/vendor/prism/src/{util/pm_buffer.c → buffer.c} +53 -21
  194. data/vendor/prism/src/{util/pm_char.c → char.c} +28 -57
  195. data/vendor/prism/src/comments.c +455 -0
  196. data/vendor/prism/src/constant_pool.c +406 -0
  197. data/vendor/prism/src/diagnostic.c +120 -68
  198. data/vendor/prism/src/encoding.c +8 -3
  199. data/vendor/prism/src/errors_format.c +519 -0
  200. data/vendor/prism/src/{util/pm_integer.c → integer.c} +38 -22
  201. data/vendor/prism/src/json.c +5733 -0
  202. data/vendor/prism/src/line_offset_list.c +100 -0
  203. data/vendor/prism/src/list.c +24 -0
  204. data/vendor/prism/src/{util/pm_memchr.c → memchr.c} +8 -6
  205. data/vendor/prism/src/node.c +3465 -7787
  206. data/vendor/prism/src/options.c +161 -54
  207. data/vendor/prism/src/parser.c +371 -0
  208. data/vendor/prism/src/prettyprint.c +421 -354
  209. data/vendor/prism/src/prism.c +8522 -7280
  210. data/vendor/prism/src/regexp.c +960 -45
  211. data/vendor/prism/src/serialize.c +2434 -2048
  212. data/vendor/prism/src/source.c +524 -0
  213. data/vendor/prism/src/static_literals.c +303 -360
  214. data/vendor/prism/src/string_query.c +180 -0
  215. data/vendor/prism/src/stringy.c +61 -0
  216. data/vendor/prism/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
  217. data/vendor/prism/src/strpbrk.c +447 -0
  218. data/vendor/prism/src/{token_type.c → tokens.c} +39 -18
  219. data/vendor/prism/src/xxh3.c +292 -0
  220. data/vendor/prism/templates/ext/prism/api_node.c.erb +58 -44
  221. data/vendor/prism/templates/include/prism/ast.h.erb +67 -17
  222. data/vendor/prism/templates/include/prism/ast.hpp.erb +31 -0
  223. data/vendor/prism/templates/include/prism/internal/diagnostic.h.erb +60 -0
  224. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/AbstractNodeVisitor.java.erb +1 -1
  225. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Loader.java.erb +232 -133
  226. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Nodes.java.erb +62 -23
  227. data/vendor/prism/templates/javascript/src/deserialize.js.erb +153 -146
  228. data/vendor/prism/templates/javascript/src/nodes.js.erb +4 -9
  229. data/vendor/prism/templates/lib/prism/compiler.rb.erb +14 -5
  230. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +20 -12
  231. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +37 -11
  232. data/vendor/prism/templates/lib/prism/dsl.rb.erb +43 -4
  233. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +26 -10
  234. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +5 -2
  235. data/vendor/prism/templates/lib/prism/node.rb.erb +283 -105
  236. data/vendor/prism/templates/lib/prism/reflection.rb.erb +11 -2
  237. data/vendor/prism/templates/lib/prism/serialize.rb.erb +291 -134
  238. data/vendor/prism/templates/lib/prism/visitor.rb.erb +18 -0
  239. data/vendor/prism/templates/src/diagnostic.c.erb +114 -63
  240. data/vendor/prism/templates/src/json.c.erb +130 -0
  241. data/vendor/prism/templates/src/node.c.erb +79 -236
  242. data/vendor/prism/templates/src/prettyprint.c.erb +24 -13
  243. data/vendor/prism/templates/src/serialize.c.erb +369 -183
  244. data/vendor/prism/templates/src/{token_type.c.erb → tokens.c.erb} +22 -11
  245. data/vendor/prism/templates/template.rb +193 -91
  246. metadata +100 -42
  247. data/vendor/prism/include/prism/defines.h +0 -260
  248. data/vendor/prism/include/prism/pack.h +0 -163
  249. data/vendor/prism/include/prism/regexp.h +0 -43
  250. data/vendor/prism/include/prism/static_literals.h +0 -121
  251. data/vendor/prism/include/prism/util/pm_buffer.h +0 -236
  252. data/vendor/prism/include/prism/util/pm_char.h +0 -204
  253. data/vendor/prism/include/prism/util/pm_constant_pool.h +0 -218
  254. data/vendor/prism/include/prism/util/pm_integer.h +0 -130
  255. data/vendor/prism/include/prism/util/pm_memchr.h +0 -29
  256. data/vendor/prism/include/prism/util/pm_newline_list.h +0 -113
  257. data/vendor/prism/include/prism/util/pm_string.h +0 -200
  258. data/vendor/prism/src/pack.c +0 -509
  259. data/vendor/prism/src/util/pm_constant_pool.c +0 -342
  260. data/vendor/prism/src/util/pm_list.c +0 -49
  261. data/vendor/prism/src/util/pm_newline_list.c +0 -125
  262. data/vendor/prism/src/util/pm_string.c +0 -381
  263. data/vendor/prism/src/util/pm_strpbrk.c +0 -206
  264. data/vendor/prism/templates/include/prism/diagnostic.h.erb +0 -130
  265. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +0 -68
  266. data/vendor/prism/templates/rbi/prism/node.rbi.erb +0 -167
  267. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +0 -18
  268. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +0 -45
  269. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +0 -31
  270. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +0 -7
  271. data/vendor/prism/templates/sig/prism/node.rbs.erb +0 -136
  272. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +0 -17
  273. data/vendor/prism/templates/sig/prism.rbs.erb +0 -92
@@ -1,4 +1,5 @@
1
1
  #include <prism.h>
2
+ #include <prism/internal/diagnostic.h>
2
3
  #include <stdbool.h>
3
4
  #include <string.h>
4
5
 
@@ -94,22 +95,21 @@ bool has_inline_case_condition(analyzed_ruby_T* analyzed) {
94
95
  }
95
96
 
96
97
  typedef struct {
97
- const uint8_t* source_start;
98
98
  uint32_t offset;
99
99
  bool found;
100
100
  } inline_condition_offset_T;
101
101
 
102
- static bool search_inline_condition_offset(const pm_node_t* node, void* data) {
102
+ static pm_visit_result_t search_inline_condition_offset(const pm_node_t* node, void* data) {
103
103
  inline_condition_offset_T* context = (inline_condition_offset_T*) data;
104
104
 
105
105
  uint32_t keyword_offset = UINT32_MAX;
106
106
 
107
107
  if (node->type == PM_WHEN_NODE) {
108
- keyword_offset = (uint32_t) (((const pm_when_node_t*) node)->keyword_loc.start - context->source_start);
108
+ keyword_offset = ((const pm_when_node_t*) node)->when_keyword_loc.start;
109
109
  } else if (node->type == PM_IN_NODE) {
110
- keyword_offset = (uint32_t) (((const pm_in_node_t*) node)->in_loc.start - context->source_start);
110
+ keyword_offset = ((const pm_in_node_t*) node)->in_keyword_loc.start;
111
111
  } else if (node->type == PM_MATCH_PREDICATE_NODE) {
112
- keyword_offset = (uint32_t) (((const pm_match_predicate_node_t*) node)->operator_loc.start - context->source_start);
112
+ keyword_offset = ((const pm_match_predicate_node_t*) node)->keyword_loc.start;
113
113
  }
114
114
 
115
115
  if (keyword_offset != UINT32_MAX && (!context->found || keyword_offset < context->offset)) {
@@ -119,7 +119,7 @@ static bool search_inline_condition_offset(const pm_node_t* node, void* data) {
119
119
 
120
120
  pm_visit_child_nodes(node, search_inline_condition_offset, context);
121
121
 
122
- return false;
122
+ return PM_VISIT_SKIP;
123
123
  }
124
124
 
125
125
  static hb_string_T control_continuation_keywords[] = HB_STRING_LIST("else", "elsif", "when", "in", "rescue", "ensure");
@@ -157,19 +157,18 @@ bool control_role_split_offset(const analyzed_ruby_T* analyzed, uint32_t* offset
157
157
  uint32_t second = UINT32_MAX;
158
158
  bool first_continues = false;
159
159
 
160
- for (const pm_diagnostic_t* diagnostic = (const pm_diagnostic_t*) analyzed->parser.error_list.head;
161
- diagnostic != NULL;
162
- diagnostic = (const pm_diagnostic_t*) diagnostic->node.next) {
160
+ const uint8_t* source = pm_parser_start(analyzed->parser);
161
+
162
+ for (const pm_diagnostic_t* diagnostic = pm_parser_errors_first(analyzed->parser); diagnostic != NULL;
163
+ diagnostic = pm_diagnostic_next(diagnostic)) {
163
164
  if (diagnostic->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE) { continue; }
164
165
 
165
- hb_string_T keyword = hb_string_from_data(
166
- (const char*) diagnostic->location.start,
167
- (size_t) (diagnostic->location.end - diagnostic->location.start)
168
- );
166
+ hb_string_T keyword =
167
+ hb_string_from_data((const char*) (source + diagnostic->location.start), diagnostic->location.length);
169
168
 
170
169
  if (!is_control_role_keyword(keyword)) { continue; }
171
170
 
172
- uint32_t start = (uint32_t) (diagnostic->location.start - analyzed->parser.start);
171
+ uint32_t start = diagnostic->location.start;
173
172
 
174
173
  if (start < first) {
175
174
  second = first;
@@ -203,7 +202,6 @@ bool inline_condition_keyword_offset(const analyzed_ruby_T* analyzed, uint32_t*
203
202
  if (!analyzed || !analyzed->root || !offset) { return false; }
204
203
 
205
204
  inline_condition_offset_T context = {
206
- .source_start = analyzed->parser.start,
207
205
  .offset = UINT32_MAX,
208
206
  .found = false,
209
207
  };
@@ -218,324 +216,175 @@ bool inline_condition_keyword_offset(const analyzed_ruby_T* analyzed, uint32_t*
218
216
  }
219
217
 
220
218
  bool has_error_message(analyzed_ruby_T* analyzed, const char* message) {
221
- for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) analyzed->parser.error_list.head; error != NULL;
222
- error = (const pm_diagnostic_t*) error->node.next) {
223
- if (string_equals(error->message, message)) { return true; }
224
- }
225
-
226
- return false;
227
- }
228
-
229
- bool search_if_nodes(const pm_node_t* node, void* data) {
230
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
231
-
232
- if (node->type == PM_IF_NODE) {
233
- const pm_if_node_t* if_node = (const pm_if_node_t*) node;
234
-
235
- bool has_if_keyword = if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL;
236
- bool has_end_keyword = if_node->end_keyword_loc.start != NULL && if_node->end_keyword_loc.end != NULL;
237
-
238
- if (has_if_keyword && has_end_keyword) { analyzed->if_node_count++; }
219
+ for (const pm_diagnostic_t* error = pm_parser_errors_first(analyzed->parser); error != NULL;
220
+ error = pm_diagnostic_next(error)) {
221
+ if (string_equals(pm_diagnostic_message(error), message)) { return true; }
239
222
  }
240
223
 
241
- pm_visit_child_nodes(node, search_if_nodes, analyzed);
242
-
243
224
  return false;
244
225
  }
245
226
 
246
- bool is_do_block(pm_location_t opening_location) {
247
- size_t length = opening_location.end - opening_location.start;
248
-
249
- return length == 2 && opening_location.start[0] == 'd' && opening_location.start[1] == 'o';
227
+ static bool location_matches(const uint8_t* source, pm_location_t location, const char* text, size_t length) {
228
+ return location.length == length && memcmp(source + location.start, text, length) == 0;
250
229
  }
251
230
 
252
- bool is_brace_block(pm_location_t opening_location) {
253
- size_t length = opening_location.end - opening_location.start;
254
-
255
- return length == 1 && opening_location.start[0] == '{';
231
+ bool is_do_block(const uint8_t* source, pm_location_t opening_location) {
232
+ return location_matches(source, opening_location, "do", 2);
256
233
  }
257
234
 
258
- static bool has_location(pm_location_t location) {
259
- return location.start != NULL && location.end != NULL && (location.end - location.start) > 0;
235
+ bool is_brace_block(const uint8_t* source, pm_location_t opening_location) {
236
+ return location_matches(source, opening_location, "{", 1);
260
237
  }
261
238
 
262
- static bool is_end_keyword(pm_location_t location) {
263
- if (location.start == NULL || location.end == NULL) { return false; }
264
-
265
- size_t length = location.end - location.start;
266
-
267
- return length == 3 && location.start[0] == 'e' && location.start[1] == 'n' && location.start[2] == 'd';
239
+ static bool is_end_keyword(const uint8_t* source, pm_location_t location) {
240
+ return location_matches(source, location, "end", 3);
268
241
  }
269
242
 
270
- bool is_closing_brace(pm_location_t location) {
271
- if (location.start == NULL || location.end == NULL) { return false; }
272
-
273
- size_t length = location.end - location.start;
274
-
275
- return length == 1 && location.start[0] == '}';
243
+ bool is_closing_brace(const uint8_t* source, pm_location_t location) {
244
+ return location_matches(source, location, "}", 1);
276
245
  }
277
246
 
278
- bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc) {
279
- if (is_do_block(opening_loc)) {
280
- return is_end_keyword(closing_loc);
281
- } else if (is_brace_block(opening_loc)) {
282
- return is_closing_brace(closing_loc);
247
+ bool has_valid_block_closing(const uint8_t* source, pm_location_t opening_loc, pm_location_t closing_loc) {
248
+ if (is_do_block(source, opening_loc)) {
249
+ return is_end_keyword(source, closing_loc);
250
+ } else if (is_brace_block(source, opening_loc)) {
251
+ return is_closing_brace(source, closing_loc);
283
252
  }
284
253
 
285
254
  return false;
286
255
  }
287
256
 
288
- bool search_block_nodes(const pm_node_t* node, void* data) {
289
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
290
-
291
- if (node->type == PM_BLOCK_NODE) {
292
- pm_block_node_t* block_node = (pm_block_node_t*) node;
293
-
294
- bool has_opening = is_do_block(block_node->opening_loc) || is_brace_block(block_node->opening_loc);
295
- bool is_unclosed = !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc);
296
-
297
- if (has_opening && is_unclosed) { analyzed->block_node_count++; }
298
- }
257
+ static bool is_unclosed_block(const uint8_t* source, pm_location_t opening_loc, pm_location_t closing_loc) {
258
+ bool has_opening = is_do_block(source, opening_loc) || is_brace_block(source, opening_loc);
299
259
 
300
- if (node->type == PM_LAMBDA_NODE) {
301
- pm_lambda_node_t* lambda_node = (pm_lambda_node_t*) node;
302
-
303
- bool has_opening = is_do_block(lambda_node->opening_loc) || is_brace_block(lambda_node->opening_loc);
304
- bool is_unclosed = !has_valid_block_closing(lambda_node->opening_loc, lambda_node->closing_loc);
305
-
306
- if (has_opening && is_unclosed) { analyzed->block_node_count++; }
307
- }
308
-
309
- pm_visit_child_nodes(node, search_block_nodes, analyzed);
310
-
311
- return false;
260
+ return has_opening && !has_valid_block_closing(source, opening_loc, closing_loc);
312
261
  }
313
262
 
314
- bool search_case_nodes(const pm_node_t* node, void* data) {
263
+ pm_visit_result_t search_control_flow_nodes(const pm_node_t* node, void* data) {
315
264
  analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
265
+ const uint8_t* source = pm_parser_start(analyzed->parser);
316
266
 
317
- if (node->type == PM_CASE_NODE) { analyzed->case_node_count++; }
318
-
319
- pm_visit_child_nodes(node, search_case_nodes, analyzed);
320
-
321
- return false;
322
- }
323
-
324
- bool search_case_match_nodes(const pm_node_t* node, void* data) {
325
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
326
-
327
- if (node->type == PM_CASE_MATCH_NODE) { analyzed->case_match_node_count++; }
328
-
329
- pm_visit_child_nodes(node, search_case_match_nodes, analyzed);
330
-
331
- return false;
332
- }
333
-
334
- bool search_while_nodes(const pm_node_t* node, void* data) {
335
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
336
-
337
- if (node->type == PM_WHILE_NODE) { analyzed->while_node_count++; }
338
-
339
- pm_visit_child_nodes(node, search_while_nodes, analyzed);
340
-
341
- return false;
342
- }
343
-
344
- bool search_for_nodes(const pm_node_t* node, void* data) {
345
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
346
-
347
- if (node->type == PM_FOR_NODE) { analyzed->for_node_count++; }
348
-
349
- pm_visit_child_nodes(node, search_for_nodes, analyzed);
350
-
351
- return false;
352
- }
353
-
354
- bool search_until_nodes(const pm_node_t* node, void* data) {
355
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
356
-
357
- if (node->type == PM_UNTIL_NODE) { analyzed->until_node_count++; }
358
-
359
- pm_visit_child_nodes(node, search_until_nodes, analyzed);
360
-
361
- return false;
362
- }
363
-
364
- bool search_begin_nodes(const pm_node_t* node, void* data) {
365
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
366
-
367
- if (node->type == PM_BEGIN_NODE) { analyzed->begin_node_count++; }
368
-
369
- pm_visit_child_nodes(node, search_begin_nodes, analyzed);
370
-
371
- return false;
372
- }
373
-
374
- bool search_unless_nodes(const pm_node_t* node, void* data) {
375
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
376
-
377
- if (node->type == PM_UNLESS_NODE) {
378
- const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
379
-
380
- bool has_if_keyword = unless_node->keyword_loc.start != NULL && unless_node->keyword_loc.end != NULL;
381
- bool has_end_keyword = unless_node->end_keyword_loc.start != NULL && unless_node->end_keyword_loc.end != NULL;
382
-
383
- if (has_if_keyword && has_end_keyword) { analyzed->unless_node_count++; }
384
- }
385
-
386
- pm_visit_child_nodes(node, search_unless_nodes, analyzed);
387
-
388
- return false;
389
- }
390
-
391
- bool search_when_nodes(const pm_node_t* node, void* data) {
392
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
393
-
394
- if (node->type == PM_WHEN_NODE) { analyzed->when_node_count++; }
395
-
396
- pm_visit_child_nodes(node, search_when_nodes, analyzed);
397
-
398
- return false;
399
- }
400
-
401
- bool search_in_nodes(const pm_node_t* node, void* data) {
402
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
267
+ switch (node->type) {
268
+ case PM_IF_NODE: {
269
+ const pm_if_node_t* if_node = (const pm_if_node_t*) node;
403
270
 
404
- if (node->type == PM_IN_NODE) { analyzed->in_node_count++; }
405
- if (node->type == PM_CASE_MATCH_NODE) {
406
- const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
271
+ if (herb_prism_location_assigned(if_node->if_keyword_loc)
272
+ && herb_prism_location_assigned(if_node->end_keyword_loc)) {
273
+ analyzed->if_node_count++;
274
+ }
407
275
 
408
- if (case_match_node->predicate != NULL && case_match_node->predicate->type == PM_MATCH_PREDICATE_NODE) {
409
- analyzed->in_node_count++;
276
+ if (herb_prism_location_assigned(if_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
277
+ break;
410
278
  }
411
- }
412
-
413
- pm_visit_child_nodes(node, search_in_nodes, analyzed);
414
-
415
- return false;
416
- }
417
-
418
- bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed) {
419
- if (has_error_message(analyzed, "unexpected 'elsif', ignoring it")) {
420
- analyzed->elsif_node_count++;
421
- return true;
422
- }
423
-
424
- return false;
425
- }
426
279
 
427
- bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed) {
428
- if (has_error_message(analyzed, "unexpected 'else', ignoring it")) {
429
- analyzed->else_node_count++;
430
- return true;
431
- }
280
+ case PM_UNLESS_NODE: {
281
+ const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
432
282
 
433
- return false;
434
- }
283
+ if (herb_prism_location_assigned(unless_node->unless_keyword_loc)
284
+ && herb_prism_location_assigned(unless_node->end_keyword_loc)) {
285
+ analyzed->unless_node_count++;
286
+ }
435
287
 
436
- bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed) {
437
- if (has_error_message(analyzed, "unexpected 'end', ignoring it")) {
438
- if (has_error_message(analyzed, "unexpected '=', ignoring it")) {
439
- // `=end`
440
- return false;
288
+ if (herb_prism_location_assigned(unless_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
289
+ break;
441
290
  }
442
291
 
443
- analyzed->end_count++;
444
- return true;
445
- }
446
-
447
- return false;
448
- }
449
-
450
- bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed) {
451
- if (has_error_message(analyzed, "unexpected '}', ignoring it")) {
452
- analyzed->block_closing_count++;
453
- return true;
454
- }
455
-
456
- return false;
457
- }
458
-
459
- bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed) {
460
- if (has_error_message(analyzed, "unexpected 'when', ignoring it")) {
461
- analyzed->when_node_count++;
462
- return true;
463
- }
464
-
465
- return false;
466
- }
467
-
468
- bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed) {
469
- if (has_error_message(analyzed, "unexpected 'in', ignoring it")) {
470
- analyzed->in_node_count++;
471
- return true;
472
- }
473
-
474
- return false;
475
- }
476
-
477
- bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed) {
478
- if (has_error_message(analyzed, "unexpected 'rescue', ignoring it")) {
479
- analyzed->rescue_node_count++;
480
- return true;
481
- }
482
-
483
- return false;
484
- }
485
-
486
- bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed) {
487
- if (has_error_message(analyzed, "unexpected 'ensure', ignoring it")) {
488
- analyzed->ensure_node_count++;
489
- return true;
490
- }
491
-
492
- return false;
493
- }
494
-
495
- bool search_yield_nodes(const pm_node_t* node, void* data) {
496
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
497
-
498
- if (node->type == PM_YIELD_NODE) { analyzed->yield_node_count++; }
292
+ case PM_WHEN_NODE: {
293
+ const pm_when_node_t* when_node = (const pm_when_node_t*) node;
499
294
 
500
- pm_visit_child_nodes(node, search_yield_nodes, analyzed);
295
+ analyzed->when_node_count++;
501
296
 
502
- return false;
503
- }
297
+ if (herb_prism_location_assigned(when_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
298
+ break;
299
+ }
504
300
 
505
- bool search_then_keywords(const pm_node_t* node, void* data) {
506
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
301
+ case PM_BLOCK_NODE: {
302
+ const pm_block_node_t* block_node = (const pm_block_node_t*) node;
507
303
 
508
- switch (node->type) {
509
- case PM_IF_NODE: {
510
- const pm_if_node_t* if_node = (const pm_if_node_t*) node;
511
- if (if_node->then_keyword_loc.start != NULL && if_node->then_keyword_loc.end != NULL) {
512
- analyzed->then_keyword_count++;
513
- }
304
+ if (is_unclosed_block(source, block_node->opening_loc, block_node->closing_loc)) { analyzed->block_node_count++; }
514
305
  break;
515
306
  }
516
307
 
517
- case PM_UNLESS_NODE: {
518
- const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
519
- if (unless_node->then_keyword_loc.start != NULL && unless_node->then_keyword_loc.end != NULL) {
520
- analyzed->then_keyword_count++;
308
+ case PM_LAMBDA_NODE: {
309
+ const pm_lambda_node_t* lambda_node = (const pm_lambda_node_t*) node;
310
+
311
+ if (is_unclosed_block(source, lambda_node->opening_loc, lambda_node->closing_loc)) {
312
+ analyzed->block_node_count++;
521
313
  }
522
314
  break;
523
315
  }
524
316
 
525
- case PM_WHEN_NODE: {
526
- const pm_when_node_t* when_node = (const pm_when_node_t*) node;
527
- if (when_node->then_keyword_loc.start != NULL && when_node->then_keyword_loc.end != NULL) {
528
- analyzed->then_keyword_count++;
317
+ case PM_CASE_MATCH_NODE: {
318
+ const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
319
+
320
+ analyzed->case_match_node_count++;
321
+
322
+ if (case_match_node->predicate != NULL && case_match_node->predicate->type == PM_MATCH_PREDICATE_NODE) {
323
+ analyzed->in_node_count++;
529
324
  }
530
325
  break;
531
326
  }
532
327
 
328
+ case PM_CASE_NODE: analyzed->case_node_count++; break;
329
+ case PM_IN_NODE: analyzed->in_node_count++; break;
330
+ case PM_WHILE_NODE: analyzed->while_node_count++; break;
331
+ case PM_FOR_NODE: analyzed->for_node_count++; break;
332
+ case PM_UNTIL_NODE: analyzed->until_node_count++; break;
333
+ case PM_BEGIN_NODE: analyzed->begin_node_count++; break;
334
+ case PM_YIELD_NODE: analyzed->yield_node_count++; break;
335
+
533
336
  default: break;
534
337
  }
535
338
 
536
- pm_visit_child_nodes(node, search_then_keywords, analyzed);
339
+ pm_visit_child_nodes(node, search_control_flow_nodes, analyzed);
340
+
341
+ return PM_VISIT_SKIP;
342
+ }
343
+
344
+ void search_unexpected_keyword_errors(analyzed_ruby_T* analyzed) {
345
+ bool unexpected_elsif = false;
346
+ bool unexpected_else = false;
347
+ bool unexpected_end = false;
348
+ bool unexpected_equals = false;
349
+ bool unexpected_closing_brace = false;
350
+ bool unexpected_when = false;
351
+ bool unexpected_in = false;
352
+ bool unexpected_rescue = false;
353
+ bool unexpected_ensure = false;
354
+
355
+ for (const pm_diagnostic_t* error = pm_parser_errors_first(analyzed->parser); error != NULL;
356
+ error = pm_diagnostic_next(error)) {
357
+ const char* message = pm_diagnostic_message(error);
358
+
359
+ if (string_equals(message, "unexpected 'elsif', ignoring it")) {
360
+ unexpected_elsif = true;
361
+ } else if (string_equals(message, "unexpected 'else', ignoring it")) {
362
+ unexpected_else = true;
363
+ } else if (string_equals(message, "unexpected 'end', ignoring it")) {
364
+ unexpected_end = true;
365
+ } else if (string_equals(message, "unexpected '=', ignoring it")) {
366
+ unexpected_equals = true;
367
+ } else if (string_equals(message, "unexpected '}', ignoring it")) {
368
+ unexpected_closing_brace = true;
369
+ } else if (string_equals(message, "unexpected 'when', ignoring it")) {
370
+ unexpected_when = true;
371
+ } else if (string_equals(message, "unexpected 'in', ignoring it")) {
372
+ unexpected_in = true;
373
+ } else if (string_equals(message, "unexpected 'rescue', ignoring it")) {
374
+ unexpected_rescue = true;
375
+ } else if (string_equals(message, "unexpected 'ensure', ignoring it")) {
376
+ unexpected_ensure = true;
377
+ }
378
+ }
537
379
 
538
- return false;
380
+ if (unexpected_elsif) { analyzed->elsif_node_count++; }
381
+ if (unexpected_else) { analyzed->else_node_count++; }
382
+ if (unexpected_end && !unexpected_equals) { analyzed->end_count++; }
383
+ if (unexpected_when) { analyzed->when_node_count++; }
384
+ if (unexpected_in) { analyzed->in_node_count++; }
385
+ if (unexpected_rescue) { analyzed->rescue_node_count++; }
386
+ if (unexpected_ensure) { analyzed->ensure_node_count++; }
387
+ if (unexpected_closing_brace) { analyzed->block_closing_count++; }
539
388
  }
540
389
 
541
390
  static bool is_postfix_conditional(const pm_statements_node_t* statements, pm_location_t keyword_location) {
@@ -544,16 +393,17 @@ static bool is_postfix_conditional(const pm_statements_node_t* statements, pm_lo
544
393
  return statements->base.location.start < keyword_location.start;
545
394
  }
546
395
 
547
- bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
396
+ pm_visit_result_t search_unclosed_control_flows(const pm_node_t* node, void* data) {
548
397
  analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
398
+ const uint8_t* source = pm_parser_start(analyzed->parser);
549
399
 
550
- if (analyzed->unclosed_control_flow_count >= 2) { return false; }
400
+ if (analyzed->unclosed_control_flow_count >= 2) { return PM_VISIT_SKIP; }
551
401
 
552
402
  switch (node->type) {
553
403
  case PM_IF_NODE: {
554
404
  const pm_if_node_t* if_node = (const pm_if_node_t*) node;
555
405
 
556
- if (has_location(if_node->if_keyword_loc) && !is_end_keyword(if_node->end_keyword_loc)) {
406
+ if (herb_prism_location_present(if_node->if_keyword_loc) && !is_end_keyword(source, if_node->end_keyword_loc)) {
557
407
  if (!is_postfix_conditional(if_node->statements, if_node->if_keyword_loc)) {
558
408
  analyzed->unclosed_control_flow_count++;
559
409
  }
@@ -565,8 +415,9 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
565
415
  case PM_UNLESS_NODE: {
566
416
  const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
567
417
 
568
- if (has_location(unless_node->keyword_loc) && !is_end_keyword(unless_node->end_keyword_loc)) {
569
- if (!is_postfix_conditional(unless_node->statements, unless_node->keyword_loc)) {
418
+ if (herb_prism_location_present(unless_node->unless_keyword_loc)
419
+ && !is_end_keyword(source, unless_node->end_keyword_loc)) {
420
+ if (!is_postfix_conditional(unless_node->statements, unless_node->unless_keyword_loc)) {
570
421
  analyzed->unclosed_control_flow_count++;
571
422
  }
572
423
  }
@@ -577,7 +428,8 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
577
428
  case PM_CASE_NODE: {
578
429
  const pm_case_node_t* case_node = (const pm_case_node_t*) node;
579
430
 
580
- if (has_location(case_node->case_keyword_loc) && !is_end_keyword(case_node->end_keyword_loc)) {
431
+ if (herb_prism_location_present(case_node->case_keyword_loc)
432
+ && !is_end_keyword(source, case_node->end_keyword_loc)) {
581
433
  analyzed->unclosed_control_flow_count++;
582
434
  }
583
435
 
@@ -587,7 +439,8 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
587
439
  case PM_CASE_MATCH_NODE: {
588
440
  const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
589
441
 
590
- if (has_location(case_match_node->case_keyword_loc) && !is_end_keyword(case_match_node->end_keyword_loc)) {
442
+ if (herb_prism_location_present(case_match_node->case_keyword_loc)
443
+ && !is_end_keyword(source, case_match_node->end_keyword_loc)) {
591
444
  analyzed->unclosed_control_flow_count++;
592
445
  }
593
446
 
@@ -597,7 +450,8 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
597
450
  case PM_WHILE_NODE: {
598
451
  const pm_while_node_t* while_node = (const pm_while_node_t*) node;
599
452
 
600
- if (has_location(while_node->keyword_loc) && !is_end_keyword(while_node->closing_loc)) {
453
+ if (herb_prism_location_present(while_node->while_keyword_loc)
454
+ && !is_end_keyword(source, while_node->end_keyword_loc)) {
601
455
  analyzed->unclosed_control_flow_count++;
602
456
  }
603
457
 
@@ -607,7 +461,8 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
607
461
  case PM_UNTIL_NODE: {
608
462
  const pm_until_node_t* until_node = (const pm_until_node_t*) node;
609
463
 
610
- if (has_location(until_node->keyword_loc) && !is_end_keyword(until_node->closing_loc)) {
464
+ if (herb_prism_location_present(until_node->until_keyword_loc)
465
+ && !is_end_keyword(source, until_node->end_keyword_loc)) {
611
466
  analyzed->unclosed_control_flow_count++;
612
467
  }
613
468
 
@@ -617,7 +472,8 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
617
472
  case PM_FOR_NODE: {
618
473
  const pm_for_node_t* for_node = (const pm_for_node_t*) node;
619
474
 
620
- if (has_location(for_node->for_keyword_loc) && !is_end_keyword(for_node->end_keyword_loc)) {
475
+ if (herb_prism_location_present(for_node->for_keyword_loc)
476
+ && !is_end_keyword(source, for_node->end_keyword_loc)) {
621
477
  analyzed->unclosed_control_flow_count++;
622
478
  }
623
479
 
@@ -627,7 +483,8 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
627
483
  case PM_BEGIN_NODE: {
628
484
  const pm_begin_node_t* begin_node = (const pm_begin_node_t*) node;
629
485
 
630
- if (has_location(begin_node->begin_keyword_loc) && !is_end_keyword(begin_node->end_keyword_loc)) {
486
+ if (herb_prism_location_present(begin_node->begin_keyword_loc)
487
+ && !is_end_keyword(source, begin_node->end_keyword_loc)) {
631
488
  analyzed->unclosed_control_flow_count++;
632
489
  }
633
490
 
@@ -636,9 +493,10 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
636
493
 
637
494
  case PM_BLOCK_NODE: {
638
495
  const pm_block_node_t* block_node = (const pm_block_node_t*) node;
639
- bool has_opening = is_do_block(block_node->opening_loc) || is_brace_block(block_node->opening_loc);
496
+ bool has_opening =
497
+ is_do_block(source, block_node->opening_loc) || is_brace_block(source, block_node->opening_loc);
640
498
 
641
- if (has_opening && !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc)) {
499
+ if (has_opening && !has_valid_block_closing(source, block_node->opening_loc, block_node->closing_loc)) {
642
500
  analyzed->unclosed_control_flow_count++;
643
501
  }
644
502
 
@@ -647,9 +505,10 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
647
505
 
648
506
  case PM_LAMBDA_NODE: {
649
507
  const pm_lambda_node_t* lambda_node = (const pm_lambda_node_t*) node;
650
- bool has_opening = is_do_block(lambda_node->opening_loc) || is_brace_block(lambda_node->opening_loc);
508
+ bool has_opening =
509
+ is_do_block(source, lambda_node->opening_loc) || is_brace_block(source, lambda_node->opening_loc);
651
510
 
652
- if (has_opening && !has_valid_block_closing(lambda_node->opening_loc, lambda_node->closing_loc)) {
511
+ if (has_opening && !has_valid_block_closing(source, lambda_node->opening_loc, lambda_node->closing_loc)) {
653
512
  analyzed->unclosed_control_flow_count++;
654
513
  }
655
514
 
@@ -661,7 +520,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
661
520
 
662
521
  pm_visit_child_nodes(node, search_unclosed_control_flows, analyzed);
663
522
 
664
- return false;
523
+ return PM_VISIT_SKIP;
665
524
  }
666
525
 
667
526
  static pm_block_node_t* find_first_block_node(pm_node_t* node) {
@@ -690,28 +549,21 @@ static pm_block_node_t* find_first_block_node(pm_node_t* node) {
690
549
  return NULL;
691
550
  }
692
551
 
693
- static position_T prism_to_source_position(
694
- const uint8_t* prism_pointer,
695
- const uint8_t* prism_source_start,
696
- size_t source_base_offset,
697
- const char* source
698
- ) {
699
- if (!source || !prism_source_start) { return (position_T) { .line = 1, .column = 0 }; }
552
+ static position_T prism_to_source_position(uint32_t prism_offset, size_t source_base_offset, const char* source) {
553
+ if (!source) { return (position_T) { .line = 1, .column = 0 }; }
700
554
 
701
- size_t prism_offset = (size_t) (prism_pointer - prism_source_start);
702
555
  return byte_offset_to_position(source, source_base_offset + prism_offset);
703
556
  }
704
557
 
705
558
  static token_T* create_parameter_name_token(
706
559
  pm_location_t location,
707
560
  const char* name,
708
- const uint8_t* prism_source_start,
709
561
  size_t source_base_offset,
710
562
  const char* source,
711
563
  hb_allocator_T* allocator
712
564
  ) {
713
- position_T start = prism_to_source_position(location.start, prism_source_start, source_base_offset, source);
714
- position_T end = prism_to_source_position(location.end, prism_source_start, source_base_offset, source);
565
+ position_T start = prism_to_source_position(location.start, source_base_offset, source);
566
+ position_T end = prism_to_source_position(herb_prism_location_end(location), source_base_offset, source);
715
567
 
716
568
  return create_synthetic_token(allocator, name, TOKEN_IDENTIFIER, start, end);
717
569
  }
@@ -777,20 +629,21 @@ static void append_multi_target_parameters(
777
629
 
778
630
  if (splat->expression && splat->expression->type == PM_REQUIRED_PARAMETER_NODE) {
779
631
  pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) splat->expression;
780
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
632
+ const pm_constant_t* constant = pm_parser_constant(parser, required->name);
781
633
 
782
634
  if (constant) {
783
- char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
635
+ char* name =
636
+ hb_allocator_strndup(allocator, (const char*) pm_constant_start(constant), pm_constant_length(constant));
784
637
  pm_node_t* node = splat->expression;
785
638
 
786
639
  append_parameter(
787
640
  result,
788
- create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
641
+ create_parameter_name_token(node->location, name, source_base_offset, source, allocator),
789
642
  NULL,
790
643
  "rest",
791
644
  false,
792
- prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source),
793
- prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source),
645
+ prism_to_source_position(node->location.start, source_base_offset, source),
646
+ prism_to_source_position(herb_prism_location_end(node->location), source_base_offset, source),
794
647
  allocator
795
648
  );
796
649
 
@@ -838,19 +691,19 @@ static void append_required_positional(
838
691
  if (node->type != PM_REQUIRED_PARAMETER_NODE) { return; }
839
692
 
840
693
  pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) node;
841
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
694
+ const pm_constant_t* constant = pm_parser_constant(parser, required->name);
842
695
  if (!constant) { return; }
843
696
 
844
- char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
697
+ char* name = hb_allocator_strndup(allocator, (const char*) pm_constant_start(constant), pm_constant_length(constant));
845
698
 
846
699
  append_parameter(
847
700
  result,
848
- create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
701
+ create_parameter_name_token(node->location, name, source_base_offset, source, allocator),
849
702
  NULL,
850
703
  "positional",
851
704
  true,
852
- prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source),
853
- prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source),
705
+ prism_to_source_position(node->location.start, source_base_offset, source),
706
+ prism_to_source_position(herb_prism_location_end(node->location), source_base_offset, source),
854
707
  allocator
855
708
  );
856
709
 
@@ -893,21 +746,25 @@ hb_array_T* extract_parameters_from_prism(
893
746
  if (node->type != PM_OPTIONAL_PARAMETER_NODE) { continue; }
894
747
 
895
748
  pm_optional_parameter_node_t* optional = (pm_optional_parameter_node_t*) node;
896
- size_t name_length = (size_t) (optional->name_loc.end - optional->name_loc.start);
897
- char* name = hb_allocator_strndup(allocator, (const char*) optional->name_loc.start, name_length);
749
+ size_t name_length = optional->name_loc.length;
750
+ char* name =
751
+ hb_allocator_strndup(allocator, (const char*) (prism_source_start + optional->name_loc.start), name_length);
898
752
 
899
- position_T start = prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source);
900
- position_T end = prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source);
753
+ position_T start = prism_to_source_position(node->location.start, source_base_offset, source);
754
+ position_T end = prism_to_source_position(herb_prism_location_end(node->location), source_base_offset, source);
901
755
 
902
756
  AST_RUBY_LITERAL_NODE_T* default_value = NULL;
903
757
 
904
758
  if (optional->value) {
905
- size_t value_length = (size_t) (optional->value->location.end - optional->value->location.start);
906
- char* value_string = hb_allocator_strndup(allocator, (const char*) optional->value->location.start, value_length);
907
- position_T value_start =
908
- prism_to_source_position(optional->value->location.start, prism_source_start, source_base_offset, source);
759
+ size_t value_length = optional->value->location.length;
760
+ char* value_string = hb_allocator_strndup(
761
+ allocator,
762
+ (const char*) (prism_source_start + optional->value->location.start),
763
+ value_length
764
+ );
765
+ position_T value_start = prism_to_source_position(optional->value->location.start, source_base_offset, source);
909
766
  position_T value_end =
910
- prism_to_source_position(optional->value->location.end, prism_source_start, source_base_offset, source);
767
+ prism_to_source_position(herb_prism_location_end(optional->value->location), source_base_offset, source);
911
768
 
912
769
  default_value = ast_ruby_literal_node_init(
913
770
  hb_string_from_c_string(value_string),
@@ -921,7 +778,7 @@ hb_array_T* extract_parameters_from_prism(
921
778
 
922
779
  append_parameter(
923
780
  result,
924
- create_parameter_name_token(optional->name_loc, name, prism_source_start, source_base_offset, source, allocator),
781
+ create_parameter_name_token(optional->name_loc, name, source_base_offset, source, allocator),
925
782
  default_value,
926
783
  "positional",
927
784
  false,
@@ -938,17 +795,17 @@ hb_array_T* extract_parameters_from_prism(
938
795
  pm_rest_parameter_node_t* rest = (pm_rest_parameter_node_t*) parameters->rest;
939
796
 
940
797
  if (rest->name) {
941
- size_t name_length = (size_t) (rest->name_loc.end - rest->name_loc.start);
942
- char* name = hb_allocator_strndup(allocator, (const char*) rest->name_loc.start, name_length);
798
+ size_t name_length = rest->name_loc.length;
799
+ char* name =
800
+ hb_allocator_strndup(allocator, (const char*) (prism_source_start + rest->name_loc.start), name_length);
943
801
 
944
- position_T start =
945
- prism_to_source_position(parameters->rest->location.start, prism_source_start, source_base_offset, source);
802
+ position_T start = prism_to_source_position(parameters->rest->location.start, source_base_offset, source);
946
803
  position_T end =
947
- prism_to_source_position(parameters->rest->location.end, prism_source_start, source_base_offset, source);
804
+ prism_to_source_position(herb_prism_location_end(parameters->rest->location), source_base_offset, source);
948
805
 
949
806
  append_parameter(
950
807
  result,
951
- create_parameter_name_token(rest->name_loc, name, prism_source_start, source_base_offset, source, allocator),
808
+ create_parameter_name_token(rest->name_loc, name, source_base_offset, source, allocator),
952
809
  NULL,
953
810
  "rest",
954
811
  false,
@@ -965,8 +822,8 @@ hb_array_T* extract_parameters_from_prism(
965
822
  NULL,
966
823
  "rest",
967
824
  false,
968
- prism_to_source_position(parameters->rest->location.start, prism_source_start, source_base_offset, source),
969
- prism_to_source_position(parameters->rest->location.end, prism_source_start, source_base_offset, source),
825
+ prism_to_source_position(parameters->rest->location.start, source_base_offset, source),
826
+ prism_to_source_position(herb_prism_location_end(parameters->rest->location), source_base_offset, source),
970
827
  allocator
971
828
  );
972
829
  }
@@ -1001,21 +858,18 @@ hb_array_T* extract_parameters_from_prism(
1001
858
  name_location = optional_keyword->name_loc;
1002
859
 
1003
860
  if (optional_keyword->value) {
1004
- size_t value_length =
1005
- (size_t) (optional_keyword->value->location.end - optional_keyword->value->location.start);
1006
- char* value_string =
1007
- hb_allocator_strndup(allocator, (const char*) optional_keyword->value->location.start, value_length);
1008
-
1009
- position_T value_start = prism_to_source_position(
1010
- optional_keyword->value->location.start,
1011
- prism_source_start,
1012
- source_base_offset,
1013
- source
861
+ size_t value_length = optional_keyword->value->location.length;
862
+ char* value_string = hb_allocator_strndup(
863
+ allocator,
864
+ (const char*) (prism_source_start + optional_keyword->value->location.start),
865
+ value_length
1014
866
  );
1015
867
 
868
+ position_T value_start =
869
+ prism_to_source_position(optional_keyword->value->location.start, source_base_offset, source);
870
+
1016
871
  position_T value_end = prism_to_source_position(
1017
- optional_keyword->value->location.end,
1018
- prism_source_start,
872
+ herb_prism_location_end(optional_keyword->value->location),
1019
873
  source_base_offset,
1020
874
  source
1021
875
  );
@@ -1034,17 +888,16 @@ hb_array_T* extract_parameters_from_prism(
1034
888
  continue;
1035
889
  }
1036
890
 
1037
- size_t name_length = (size_t) (name_location.end - name_location.start);
1038
- if (name_length > 0 && name_location.start[name_length - 1] == ':') { name_length--; }
1039
- char* name = hb_allocator_strndup(allocator, (const char*) name_location.start, name_length);
891
+ size_t name_length = name_location.length;
892
+ if (name_length > 0 && prism_source_start[name_location.start + name_length - 1] == ':') { name_length--; }
893
+ char* name = hb_allocator_strndup(allocator, (const char*) (prism_source_start + name_location.start), name_length);
1040
894
 
1041
- position_T start =
1042
- prism_to_source_position(keyword->location.start, prism_source_start, source_base_offset, source);
1043
- position_T end = prism_to_source_position(keyword->location.end, prism_source_start, source_base_offset, source);
895
+ position_T start = prism_to_source_position(keyword->location.start, source_base_offset, source);
896
+ position_T end = prism_to_source_position(herb_prism_location_end(keyword->location), source_base_offset, source);
1044
897
 
1045
898
  append_parameter(
1046
899
  result,
1047
- create_parameter_name_token(name_location, name, prism_source_start, source_base_offset, source, allocator),
900
+ create_parameter_name_token(name_location, name, source_base_offset, source, allocator),
1048
901
  default_value,
1049
902
  "keyword",
1050
903
  is_required,
@@ -1060,30 +913,19 @@ hb_array_T* extract_parameters_from_prism(
1060
913
  if (parameters->keyword_rest && parameters->keyword_rest->type == PM_KEYWORD_REST_PARAMETER_NODE) {
1061
914
  pm_keyword_rest_parameter_node_t* keyword_rest = (pm_keyword_rest_parameter_node_t*) parameters->keyword_rest;
1062
915
 
1063
- position_T start = prism_to_source_position(
1064
- parameters->keyword_rest->location.start,
1065
- prism_source_start,
1066
- source_base_offset,
1067
- source
1068
- );
916
+ position_T start = prism_to_source_position(parameters->keyword_rest->location.start, source_base_offset, source);
1069
917
 
1070
918
  position_T end =
1071
- prism_to_source_position(parameters->keyword_rest->location.end, prism_source_start, source_base_offset, source);
919
+ prism_to_source_position(herb_prism_location_end(parameters->keyword_rest->location), source_base_offset, source);
1072
920
 
1073
921
  if (keyword_rest->name) {
1074
- size_t name_length = (size_t) (keyword_rest->name_loc.end - keyword_rest->name_loc.start);
1075
- char* name = hb_allocator_strndup(allocator, (const char*) keyword_rest->name_loc.start, name_length);
922
+ size_t name_length = keyword_rest->name_loc.length;
923
+ char* name =
924
+ hb_allocator_strndup(allocator, (const char*) (prism_source_start + keyword_rest->name_loc.start), name_length);
1076
925
 
1077
926
  append_parameter(
1078
927
  result,
1079
- create_parameter_name_token(
1080
- keyword_rest->name_loc,
1081
- name,
1082
- prism_source_start,
1083
- source_base_offset,
1084
- source,
1085
- allocator
1086
- ),
928
+ create_parameter_name_token(keyword_rest->name_loc, name, source_base_offset, source, allocator),
1087
929
  NULL,
1088
930
  "keyword_rest",
1089
931
  false,
@@ -1100,28 +942,21 @@ hb_array_T* extract_parameters_from_prism(
1100
942
  }
1101
943
 
1102
944
  // Block: |&blk|
1103
- if (parameters->block) {
1104
- pm_block_parameter_node_t* block_param = parameters->block;
945
+ if (parameters->block && parameters->block->type == PM_BLOCK_PARAMETER_NODE) {
946
+ pm_block_parameter_node_t* block_param = (pm_block_parameter_node_t*) parameters->block;
1105
947
 
1106
948
  if (block_param->name) {
1107
- size_t name_length = (size_t) (block_param->name_loc.end - block_param->name_loc.start);
1108
- char* name = hb_allocator_strndup(allocator, (const char*) block_param->name_loc.start, name_length);
949
+ size_t name_length = block_param->name_loc.length;
950
+ char* name =
951
+ hb_allocator_strndup(allocator, (const char*) (prism_source_start + block_param->name_loc.start), name_length);
1109
952
 
1110
- position_T start =
1111
- prism_to_source_position(block_param->base.location.start, prism_source_start, source_base_offset, source);
953
+ position_T start = prism_to_source_position(block_param->base.location.start, source_base_offset, source);
1112
954
  position_T end =
1113
- prism_to_source_position(block_param->base.location.end, prism_source_start, source_base_offset, source);
955
+ prism_to_source_position(herb_prism_location_end(block_param->base.location), source_base_offset, source);
1114
956
 
1115
957
  append_parameter(
1116
958
  result,
1117
- create_parameter_name_token(
1118
- block_param->name_loc,
1119
- name,
1120
- prism_source_start,
1121
- source_base_offset,
1122
- source,
1123
- allocator
1124
- ),
959
+ create_parameter_name_token(block_param->name_loc, name, source_base_offset, source, allocator),
1125
960
  NULL,
1126
961
  "block",
1127
962
  false,
@@ -1138,8 +973,8 @@ hb_array_T* extract_parameters_from_prism(
1138
973
  NULL,
1139
974
  "block",
1140
975
  false,
1141
- prism_to_source_position(block_param->base.location.start, prism_source_start, source_base_offset, source),
1142
- prism_to_source_position(block_param->base.location.end, prism_source_start, source_base_offset, source),
976
+ prism_to_source_position(block_param->base.location.start, source_base_offset, source),
977
+ prism_to_source_position(herb_prism_location_end(block_param->base.location), source_base_offset, source),
1143
978
  allocator
1144
979
  );
1145
980
  }
@@ -1156,7 +991,7 @@ hb_array_T* extract_block_arguments_from_erb_node(
1156
991
  ) {
1157
992
  if (!erb_node || !erb_node->analyzed_ruby || !erb_node->analyzed_ruby->parsed) { return hb_array_init(0, allocator); }
1158
993
 
1159
- pm_parser_t* parser = &erb_node->analyzed_ruby->parser;
994
+ pm_parser_t* parser = erb_node->analyzed_ruby->parser;
1160
995
  pm_block_node_t* block_node = find_first_block_node(erb_node->analyzed_ruby->root);
1161
996
 
1162
997
  if (!block_node || !block_node->parameters) { return hb_array_init(0, allocator); }
@@ -1169,17 +1004,17 @@ hb_array_T* extract_block_arguments_from_erb_node(
1169
1004
  erb_content_offset = calculate_byte_offset_from_position(source, erb_node->content->location.start);
1170
1005
  }
1171
1006
 
1172
- const uint8_t* prism_source_start = (const uint8_t*) parser->start;
1007
+ const uint8_t* prism_source_start = pm_parser_start(parser);
1173
1008
 
1174
1009
  if (errors) {
1175
- for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser->error_list.head; error != NULL;
1176
- error = (const pm_diagnostic_t*) error->node.next) {
1010
+ for (const pm_diagnostic_t* error = pm_parser_errors_first(parser); error != NULL;
1011
+ error = pm_diagnostic_next(error)) {
1177
1012
  if (error->diag_id == PM_ERR_BLOCK_TERM_END) { continue; }
1178
1013
  if (error->diag_id == PM_ERR_BLOCK_TERM_BRACE) { continue; }
1179
1014
  if (error->diag_id == PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) { continue; }
1180
1015
 
1181
- size_t error_start_offset = (size_t) (error->location.start - prism_source_start);
1182
- size_t error_end_offset = (size_t) (error->location.end - prism_source_start);
1016
+ size_t error_start_offset = error->location.start;
1017
+ size_t error_end_offset = herb_prism_location_end(error->location);
1183
1018
 
1184
1019
  position_T error_start = byte_offset_to_position(source, erb_content_offset + error_start_offset);
1185
1020
  position_T error_end = byte_offset_to_position(source, erb_content_offset + error_end_offset);
@@ -1238,7 +1073,7 @@ static bool is_plain_decimal_integer(hb_string_T source) {
1238
1073
  return true;
1239
1074
  }
1240
1075
 
1241
- static bool prism_node_static_output(const pm_node_t* node, hb_string_T* output) {
1076
+ static bool prism_node_static_output(const uint8_t* source, const pm_node_t* node, hb_string_T* output) {
1242
1077
  if (!node || !output) { return false; }
1243
1078
 
1244
1079
  switch (node->type) {
@@ -1257,12 +1092,11 @@ static bool prism_node_static_output(const pm_node_t* node, hb_string_T* output)
1257
1092
  }
1258
1093
 
1259
1094
  case PM_INTEGER_NODE: {
1260
- hb_string_T source =
1261
- hb_string_from_data((const char*) node->location.start, (size_t) (node->location.end - node->location.start));
1095
+ hb_string_T integer = hb_string_from_data((const char*) (source + node->location.start), node->location.length);
1262
1096
 
1263
- if (!is_plain_decimal_integer(source)) { return false; }
1097
+ if (!is_plain_decimal_integer(integer)) { return false; }
1264
1098
 
1265
- *output = source;
1099
+ *output = integer;
1266
1100
  break;
1267
1101
  }
1268
1102
 
@@ -1311,17 +1145,18 @@ bool append_static_output_node(
1311
1145
  if (body->body.size != 1) { return false; }
1312
1146
 
1313
1147
  const pm_node_t* literal = body->body.nodes[0];
1314
- const uint8_t* parser_start = analyzed->parser.start;
1148
+ const uint8_t* parser_start = pm_parser_start(analyzed->parser);
1149
+ size_t source_length = (size_t) (pm_parser_end(analyzed->parser) - parser_start);
1315
1150
 
1316
- if (literal->location.start < parser_start || literal->location.end > analyzed->parser.end) { return false; }
1151
+ if (herb_prism_location_end(literal->location) > source_length) { return false; }
1317
1152
 
1318
1153
  hb_string_T content;
1319
1154
 
1320
- if (!prism_node_static_output(literal, &content)) { return false; }
1155
+ if (!prism_node_static_output(parser_start, literal, &content)) { return false; }
1321
1156
  if (content.length == 0) { return true; }
1322
1157
 
1323
- size_t offset = (size_t) (literal->location.start - parser_start);
1324
- size_t length = (size_t) (literal->location.end - literal->location.start);
1158
+ size_t offset = literal->location.start;
1159
+ size_t length = literal->location.length;
1325
1160
 
1326
1161
  position_T start_position = { .line = content_start.line, .column = content_start.column + (uint32_t) offset };
1327
1162
  position_T end_position = { .line = content_start.line,