herb 0.7.5-x86_64-darwin → 0.8.1-x86_64-darwin

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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +8 -5
  3. data/config.yml +26 -6
  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 +3 -3
  9. data/ext/herb/extension_helpers.h +1 -1
  10. data/ext/herb/nodes.c +72 -37
  11. data/herb.gemspec +0 -2
  12. data/lib/herb/3.0/herb.bundle +0 -0
  13. data/lib/herb/3.1/herb.bundle +0 -0
  14. data/lib/herb/3.2/herb.bundle +0 -0
  15. data/lib/herb/3.3/herb.bundle +0 -0
  16. data/lib/herb/3.4/herb.bundle +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 +8 -14
  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 +549 -204
  42. data/src/analyze_helpers.c +17 -4
  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 +5 -5
  47. data/src/ast_nodes.c +179 -179
  48. data/src/ast_pretty_print.c +232 -232
  49. data/src/element_source.c +7 -6
  50. data/src/errors.c +246 -126
  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 +2 -2
  58. data/src/include/ast_nodes.h +67 -66
  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 +30 -14
  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 +14 -14
  67. data/src/include/lexer_struct.h +3 -2
  68. data/src/include/macros.h +4 -0
  69. data/src/include/parser.h +12 -6
  70. data/src/include/parser_helpers.h +25 -15
  71. data/src/include/pretty_print.h +38 -28
  72. data/src/include/token.h +5 -8
  73. data/src/include/utf8.h +3 -2
  74. data/src/include/util/hb_arena.h +31 -0
  75. data/src/include/util/hb_arena_debug.h +8 -0
  76. data/src/include/util/hb_array.h +33 -0
  77. data/src/include/util/hb_buffer.h +33 -0
  78. data/src/include/util/hb_string.h +29 -0
  79. data/src/include/util/hb_system.h +9 -0
  80. data/src/include/util.h +3 -14
  81. data/src/include/version.h +1 -1
  82. data/src/include/visitor.h +1 -1
  83. data/src/io.c +7 -4
  84. data/src/lexer.c +61 -88
  85. data/src/lexer_peek_helpers.c +35 -37
  86. data/src/main.c +19 -23
  87. data/src/parser.c +280 -201
  88. data/src/parser_helpers.c +46 -40
  89. data/src/parser_match_tags.c +316 -0
  90. data/src/pretty_print.c +82 -106
  91. data/src/token.c +18 -65
  92. data/src/utf8.c +4 -4
  93. data/src/util/hb_arena.c +179 -0
  94. data/src/util/hb_arena_debug.c +237 -0
  95. data/src/{array.c → util/hb_array.c} +26 -27
  96. data/src/util/hb_buffer.c +194 -0
  97. data/src/util/hb_string.c +85 -0
  98. data/src/util/hb_system.c +30 -0
  99. data/src/util.c +29 -99
  100. data/src/visitor.c +54 -54
  101. data/templates/ext/herb/error_helpers.c.erb +3 -3
  102. data/templates/ext/herb/error_helpers.h.erb +1 -1
  103. data/templates/ext/herb/nodes.c.erb +11 -6
  104. data/templates/java/error_helpers.c.erb +75 -0
  105. data/templates/java/error_helpers.h.erb +20 -0
  106. data/templates/java/nodes.c.erb +97 -0
  107. data/templates/java/nodes.h.erb +23 -0
  108. data/templates/java/org/herb/ast/Errors.java.erb +121 -0
  109. data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
  110. data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
  111. data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
  112. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
  113. data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
  114. data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
  115. data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
  116. data/templates/lib/herb/ast/nodes.rb.erb +28 -16
  117. data/templates/lib/herb/errors.rb.erb +17 -12
  118. data/templates/rust/src/ast/nodes.rs.erb +220 -0
  119. data/templates/rust/src/errors.rs.erb +216 -0
  120. data/templates/rust/src/nodes.rs.erb +374 -0
  121. data/templates/src/analyze_missing_end.c.erb +36 -0
  122. data/templates/src/analyze_transform.c.erb +24 -0
  123. data/templates/src/ast_nodes.c.erb +14 -14
  124. data/templates/src/ast_pretty_print.c.erb +36 -36
  125. data/templates/src/errors.c.erb +31 -31
  126. data/templates/src/include/ast_nodes.h.erb +10 -9
  127. data/templates/src/include/ast_pretty_print.h.erb +2 -2
  128. data/templates/src/include/errors.h.erb +6 -6
  129. data/templates/src/parser_match_tags.c.erb +38 -0
  130. data/templates/src/visitor.c.erb +4 -4
  131. data/templates/template.rb +22 -3
  132. data/templates/wasm/error_helpers.cpp.erb +9 -9
  133. data/templates/wasm/error_helpers.h.erb +1 -1
  134. data/templates/wasm/nodes.cpp.erb +9 -9
  135. data/templates/wasm/nodes.h.erb +1 -1
  136. data/vendor/prism/Rakefile +4 -1
  137. data/vendor/prism/config.yml +2 -1
  138. data/vendor/prism/include/prism/ast.h +31 -1
  139. data/vendor/prism/include/prism/diagnostic.h +1 -0
  140. data/vendor/prism/include/prism/version.h +3 -3
  141. data/vendor/prism/src/diagnostic.c +3 -1
  142. data/vendor/prism/src/prism.c +130 -71
  143. data/vendor/prism/src/util/pm_string.c +6 -8
  144. data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
  145. data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
  146. data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
  147. data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
  148. data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
  149. data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
  150. metadata +34 -20
  151. data/lib/herb/libherb/array.rb +0 -51
  152. data/lib/herb/libherb/ast_node.rb +0 -50
  153. data/lib/herb/libherb/buffer.rb +0 -56
  154. data/lib/herb/libherb/extract_result.rb +0 -20
  155. data/lib/herb/libherb/lex_result.rb +0 -32
  156. data/lib/herb/libherb/libherb.rb +0 -52
  157. data/lib/herb/libherb/parse_result.rb +0 -20
  158. data/lib/herb/libherb/token.rb +0 -46
  159. data/lib/herb/libherb.rb +0 -35
  160. data/src/buffer.c +0 -241
  161. data/src/include/array.h +0 -33
  162. data/src/include/buffer.h +0 -39
  163. data/src/include/json.h +0 -28
  164. data/src/include/memory.h +0 -12
  165. data/src/json.c +0 -205
  166. data/src/memory.c +0 -53
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,22 +74,154 @@ 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,
89
90
  control_type_t parent_type
90
91
  );
91
92
 
93
+ typedef struct {
94
+ control_type_t type;
95
+ uint32_t offset;
96
+ bool found;
97
+ } earliest_control_keyword_t;
98
+
99
+ typedef struct {
100
+ earliest_control_keyword_t* result;
101
+ const uint8_t* source_start;
102
+ } location_walker_context_t;
103
+
104
+ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* data) {
105
+ if (!node) { return true; }
106
+
107
+ location_walker_context_t* context = (location_walker_context_t*) data;
108
+ earliest_control_keyword_t* result = context->result;
109
+
110
+ control_type_t current_type = CONTROL_TYPE_UNKNOWN;
111
+ uint32_t keyword_offset = UINT32_MAX;
112
+
113
+ switch (node->type) {
114
+ case PM_IF_NODE: {
115
+ pm_if_node_t* if_node = (pm_if_node_t*) node;
116
+ current_type = CONTROL_TYPE_IF;
117
+ keyword_offset = (uint32_t) (if_node->if_keyword_loc.start - context->source_start);
118
+ break;
119
+ }
120
+
121
+ case PM_UNLESS_NODE: {
122
+ pm_unless_node_t* unless_node = (pm_unless_node_t*) node;
123
+ current_type = CONTROL_TYPE_UNLESS;
124
+ keyword_offset = (uint32_t) (unless_node->keyword_loc.start - context->source_start);
125
+ break;
126
+ }
127
+
128
+ case PM_CASE_NODE: {
129
+ pm_case_node_t* case_node = (pm_case_node_t*) node;
130
+ current_type = CONTROL_TYPE_CASE;
131
+ keyword_offset = (uint32_t) (case_node->case_keyword_loc.start - context->source_start);
132
+ break;
133
+ }
134
+
135
+ case PM_CASE_MATCH_NODE: {
136
+ pm_case_match_node_t* case_match_node = (pm_case_match_node_t*) node;
137
+ current_type = CONTROL_TYPE_CASE_MATCH;
138
+ keyword_offset = (uint32_t) (case_match_node->case_keyword_loc.start - context->source_start);
139
+ break;
140
+ }
141
+
142
+ case PM_WHILE_NODE: {
143
+ pm_while_node_t* while_node = (pm_while_node_t*) node;
144
+ current_type = CONTROL_TYPE_WHILE;
145
+ keyword_offset = (uint32_t) (while_node->keyword_loc.start - context->source_start);
146
+ break;
147
+ }
148
+
149
+ case PM_UNTIL_NODE: {
150
+ pm_until_node_t* until_node = (pm_until_node_t*) node;
151
+ current_type = CONTROL_TYPE_UNTIL;
152
+ keyword_offset = (uint32_t) (until_node->keyword_loc.start - context->source_start);
153
+ break;
154
+ }
155
+
156
+ case PM_FOR_NODE: {
157
+ pm_for_node_t* for_node = (pm_for_node_t*) node;
158
+ current_type = CONTROL_TYPE_FOR;
159
+ keyword_offset = (uint32_t) (for_node->for_keyword_loc.start - context->source_start);
160
+ break;
161
+ }
162
+
163
+ case PM_BEGIN_NODE: {
164
+ pm_begin_node_t* begin_node = (pm_begin_node_t*) node;
165
+ current_type = CONTROL_TYPE_BEGIN;
166
+
167
+ if (begin_node->begin_keyword_loc.start != NULL) {
168
+ keyword_offset = (uint32_t) (begin_node->begin_keyword_loc.start - context->source_start);
169
+ } else {
170
+ keyword_offset = (uint32_t) (node->location.start - context->source_start);
171
+ }
172
+ break;
173
+ }
174
+
175
+ case PM_YIELD_NODE: {
176
+ current_type = CONTROL_TYPE_YIELD;
177
+ keyword_offset = (uint32_t) (node->location.start - context->source_start);
178
+ break;
179
+ }
180
+
181
+ case PM_CALL_NODE: {
182
+ pm_call_node_t* call = (pm_call_node_t*) node;
183
+
184
+ if (call->block != NULL) {
185
+ current_type = CONTROL_TYPE_BLOCK;
186
+ keyword_offset = (uint32_t) (node->location.start - context->source_start);
187
+ }
188
+ break;
189
+ }
190
+
191
+ case PM_NEXT_NODE:
192
+ case PM_BREAK_NODE:
193
+ case PM_RETURN_NODE: {
194
+ current_type = CONTROL_TYPE_UNKNOWN;
195
+ keyword_offset = (uint32_t) (node->location.start - context->source_start);
196
+ break;
197
+ }
198
+
199
+ default: break;
200
+ }
201
+
202
+ if (keyword_offset != UINT32_MAX) {
203
+ if (!result->found || keyword_offset < result->offset) {
204
+ result->type = current_type;
205
+ result->offset = keyword_offset;
206
+ result->found = true;
207
+ }
208
+ }
209
+
210
+ return true;
211
+ }
212
+
213
+ static control_type_t find_earliest_control_keyword(pm_node_t* root, const uint8_t* source_start) {
214
+ if (!root) { return CONTROL_TYPE_UNKNOWN; }
215
+
216
+ earliest_control_keyword_t result = { .type = CONTROL_TYPE_UNKNOWN, .offset = UINT32_MAX, .found = false };
217
+
218
+ location_walker_context_t context = { .result = &result, .source_start = source_start };
219
+
220
+ pm_visit_node(root, find_earliest_control_keyword_walker, &context);
221
+
222
+ return result.found ? result.type : CONTROL_TYPE_UNKNOWN;
223
+ }
224
+
92
225
  static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
93
226
  if (!erb_node || erb_node->base.type != AST_ERB_CONTENT_NODE) { return CONTROL_TYPE_UNKNOWN; }
94
227
 
@@ -98,26 +231,18 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
98
231
 
99
232
  if (ruby->valid) { return CONTROL_TYPE_UNKNOWN; }
100
233
 
101
- if (has_block_node(ruby)) { return CONTROL_TYPE_BLOCK; }
102
- if (has_if_node(ruby)) { return CONTROL_TYPE_IF; }
234
+ pm_node_t* root = ruby->root;
235
+
103
236
  if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
104
237
  if (has_else_node(ruby)) { return CONTROL_TYPE_ELSE; }
105
238
  if (has_end(ruby)) { return CONTROL_TYPE_END; }
106
- if (has_case_node(ruby)) { return CONTROL_TYPE_CASE; }
107
- if (has_case_match_node(ruby)) { return CONTROL_TYPE_CASE_MATCH; }
108
239
  if (has_when_node(ruby)) { return CONTROL_TYPE_WHEN; }
109
240
  if (has_in_node(ruby)) { return CONTROL_TYPE_IN; }
110
- if (has_begin_node(ruby)) { return CONTROL_TYPE_BEGIN; }
111
241
  if (has_rescue_node(ruby)) { return CONTROL_TYPE_RESCUE; }
112
242
  if (has_ensure_node(ruby)) { return CONTROL_TYPE_ENSURE; }
113
- if (has_unless_node(ruby)) { return CONTROL_TYPE_UNLESS; }
114
- if (has_while_node(ruby)) { return CONTROL_TYPE_WHILE; }
115
- if (has_until_node(ruby)) { return CONTROL_TYPE_UNTIL; }
116
- if (has_for_node(ruby)) { return CONTROL_TYPE_FOR; }
117
243
  if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
118
- if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
119
244
 
120
- return CONTROL_TYPE_UNKNOWN;
245
+ return find_earliest_control_keyword(root, ruby->parser.start);
121
246
  }
122
247
 
123
248
  static bool is_subsequent_type(control_type_t parent_type, control_type_t child_type) {
@@ -149,19 +274,21 @@ static bool is_terminator_type(control_type_t parent_type, control_type_t child_
149
274
 
150
275
  static AST_NODE_T* create_control_node(
151
276
  AST_ERB_CONTENT_NODE_T* erb_node,
152
- array_T* children,
277
+ hb_array_T* children,
153
278
  AST_NODE_T* subsequent,
154
279
  AST_ERB_END_NODE_T* end_node,
155
280
  control_type_t control_type
156
281
  ) {
157
- array_T* errors = array_init(8);
282
+ hb_array_T* errors = erb_node->base.errors;
283
+ erb_node->base.errors = NULL;
284
+
158
285
  position_T start_position = erb_node->tag_opening->location.start;
159
286
  position_T end_position = erb_node->tag_closing->location.end;
160
287
 
161
288
  if (end_node) {
162
289
  end_position = end_node->base.location.end;
163
- } else if (children && array_size(children) > 0) {
164
- AST_NODE_T* last_child = array_get(children, array_size(children) - 1);
290
+ } else if (children && hb_array_size(children) > 0) {
291
+ AST_NODE_T* last_child = hb_array_get(children, hb_array_size(children) - 1);
165
292
  end_position = last_child->location.end;
166
293
  } else if (subsequent) {
167
294
  end_position = subsequent->location.end;
@@ -173,7 +300,7 @@ static AST_NODE_T* create_control_node(
173
300
 
174
301
  switch (control_type) {
175
302
  case CONTROL_TYPE_IF:
176
- case CONTROL_TYPE_ELSIF:
303
+ case CONTROL_TYPE_ELSIF: {
177
304
  return (AST_NODE_T*) ast_erb_if_node_init(
178
305
  tag_opening,
179
306
  content,
@@ -185,32 +312,40 @@ static AST_NODE_T* create_control_node(
185
312
  end_position,
186
313
  errors
187
314
  );
315
+ }
188
316
 
189
- case CONTROL_TYPE_ELSE:
190
- return (AST_NODE_T*)
191
- ast_erb_else_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
317
+ case CONTROL_TYPE_ELSE: {
318
+ return (
319
+ AST_NODE_T*
320
+ ) ast_erb_else_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
321
+ }
192
322
 
193
323
  case CONTROL_TYPE_CASE:
194
324
  case CONTROL_TYPE_CASE_MATCH: {
195
325
  AST_ERB_ELSE_NODE_T* else_node = NULL;
196
326
  if (subsequent && subsequent->type == AST_ERB_ELSE_NODE) { else_node = (AST_ERB_ELSE_NODE_T*) subsequent; }
197
327
 
198
- array_T* when_conditions = array_init(8);
199
- array_T* in_conditions = array_init(8);
200
- array_T* non_when_non_in_children = array_init(8);
328
+ hb_array_T* when_conditions = hb_array_init(8);
329
+ hb_array_T* in_conditions = hb_array_init(8);
330
+ hb_array_T* non_when_non_in_children = hb_array_init(8);
331
+
332
+ for (size_t i = 0; i < hb_array_size(children); i++) {
333
+ AST_NODE_T* child = hb_array_get(children, i);
201
334
 
202
- for (size_t i = 0; i < array_size(children); i++) {
203
- AST_NODE_T* child = array_get(children, i);
204
335
  if (child && child->type == AST_ERB_WHEN_NODE) {
205
- array_append(when_conditions, child);
336
+ hb_array_append(when_conditions, child);
206
337
  } else if (child && child->type == AST_ERB_IN_NODE) {
207
- array_append(in_conditions, child);
338
+ hb_array_append(in_conditions, child);
208
339
  } else {
209
- array_append(non_when_non_in_children, child);
340
+ hb_array_append(non_when_non_in_children, child);
210
341
  }
211
342
  }
212
343
 
213
- if (array_size(in_conditions) > 0) {
344
+ hb_array_free(&children);
345
+
346
+ if (hb_array_size(in_conditions) > 0) {
347
+ hb_array_free(&when_conditions);
348
+
214
349
  return (AST_NODE_T*) ast_erb_case_match_node_init(
215
350
  tag_opening,
216
351
  content,
@@ -223,30 +358,34 @@ static AST_NODE_T* create_control_node(
223
358
  end_position,
224
359
  errors
225
360
  );
226
- }
361
+ } else {
362
+ hb_array_free(&in_conditions);
227
363
 
228
- return (AST_NODE_T*) ast_erb_case_node_init(
229
- tag_opening,
230
- content,
231
- tag_closing,
232
- non_when_non_in_children,
233
- when_conditions,
234
- else_node,
235
- end_node,
236
- start_position,
237
- end_position,
238
- errors
239
- );
364
+ return (AST_NODE_T*) ast_erb_case_node_init(
365
+ tag_opening,
366
+ content,
367
+ tag_closing,
368
+ non_when_non_in_children,
369
+ when_conditions,
370
+ else_node,
371
+ end_node,
372
+ start_position,
373
+ end_position,
374
+ errors
375
+ );
376
+ }
240
377
  }
241
378
 
242
379
  case CONTROL_TYPE_WHEN: {
243
- return (AST_NODE_T*)
244
- ast_erb_when_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
380
+ return (
381
+ AST_NODE_T*
382
+ ) ast_erb_when_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
245
383
  }
246
384
 
247
385
  case CONTROL_TYPE_IN: {
248
- return (AST_NODE_T*)
249
- ast_erb_in_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
386
+ return (
387
+ AST_NODE_T*
388
+ ) ast_erb_in_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
250
389
  }
251
390
 
252
391
  case CONTROL_TYPE_BEGIN: {
@@ -297,8 +436,9 @@ static AST_NODE_T* create_control_node(
297
436
  }
298
437
 
299
438
  case CONTROL_TYPE_ENSURE: {
300
- return (AST_NODE_T*)
301
- ast_erb_ensure_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
439
+ return (
440
+ AST_NODE_T*
441
+ ) ast_erb_ensure_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
302
442
  }
303
443
 
304
444
  case CONTROL_TYPE_UNLESS: {
@@ -372,34 +512,35 @@ static AST_NODE_T* create_control_node(
372
512
  }
373
513
 
374
514
  case CONTROL_TYPE_YIELD: {
375
- return (AST_NODE_T*)
376
- ast_erb_yield_node_init(tag_opening, content, tag_closing, start_position, end_position, errors);
515
+ return (
516
+ AST_NODE_T*
517
+ ) ast_erb_yield_node_init(tag_opening, content, tag_closing, start_position, end_position, errors);
377
518
  }
378
519
 
379
- default: array_free(&errors); return NULL;
520
+ default: return NULL;
380
521
  }
381
522
  }
382
523
 
383
524
  static size_t process_control_structure(
384
525
  AST_NODE_T* node,
385
- array_T* array,
526
+ hb_array_T* array,
386
527
  size_t index,
387
- array_T* output_array,
528
+ hb_array_T* output_array,
388
529
  analyze_ruby_context_T* context,
389
530
  control_type_t initial_type
390
531
  ) {
391
- AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
392
- array_T* children = array_init(8);
532
+ AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) hb_array_get(array, index);
533
+ hb_array_T* children = hb_array_init(8);
393
534
 
394
535
  index++;
395
536
 
396
537
  if (initial_type == CONTROL_TYPE_CASE || initial_type == CONTROL_TYPE_CASE_MATCH) {
397
- array_T* when_conditions = array_init(8);
398
- array_T* in_conditions = array_init(8);
399
- array_T* non_when_non_in_children = array_init(8);
538
+ hb_array_T* when_conditions = hb_array_init(8);
539
+ hb_array_T* in_conditions = hb_array_init(8);
540
+ hb_array_T* non_when_non_in_children = hb_array_init(8);
400
541
 
401
- while (index < array_size(array)) {
402
- AST_NODE_T* next_node = array_get(array, index);
542
+ while (index < hb_array_size(array)) {
543
+ AST_NODE_T* next_node = hb_array_get(array, index);
403
544
 
404
545
  if (!next_node) { break; }
405
546
 
@@ -410,17 +551,17 @@ static size_t process_control_structure(
410
551
  if (next_type == CONTROL_TYPE_WHEN || next_type == CONTROL_TYPE_IN) { break; }
411
552
  }
412
553
 
413
- array_append(non_when_non_in_children, next_node);
554
+ hb_array_append(non_when_non_in_children, next_node);
414
555
  index++;
415
556
  }
416
557
 
417
- while (index < array_size(array)) {
418
- AST_NODE_T* next_node = array_get(array, index);
558
+ while (index < hb_array_size(array)) {
559
+ AST_NODE_T* next_node = hb_array_get(array, index);
419
560
 
420
561
  if (!next_node) { break; }
421
562
 
422
563
  if (next_node->type != AST_ERB_CONTENT_NODE) {
423
- array_append(non_when_non_in_children, next_node);
564
+ hb_array_append(non_when_non_in_children, next_node);
424
565
  index++;
425
566
  continue;
426
567
  }
@@ -429,11 +570,14 @@ static size_t process_control_structure(
429
570
  control_type_t next_type = detect_control_type(erb_content);
430
571
 
431
572
  if (next_type == CONTROL_TYPE_WHEN) {
432
- array_T* when_statements = array_init(8);
573
+ hb_array_T* when_statements = hb_array_init(8);
433
574
  index++;
434
575
 
435
576
  index = process_block_children(node, array, index, when_statements, context, CONTROL_TYPE_WHEN);
436
577
 
578
+ hb_array_T* when_errors = erb_content->base.errors;
579
+ erb_content->base.errors = NULL;
580
+
437
581
  AST_ERB_WHEN_NODE_T* when_node = ast_erb_when_node_init(
438
582
  erb_content->tag_opening,
439
583
  erb_content->content,
@@ -441,18 +585,23 @@ static size_t process_control_structure(
441
585
  when_statements,
442
586
  erb_content->tag_opening->location.start,
443
587
  erb_content->tag_closing->location.end,
444
- array_init(8)
588
+ when_errors
445
589
  );
446
590
 
447
- array_append(when_conditions, (AST_NODE_T*) when_node);
591
+ ast_node_free((AST_NODE_T*) erb_content);
592
+
593
+ hb_array_append(when_conditions, (AST_NODE_T*) when_node);
448
594
 
449
595
  continue;
450
596
  } else if (next_type == CONTROL_TYPE_IN) {
451
- array_T* in_statements = array_init(8);
597
+ hb_array_T* in_statements = hb_array_init(8);
452
598
  index++;
453
599
 
454
600
  index = process_block_children(node, array, index, in_statements, context, CONTROL_TYPE_IN);
455
601
 
602
+ hb_array_T* in_errors = erb_content->base.errors;
603
+ erb_content->base.errors = NULL;
604
+
456
605
  AST_ERB_IN_NODE_T* in_node = ast_erb_in_node_init(
457
606
  erb_content->tag_opening,
458
607
  erb_content->content,
@@ -460,49 +609,40 @@ static size_t process_control_structure(
460
609
  in_statements,
461
610
  erb_content->tag_opening->location.start,
462
611
  erb_content->tag_closing->location.end,
463
- array_init(8)
612
+ in_errors
464
613
  );
465
614
 
466
- array_append(in_conditions, (AST_NODE_T*) in_node);
615
+ ast_node_free((AST_NODE_T*) erb_content);
616
+
617
+ hb_array_append(in_conditions, (AST_NODE_T*) in_node);
467
618
 
468
619
  continue;
469
620
  } else if (next_type == CONTROL_TYPE_ELSE || next_type == CONTROL_TYPE_END) {
470
621
  break;
471
622
  } else {
472
- array_append(non_when_non_in_children, next_node);
623
+ hb_array_append(non_when_non_in_children, next_node);
473
624
  index++;
474
625
  }
475
626
  }
476
627
 
477
628
  AST_ERB_ELSE_NODE_T* else_clause = NULL;
478
629
 
479
- if (index < array_size(array)) {
480
- AST_NODE_T* next_node = array_get(array, index);
630
+ if (index < hb_array_size(array)) {
631
+ AST_NODE_T* next_node = hb_array_get(array, index);
481
632
 
482
633
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
483
634
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
484
635
  control_type_t next_type = detect_control_type(next_erb);
485
636
 
486
637
  if (next_type == CONTROL_TYPE_ELSE) {
487
- array_T* else_children = array_init(8);
638
+ hb_array_T* else_children = hb_array_init(8);
488
639
 
489
640
  index++;
490
641
 
491
- while (index < array_size(array)) {
492
- AST_NODE_T* child = array_get(array, index);
493
-
494
- if (!child) { break; }
495
-
496
- if (child->type == AST_ERB_CONTENT_NODE) {
497
- AST_ERB_CONTENT_NODE_T* child_erb = (AST_ERB_CONTENT_NODE_T*) child;
498
- control_type_t child_type = detect_control_type(child_erb);
499
-
500
- if (child_type == CONTROL_TYPE_END) { break; }
501
- }
642
+ index = process_block_children(node, array, index, else_children, context, initial_type);
502
643
 
503
- array_append(else_children, child);
504
- index++;
505
- }
644
+ hb_array_T* else_errors = next_erb->base.errors;
645
+ next_erb->base.errors = NULL;
506
646
 
507
647
  else_clause = ast_erb_else_node_init(
508
648
  next_erb->tag_opening,
@@ -511,30 +651,37 @@ static size_t process_control_structure(
511
651
  else_children,
512
652
  next_erb->tag_opening->location.start,
513
653
  next_erb->tag_closing->location.end,
514
- array_init(8)
654
+ else_errors
515
655
  );
656
+
657
+ ast_node_free((AST_NODE_T*) next_erb);
516
658
  }
517
659
  }
518
660
  }
519
661
 
520
662
  AST_ERB_END_NODE_T* end_node = NULL;
521
663
 
522
- if (index < array_size(array)) {
523
- AST_NODE_T* potential_end = array_get(array, index);
664
+ if (index < hb_array_size(array)) {
665
+ AST_NODE_T* potential_end = hb_array_get(array, index);
524
666
 
525
667
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
526
668
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
527
669
 
528
670
  if (detect_control_type(end_erb) == CONTROL_TYPE_END) {
671
+ hb_array_T* end_errors = end_erb->base.errors;
672
+ end_erb->base.errors = NULL;
673
+
529
674
  end_node = ast_erb_end_node_init(
530
675
  end_erb->tag_opening,
531
676
  end_erb->content,
532
677
  end_erb->tag_closing,
533
678
  end_erb->tag_opening->location.start,
534
679
  end_erb->tag_closing->location.end,
535
- end_erb->base.errors
680
+ end_errors
536
681
  );
537
682
 
683
+ ast_node_free((AST_NODE_T*) end_erb);
684
+
538
685
  index++;
539
686
  }
540
687
  }
@@ -547,15 +694,18 @@ static size_t process_control_structure(
547
694
  end_position = end_node->base.location.end;
548
695
  } else if (else_clause) {
549
696
  end_position = else_clause->base.location.end;
550
- } else if (array_size(when_conditions) > 0) {
551
- AST_NODE_T* last_when = array_get(when_conditions, array_size(when_conditions) - 1);
697
+ } else if (hb_array_size(when_conditions) > 0) {
698
+ AST_NODE_T* last_when = hb_array_get(when_conditions, hb_array_size(when_conditions) - 1);
552
699
  end_position = last_when->location.end;
553
- } else if (array_size(in_conditions) > 0) {
554
- AST_NODE_T* last_in = array_get(in_conditions, array_size(in_conditions) - 1);
700
+ } else if (hb_array_size(in_conditions) > 0) {
701
+ AST_NODE_T* last_in = hb_array_get(in_conditions, hb_array_size(in_conditions) - 1);
555
702
  end_position = last_in->location.end;
556
703
  }
557
704
 
558
- if (array_size(in_conditions) > 0) {
705
+ if (hb_array_size(in_conditions) > 0) {
706
+ hb_array_T* case_match_errors = erb_node->base.errors;
707
+ erb_node->base.errors = NULL;
708
+
559
709
  AST_ERB_CASE_MATCH_NODE_T* case_match_node = ast_erb_case_match_node_init(
560
710
  erb_node->tag_opening,
561
711
  erb_node->content,
@@ -566,13 +716,21 @@ static size_t process_control_structure(
566
716
  end_node,
567
717
  start_position,
568
718
  end_position,
569
- array_init(8)
719
+ case_match_errors
570
720
  );
571
721
 
572
- array_append(output_array, (AST_NODE_T*) case_match_node);
722
+ ast_node_free((AST_NODE_T*) erb_node);
723
+
724
+ hb_array_append(output_array, (AST_NODE_T*) case_match_node);
725
+ hb_array_free(&when_conditions);
726
+ hb_array_free(&children);
727
+
573
728
  return index;
574
729
  }
575
730
 
731
+ hb_array_T* case_errors = erb_node->base.errors;
732
+ erb_node->base.errors = NULL;
733
+
576
734
  AST_ERB_CASE_NODE_T* case_node = ast_erb_case_node_init(
577
735
  erb_node->tag_opening,
578
736
  erb_node->content,
@@ -583,10 +741,15 @@ static size_t process_control_structure(
583
741
  end_node,
584
742
  start_position,
585
743
  end_position,
586
- array_init(8)
744
+ case_errors
587
745
  );
588
746
 
589
- array_append(output_array, (AST_NODE_T*) case_node);
747
+ ast_node_free((AST_NODE_T*) erb_node);
748
+
749
+ hb_array_append(output_array, (AST_NODE_T*) case_node);
750
+ hb_array_free(&in_conditions);
751
+ hb_array_free(&children);
752
+
590
753
  return index;
591
754
  }
592
755
 
@@ -597,8 +760,8 @@ static size_t process_control_structure(
597
760
  AST_ERB_ELSE_NODE_T* else_clause = NULL;
598
761
  AST_ERB_ENSURE_NODE_T* ensure_clause = NULL;
599
762
 
600
- if (index < array_size(array)) {
601
- AST_NODE_T* next_node = array_get(array, index);
763
+ if (index < hb_array_size(array)) {
764
+ AST_NODE_T* next_node = hb_array_get(array, index);
602
765
 
603
766
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
604
767
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -612,33 +775,22 @@ static size_t process_control_structure(
612
775
  }
613
776
  }
614
777
 
615
- if (index < array_size(array)) {
616
- AST_NODE_T* next_node = array_get(array, index);
778
+ if (index < hb_array_size(array)) {
779
+ AST_NODE_T* next_node = hb_array_get(array, index);
617
780
 
618
781
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
619
782
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
620
783
  control_type_t next_type = detect_control_type(next_erb);
621
784
 
622
785
  if (next_type == CONTROL_TYPE_ELSE) {
623
- array_T* else_children = array_init(8);
786
+ hb_array_T* else_children = hb_array_init(8);
624
787
 
625
788
  index++;
626
789
 
627
- while (index < array_size(array)) {
628
- AST_NODE_T* child = array_get(array, index);
790
+ index = process_block_children(node, array, index, else_children, context, initial_type);
629
791
 
630
- if (!child) { break; }
631
-
632
- if (child->type == AST_ERB_CONTENT_NODE) {
633
- AST_ERB_CONTENT_NODE_T* child_erb = (AST_ERB_CONTENT_NODE_T*) child;
634
- control_type_t child_type = detect_control_type(child_erb);
635
-
636
- if (child_type == CONTROL_TYPE_ENSURE || child_type == CONTROL_TYPE_END) { break; }
637
- }
638
-
639
- array_append(else_children, child);
640
- index++;
641
- }
792
+ hb_array_T* else_errors = next_erb->base.errors;
793
+ next_erb->base.errors = NULL;
642
794
 
643
795
  else_clause = ast_erb_else_node_init(
644
796
  next_erb->tag_opening,
@@ -647,26 +799,28 @@ static size_t process_control_structure(
647
799
  else_children,
648
800
  next_erb->tag_opening->location.start,
649
801
  next_erb->tag_closing->location.end,
650
- array_init(8)
802
+ else_errors
651
803
  );
804
+
805
+ ast_node_free((AST_NODE_T*) next_erb);
652
806
  }
653
807
  }
654
808
  }
655
809
 
656
- if (index < array_size(array)) {
657
- AST_NODE_T* next_node = array_get(array, index);
810
+ if (index < hb_array_size(array)) {
811
+ AST_NODE_T* next_node = hb_array_get(array, index);
658
812
 
659
813
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
660
814
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
661
815
  control_type_t next_type = detect_control_type(next_erb);
662
816
 
663
817
  if (next_type == CONTROL_TYPE_ENSURE) {
664
- array_T* ensure_children = array_init(8);
818
+ hb_array_T* ensure_children = hb_array_init(8);
665
819
 
666
820
  index++;
667
821
 
668
- while (index < array_size(array)) {
669
- AST_NODE_T* child = array_get(array, index);
822
+ while (index < hb_array_size(array)) {
823
+ AST_NODE_T* child = hb_array_get(array, index);
670
824
 
671
825
  if (!child) { break; }
672
826
 
@@ -677,10 +831,13 @@ static size_t process_control_structure(
677
831
  if (child_type == CONTROL_TYPE_END) { break; }
678
832
  }
679
833
 
680
- array_append(ensure_children, child);
834
+ hb_array_append(ensure_children, child);
681
835
  index++;
682
836
  }
683
837
 
838
+ hb_array_T* ensure_errors = next_erb->base.errors;
839
+ next_erb->base.errors = NULL;
840
+
684
841
  ensure_clause = ast_erb_ensure_node_init(
685
842
  next_erb->tag_opening,
686
843
  next_erb->content,
@@ -688,30 +845,37 @@ static size_t process_control_structure(
688
845
  ensure_children,
689
846
  next_erb->tag_opening->location.start,
690
847
  next_erb->tag_closing->location.end,
691
- array_init(8)
848
+ ensure_errors
692
849
  );
850
+
851
+ ast_node_free((AST_NODE_T*) next_erb);
693
852
  }
694
853
  }
695
854
  }
696
855
 
697
856
  AST_ERB_END_NODE_T* end_node = NULL;
698
857
 
699
- if (index < array_size(array)) {
700
- AST_NODE_T* potential_end = array_get(array, index);
858
+ if (index < hb_array_size(array)) {
859
+ AST_NODE_T* potential_end = hb_array_get(array, index);
701
860
 
702
861
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
703
862
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
704
863
 
705
864
  if (detect_control_type(end_erb) == CONTROL_TYPE_END) {
865
+ hb_array_T* end_errors = end_erb->base.errors;
866
+ end_erb->base.errors = NULL;
867
+
706
868
  end_node = ast_erb_end_node_init(
707
869
  end_erb->tag_opening,
708
870
  end_erb->content,
709
871
  end_erb->tag_closing,
710
872
  end_erb->tag_opening->location.start,
711
873
  end_erb->tag_closing->location.end,
712
- end_erb->base.errors
874
+ end_errors
713
875
  );
714
876
 
877
+ ast_node_free((AST_NODE_T*) end_erb);
878
+
715
879
  index++;
716
880
  }
717
881
  }
@@ -730,6 +894,9 @@ static size_t process_control_structure(
730
894
  end_position = rescue_clause->base.location.end;
731
895
  }
732
896
 
897
+ hb_array_T* begin_errors = erb_node->base.errors;
898
+ erb_node->base.errors = NULL;
899
+
733
900
  AST_ERB_BEGIN_NODE_T* begin_node = ast_erb_begin_node_init(
734
901
  erb_node->tag_opening,
735
902
  erb_node->content,
@@ -741,10 +908,12 @@ static size_t process_control_structure(
741
908
  end_node,
742
909
  start_position,
743
910
  end_position,
744
- array_init(8)
911
+ begin_errors
745
912
  );
746
913
 
747
- array_append(output_array, (AST_NODE_T*) begin_node);
914
+ ast_node_free((AST_NODE_T*) erb_node);
915
+
916
+ hb_array_append(output_array, (AST_NODE_T*) begin_node);
748
917
  return index;
749
918
  }
750
919
 
@@ -753,23 +922,28 @@ static size_t process_control_structure(
753
922
 
754
923
  AST_ERB_END_NODE_T* end_node = NULL;
755
924
 
756
- if (index < array_size(array)) {
757
- AST_NODE_T* potential_close = array_get(array, index);
925
+ if (index < hb_array_size(array)) {
926
+ AST_NODE_T* potential_close = hb_array_get(array, index);
758
927
 
759
928
  if (potential_close && potential_close->type == AST_ERB_CONTENT_NODE) {
760
929
  AST_ERB_CONTENT_NODE_T* close_erb = (AST_ERB_CONTENT_NODE_T*) potential_close;
761
930
  control_type_t close_type = detect_control_type(close_erb);
762
931
 
763
932
  if (close_type == CONTROL_TYPE_BLOCK_CLOSE || close_type == CONTROL_TYPE_END) {
933
+ hb_array_T* end_errors = close_erb->base.errors;
934
+ close_erb->base.errors = NULL;
935
+
764
936
  end_node = ast_erb_end_node_init(
765
937
  close_erb->tag_opening,
766
938
  close_erb->content,
767
939
  close_erb->tag_closing,
768
940
  close_erb->tag_opening->location.start,
769
941
  close_erb->tag_closing->location.end,
770
- close_erb->base.errors
942
+ end_errors
771
943
  );
772
944
 
945
+ ast_node_free((AST_NODE_T*) close_erb);
946
+
773
947
  index++;
774
948
  }
775
949
  }
@@ -780,11 +954,14 @@ static size_t process_control_structure(
780
954
 
781
955
  if (end_node) {
782
956
  end_position = end_node->base.location.end;
783
- } else if (children && array_size(children) > 0) {
784
- AST_NODE_T* last_child = array_get(children, array_size(children) - 1);
957
+ } else if (children && hb_array_size(children) > 0) {
958
+ AST_NODE_T* last_child = hb_array_get(children, hb_array_size(children) - 1);
785
959
  end_position = last_child->location.end;
786
960
  }
787
961
 
962
+ hb_array_T* block_errors = erb_node->base.errors;
963
+ erb_node->base.errors = NULL;
964
+
788
965
  AST_ERB_BLOCK_NODE_T* block_node = ast_erb_block_node_init(
789
966
  erb_node->tag_opening,
790
967
  erb_node->content,
@@ -793,10 +970,12 @@ static size_t process_control_structure(
793
970
  end_node,
794
971
  start_position,
795
972
  end_position,
796
- array_init(8)
973
+ block_errors
797
974
  );
798
975
 
799
- array_append(output_array, (AST_NODE_T*) block_node);
976
+ ast_node_free((AST_NODE_T*) erb_node);
977
+
978
+ hb_array_append(output_array, (AST_NODE_T*) block_node);
800
979
  return index;
801
980
  }
802
981
 
@@ -805,8 +984,8 @@ static size_t process_control_structure(
805
984
  AST_NODE_T* subsequent = NULL;
806
985
  AST_ERB_END_NODE_T* end_node = NULL;
807
986
 
808
- if (index < array_size(array)) {
809
- AST_NODE_T* next_node = array_get(array, index);
987
+ if (index < hb_array_size(array)) {
988
+ AST_NODE_T* next_node = hb_array_get(array, index);
810
989
 
811
990
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
812
991
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -818,22 +997,27 @@ static size_t process_control_structure(
818
997
  }
819
998
  }
820
999
 
821
- if (index < array_size(array)) {
822
- AST_NODE_T* potential_end = array_get(array, index);
1000
+ if (index < hb_array_size(array)) {
1001
+ AST_NODE_T* potential_end = hb_array_get(array, index);
823
1002
 
824
1003
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
825
1004
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
826
1005
 
827
1006
  if (detect_control_type(end_erb) == CONTROL_TYPE_END) {
1007
+ hb_array_T* end_errors = end_erb->base.errors;
1008
+ end_erb->base.errors = NULL;
1009
+
828
1010
  end_node = ast_erb_end_node_init(
829
1011
  end_erb->tag_opening,
830
1012
  end_erb->content,
831
1013
  end_erb->tag_closing,
832
1014
  end_erb->tag_opening->location.start,
833
1015
  end_erb->tag_closing->location.end,
834
- end_erb->base.errors
1016
+ end_errors
835
1017
  );
836
1018
 
1019
+ ast_node_free((AST_NODE_T*) end_erb);
1020
+
837
1021
  index++;
838
1022
  }
839
1023
  }
@@ -841,22 +1025,27 @@ static size_t process_control_structure(
841
1025
 
842
1026
  AST_NODE_T* control_node = create_control_node(erb_node, children, subsequent, end_node, initial_type);
843
1027
 
844
- if (control_node) { array_append(output_array, control_node); }
1028
+ if (control_node) {
1029
+ ast_node_free((AST_NODE_T*) erb_node);
1030
+ hb_array_append(output_array, control_node);
1031
+ } else {
1032
+ hb_array_free(&children);
1033
+ }
845
1034
 
846
1035
  return index;
847
1036
  }
848
1037
 
849
1038
  static size_t process_subsequent_block(
850
1039
  AST_NODE_T* node,
851
- array_T* array,
1040
+ hb_array_T* array,
852
1041
  size_t index,
853
1042
  AST_NODE_T** subsequent_out,
854
1043
  analyze_ruby_context_T* context,
855
1044
  control_type_t parent_type
856
1045
  ) {
857
- AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
1046
+ AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) hb_array_get(array, index);
858
1047
  control_type_t type = detect_control_type(erb_node);
859
- array_T* children = array_init(8);
1048
+ hb_array_T* children = hb_array_init(8);
860
1049
 
861
1050
  index++;
862
1051
 
@@ -864,8 +1053,14 @@ static size_t process_subsequent_block(
864
1053
 
865
1054
  AST_NODE_T* subsequent_node = create_control_node(erb_node, children, NULL, NULL, type);
866
1055
 
867
- if (index < array_size(array)) {
868
- AST_NODE_T* next_node = array_get(array, index);
1056
+ if (subsequent_node) {
1057
+ ast_node_free((AST_NODE_T*) erb_node);
1058
+ } else {
1059
+ hb_array_free(&children);
1060
+ }
1061
+
1062
+ if (index < hb_array_size(array)) {
1063
+ AST_NODE_T* next_node = hb_array_get(array, index);
869
1064
 
870
1065
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
871
1066
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -916,19 +1111,19 @@ static size_t process_subsequent_block(
916
1111
 
917
1112
  static size_t process_block_children(
918
1113
  AST_NODE_T* node,
919
- array_T* array,
1114
+ hb_array_T* array,
920
1115
  size_t index,
921
- array_T* children_array,
1116
+ hb_array_T* children_array,
922
1117
  analyze_ruby_context_T* context,
923
1118
  control_type_t parent_type
924
1119
  ) {
925
- while (index < array_size(array)) {
926
- AST_NODE_T* child = array_get(array, index);
1120
+ while (index < hb_array_size(array)) {
1121
+ AST_NODE_T* child = hb_array_get(array, index);
927
1122
 
928
1123
  if (!child) { break; }
929
1124
 
930
1125
  if (child->type != AST_ERB_CONTENT_NODE) {
931
- array_append(children_array, child);
1126
+ hb_array_append(children_array, child);
932
1127
  index++;
933
1128
  continue;
934
1129
  }
@@ -941,35 +1136,35 @@ static size_t process_block_children(
941
1136
  if (child_type == CONTROL_TYPE_IF || child_type == CONTROL_TYPE_CASE || child_type == CONTROL_TYPE_CASE_MATCH
942
1137
  || child_type == CONTROL_TYPE_BEGIN || child_type == CONTROL_TYPE_UNLESS || child_type == CONTROL_TYPE_WHILE
943
1138
  || child_type == CONTROL_TYPE_UNTIL || child_type == CONTROL_TYPE_FOR || child_type == CONTROL_TYPE_BLOCK) {
944
- array_T* temp_array = array_init(1);
1139
+ hb_array_T* temp_array = hb_array_init(1);
945
1140
  size_t new_index = process_control_structure(node, array, index, temp_array, context, child_type);
946
1141
 
947
- if (array_size(temp_array) > 0) { array_append(children_array, array_get(temp_array, 0)); }
1142
+ if (hb_array_size(temp_array) > 0) { hb_array_append(children_array, hb_array_get(temp_array, 0)); }
948
1143
 
949
- array_free(&temp_array);
1144
+ hb_array_free(&temp_array);
950
1145
 
951
1146
  index = new_index;
952
1147
  continue;
953
1148
  }
954
1149
 
955
- array_append(children_array, child);
1150
+ hb_array_append(children_array, child);
956
1151
  index++;
957
1152
  }
958
1153
 
959
1154
  return index;
960
1155
  }
961
1156
 
962
- static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_ruby_context_T* context) {
963
- array_T* new_array = array_init(array_size(array));
1157
+ hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby_context_T* context) {
1158
+ hb_array_T* new_array = hb_array_init(hb_array_size(array));
964
1159
  size_t index = 0;
965
1160
 
966
- while (index < array_size(array)) {
967
- AST_NODE_T* item = array_get(array, index);
1161
+ while (index < hb_array_size(array)) {
1162
+ AST_NODE_T* item = hb_array_get(array, index);
968
1163
 
969
1164
  if (!item) { break; }
970
1165
 
971
1166
  if (item->type != AST_ERB_CONTENT_NODE) {
972
- array_append(new_array, item);
1167
+ hb_array_append(new_array, item);
973
1168
  index++;
974
1169
  continue;
975
1170
  }
@@ -991,12 +1186,13 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
991
1186
  continue;
992
1187
 
993
1188
  case CONTROL_TYPE_YIELD: {
994
- AST_NODE_T* yield_node = create_control_node(erb_node, array_init(8), NULL, NULL, type);
1189
+ AST_NODE_T* yield_node = create_control_node(erb_node, NULL, NULL, NULL, type);
995
1190
 
996
1191
  if (yield_node) {
997
- array_append(new_array, yield_node);
1192
+ ast_node_free((AST_NODE_T*) erb_node);
1193
+ hb_array_append(new_array, yield_node);
998
1194
  } else {
999
- array_append(new_array, item);
1195
+ hb_array_append(new_array, item);
1000
1196
  }
1001
1197
 
1002
1198
  index++;
@@ -1004,7 +1200,7 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1004
1200
  }
1005
1201
 
1006
1202
  default:
1007
- array_append(new_array, item);
1203
+ hb_array_append(new_array, item);
1008
1204
  index++;
1009
1205
  break;
1010
1206
  }
@@ -1013,41 +1209,178 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1013
1209
  return new_array;
1014
1210
  }
1015
1211
 
1016
- static bool transform_erb_nodes(const AST_NODE_T* node, void* data) {
1017
- analyze_ruby_context_T* context = (analyze_ruby_context_T*) data;
1018
- context->parent = (AST_NODE_T*) node;
1212
+ static bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data) {
1213
+ invalid_erb_context_T* context = (invalid_erb_context_T*) data;
1214
+
1215
+ if (node->type == AST_HTML_ATTRIBUTE_NAME_NODE) { return false; }
1216
+
1217
+ bool is_loop_node =
1218
+ (node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE || node->type == AST_ERB_FOR_NODE
1219
+ || node->type == AST_ERB_BLOCK_NODE);
1220
+
1221
+ bool is_begin_node = (node->type == AST_ERB_BEGIN_NODE);
1222
+
1223
+ if (is_loop_node) { context->loop_depth++; }
1224
+
1225
+ if (is_begin_node) { context->rescue_depth++; }
1226
+
1227
+ if (node->type == AST_ERB_CONTENT_NODE) {
1228
+ const AST_ERB_CONTENT_NODE_T* content_node = (const AST_ERB_CONTENT_NODE_T*) node;
1229
+
1230
+ if (content_node->parsed && !content_node->valid && content_node->analyzed_ruby != NULL) {
1231
+ analyzed_ruby_T* analyzed = content_node->analyzed_ruby;
1232
+
1233
+ // =begin
1234
+ if (has_error_message(analyzed, "embedded document meets end of file")) {
1235
+ if (is_loop_node) { context->loop_depth--; }
1236
+ if (is_begin_node) { context->rescue_depth--; }
1237
+
1238
+ return true;
1239
+ }
1240
+
1241
+ // =end
1242
+ if (has_error_message(analyzed, "unexpected '=', ignoring it")
1243
+ && has_error_message(analyzed, "unexpected 'end', ignoring it")) {
1244
+ if (is_loop_node) { context->loop_depth--; }
1245
+ if (is_begin_node) { context->rescue_depth--; }
1246
+
1247
+ return true;
1248
+ }
1249
+
1250
+ const char* keyword = NULL;
1251
+
1252
+ if (context->loop_depth == 0) {
1253
+ if (has_error_message(analyzed, "Invalid break")) {
1254
+ keyword = "`<% break %>`";
1255
+ } else if (has_error_message(analyzed, "Invalid next")) {
1256
+ keyword = "`<% next %>`";
1257
+ } else if (has_error_message(analyzed, "Invalid redo")) {
1258
+ keyword = "`<% redo %>`";
1259
+ }
1260
+ } else {
1261
+ if (has_error_message(analyzed, "Invalid redo") || has_error_message(analyzed, "Invalid break")
1262
+ || has_error_message(analyzed, "Invalid next")) {
1263
+
1264
+ if (is_loop_node) { context->loop_depth--; }
1265
+ if (is_begin_node) { context->rescue_depth--; }
1266
+
1267
+ return true;
1268
+ }
1269
+ }
1019
1270
 
1020
- if (node->type == AST_DOCUMENT_NODE) {
1021
- AST_DOCUMENT_NODE_T* document_node = (AST_DOCUMENT_NODE_T*) node;
1022
- array_T* old_array = document_node->children;
1023
- document_node->children = rewrite_node_array((AST_NODE_T*) node, document_node->children, context);
1024
- array_free(&old_array);
1271
+ if (context->rescue_depth == 0) {
1272
+ if (has_error_message(analyzed, "Invalid retry without rescue")) { keyword = "`<% retry %>`"; }
1273
+ } else {
1274
+ if (has_error_message(analyzed, "Invalid retry without rescue")) {
1275
+ if (is_loop_node) { context->loop_depth--; }
1276
+ if (is_begin_node) { context->rescue_depth--; }
1277
+
1278
+ return true;
1279
+ }
1280
+ }
1281
+
1282
+ if (keyword == NULL) { keyword = erb_keyword_from_analyzed_ruby(analyzed); }
1283
+
1284
+ if (keyword != NULL && !token_value_empty(content_node->tag_closing)) {
1285
+ append_erb_control_flow_scope_error(keyword, node->location.start, node->location.end, node->errors);
1286
+ }
1287
+ }
1288
+ }
1289
+
1290
+ if (node->type == AST_ERB_IF_NODE) {
1291
+ const AST_ERB_IF_NODE_T* if_node = (const AST_ERB_IF_NODE_T*) node;
1292
+
1293
+ if (if_node->end_node == NULL) { check_erb_node_for_missing_end(node); }
1294
+
1295
+ if (if_node->statements != NULL) {
1296
+ for (size_t i = 0; i < hb_array_size(if_node->statements); i++) {
1297
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(if_node->statements, i);
1298
+
1299
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
1300
+ }
1301
+ }
1302
+
1303
+ AST_NODE_T* subsequent = if_node->subsequent;
1304
+
1305
+ while (subsequent != NULL) {
1306
+ if (subsequent->type == AST_ERB_CONTENT_NODE) {
1307
+ const AST_ERB_CONTENT_NODE_T* content_node = (const AST_ERB_CONTENT_NODE_T*) subsequent;
1308
+
1309
+ if (content_node->parsed && !content_node->valid && content_node->analyzed_ruby != NULL) {
1310
+ analyzed_ruby_T* analyzed = content_node->analyzed_ruby;
1311
+ const char* keyword = erb_keyword_from_analyzed_ruby(analyzed);
1312
+
1313
+ if (!token_value_empty(content_node->tag_closing)) {
1314
+ append_erb_control_flow_scope_error(
1315
+ keyword,
1316
+ subsequent->location.start,
1317
+ subsequent->location.end,
1318
+ subsequent->errors
1319
+ );
1320
+ }
1321
+ }
1322
+ }
1323
+
1324
+ if (subsequent->type == AST_ERB_IF_NODE) {
1325
+ const AST_ERB_IF_NODE_T* elsif_node = (const AST_ERB_IF_NODE_T*) subsequent;
1326
+
1327
+ if (elsif_node->statements != NULL) {
1328
+ for (size_t i = 0; i < hb_array_size(elsif_node->statements); i++) {
1329
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(elsif_node->statements, i);
1330
+
1331
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
1332
+ }
1333
+ }
1334
+
1335
+ subsequent = elsif_node->subsequent;
1336
+ } else if (subsequent->type == AST_ERB_ELSE_NODE) {
1337
+ const AST_ERB_ELSE_NODE_T* else_node = (const AST_ERB_ELSE_NODE_T*) subsequent;
1338
+
1339
+ if (else_node->statements != NULL) {
1340
+ for (size_t i = 0; i < hb_array_size(else_node->statements); i++) {
1341
+ AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(else_node->statements, i);
1342
+
1343
+ if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
1344
+ }
1345
+ }
1346
+
1347
+ break;
1348
+ } else {
1349
+ break;
1350
+ }
1351
+ }
1025
1352
  }
1026
1353
 
1027
- if (node->type == AST_HTML_ELEMENT_NODE) {
1028
- AST_HTML_ELEMENT_NODE_T* element_node = (AST_HTML_ELEMENT_NODE_T*) node;
1029
- array_T* old_array = element_node->body;
1030
- element_node->body = rewrite_node_array((AST_NODE_T*) node, element_node->body, context);
1031
- array_free(&old_array);
1354
+ if (node->type == AST_ERB_UNLESS_NODE || node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE
1355
+ || node->type == AST_ERB_FOR_NODE || node->type == AST_ERB_CASE_NODE || node->type == AST_ERB_CASE_MATCH_NODE
1356
+ || node->type == AST_ERB_BEGIN_NODE || node->type == AST_ERB_BLOCK_NODE || node->type == AST_ERB_ELSE_NODE) {
1357
+ herb_visit_child_nodes(node, detect_invalid_erb_structures, context);
1032
1358
  }
1033
1359
 
1034
- if (node->type == AST_HTML_OPEN_TAG_NODE) {
1035
- AST_HTML_OPEN_TAG_NODE_T* open_tag = (AST_HTML_OPEN_TAG_NODE_T*) node;
1036
- array_T* old_array = open_tag->children;
1037
- open_tag->children = rewrite_node_array((AST_NODE_T*) node, open_tag->children, context);
1038
- array_free(&old_array);
1360
+ if (node->type == AST_ERB_UNLESS_NODE || node->type == AST_ERB_WHILE_NODE || node->type == AST_ERB_UNTIL_NODE
1361
+ || node->type == AST_ERB_FOR_NODE || node->type == AST_ERB_CASE_NODE || node->type == AST_ERB_CASE_MATCH_NODE
1362
+ || node->type == AST_ERB_BEGIN_NODE || node->type == AST_ERB_BLOCK_NODE || node->type == AST_ERB_ELSE_NODE) {
1363
+ check_erb_node_for_missing_end(node);
1364
+
1365
+ if (is_loop_node) { context->loop_depth--; }
1366
+ if (is_begin_node) { context->rescue_depth--; }
1367
+
1368
+ return false;
1039
1369
  }
1040
1370
 
1041
- if (node->type == AST_HTML_ATTRIBUTE_VALUE_NODE) {
1042
- AST_HTML_ATTRIBUTE_VALUE_NODE_T* value_node = (AST_HTML_ATTRIBUTE_VALUE_NODE_T*) node;
1043
- array_T* old_array = value_node->children;
1044
- value_node->children = rewrite_node_array((AST_NODE_T*) node, value_node->children, context);
1045
- array_free(&old_array);
1371
+ if (node->type == AST_ERB_IF_NODE) {
1372
+ if (is_loop_node) { context->loop_depth--; }
1373
+ if (is_begin_node) { context->rescue_depth--; }
1374
+
1375
+ return false;
1046
1376
  }
1047
1377
 
1048
- herb_visit_child_nodes(node, transform_erb_nodes, data);
1378
+ bool result = true;
1049
1379
 
1050
- return false;
1380
+ if (is_loop_node) { context->loop_depth--; }
1381
+ if (is_begin_node) { context->rescue_depth--; }
1382
+
1383
+ return result;
1051
1384
  }
1052
1385
 
1053
1386
  void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source) {
@@ -1056,19 +1389,31 @@ void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source)
1056
1389
  analyze_ruby_context_T* context = malloc(sizeof(analyze_ruby_context_T));
1057
1390
  context->document = document;
1058
1391
  context->parent = NULL;
1059
- context->ruby_context_stack = array_init(8);
1392
+ context->ruby_context_stack = hb_array_init(8);
1060
1393
 
1061
1394
  herb_visit_node((AST_NODE_T*) document, transform_erb_nodes, context);
1062
1395
 
1396
+ invalid_erb_context_T* invalid_context = malloc(sizeof(invalid_erb_context_T));
1397
+ invalid_context->loop_depth = 0;
1398
+ invalid_context->rescue_depth = 0;
1399
+
1400
+ herb_visit_node((AST_NODE_T*) document, detect_invalid_erb_structures, invalid_context);
1401
+
1063
1402
  herb_analyze_parse_errors(document, source);
1064
1403
 
1065
- array_free(&context->ruby_context_stack);
1404
+ herb_parser_match_html_tags_post_analyze(document);
1405
+
1406
+ hb_array_free(&context->ruby_context_stack);
1407
+
1066
1408
  free(context);
1409
+ free(invalid_context);
1067
1410
  }
1068
1411
 
1069
1412
  void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source) {
1070
1413
  char* extracted_ruby = herb_extract_ruby_with_semicolons(source);
1071
1414
 
1415
+ if (!extracted_ruby) { return; }
1416
+
1072
1417
  pm_parser_t parser;
1073
1418
  pm_options_t options = { 0, .partial_script = true };
1074
1419
  pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
@@ -1079,7 +1424,7 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source
1079
1424
  error = (const pm_diagnostic_t*) error->node.next) {
1080
1425
 
1081
1426
  RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser);
1082
- array_append(document->base.errors, parse_error);
1427
+ hb_array_append(document->base.errors, parse_error);
1083
1428
  }
1084
1429
 
1085
1430
  pm_node_destroy(&parser, root);