herb 0.7.4-aarch64-linux-gnu → 0.8.0-aarch64-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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +8 -5
  3. data/config.yml +40 -20
  4. data/ext/herb/error_helpers.c +57 -3
  5. data/ext/herb/error_helpers.h +1 -1
  6. data/ext/herb/extconf.rb +1 -0
  7. data/ext/herb/extension.c +10 -24
  8. data/ext/herb/extension_helpers.c +12 -18
  9. data/ext/herb/extension_helpers.h +4 -4
  10. data/ext/herb/nodes.c +72 -37
  11. data/herb.gemspec +0 -2
  12. data/lib/herb/3.0/herb.so +0 -0
  13. data/lib/herb/3.1/herb.so +0 -0
  14. data/lib/herb/3.2/herb.so +0 -0
  15. data/lib/herb/3.3/herb.so +0 -0
  16. data/lib/herb/3.4/herb.so +0 -0
  17. data/lib/herb/ast/helpers.rb +11 -0
  18. data/lib/herb/ast/node.rb +15 -6
  19. data/lib/herb/ast/nodes.rb +609 -392
  20. data/lib/herb/cli.rb +31 -0
  21. data/lib/herb/colors.rb +82 -0
  22. data/lib/herb/engine/compiler.rb +140 -14
  23. data/lib/herb/engine/debug_visitor.rb +1 -5
  24. data/lib/herb/engine/parser_error_overlay.rb +1 -1
  25. data/lib/herb/engine.rb +18 -20
  26. data/lib/herb/errors.rb +166 -56
  27. data/lib/herb/location.rb +2 -2
  28. data/lib/herb/project.rb +86 -21
  29. data/lib/herb/token.rb +14 -2
  30. data/lib/herb/version.rb +1 -1
  31. data/lib/herb.rb +1 -0
  32. data/sig/herb/ast/helpers.rbs +3 -0
  33. data/sig/herb/ast/node.rbs +12 -5
  34. data/sig/herb/ast/nodes.rbs +124 -62
  35. data/sig/herb/colors.rbs +35 -0
  36. data/sig/herb/engine/compiler.rbs +23 -1
  37. data/sig/herb/errors.rbs +74 -20
  38. data/sig/herb/token.rbs +8 -0
  39. data/sig/herb_c_extension.rbs +1 -1
  40. data/sig/serialized_ast_errors.rbs +8 -0
  41. data/src/analyze.c +461 -249
  42. data/src/analyze_helpers.c +5 -0
  43. data/src/analyze_missing_end.c +147 -0
  44. data/src/analyze_transform.c +196 -0
  45. data/src/analyzed_ruby.c +23 -2
  46. data/src/ast_node.c +14 -17
  47. data/src/ast_nodes.c +179 -181
  48. data/src/ast_pretty_print.c +232 -232
  49. data/src/element_source.c +7 -6
  50. data/src/errors.c +272 -152
  51. data/src/extract.c +92 -34
  52. data/src/herb.c +37 -49
  53. data/src/html_util.c +34 -96
  54. data/src/include/analyze.h +10 -2
  55. data/src/include/analyze_helpers.h +3 -0
  56. data/src/include/analyzed_ruby.h +4 -2
  57. data/src/include/ast_node.h +4 -4
  58. data/src/include/ast_nodes.h +68 -67
  59. data/src/include/ast_pretty_print.h +2 -2
  60. data/src/include/element_source.h +3 -1
  61. data/src/include/errors.h +42 -26
  62. data/src/include/extract.h +4 -4
  63. data/src/include/herb.h +6 -7
  64. data/src/include/html_util.h +4 -5
  65. data/src/include/lexer.h +1 -3
  66. data/src/include/lexer_peek_helpers.h +21 -19
  67. data/src/include/lexer_struct.h +12 -10
  68. data/src/include/location.h +10 -13
  69. data/src/include/macros.h +4 -0
  70. data/src/include/parser.h +12 -6
  71. data/src/include/parser_helpers.h +26 -16
  72. data/src/include/position.h +3 -14
  73. data/src/include/pretty_print.h +38 -28
  74. data/src/include/prism_helpers.h +1 -1
  75. data/src/include/range.h +4 -13
  76. data/src/include/token.h +5 -11
  77. data/src/include/token_struct.h +2 -2
  78. data/src/include/utf8.h +3 -2
  79. data/src/include/util/hb_arena.h +31 -0
  80. data/src/include/util/hb_arena_debug.h +8 -0
  81. data/src/include/util/hb_array.h +33 -0
  82. data/src/include/util/hb_buffer.h +34 -0
  83. data/src/include/util/hb_string.h +29 -0
  84. data/src/include/util/hb_system.h +9 -0
  85. data/src/include/util.h +3 -14
  86. data/src/include/version.h +1 -1
  87. data/src/include/visitor.h +1 -1
  88. data/src/io.c +7 -4
  89. data/src/lexer.c +62 -88
  90. data/src/lexer_peek_helpers.c +42 -38
  91. data/src/location.c +9 -37
  92. data/src/main.c +19 -23
  93. data/src/parser.c +373 -313
  94. data/src/parser_helpers.c +60 -54
  95. data/src/parser_match_tags.c +316 -0
  96. data/src/pretty_print.c +88 -117
  97. data/src/prism_helpers.c +7 -7
  98. data/src/range.c +2 -35
  99. data/src/token.c +36 -87
  100. data/src/utf8.c +4 -4
  101. data/src/util/hb_arena.c +179 -0
  102. data/src/util/hb_arena_debug.c +237 -0
  103. data/src/{array.c → util/hb_array.c} +26 -27
  104. data/src/util/hb_buffer.c +203 -0
  105. data/src/util/hb_string.c +85 -0
  106. data/src/util/hb_system.c +30 -0
  107. data/src/util.c +29 -99
  108. data/src/visitor.c +54 -54
  109. data/templates/ext/herb/error_helpers.c.erb +3 -3
  110. data/templates/ext/herb/error_helpers.h.erb +1 -1
  111. data/templates/ext/herb/nodes.c.erb +11 -6
  112. data/templates/java/error_helpers.c.erb +75 -0
  113. data/templates/java/error_helpers.h.erb +20 -0
  114. data/templates/java/nodes.c.erb +97 -0
  115. data/templates/java/nodes.h.erb +23 -0
  116. data/templates/java/org/herb/ast/Errors.java.erb +121 -0
  117. data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
  118. data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
  119. data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
  120. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -1
  121. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
  122. data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
  123. data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
  124. data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
  125. data/templates/lib/herb/ast/nodes.rb.erb +28 -16
  126. data/templates/lib/herb/errors.rb.erb +17 -12
  127. data/templates/rust/src/ast/nodes.rs.erb +220 -0
  128. data/templates/rust/src/errors.rs.erb +216 -0
  129. data/templates/rust/src/nodes.rs.erb +374 -0
  130. data/templates/src/analyze_missing_end.c.erb +36 -0
  131. data/templates/src/analyze_transform.c.erb +24 -0
  132. data/templates/src/ast_nodes.c.erb +14 -16
  133. data/templates/src/ast_pretty_print.c.erb +36 -36
  134. data/templates/src/errors.c.erb +36 -38
  135. data/templates/src/include/ast_nodes.h.erb +11 -10
  136. data/templates/src/include/ast_pretty_print.h.erb +2 -2
  137. data/templates/src/include/errors.h.erb +9 -9
  138. data/templates/src/parser_match_tags.c.erb +38 -0
  139. data/templates/src/visitor.c.erb +4 -4
  140. data/templates/template.rb +22 -3
  141. data/templates/wasm/error_helpers.cpp.erb +9 -9
  142. data/templates/wasm/error_helpers.h.erb +1 -1
  143. data/templates/wasm/nodes.cpp.erb +9 -9
  144. data/templates/wasm/nodes.h.erb +1 -1
  145. data/vendor/prism/Rakefile +4 -1
  146. data/vendor/prism/config.yml +2 -1
  147. data/vendor/prism/include/prism/ast.h +31 -1
  148. data/vendor/prism/include/prism/diagnostic.h +1 -0
  149. data/vendor/prism/include/prism/version.h +3 -3
  150. data/vendor/prism/src/diagnostic.c +3 -1
  151. data/vendor/prism/src/prism.c +130 -71
  152. data/vendor/prism/src/util/pm_string.c +6 -8
  153. data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
  154. data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
  155. data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
  156. data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
  157. data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
  158. data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
  159. metadata +34 -21
  160. data/lib/herb/libherb/array.rb +0 -51
  161. data/lib/herb/libherb/ast_node.rb +0 -50
  162. data/lib/herb/libherb/buffer.rb +0 -56
  163. data/lib/herb/libherb/extract_result.rb +0 -20
  164. data/lib/herb/libherb/lex_result.rb +0 -32
  165. data/lib/herb/libherb/libherb.rb +0 -52
  166. data/lib/herb/libherb/parse_result.rb +0 -20
  167. data/lib/herb/libherb/token.rb +0 -46
  168. data/lib/herb/libherb.rb +0 -35
  169. data/src/buffer.c +0 -232
  170. data/src/include/array.h +0 -33
  171. data/src/include/buffer.h +0 -39
  172. data/src/include/json.h +0 -28
  173. data/src/include/memory.h +0 -12
  174. data/src/json.c +0 -205
  175. data/src/memory.c +0 -53
  176. data/src/position.c +0 -33
data/src/analyze.c CHANGED
@@ -1,16 +1,19 @@
1
1
  #include "include/analyze.h"
2
2
  #include "include/analyze_helpers.h"
3
3
  #include "include/analyzed_ruby.h"
4
- #include "include/array.h"
4
+ #include "include/ast_node.h"
5
5
  #include "include/ast_nodes.h"
6
6
  #include "include/errors.h"
7
7
  #include "include/extract.h"
8
8
  #include "include/location.h"
9
+ #include "include/parser.h"
9
10
  #include "include/position.h"
10
11
  #include "include/pretty_print.h"
11
12
  #include "include/prism_helpers.h"
12
13
  #include "include/token_struct.h"
13
14
  #include "include/util.h"
15
+ #include "include/util/hb_array.h"
16
+ #include "include/util/hb_string.h"
14
17
  #include "include/visitor.h"
15
18
 
16
19
  #include <prism.h>
@@ -19,7 +22,7 @@
19
22
  #include <stdlib.h>
20
23
  #include <string.h>
21
24
 
22
- static analyzed_ruby_T* herb_analyze_ruby(char* source) {
25
+ static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source) {
23
26
  analyzed_ruby_T* analyzed = init_analyzed_ruby(source);
24
27
 
25
28
  pm_visit_node(analyzed->root, search_if_nodes, analyzed);
@@ -52,9 +55,7 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
52
55
  const char* opening = erb_content_node->tag_opening->value;
53
56
 
54
57
  if (strcmp(opening, "<%%") != 0 && strcmp(opening, "<%%=") != 0 && strcmp(opening, "<%#") != 0) {
55
- analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value);
56
-
57
- if (false) { pretty_print_analyzed_ruby(analyzed, erb_content_node->content->value); }
58
+ analyzed_ruby_T* analyzed = herb_analyze_ruby(hb_string(erb_content_node->content->value));
58
59
 
59
60
  erb_content_node->parsed = true;
60
61
  erb_content_node->valid = analyzed->valid;
@@ -73,16 +74,16 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
73
74
 
74
75
  static size_t process_block_children(
75
76
  AST_NODE_T* node,
76
- array_T* array,
77
+ hb_array_T* array,
77
78
  size_t index,
78
- array_T* children_array,
79
+ hb_array_T* children_array,
79
80
  analyze_ruby_context_T* context,
80
81
  control_type_t parent_type
81
82
  );
82
83
 
83
84
  static size_t process_subsequent_block(
84
85
  AST_NODE_T* node,
85
- array_T* array,
86
+ hb_array_T* array,
86
87
  size_t index,
87
88
  AST_NODE_T** subsequent_out,
88
89
  analyze_ruby_context_T* context,
@@ -96,12 +97,8 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
96
97
 
97
98
  if (!ruby) { return CONTROL_TYPE_UNKNOWN; }
98
99
 
99
- if (ruby->valid) {
100
- if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
101
- return CONTROL_TYPE_UNKNOWN;
102
- }
100
+ if (ruby->valid) { return CONTROL_TYPE_UNKNOWN; }
103
101
 
104
- if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
105
102
  if (has_block_node(ruby)) { return CONTROL_TYPE_BLOCK; }
106
103
  if (has_if_node(ruby)) { return CONTROL_TYPE_IF; }
107
104
  if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
@@ -119,6 +116,7 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
119
116
  if (has_until_node(ruby)) { return CONTROL_TYPE_UNTIL; }
120
117
  if (has_for_node(ruby)) { return CONTROL_TYPE_FOR; }
121
118
  if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
119
+ if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
122
120
 
123
121
  return CONTROL_TYPE_UNKNOWN;
124
122
  }
@@ -152,22 +150,24 @@ static bool is_terminator_type(control_type_t parent_type, control_type_t child_
152
150
 
153
151
  static AST_NODE_T* create_control_node(
154
152
  AST_ERB_CONTENT_NODE_T* erb_node,
155
- array_T* children,
153
+ hb_array_T* children,
156
154
  AST_NODE_T* subsequent,
157
155
  AST_ERB_END_NODE_T* end_node,
158
156
  control_type_t control_type
159
157
  ) {
160
- array_T* errors = array_init(8);
161
- position_T* start_position = erb_node->tag_opening->location->start;
162
- position_T* end_position = erb_node->tag_closing->location->end;
158
+ hb_array_T* errors = erb_node->base.errors;
159
+ erb_node->base.errors = NULL;
160
+
161
+ position_T start_position = erb_node->tag_opening->location.start;
162
+ position_T end_position = erb_node->tag_closing->location.end;
163
163
 
164
164
  if (end_node) {
165
- end_position = end_node->base.location->end;
166
- } else if (children && array_size(children) > 0) {
167
- AST_NODE_T* last_child = array_get(children, array_size(children) - 1);
168
- end_position = last_child->location->end;
165
+ end_position = end_node->base.location.end;
166
+ } else if (children && hb_array_size(children) > 0) {
167
+ AST_NODE_T* last_child = hb_array_get(children, hb_array_size(children) - 1);
168
+ end_position = last_child->location.end;
169
169
  } else if (subsequent) {
170
- end_position = subsequent->location->end;
170
+ end_position = subsequent->location.end;
171
171
  }
172
172
 
173
173
  token_T* tag_opening = erb_node->tag_opening;
@@ -176,7 +176,7 @@ static AST_NODE_T* create_control_node(
176
176
 
177
177
  switch (control_type) {
178
178
  case CONTROL_TYPE_IF:
179
- case CONTROL_TYPE_ELSIF:
179
+ case CONTROL_TYPE_ELSIF: {
180
180
  return (AST_NODE_T*) ast_erb_if_node_init(
181
181
  tag_opening,
182
182
  content,
@@ -188,32 +188,40 @@ static AST_NODE_T* create_control_node(
188
188
  end_position,
189
189
  errors
190
190
  );
191
+ }
191
192
 
192
- case CONTROL_TYPE_ELSE:
193
- return (AST_NODE_T*)
194
- ast_erb_else_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
193
+ case CONTROL_TYPE_ELSE: {
194
+ return (
195
+ AST_NODE_T*
196
+ ) ast_erb_else_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
197
+ }
195
198
 
196
199
  case CONTROL_TYPE_CASE:
197
200
  case CONTROL_TYPE_CASE_MATCH: {
198
201
  AST_ERB_ELSE_NODE_T* else_node = NULL;
199
202
  if (subsequent && subsequent->type == AST_ERB_ELSE_NODE) { else_node = (AST_ERB_ELSE_NODE_T*) subsequent; }
200
203
 
201
- array_T* when_conditions = array_init(8);
202
- array_T* in_conditions = array_init(8);
203
- array_T* non_when_non_in_children = array_init(8);
204
+ hb_array_T* when_conditions = hb_array_init(8);
205
+ hb_array_T* in_conditions = hb_array_init(8);
206
+ hb_array_T* non_when_non_in_children = hb_array_init(8);
207
+
208
+ for (size_t i = 0; i < hb_array_size(children); i++) {
209
+ AST_NODE_T* child = hb_array_get(children, i);
204
210
 
205
- for (size_t i = 0; i < array_size(children); i++) {
206
- AST_NODE_T* child = array_get(children, i);
207
211
  if (child && child->type == AST_ERB_WHEN_NODE) {
208
- array_append(when_conditions, child);
212
+ hb_array_append(when_conditions, child);
209
213
  } else if (child && child->type == AST_ERB_IN_NODE) {
210
- array_append(in_conditions, child);
214
+ hb_array_append(in_conditions, child);
211
215
  } else {
212
- array_append(non_when_non_in_children, child);
216
+ hb_array_append(non_when_non_in_children, child);
213
217
  }
214
218
  }
215
219
 
216
- if (array_size(in_conditions) > 0) {
220
+ hb_array_free(&children);
221
+
222
+ if (hb_array_size(in_conditions) > 0) {
223
+ hb_array_free(&when_conditions);
224
+
217
225
  return (AST_NODE_T*) ast_erb_case_match_node_init(
218
226
  tag_opening,
219
227
  content,
@@ -226,30 +234,34 @@ static AST_NODE_T* create_control_node(
226
234
  end_position,
227
235
  errors
228
236
  );
229
- }
237
+ } else {
238
+ hb_array_free(&in_conditions);
230
239
 
231
- return (AST_NODE_T*) ast_erb_case_node_init(
232
- tag_opening,
233
- content,
234
- tag_closing,
235
- non_when_non_in_children,
236
- when_conditions,
237
- else_node,
238
- end_node,
239
- start_position,
240
- end_position,
241
- errors
242
- );
240
+ return (AST_NODE_T*) ast_erb_case_node_init(
241
+ tag_opening,
242
+ content,
243
+ tag_closing,
244
+ non_when_non_in_children,
245
+ when_conditions,
246
+ else_node,
247
+ end_node,
248
+ start_position,
249
+ end_position,
250
+ errors
251
+ );
252
+ }
243
253
  }
244
254
 
245
255
  case CONTROL_TYPE_WHEN: {
246
- return (AST_NODE_T*)
247
- ast_erb_when_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
256
+ return (
257
+ AST_NODE_T*
258
+ ) ast_erb_when_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
248
259
  }
249
260
 
250
261
  case CONTROL_TYPE_IN: {
251
- return (AST_NODE_T*)
252
- ast_erb_in_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
262
+ return (
263
+ AST_NODE_T*
264
+ ) ast_erb_in_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
253
265
  }
254
266
 
255
267
  case CONTROL_TYPE_BEGIN: {
@@ -300,8 +312,9 @@ static AST_NODE_T* create_control_node(
300
312
  }
301
313
 
302
314
  case CONTROL_TYPE_ENSURE: {
303
- return (AST_NODE_T*)
304
- ast_erb_ensure_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
315
+ return (
316
+ AST_NODE_T*
317
+ ) ast_erb_ensure_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
305
318
  }
306
319
 
307
320
  case CONTROL_TYPE_UNLESS: {
@@ -375,34 +388,35 @@ static AST_NODE_T* create_control_node(
375
388
  }
376
389
 
377
390
  case CONTROL_TYPE_YIELD: {
378
- return (AST_NODE_T*)
379
- ast_erb_yield_node_init(tag_opening, content, tag_closing, start_position, end_position, errors);
391
+ return (
392
+ AST_NODE_T*
393
+ ) ast_erb_yield_node_init(tag_opening, content, tag_closing, start_position, end_position, errors);
380
394
  }
381
395
 
382
- default: array_free(&errors); return NULL;
396
+ default: return NULL;
383
397
  }
384
398
  }
385
399
 
386
400
  static size_t process_control_structure(
387
401
  AST_NODE_T* node,
388
- array_T* array,
402
+ hb_array_T* array,
389
403
  size_t index,
390
- array_T* output_array,
404
+ hb_array_T* output_array,
391
405
  analyze_ruby_context_T* context,
392
406
  control_type_t initial_type
393
407
  ) {
394
- AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
395
- array_T* children = array_init(8);
408
+ AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) hb_array_get(array, index);
409
+ hb_array_T* children = hb_array_init(8);
396
410
 
397
411
  index++;
398
412
 
399
413
  if (initial_type == CONTROL_TYPE_CASE || initial_type == CONTROL_TYPE_CASE_MATCH) {
400
- array_T* when_conditions = array_init(8);
401
- array_T* in_conditions = array_init(8);
402
- array_T* non_when_non_in_children = array_init(8);
414
+ hb_array_T* when_conditions = hb_array_init(8);
415
+ hb_array_T* in_conditions = hb_array_init(8);
416
+ hb_array_T* non_when_non_in_children = hb_array_init(8);
403
417
 
404
- while (index < array_size(array)) {
405
- AST_NODE_T* next_node = array_get(array, index);
418
+ while (index < hb_array_size(array)) {
419
+ AST_NODE_T* next_node = hb_array_get(array, index);
406
420
 
407
421
  if (!next_node) { break; }
408
422
 
@@ -413,17 +427,17 @@ static size_t process_control_structure(
413
427
  if (next_type == CONTROL_TYPE_WHEN || next_type == CONTROL_TYPE_IN) { break; }
414
428
  }
415
429
 
416
- array_append(non_when_non_in_children, next_node);
430
+ hb_array_append(non_when_non_in_children, next_node);
417
431
  index++;
418
432
  }
419
433
 
420
- while (index < array_size(array)) {
421
- AST_NODE_T* next_node = array_get(array, index);
434
+ while (index < hb_array_size(array)) {
435
+ AST_NODE_T* next_node = hb_array_get(array, index);
422
436
 
423
437
  if (!next_node) { break; }
424
438
 
425
439
  if (next_node->type != AST_ERB_CONTENT_NODE) {
426
- array_append(non_when_non_in_children, next_node);
440
+ hb_array_append(non_when_non_in_children, next_node);
427
441
  index++;
428
442
  continue;
429
443
  }
@@ -432,101 +446,77 @@ static size_t process_control_structure(
432
446
  control_type_t next_type = detect_control_type(erb_content);
433
447
 
434
448
  if (next_type == CONTROL_TYPE_WHEN) {
435
- array_T* when_statements = array_init(8);
449
+ hb_array_T* when_statements = hb_array_init(8);
436
450
  index++;
437
451
 
438
- while (index < array_size(array)) {
439
- AST_NODE_T* child = array_get(array, index);
440
-
441
- if (!child) { break; }
452
+ index = process_block_children(node, array, index, when_statements, context, CONTROL_TYPE_WHEN);
442
453
 
443
- if (child->type == AST_ERB_CONTENT_NODE) {
444
- AST_ERB_CONTENT_NODE_T* child_erb = (AST_ERB_CONTENT_NODE_T*) child;
445
- control_type_t child_type = detect_control_type(child_erb);
446
-
447
- if (child_type == CONTROL_TYPE_WHEN || child_type == CONTROL_TYPE_IN || child_type == CONTROL_TYPE_ELSE
448
- || child_type == CONTROL_TYPE_END) {
449
- break;
450
- }
451
- }
452
-
453
- array_append(when_statements, child);
454
- index++;
455
- }
454
+ hb_array_T* when_errors = erb_content->base.errors;
455
+ erb_content->base.errors = NULL;
456
456
 
457
457
  AST_ERB_WHEN_NODE_T* when_node = ast_erb_when_node_init(
458
458
  erb_content->tag_opening,
459
459
  erb_content->content,
460
460
  erb_content->tag_closing,
461
461
  when_statements,
462
- erb_content->tag_opening->location->start,
463
- erb_content->tag_closing->location->end,
464
- array_init(8)
462
+ erb_content->tag_opening->location.start,
463
+ erb_content->tag_closing->location.end,
464
+ when_errors
465
465
  );
466
466
 
467
- array_append(when_conditions, (AST_NODE_T*) when_node);
467
+ ast_node_free((AST_NODE_T*) erb_content);
468
+
469
+ hb_array_append(when_conditions, (AST_NODE_T*) when_node);
468
470
 
469
471
  continue;
470
472
  } else if (next_type == CONTROL_TYPE_IN) {
471
- array_T* in_statements = array_init(8);
473
+ hb_array_T* in_statements = hb_array_init(8);
472
474
  index++;
473
475
 
474
- while (index < array_size(array)) {
475
- AST_NODE_T* child = array_get(array, index);
476
-
477
- if (!child) { break; }
478
-
479
- if (child->type == AST_ERB_CONTENT_NODE) {
480
- AST_ERB_CONTENT_NODE_T* child_erb = (AST_ERB_CONTENT_NODE_T*) child;
481
- control_type_t child_type = detect_control_type(child_erb);
476
+ index = process_block_children(node, array, index, in_statements, context, CONTROL_TYPE_IN);
482
477
 
483
- if (child_type == CONTROL_TYPE_IN || child_type == CONTROL_TYPE_WHEN || child_type == CONTROL_TYPE_ELSE
484
- || child_type == CONTROL_TYPE_END) {
485
- break;
486
- }
487
- }
488
-
489
- array_append(in_statements, child);
490
- index++;
491
- }
478
+ hb_array_T* in_errors = erb_content->base.errors;
479
+ erb_content->base.errors = NULL;
492
480
 
493
481
  AST_ERB_IN_NODE_T* in_node = ast_erb_in_node_init(
494
482
  erb_content->tag_opening,
495
483
  erb_content->content,
496
484
  erb_content->tag_closing,
497
485
  in_statements,
498
- erb_content->tag_opening->location->start,
499
- erb_content->tag_closing->location->end,
500
- array_init(8)
486
+ erb_content->tag_opening->location.start,
487
+ erb_content->tag_closing->location.end,
488
+ in_errors
501
489
  );
502
490
 
503
- array_append(in_conditions, (AST_NODE_T*) in_node);
491
+ ast_node_free((AST_NODE_T*) erb_content);
492
+
493
+ hb_array_append(in_conditions, (AST_NODE_T*) in_node);
504
494
 
505
495
  continue;
506
496
  } else if (next_type == CONTROL_TYPE_ELSE || next_type == CONTROL_TYPE_END) {
507
497
  break;
508
498
  } else {
509
- array_append(non_when_non_in_children, next_node);
499
+ hb_array_append(non_when_non_in_children, next_node);
510
500
  index++;
511
501
  }
512
502
  }
513
503
 
514
504
  AST_ERB_ELSE_NODE_T* else_clause = NULL;
515
505
 
516
- if (index < array_size(array)) {
517
- AST_NODE_T* next_node = array_get(array, index);
506
+ if (index < hb_array_size(array)) {
507
+ AST_NODE_T* next_node = hb_array_get(array, index);
518
508
 
519
509
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
520
510
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
521
511
  control_type_t next_type = detect_control_type(next_erb);
522
512
 
523
513
  if (next_type == CONTROL_TYPE_ELSE) {
524
- array_T* else_children = array_init(8);
514
+ hb_array_T* else_children = hb_array_init(8);
525
515
 
526
516
  index++;
527
517
 
528
- while (index < array_size(array)) {
529
- AST_NODE_T* child = array_get(array, index);
518
+ while (index < hb_array_size(array)) {
519
+ AST_NODE_T* child = hb_array_get(array, index);
530
520
 
531
521
  if (!child) { break; }
532
522
 
@@ -537,62 +527,75 @@ static size_t process_control_structure(
537
527
  if (child_type == CONTROL_TYPE_END) { break; }
538
528
  }
539
529
 
540
- array_append(else_children, child);
530
+ hb_array_append(else_children, child);
541
531
  index++;
542
532
  }
543
533
 
534
+ hb_array_T* else_errors = next_erb->base.errors;
535
+ next_erb->base.errors = NULL;
536
+
544
537
  else_clause = ast_erb_else_node_init(
545
538
  next_erb->tag_opening,
546
539
  next_erb->content,
547
540
  next_erb->tag_closing,
548
541
  else_children,
549
- next_erb->tag_opening->location->start,
550
- next_erb->tag_closing->location->end,
551
- array_init(8)
542
+ next_erb->tag_opening->location.start,
543
+ next_erb->tag_closing->location.end,
544
+ else_errors
552
545
  );
546
+
547
+ ast_node_free((AST_NODE_T*) next_erb);
553
548
  }
554
549
  }
555
550
  }
556
551
 
557
552
  AST_ERB_END_NODE_T* end_node = NULL;
558
553
 
559
- if (index < array_size(array)) {
560
- AST_NODE_T* potential_end = array_get(array, index);
554
+ if (index < hb_array_size(array)) {
555
+ AST_NODE_T* potential_end = hb_array_get(array, index);
561
556
 
562
557
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
563
558
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
564
559
 
565
560
  if (detect_control_type(end_erb) == CONTROL_TYPE_END) {
561
+ hb_array_T* end_errors = end_erb->base.errors;
562
+ end_erb->base.errors = NULL;
563
+
566
564
  end_node = ast_erb_end_node_init(
567
565
  end_erb->tag_opening,
568
566
  end_erb->content,
569
567
  end_erb->tag_closing,
570
- end_erb->tag_opening->location->start,
571
- end_erb->tag_closing->location->end,
572
- end_erb->base.errors
568
+ end_erb->tag_opening->location.start,
569
+ end_erb->tag_closing->location.end,
570
+ end_errors
573
571
  );
574
572
 
573
+ ast_node_free((AST_NODE_T*) end_erb);
574
+
575
575
  index++;
576
576
  }
577
577
  }
578
578
  }
579
579
 
580
- position_T* start_position = erb_node->tag_opening->location->start;
581
- position_T* end_position = erb_node->tag_closing->location->end;
580
+ position_T start_position = erb_node->tag_opening->location.start;
581
+ position_T end_position = erb_node->tag_closing->location.end;
582
582
 
583
583
  if (end_node) {
584
- end_position = end_node->base.location->end;
584
+ end_position = end_node->base.location.end;
585
585
  } else if (else_clause) {
586
- end_position = else_clause->base.location->end;
587
- } else if (array_size(when_conditions) > 0) {
588
- AST_NODE_T* last_when = array_get(when_conditions, array_size(when_conditions) - 1);
589
- end_position = last_when->location->end;
590
- } else if (array_size(in_conditions) > 0) {
591
- AST_NODE_T* last_in = array_get(in_conditions, array_size(in_conditions) - 1);
592
- end_position = last_in->location->end;
586
+ end_position = else_clause->base.location.end;
587
+ } else if (hb_array_size(when_conditions) > 0) {
588
+ AST_NODE_T* last_when = hb_array_get(when_conditions, hb_array_size(when_conditions) - 1);
589
+ end_position = last_when->location.end;
590
+ } else if (hb_array_size(in_conditions) > 0) {
591
+ AST_NODE_T* last_in = hb_array_get(in_conditions, hb_array_size(in_conditions) - 1);
592
+ end_position = last_in->location.end;
593
593
  }
594
594
 
595
- if (array_size(in_conditions) > 0) {
595
+ if (hb_array_size(in_conditions) > 0) {
596
+ hb_array_T* case_match_errors = erb_node->base.errors;
597
+ erb_node->base.errors = NULL;
598
+
596
599
  AST_ERB_CASE_MATCH_NODE_T* case_match_node = ast_erb_case_match_node_init(
597
600
  erb_node->tag_opening,
598
601
  erb_node->content,
@@ -603,13 +606,21 @@ static size_t process_control_structure(
603
606
  end_node,
604
607
  start_position,
605
608
  end_position,
606
- array_init(8)
609
+ case_match_errors
607
610
  );
608
611
 
609
- array_append(output_array, (AST_NODE_T*) case_match_node);
612
+ ast_node_free((AST_NODE_T*) erb_node);
613
+
614
+ hb_array_append(output_array, (AST_NODE_T*) case_match_node);
615
+ hb_array_free(&when_conditions);
616
+ hb_array_free(&children);
617
+
610
618
  return index;
611
619
  }
612
620
 
621
+ hb_array_T* case_errors = erb_node->base.errors;
622
+ erb_node->base.errors = NULL;
623
+
613
624
  AST_ERB_CASE_NODE_T* case_node = ast_erb_case_node_init(
614
625
  erb_node->tag_opening,
615
626
  erb_node->content,
@@ -620,10 +631,15 @@ static size_t process_control_structure(
620
631
  end_node,
621
632
  start_position,
622
633
  end_position,
623
- array_init(8)
634
+ case_errors
624
635
  );
625
636
 
626
- array_append(output_array, (AST_NODE_T*) case_node);
637
+ ast_node_free((AST_NODE_T*) erb_node);
638
+
639
+ hb_array_append(output_array, (AST_NODE_T*) case_node);
640
+ hb_array_free(&in_conditions);
641
+ hb_array_free(&children);
642
+
627
643
  return index;
628
644
  }
629
645
 
@@ -634,8 +650,8 @@ static size_t process_control_structure(
634
650
  AST_ERB_ELSE_NODE_T* else_clause = NULL;
635
651
  AST_ERB_ENSURE_NODE_T* ensure_clause = NULL;
636
652
 
637
- if (index < array_size(array)) {
638
- AST_NODE_T* next_node = array_get(array, index);
653
+ if (index < hb_array_size(array)) {
654
+ AST_NODE_T* next_node = hb_array_get(array, index);
639
655
 
640
656
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
641
657
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -649,20 +665,20 @@ static size_t process_control_structure(
649
665
  }
650
666
  }
651
667
 
652
- if (index < array_size(array)) {
653
- AST_NODE_T* next_node = array_get(array, index);
668
+ if (index < hb_array_size(array)) {
669
+ AST_NODE_T* next_node = hb_array_get(array, index);
654
670
 
655
671
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
656
672
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
657
673
  control_type_t next_type = detect_control_type(next_erb);
658
674
 
659
675
  if (next_type == CONTROL_TYPE_ELSE) {
660
- array_T* else_children = array_init(8);
676
+ hb_array_T* else_children = hb_array_init(8);
661
677
 
662
678
  index++;
663
679
 
664
- while (index < array_size(array)) {
665
- AST_NODE_T* child = array_get(array, index);
680
+ while (index < hb_array_size(array)) {
681
+ AST_NODE_T* child = hb_array_get(array, index);
666
682
 
667
683
  if (!child) { break; }
668
684
 
@@ -673,37 +689,42 @@ static size_t process_control_structure(
673
689
  if (child_type == CONTROL_TYPE_ENSURE || child_type == CONTROL_TYPE_END) { break; }
674
690
  }
675
691
 
676
- array_append(else_children, child);
692
+ hb_array_append(else_children, child);
677
693
  index++;
678
694
  }
679
695
 
696
+ hb_array_T* else_errors = next_erb->base.errors;
697
+ next_erb->base.errors = NULL;
698
+
680
699
  else_clause = ast_erb_else_node_init(
681
700
  next_erb->tag_opening,
682
701
  next_erb->content,
683
702
  next_erb->tag_closing,
684
703
  else_children,
685
- next_erb->tag_opening->location->start,
686
- next_erb->tag_closing->location->end,
687
- array_init(8)
704
+ next_erb->tag_opening->location.start,
705
+ next_erb->tag_closing->location.end,
706
+ else_errors
688
707
  );
708
+
709
+ ast_node_free((AST_NODE_T*) next_erb);
689
710
  }
690
711
  }
691
712
  }
692
713
 
693
- if (index < array_size(array)) {
694
- AST_NODE_T* next_node = array_get(array, index);
714
+ if (index < hb_array_size(array)) {
715
+ AST_NODE_T* next_node = hb_array_get(array, index);
695
716
 
696
717
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
697
718
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
698
719
  control_type_t next_type = detect_control_type(next_erb);
699
720
 
700
721
  if (next_type == CONTROL_TYPE_ENSURE) {
701
- array_T* ensure_children = array_init(8);
722
+ hb_array_T* ensure_children = hb_array_init(8);
702
723
 
703
724
  index++;
704
725
 
705
- while (index < array_size(array)) {
706
- AST_NODE_T* child = array_get(array, index);
726
+ while (index < hb_array_size(array)) {
727
+ AST_NODE_T* child = hb_array_get(array, index);
707
728
 
708
729
  if (!child) { break; }
709
730
 
@@ -714,59 +735,72 @@ static size_t process_control_structure(
714
735
  if (child_type == CONTROL_TYPE_END) { break; }
715
736
  }
716
737
 
717
- array_append(ensure_children, child);
738
+ hb_array_append(ensure_children, child);
718
739
  index++;
719
740
  }
720
741
 
742
+ hb_array_T* ensure_errors = next_erb->base.errors;
743
+ next_erb->base.errors = NULL;
744
+
721
745
  ensure_clause = ast_erb_ensure_node_init(
722
746
  next_erb->tag_opening,
723
747
  next_erb->content,
724
748
  next_erb->tag_closing,
725
749
  ensure_children,
726
- next_erb->tag_opening->location->start,
727
- next_erb->tag_closing->location->end,
728
- array_init(8)
750
+ next_erb->tag_opening->location.start,
751
+ next_erb->tag_closing->location.end,
752
+ ensure_errors
729
753
  );
754
+
755
+ ast_node_free((AST_NODE_T*) next_erb);
730
756
  }
731
757
  }
732
758
  }
733
759
 
734
760
  AST_ERB_END_NODE_T* end_node = NULL;
735
761
 
736
- if (index < array_size(array)) {
737
- AST_NODE_T* potential_end = array_get(array, index);
762
+ if (index < hb_array_size(array)) {
763
+ AST_NODE_T* potential_end = hb_array_get(array, index);
738
764
 
739
765
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
740
766
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
741
767
 
742
768
  if (detect_control_type(end_erb) == CONTROL_TYPE_END) {
769
+ hb_array_T* end_errors = end_erb->base.errors;
770
+ end_erb->base.errors = NULL;
771
+
743
772
  end_node = ast_erb_end_node_init(
744
773
  end_erb->tag_opening,
745
774
  end_erb->content,
746
775
  end_erb->tag_closing,
747
- end_erb->tag_opening->location->start,
748
- end_erb->tag_closing->location->end,
749
- end_erb->base.errors
776
+ end_erb->tag_opening->location.start,
777
+ end_erb->tag_closing->location.end,
778
+ end_errors
750
779
  );
751
780
 
781
+ ast_node_free((AST_NODE_T*) end_erb);
782
+
752
783
  index++;
753
784
  }
754
785
  }
755
786
  }
756
787
 
757
- position_T* start_position = erb_node->tag_opening->location->start;
758
- position_T* end_position = erb_node->tag_closing->location->end;
788
+ position_T start_position = erb_node->tag_opening->location.start;
789
+ position_T end_position = erb_node->tag_closing->location.end;
759
790
 
760
791
  if (end_node) {
761
- end_position = end_node->base.location->end;
792
+ end_position = end_node->base.location.end;
762
793
  } else if (ensure_clause) {
763
- end_position = ensure_clause->base.location->end;
794
+ end_position = ensure_clause->base.location.end;
764
795
  } else if (else_clause) {
765
- end_position = else_clause->base.location->end;
796
+ end_position = else_clause->base.location.end;
766
797
  } else if (rescue_clause) {
767
- end_position = rescue_clause->base.location->end;
798
+ end_position = rescue_clause->base.location.end;
768
799
  }
769
800
 
801
+ hb_array_T* begin_errors = erb_node->base.errors;
802
+ erb_node->base.errors = NULL;
803
+
770
804
  AST_ERB_BEGIN_NODE_T* begin_node = ast_erb_begin_node_init(
771
805
  erb_node->tag_opening,
772
806
  erb_node->content,
@@ -778,10 +812,12 @@ static size_t process_control_structure(
778
812
  end_node,
779
813
  start_position,
780
814
  end_position,
781
- array_init(8)
815
+ begin_errors
782
816
  );
783
817
 
784
- array_append(output_array, (AST_NODE_T*) begin_node);
818
+ ast_node_free((AST_NODE_T*) erb_node);
819
+
820
+ hb_array_append(output_array, (AST_NODE_T*) begin_node);
785
821
  return index;
786
822
  }
787
823
 
@@ -790,38 +826,46 @@ static size_t process_control_structure(
790
826
 
791
827
  AST_ERB_END_NODE_T* end_node = NULL;
792
828
 
793
- if (index < array_size(array)) {
794
- AST_NODE_T* potential_close = array_get(array, index);
829
+ if (index < hb_array_size(array)) {
830
+ AST_NODE_T* potential_close = hb_array_get(array, index);
795
831
 
796
832
  if (potential_close && potential_close->type == AST_ERB_CONTENT_NODE) {
797
833
  AST_ERB_CONTENT_NODE_T* close_erb = (AST_ERB_CONTENT_NODE_T*) potential_close;
798
834
  control_type_t close_type = detect_control_type(close_erb);
799
835
 
800
836
  if (close_type == CONTROL_TYPE_BLOCK_CLOSE || close_type == CONTROL_TYPE_END) {
837
+ hb_array_T* end_errors = close_erb->base.errors;
838
+ close_erb->base.errors = NULL;
839
+
801
840
  end_node = ast_erb_end_node_init(
802
841
  close_erb->tag_opening,
803
842
  close_erb->content,
804
843
  close_erb->tag_closing,
805
- close_erb->tag_opening->location->start,
806
- close_erb->tag_closing->location->end,
807
- close_erb->base.errors
844
+ close_erb->tag_opening->location.start,
845
+ close_erb->tag_closing->location.end,
846
+ end_errors
808
847
  );
809
848
 
849
+ ast_node_free((AST_NODE_T*) close_erb);
850
+
810
851
  index++;
811
852
  }
812
853
  }
813
854
  }
814
855
 
815
- position_T* start_position = erb_node->tag_opening->location->start;
816
- position_T* end_position = erb_node->tag_closing->location->end;
856
+ position_T start_position = erb_node->tag_opening->location.start;
857
+ position_T end_position = erb_node->tag_closing->location.end;
817
858
 
818
859
  if (end_node) {
819
- end_position = end_node->base.location->end;
820
- } else if (children && array_size(children) > 0) {
821
- AST_NODE_T* last_child = array_get(children, array_size(children) - 1);
822
- end_position = last_child->location->end;
860
+ end_position = end_node->base.location.end;
861
+ } else if (children && hb_array_size(children) > 0) {
862
+ AST_NODE_T* last_child = hb_array_get(children, hb_array_size(children) - 1);
863
+ end_position = last_child->location.end;
823
864
  }
824
865
 
866
+ hb_array_T* block_errors = erb_node->base.errors;
867
+ erb_node->base.errors = NULL;
868
+
825
869
  AST_ERB_BLOCK_NODE_T* block_node = ast_erb_block_node_init(
826
870
  erb_node->tag_opening,
827
871
  erb_node->content,
@@ -830,10 +874,12 @@ static size_t process_control_structure(
830
874
  end_node,
831
875
  start_position,
832
876
  end_position,
833
- array_init(8)
877
+ block_errors
834
878
  );
835
879
 
836
- array_append(output_array, (AST_NODE_T*) block_node);
880
+ ast_node_free((AST_NODE_T*) erb_node);
881
+
882
+ hb_array_append(output_array, (AST_NODE_T*) block_node);
837
883
  return index;
838
884
  }
839
885
 
@@ -842,8 +888,8 @@ static size_t process_control_structure(
842
888
  AST_NODE_T* subsequent = NULL;
843
889
  AST_ERB_END_NODE_T* end_node = NULL;
844
890
 
845
- if (index < array_size(array)) {
846
- AST_NODE_T* next_node = array_get(array, index);
891
+ if (index < hb_array_size(array)) {
892
+ AST_NODE_T* next_node = hb_array_get(array, index);
847
893
 
848
894
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
849
895
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -855,22 +901,27 @@ static size_t process_control_structure(
855
901
  }
856
902
  }
857
903
 
858
- if (index < array_size(array)) {
859
- AST_NODE_T* potential_end = array_get(array, index);
904
+ if (index < hb_array_size(array)) {
905
+ AST_NODE_T* potential_end = hb_array_get(array, index);
860
906
 
861
907
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
862
908
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
863
909
 
864
910
  if (detect_control_type(end_erb) == CONTROL_TYPE_END) {
911
+ hb_array_T* end_errors = end_erb->base.errors;
912
+ end_erb->base.errors = NULL;
913
+
865
914
  end_node = ast_erb_end_node_init(
866
915
  end_erb->tag_opening,
867
916
  end_erb->content,
868
917
  end_erb->tag_closing,
869
- end_erb->tag_opening->location->start,
870
- end_erb->tag_closing->location->end,
871
- end_erb->base.errors
918
+ end_erb->tag_opening->location.start,
919
+ end_erb->tag_closing->location.end,
920
+ end_errors
872
921
  );
873
922
 
923
+ ast_node_free((AST_NODE_T*) end_erb);
924
+
874
925
  index++;
875
926
  }
876
927
  }
@@ -878,22 +929,27 @@ static size_t process_control_structure(
878
929
 
879
930
  AST_NODE_T* control_node = create_control_node(erb_node, children, subsequent, end_node, initial_type);
880
931
 
881
- if (control_node) { array_append(output_array, control_node); }
932
+ if (control_node) {
933
+ ast_node_free((AST_NODE_T*) erb_node);
934
+ hb_array_append(output_array, control_node);
935
+ } else {
936
+ hb_array_free(&children);
937
+ }
882
938
 
883
939
  return index;
884
940
  }
885
941
 
886
942
  static size_t process_subsequent_block(
887
943
  AST_NODE_T* node,
888
- array_T* array,
944
+ hb_array_T* array,
889
945
  size_t index,
890
946
  AST_NODE_T** subsequent_out,
891
947
  analyze_ruby_context_T* context,
892
948
  control_type_t parent_type
893
949
  ) {
894
- AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
950
+ AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) hb_array_get(array, index);
895
951
  control_type_t type = detect_control_type(erb_node);
896
- array_T* children = array_init(8);
952
+ hb_array_T* children = hb_array_init(8);
897
953
 
898
954
  index++;
899
955
 
@@ -901,8 +957,14 @@ static size_t process_subsequent_block(
901
957
 
902
958
  AST_NODE_T* subsequent_node = create_control_node(erb_node, children, NULL, NULL, type);
903
959
 
904
- if (index < array_size(array)) {
905
- AST_NODE_T* next_node = array_get(array, index);
960
+ if (subsequent_node) {
961
+ ast_node_free((AST_NODE_T*) erb_node);
962
+ } else {
963
+ hb_array_free(&children);
964
+ }
965
+
966
+ if (index < hb_array_size(array)) {
967
+ AST_NODE_T* next_node = hb_array_get(array, index);
906
968
 
907
969
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
908
970
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -953,19 +1015,19 @@ static size_t process_subsequent_block(
953
1015
 
954
1016
  static size_t process_block_children(
955
1017
  AST_NODE_T* node,
956
- array_T* array,
1018
+ hb_array_T* array,
957
1019
  size_t index,
958
- array_T* children_array,
1020
+ hb_array_T* children_array,
959
1021
  analyze_ruby_context_T* context,
960
1022
  control_type_t parent_type
961
1023
  ) {
962
- while (index < array_size(array)) {
963
- AST_NODE_T* child = array_get(array, index);
1024
+ while (index < hb_array_size(array)) {
1025
+ AST_NODE_T* child = hb_array_get(array, index);
964
1026
 
965
1027
  if (!child) { break; }
966
1028
 
967
1029
  if (child->type != AST_ERB_CONTENT_NODE) {
968
- array_append(children_array, child);
1030
+ hb_array_append(children_array, child);
969
1031
  index++;
970
1032
  continue;
971
1033
  }
@@ -978,35 +1040,35 @@ static size_t process_block_children(
978
1040
  if (child_type == CONTROL_TYPE_IF || child_type == CONTROL_TYPE_CASE || child_type == CONTROL_TYPE_CASE_MATCH
979
1041
  || child_type == CONTROL_TYPE_BEGIN || child_type == CONTROL_TYPE_UNLESS || child_type == CONTROL_TYPE_WHILE
980
1042
  || child_type == CONTROL_TYPE_UNTIL || child_type == CONTROL_TYPE_FOR || child_type == CONTROL_TYPE_BLOCK) {
981
- array_T* temp_array = array_init(1);
1043
+ hb_array_T* temp_array = hb_array_init(1);
982
1044
  size_t new_index = process_control_structure(node, array, index, temp_array, context, child_type);
983
1045
 
984
- if (array_size(temp_array) > 0) { array_append(children_array, array_get(temp_array, 0)); }
1046
+ if (hb_array_size(temp_array) > 0) { hb_array_append(children_array, hb_array_get(temp_array, 0)); }
985
1047
 
986
- array_free(&temp_array);
1048
+ hb_array_free(&temp_array);
987
1049
 
988
1050
  index = new_index;
989
1051
  continue;
990
1052
  }
991
1053
 
992
- array_append(children_array, child);
1054
+ hb_array_append(children_array, child);
993
1055
  index++;
994
1056
  }
995
1057
 
996
1058
  return index;
997
1059
  }
998
1060
 
999
- static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_ruby_context_T* context) {
1000
- array_T* new_array = array_init(array_size(array));
1061
+ hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby_context_T* context) {
1062
+ hb_array_T* new_array = hb_array_init(hb_array_size(array));
1001
1063
  size_t index = 0;
1002
1064
 
1003
- while (index < array_size(array)) {
1004
- AST_NODE_T* item = array_get(array, index);
1065
+ while (index < hb_array_size(array)) {
1066
+ AST_NODE_T* item = hb_array_get(array, index);
1005
1067
 
1006
1068
  if (!item) { break; }
1007
1069
 
1008
1070
  if (item->type != AST_ERB_CONTENT_NODE) {
1009
- array_append(new_array, item);
1071
+ hb_array_append(new_array, item);
1010
1072
  index++;
1011
1073
  continue;
1012
1074
  }
@@ -1028,12 +1090,13 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1028
1090
  continue;
1029
1091
 
1030
1092
  case CONTROL_TYPE_YIELD: {
1031
- AST_NODE_T* yield_node = create_control_node(erb_node, array_init(8), NULL, NULL, type);
1093
+ AST_NODE_T* yield_node = create_control_node(erb_node, NULL, NULL, NULL, type);
1032
1094
 
1033
1095
  if (yield_node) {
1034
- array_append(new_array, yield_node);
1096
+ ast_node_free((AST_NODE_T*) erb_node);
1097
+ hb_array_append(new_array, yield_node);
1035
1098
  } else {
1036
- array_append(new_array, item);
1099
+ hb_array_append(new_array, item);
1037
1100
  }
1038
1101
 
1039
1102
  index++;
@@ -1041,7 +1104,7 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1041
1104
  }
1042
1105
 
1043
1106
  default:
1044
- array_append(new_array, item);
1107
+ hb_array_append(new_array, item);
1045
1108
  index++;
1046
1109
  break;
1047
1110
  }
@@ -1050,41 +1113,178 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1050
1113
  return new_array;
1051
1114
  }
1052
1115
 
1053
- static bool transform_erb_nodes(const AST_NODE_T* node, void* data) {
1054
- analyze_ruby_context_T* context = (analyze_ruby_context_T*) data;
1055
- context->parent = (AST_NODE_T*) node;
1116
+ static bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data) {
1117
+ invalid_erb_context_T* context = (invalid_erb_context_T*) data;
1118
+
1119
+ if (node->type == AST_HTML_ATTRIBUTE_NAME_NODE) { return false; }
1120
+
1121
+ bool is_loop_node =
1122
+ (node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE || node->type == AST_ERB_FOR_NODE
1123
+ || node->type == AST_ERB_BLOCK_NODE);
1124
+
1125
+ bool is_begin_node = (node->type == AST_ERB_BEGIN_NODE);
1126
+
1127
+ if (is_loop_node) { context->loop_depth++; }
1128
+
1129
+ if (is_begin_node) { context->rescue_depth++; }
1130
+
1131
+ if (node->type == AST_ERB_CONTENT_NODE) {
1132
+ const AST_ERB_CONTENT_NODE_T* content_node = (const AST_ERB_CONTENT_NODE_T*) node;
1133
+
1134
+ if (content_node->parsed && !content_node->valid && content_node->analyzed_ruby != NULL) {
1135
+ analyzed_ruby_T* analyzed = content_node->analyzed_ruby;
1136
+
1137
+ // =begin
1138
+ if (has_error_message(analyzed, "embedded document meets end of file")) {
1139
+ if (is_loop_node) { context->loop_depth--; }
1140
+ if (is_begin_node) { context->rescue_depth--; }
1141
+
1142
+ return true;
1143
+ }
1144
+
1145
+ // =end
1146
+ if (has_error_message(analyzed, "unexpected '=', ignoring it")
1147
+ && has_error_message(analyzed, "unexpected 'end', ignoring it")) {
1148
+ if (is_loop_node) { context->loop_depth--; }
1149
+ if (is_begin_node) { context->rescue_depth--; }
1150
+
1151
+ return true;
1152
+ }
1153
+
1154
+ const char* keyword = NULL;
1155
+
1156
+ if (context->loop_depth == 0) {
1157
+ if (has_error_message(analyzed, "Invalid break")) {
1158
+ keyword = "`<% break %>`";
1159
+ } else if (has_error_message(analyzed, "Invalid next")) {
1160
+ keyword = "`<% next %>`";
1161
+ } else if (has_error_message(analyzed, "Invalid redo")) {
1162
+ keyword = "`<% redo %>`";
1163
+ }
1164
+ } else {
1165
+ if (has_error_message(analyzed, "Invalid redo") || has_error_message(analyzed, "Invalid break")
1166
+ || has_error_message(analyzed, "Invalid next")) {
1167
+
1168
+ if (is_loop_node) { context->loop_depth--; }
1169
+ if (is_begin_node) { context->rescue_depth--; }
1170
+
1171
+ return true;
1172
+ }
1173
+ }
1174
+
1175
+ if (context->rescue_depth == 0) {
1176
+ if (has_error_message(analyzed, "Invalid retry without rescue")) { keyword = "`<% retry %>`"; }
1177
+ } else {
1178
+ if (has_error_message(analyzed, "Invalid retry without rescue")) {
1179
+ if (is_loop_node) { context->loop_depth--; }
1180
+ if (is_begin_node) { context->rescue_depth--; }
1181
+
1182
+ return true;
1183
+ }
1184
+ }
1185
+
1186
+ if (keyword == NULL) { keyword = erb_keyword_from_analyzed_ruby(analyzed); }
1187
+
1188
+ if (keyword != NULL && !token_value_empty(content_node->tag_closing)) {
1189
+ append_erb_control_flow_scope_error(keyword, node->location.start, node->location.end, node->errors);
1190
+ }
1191
+ }
1192
+ }
1193
+
1194
+ if (node->type == AST_ERB_IF_NODE) {
1195
+ const AST_ERB_IF_NODE_T* if_node = (const AST_ERB_IF_NODE_T*) node;
1196
+
1197
+ if (if_node->end_node == NULL) { check_erb_node_for_missing_end(node); }
1056
1198
 
1057
- if (node->type == AST_DOCUMENT_NODE) {
1058
- AST_DOCUMENT_NODE_T* document_node = (AST_DOCUMENT_NODE_T*) node;
1059
- array_T* old_array = document_node->children;
1060
- document_node->children = rewrite_node_array((AST_NODE_T*) node, document_node->children, context);
1061
- array_free(&old_array);
1199
+ if (if_node->statements != NULL) {
1200
+ for (size_t i = 0; i < hb_array_size(if_node->statements); i++) {
1201
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(if_node->statements, i);
1202
+
1203
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
1204
+ }
1205
+ }
1206
+
1207
+ AST_NODE_T* subsequent = if_node->subsequent;
1208
+
1209
+ while (subsequent != NULL) {
1210
+ if (subsequent->type == AST_ERB_CONTENT_NODE) {
1211
+ const AST_ERB_CONTENT_NODE_T* content_node = (const AST_ERB_CONTENT_NODE_T*) subsequent;
1212
+
1213
+ if (content_node->parsed && !content_node->valid && content_node->analyzed_ruby != NULL) {
1214
+ analyzed_ruby_T* analyzed = content_node->analyzed_ruby;
1215
+ const char* keyword = erb_keyword_from_analyzed_ruby(analyzed);
1216
+
1217
+ if (!token_value_empty(content_node->tag_closing)) {
1218
+ append_erb_control_flow_scope_error(
1219
+ keyword,
1220
+ subsequent->location.start,
1221
+ subsequent->location.end,
1222
+ subsequent->errors
1223
+ );
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ if (subsequent->type == AST_ERB_IF_NODE) {
1229
+ const AST_ERB_IF_NODE_T* elsif_node = (const AST_ERB_IF_NODE_T*) subsequent;
1230
+
1231
+ if (elsif_node->statements != NULL) {
1232
+ for (size_t i = 0; i < hb_array_size(elsif_node->statements); i++) {
1233
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(elsif_node->statements, i);
1234
+
1235
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
1236
+ }
1237
+ }
1238
+
1239
+ subsequent = elsif_node->subsequent;
1240
+ } else if (subsequent->type == AST_ERB_ELSE_NODE) {
1241
+ const AST_ERB_ELSE_NODE_T* else_node = (const AST_ERB_ELSE_NODE_T*) subsequent;
1242
+
1243
+ if (else_node->statements != NULL) {
1244
+ for (size_t i = 0; i < hb_array_size(else_node->statements); i++) {
1245
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(else_node->statements, i);
1246
+
1247
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
1248
+ }
1249
+ }
1250
+
1251
+ break;
1252
+ } else {
1253
+ break;
1254
+ }
1255
+ }
1062
1256
  }
1063
1257
 
1064
- if (node->type == AST_HTML_ELEMENT_NODE) {
1065
- AST_HTML_ELEMENT_NODE_T* element_node = (AST_HTML_ELEMENT_NODE_T*) node;
1066
- array_T* old_array = element_node->body;
1067
- element_node->body = rewrite_node_array((AST_NODE_T*) node, element_node->body, context);
1068
- array_free(&old_array);
1258
+ if (node->type == AST_ERB_UNLESS_NODE || node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE
1259
+ || node->type == AST_ERB_FOR_NODE || node->type == AST_ERB_CASE_NODE || node->type == AST_ERB_CASE_MATCH_NODE
1260
+ || node->type == AST_ERB_BEGIN_NODE || node->type == AST_ERB_BLOCK_NODE || node->type == AST_ERB_ELSE_NODE) {
1261
+ herb_visit_child_nodes(node, detect_invalid_erb_structures, context);
1069
1262
  }
1070
1263
 
1071
- if (node->type == AST_HTML_OPEN_TAG_NODE) {
1072
- AST_HTML_OPEN_TAG_NODE_T* open_tag = (AST_HTML_OPEN_TAG_NODE_T*) node;
1073
- array_T* old_array = open_tag->children;
1074
- open_tag->children = rewrite_node_array((AST_NODE_T*) node, open_tag->children, context);
1075
- array_free(&old_array);
1264
+ if (node->type == AST_ERB_UNLESS_NODE || node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE
1265
+ || node->type == AST_ERB_FOR_NODE || node->type == AST_ERB_CASE_NODE || node->type == AST_ERB_CASE_MATCH_NODE
1266
+ || node->type == AST_ERB_BEGIN_NODE || node->type == AST_ERB_BLOCK_NODE || node->type == AST_ERB_ELSE_NODE) {
1267
+ check_erb_node_for_missing_end(node);
1268
+
1269
+ if (is_loop_node) { context->loop_depth--; }
1270
+ if (is_begin_node) { context->rescue_depth--; }
1271
+
1272
+ return false;
1076
1273
  }
1077
1274
 
1078
- if (node->type == AST_HTML_ATTRIBUTE_VALUE_NODE) {
1079
- AST_HTML_ATTRIBUTE_VALUE_NODE_T* value_node = (AST_HTML_ATTRIBUTE_VALUE_NODE_T*) node;
1080
- array_T* old_array = value_node->children;
1081
- value_node->children = rewrite_node_array((AST_NODE_T*) node, value_node->children, context);
1082
- array_free(&old_array);
1275
+ if (node->type == AST_ERB_IF_NODE) {
1276
+ if (is_loop_node) { context->loop_depth--; }
1277
+ if (is_begin_node) { context->rescue_depth--; }
1278
+
1279
+ return false;
1083
1280
  }
1084
1281
 
1085
- herb_visit_child_nodes(node, transform_erb_nodes, data);
1282
+ bool result = true;
1086
1283
 
1087
- return false;
1284
+ if (is_loop_node) { context->loop_depth--; }
1285
+ if (is_begin_node) { context->rescue_depth--; }
1286
+
1287
+ return result;
1088
1288
  }
1089
1289
 
1090
1290
  void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source) {
@@ -1093,19 +1293,31 @@ void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source)
1093
1293
  analyze_ruby_context_T* context = malloc(sizeof(analyze_ruby_context_T));
1094
1294
  context->document = document;
1095
1295
  context->parent = NULL;
1096
- context->ruby_context_stack = array_init(8);
1296
+ context->ruby_context_stack = hb_array_init(8);
1097
1297
 
1098
1298
  herb_visit_node((AST_NODE_T*) document, transform_erb_nodes, context);
1099
1299
 
1300
+ invalid_erb_context_T* invalid_context = malloc(sizeof(invalid_erb_context_T));
1301
+ invalid_context->loop_depth = 0;
1302
+ invalid_context->rescue_depth = 0;
1303
+
1304
+ herb_visit_node((AST_NODE_T*) document, detect_invalid_erb_structures, invalid_context);
1305
+
1100
1306
  herb_analyze_parse_errors(document, source);
1101
1307
 
1102
- array_free(&context->ruby_context_stack);
1308
+ herb_parser_match_html_tags_post_analyze(document);
1309
+
1310
+ hb_array_free(&context->ruby_context_stack);
1311
+
1103
1312
  free(context);
1313
+ free(invalid_context);
1104
1314
  }
1105
1315
 
1106
1316
  void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source) {
1107
1317
  char* extracted_ruby = herb_extract_ruby_with_semicolons(source);
1108
1318
 
1319
+ if (!extracted_ruby) { return; }
1320
+
1109
1321
  pm_parser_t parser;
1110
1322
  pm_options_t options = { 0, .partial_script = true };
1111
1323
  pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
@@ -1116,7 +1328,7 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source
1116
1328
  error = (const pm_diagnostic_t*) error->node.next) {
1117
1329
 
1118
1330
  RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser);
1119
- array_append(document->base.errors, parse_error);
1331
+ hb_array_append(document->base.errors, parse_error);
1120
1332
  }
1121
1333
 
1122
1334
  pm_node_destroy(&parser, root);