herb 0.7.4-x86_64-linux-gnu → 0.8.2-x86_64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +8 -5
  3. data/README.md +6 -1
  4. data/config.yml +40 -20
  5. data/ext/herb/error_helpers.c +57 -3
  6. data/ext/herb/error_helpers.h +1 -1
  7. data/ext/herb/extconf.rb +1 -0
  8. data/ext/herb/extension.c +10 -24
  9. data/ext/herb/extension_helpers.c +12 -18
  10. data/ext/herb/extension_helpers.h +4 -4
  11. data/ext/herb/nodes.c +72 -37
  12. data/herb.gemspec +0 -2
  13. data/lib/herb/3.0/herb.so +0 -0
  14. data/lib/herb/3.1/herb.so +0 -0
  15. data/lib/herb/3.2/herb.so +0 -0
  16. data/lib/herb/3.3/herb.so +0 -0
  17. data/lib/herb/3.4/herb.so +0 -0
  18. data/lib/herb/ast/helpers.rb +11 -0
  19. data/lib/herb/ast/node.rb +15 -6
  20. data/lib/herb/ast/nodes.rb +609 -392
  21. data/lib/herb/cli.rb +31 -0
  22. data/lib/herb/colors.rb +82 -0
  23. data/lib/herb/engine/compiler.rb +140 -14
  24. data/lib/herb/engine/debug_visitor.rb +1 -5
  25. data/lib/herb/engine/parser_error_overlay.rb +1 -1
  26. data/lib/herb/engine.rb +18 -20
  27. data/lib/herb/errors.rb +166 -56
  28. data/lib/herb/location.rb +2 -2
  29. data/lib/herb/project.rb +86 -21
  30. data/lib/herb/token.rb +14 -2
  31. data/lib/herb/version.rb +1 -1
  32. data/lib/herb.rb +1 -0
  33. data/sig/herb/ast/helpers.rbs +3 -0
  34. data/sig/herb/ast/node.rbs +12 -5
  35. data/sig/herb/ast/nodes.rbs +124 -62
  36. data/sig/herb/colors.rbs +35 -0
  37. data/sig/herb/engine/compiler.rbs +23 -1
  38. data/sig/herb/errors.rbs +74 -20
  39. data/sig/herb/token.rbs +8 -0
  40. data/sig/herb_c_extension.rbs +1 -1
  41. data/sig/serialized_ast_errors.rbs +8 -0
  42. data/src/analyze.c +589 -281
  43. data/src/analyze_helpers.c +17 -4
  44. data/src/analyze_missing_end.c +147 -0
  45. data/src/analyze_transform.c +196 -0
  46. data/src/analyzed_ruby.c +23 -2
  47. data/src/ast_node.c +14 -17
  48. data/src/ast_nodes.c +179 -181
  49. data/src/ast_pretty_print.c +232 -232
  50. data/src/element_source.c +7 -6
  51. data/src/errors.c +272 -152
  52. data/src/extract.c +92 -34
  53. data/src/herb.c +37 -49
  54. data/src/html_util.c +34 -96
  55. data/src/include/analyze.h +10 -2
  56. data/src/include/analyze_helpers.h +3 -0
  57. data/src/include/analyzed_ruby.h +4 -2
  58. data/src/include/ast_node.h +4 -4
  59. data/src/include/ast_nodes.h +68 -67
  60. data/src/include/ast_pretty_print.h +2 -2
  61. data/src/include/element_source.h +3 -1
  62. data/src/include/errors.h +42 -26
  63. data/src/include/extract.h +4 -4
  64. data/src/include/herb.h +6 -7
  65. data/src/include/html_util.h +4 -5
  66. data/src/include/lexer.h +1 -3
  67. data/src/include/lexer_peek_helpers.h +21 -19
  68. data/src/include/lexer_struct.h +12 -10
  69. data/src/include/location.h +10 -13
  70. data/src/include/macros.h +4 -0
  71. data/src/include/parser.h +12 -6
  72. data/src/include/parser_helpers.h +26 -16
  73. data/src/include/position.h +3 -14
  74. data/src/include/pretty_print.h +38 -28
  75. data/src/include/prism_helpers.h +1 -1
  76. data/src/include/range.h +4 -13
  77. data/src/include/token.h +5 -11
  78. data/src/include/token_struct.h +2 -2
  79. data/src/include/utf8.h +3 -2
  80. data/src/include/util/hb_arena.h +31 -0
  81. data/src/include/util/hb_arena_debug.h +8 -0
  82. data/src/include/util/hb_array.h +33 -0
  83. data/src/include/util/hb_buffer.h +36 -0
  84. data/src/include/util/hb_string.h +29 -0
  85. data/src/include/util/hb_system.h +9 -0
  86. data/src/include/util.h +3 -14
  87. data/src/include/version.h +1 -1
  88. data/src/include/visitor.h +1 -1
  89. data/src/io.c +7 -4
  90. data/src/lexer.c +62 -88
  91. data/src/lexer_peek_helpers.c +42 -38
  92. data/src/location.c +9 -37
  93. data/src/main.c +19 -23
  94. data/src/parser.c +371 -313
  95. data/src/parser_helpers.c +60 -54
  96. data/src/parser_match_tags.c +316 -0
  97. data/src/pretty_print.c +88 -117
  98. data/src/prism_helpers.c +7 -7
  99. data/src/range.c +2 -35
  100. data/src/token.c +36 -87
  101. data/src/utf8.c +4 -4
  102. data/src/util/hb_arena.c +179 -0
  103. data/src/util/hb_arena_debug.c +237 -0
  104. data/src/{array.c → util/hb_array.c} +26 -27
  105. data/src/util/hb_buffer.c +211 -0
  106. data/src/util/hb_string.c +85 -0
  107. data/src/util/hb_system.c +30 -0
  108. data/src/util.c +29 -99
  109. data/src/visitor.c +54 -54
  110. data/templates/ext/herb/error_helpers.c.erb +3 -3
  111. data/templates/ext/herb/error_helpers.h.erb +1 -1
  112. data/templates/ext/herb/nodes.c.erb +11 -6
  113. data/templates/java/error_helpers.c.erb +75 -0
  114. data/templates/java/error_helpers.h.erb +20 -0
  115. data/templates/java/nodes.c.erb +97 -0
  116. data/templates/java/nodes.h.erb +23 -0
  117. data/templates/java/org/herb/ast/Errors.java.erb +121 -0
  118. data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
  119. data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
  120. data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
  121. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -1
  122. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
  123. data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
  124. data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
  125. data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
  126. data/templates/lib/herb/ast/nodes.rb.erb +28 -16
  127. data/templates/lib/herb/errors.rb.erb +17 -12
  128. data/templates/rust/src/ast/nodes.rs.erb +220 -0
  129. data/templates/rust/src/errors.rs.erb +216 -0
  130. data/templates/rust/src/nodes.rs.erb +374 -0
  131. data/templates/src/analyze_missing_end.c.erb +36 -0
  132. data/templates/src/analyze_transform.c.erb +24 -0
  133. data/templates/src/ast_nodes.c.erb +14 -16
  134. data/templates/src/ast_pretty_print.c.erb +36 -36
  135. data/templates/src/errors.c.erb +36 -38
  136. data/templates/src/include/ast_nodes.h.erb +11 -10
  137. data/templates/src/include/ast_pretty_print.h.erb +2 -2
  138. data/templates/src/include/errors.h.erb +9 -9
  139. data/templates/src/parser_match_tags.c.erb +38 -0
  140. data/templates/src/visitor.c.erb +4 -4
  141. data/templates/template.rb +22 -3
  142. data/templates/wasm/error_helpers.cpp.erb +9 -9
  143. data/templates/wasm/error_helpers.h.erb +1 -1
  144. data/templates/wasm/nodes.cpp.erb +9 -9
  145. data/templates/wasm/nodes.h.erb +1 -1
  146. data/vendor/prism/Rakefile +4 -1
  147. data/vendor/prism/config.yml +2 -1
  148. data/vendor/prism/include/prism/ast.h +31 -1
  149. data/vendor/prism/include/prism/diagnostic.h +1 -0
  150. data/vendor/prism/include/prism/version.h +3 -3
  151. data/vendor/prism/src/diagnostic.c +3 -1
  152. data/vendor/prism/src/prism.c +130 -71
  153. data/vendor/prism/src/util/pm_string.c +6 -8
  154. data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
  155. data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
  156. data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
  157. data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
  158. data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
  159. data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
  160. metadata +34 -21
  161. data/lib/herb/libherb/array.rb +0 -51
  162. data/lib/herb/libherb/ast_node.rb +0 -50
  163. data/lib/herb/libherb/buffer.rb +0 -56
  164. data/lib/herb/libherb/extract_result.rb +0 -20
  165. data/lib/herb/libherb/lex_result.rb +0 -32
  166. data/lib/herb/libherb/libherb.rb +0 -52
  167. data/lib/herb/libherb/parse_result.rb +0 -20
  168. data/lib/herb/libherb/token.rb +0 -46
  169. data/lib/herb/libherb.rb +0 -35
  170. data/src/buffer.c +0 -232
  171. data/src/include/array.h +0 -33
  172. data/src/include/buffer.h +0 -39
  173. data/src/include/json.h +0 -28
  174. data/src/include/memory.h +0 -12
  175. data/src/json.c +0 -205
  176. data/src/memory.c +0 -53
  177. 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,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
 
@@ -96,31 +229,20 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
96
229
 
97
230
  if (!ruby) { return CONTROL_TYPE_UNKNOWN; }
98
231
 
99
- if (ruby->valid) {
100
- if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
101
- return CONTROL_TYPE_UNKNOWN;
102
- }
232
+ if (ruby->valid) { return CONTROL_TYPE_UNKNOWN; }
233
+
234
+ pm_node_t* root = ruby->root;
103
235
 
104
- if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
105
- if (has_block_node(ruby)) { return CONTROL_TYPE_BLOCK; }
106
- if (has_if_node(ruby)) { return CONTROL_TYPE_IF; }
107
236
  if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
108
237
  if (has_else_node(ruby)) { return CONTROL_TYPE_ELSE; }
109
238
  if (has_end(ruby)) { return CONTROL_TYPE_END; }
110
- if (has_case_node(ruby)) { return CONTROL_TYPE_CASE; }
111
- if (has_case_match_node(ruby)) { return CONTROL_TYPE_CASE_MATCH; }
112
239
  if (has_when_node(ruby)) { return CONTROL_TYPE_WHEN; }
113
240
  if (has_in_node(ruby)) { return CONTROL_TYPE_IN; }
114
- if (has_begin_node(ruby)) { return CONTROL_TYPE_BEGIN; }
115
241
  if (has_rescue_node(ruby)) { return CONTROL_TYPE_RESCUE; }
116
242
  if (has_ensure_node(ruby)) { return CONTROL_TYPE_ENSURE; }
117
- if (has_unless_node(ruby)) { return CONTROL_TYPE_UNLESS; }
118
- if (has_while_node(ruby)) { return CONTROL_TYPE_WHILE; }
119
- if (has_until_node(ruby)) { return CONTROL_TYPE_UNTIL; }
120
- if (has_for_node(ruby)) { return CONTROL_TYPE_FOR; }
121
243
  if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
122
244
 
123
- return CONTROL_TYPE_UNKNOWN;
245
+ return find_earliest_control_keyword(root, ruby->parser.start);
124
246
  }
125
247
 
126
248
  static bool is_subsequent_type(control_type_t parent_type, control_type_t child_type) {
@@ -152,22 +274,24 @@ static bool is_terminator_type(control_type_t parent_type, control_type_t child_
152
274
 
153
275
  static AST_NODE_T* create_control_node(
154
276
  AST_ERB_CONTENT_NODE_T* erb_node,
155
- array_T* children,
277
+ hb_array_T* children,
156
278
  AST_NODE_T* subsequent,
157
279
  AST_ERB_END_NODE_T* end_node,
158
280
  control_type_t control_type
159
281
  ) {
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;
282
+ hb_array_T* errors = erb_node->base.errors;
283
+ erb_node->base.errors = NULL;
284
+
285
+ position_T start_position = erb_node->tag_opening->location.start;
286
+ position_T end_position = erb_node->tag_closing->location.end;
163
287
 
164
288
  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;
289
+ end_position = end_node->base.location.end;
290
+ } else if (children && hb_array_size(children) > 0) {
291
+ AST_NODE_T* last_child = hb_array_last(children);
292
+ end_position = last_child->location.end;
169
293
  } else if (subsequent) {
170
- end_position = subsequent->location->end;
294
+ end_position = subsequent->location.end;
171
295
  }
172
296
 
173
297
  token_T* tag_opening = erb_node->tag_opening;
@@ -176,7 +300,7 @@ static AST_NODE_T* create_control_node(
176
300
 
177
301
  switch (control_type) {
178
302
  case CONTROL_TYPE_IF:
179
- case CONTROL_TYPE_ELSIF:
303
+ case CONTROL_TYPE_ELSIF: {
180
304
  return (AST_NODE_T*) ast_erb_if_node_init(
181
305
  tag_opening,
182
306
  content,
@@ -188,32 +312,40 @@ static AST_NODE_T* create_control_node(
188
312
  end_position,
189
313
  errors
190
314
  );
315
+ }
191
316
 
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);
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
+ }
195
322
 
196
323
  case CONTROL_TYPE_CASE:
197
324
  case CONTROL_TYPE_CASE_MATCH: {
198
325
  AST_ERB_ELSE_NODE_T* else_node = NULL;
199
326
  if (subsequent && subsequent->type == AST_ERB_ELSE_NODE) { else_node = (AST_ERB_ELSE_NODE_T*) subsequent; }
200
327
 
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);
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);
204
334
 
205
- for (size_t i = 0; i < array_size(children); i++) {
206
- AST_NODE_T* child = array_get(children, i);
207
335
  if (child && child->type == AST_ERB_WHEN_NODE) {
208
- array_append(when_conditions, child);
336
+ hb_array_append(when_conditions, child);
209
337
  } else if (child && child->type == AST_ERB_IN_NODE) {
210
- array_append(in_conditions, child);
338
+ hb_array_append(in_conditions, child);
211
339
  } else {
212
- array_append(non_when_non_in_children, child);
340
+ hb_array_append(non_when_non_in_children, child);
213
341
  }
214
342
  }
215
343
 
216
- 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
+
217
349
  return (AST_NODE_T*) ast_erb_case_match_node_init(
218
350
  tag_opening,
219
351
  content,
@@ -226,30 +358,34 @@ static AST_NODE_T* create_control_node(
226
358
  end_position,
227
359
  errors
228
360
  );
229
- }
361
+ } else {
362
+ hb_array_free(&in_conditions);
230
363
 
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
- );
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
+ }
243
377
  }
244
378
 
245
379
  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);
380
+ return (
381
+ AST_NODE_T*
382
+ ) ast_erb_when_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
248
383
  }
249
384
 
250
385
  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);
386
+ return (
387
+ AST_NODE_T*
388
+ ) ast_erb_in_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
253
389
  }
254
390
 
255
391
  case CONTROL_TYPE_BEGIN: {
@@ -300,8 +436,9 @@ static AST_NODE_T* create_control_node(
300
436
  }
301
437
 
302
438
  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);
439
+ return (
440
+ AST_NODE_T*
441
+ ) ast_erb_ensure_node_init(tag_opening, content, tag_closing, children, start_position, end_position, errors);
305
442
  }
306
443
 
307
444
  case CONTROL_TYPE_UNLESS: {
@@ -375,34 +512,35 @@ static AST_NODE_T* create_control_node(
375
512
  }
376
513
 
377
514
  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);
515
+ return (
516
+ AST_NODE_T*
517
+ ) ast_erb_yield_node_init(tag_opening, content, tag_closing, start_position, end_position, errors);
380
518
  }
381
519
 
382
- default: array_free(&errors); return NULL;
520
+ default: return NULL;
383
521
  }
384
522
  }
385
523
 
386
524
  static size_t process_control_structure(
387
525
  AST_NODE_T* node,
388
- array_T* array,
526
+ hb_array_T* array,
389
527
  size_t index,
390
- array_T* output_array,
528
+ hb_array_T* output_array,
391
529
  analyze_ruby_context_T* context,
392
530
  control_type_t initial_type
393
531
  ) {
394
- AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
395
- 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);
396
534
 
397
535
  index++;
398
536
 
399
537
  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);
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);
403
541
 
404
- while (index < array_size(array)) {
405
- 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);
406
544
 
407
545
  if (!next_node) { break; }
408
546
 
@@ -413,17 +551,17 @@ static size_t process_control_structure(
413
551
  if (next_type == CONTROL_TYPE_WHEN || next_type == CONTROL_TYPE_IN) { break; }
414
552
  }
415
553
 
416
- array_append(non_when_non_in_children, next_node);
554
+ hb_array_append(non_when_non_in_children, next_node);
417
555
  index++;
418
556
  }
419
557
 
420
- while (index < array_size(array)) {
421
- 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);
422
560
 
423
561
  if (!next_node) { break; }
424
562
 
425
563
  if (next_node->type != AST_ERB_CONTENT_NODE) {
426
- array_append(non_when_non_in_children, next_node);
564
+ hb_array_append(non_when_non_in_children, next_node);
427
565
  index++;
428
566
  continue;
429
567
  }
@@ -432,167 +570,142 @@ static size_t process_control_structure(
432
570
  control_type_t next_type = detect_control_type(erb_content);
433
571
 
434
572
  if (next_type == CONTROL_TYPE_WHEN) {
435
- array_T* when_statements = array_init(8);
573
+ hb_array_T* when_statements = hb_array_init(8);
436
574
  index++;
437
575
 
438
- while (index < array_size(array)) {
439
- AST_NODE_T* child = array_get(array, index);
440
-
441
- if (!child) { break; }
442
-
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);
576
+ index = process_block_children(node, array, index, when_statements, context, CONTROL_TYPE_WHEN);
446
577
 
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
- }
578
+ hb_array_T* when_errors = erb_content->base.errors;
579
+ erb_content->base.errors = NULL;
456
580
 
457
581
  AST_ERB_WHEN_NODE_T* when_node = ast_erb_when_node_init(
458
582
  erb_content->tag_opening,
459
583
  erb_content->content,
460
584
  erb_content->tag_closing,
461
585
  when_statements,
462
- erb_content->tag_opening->location->start,
463
- erb_content->tag_closing->location->end,
464
- array_init(8)
586
+ erb_content->tag_opening->location.start,
587
+ erb_content->tag_closing->location.end,
588
+ when_errors
465
589
  );
466
590
 
467
- 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);
468
594
 
469
595
  continue;
470
596
  } else if (next_type == CONTROL_TYPE_IN) {
471
- array_T* in_statements = array_init(8);
597
+ hb_array_T* in_statements = hb_array_init(8);
472
598
  index++;
473
599
 
474
- while (index < array_size(array)) {
475
- AST_NODE_T* child = array_get(array, index);
476
-
477
- if (!child) { break; }
600
+ index = process_block_children(node, array, index, in_statements, context, CONTROL_TYPE_IN);
478
601
 
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);
482
-
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
- }
602
+ hb_array_T* in_errors = erb_content->base.errors;
603
+ erb_content->base.errors = NULL;
492
604
 
493
605
  AST_ERB_IN_NODE_T* in_node = ast_erb_in_node_init(
494
606
  erb_content->tag_opening,
495
607
  erb_content->content,
496
608
  erb_content->tag_closing,
497
609
  in_statements,
498
- erb_content->tag_opening->location->start,
499
- erb_content->tag_closing->location->end,
500
- array_init(8)
610
+ erb_content->tag_opening->location.start,
611
+ erb_content->tag_closing->location.end,
612
+ in_errors
501
613
  );
502
614
 
503
- 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);
504
618
 
505
619
  continue;
506
620
  } else if (next_type == CONTROL_TYPE_ELSE || next_type == CONTROL_TYPE_END) {
507
621
  break;
508
622
  } else {
509
- array_append(non_when_non_in_children, next_node);
623
+ hb_array_append(non_when_non_in_children, next_node);
510
624
  index++;
511
625
  }
512
626
  }
513
627
 
514
628
  AST_ERB_ELSE_NODE_T* else_clause = NULL;
515
629
 
516
- if (index < array_size(array)) {
517
- 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);
518
632
 
519
633
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
520
634
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
521
635
  control_type_t next_type = detect_control_type(next_erb);
522
636
 
523
637
  if (next_type == CONTROL_TYPE_ELSE) {
524
- array_T* else_children = array_init(8);
638
+ hb_array_T* else_children = hb_array_init(8);
525
639
 
526
640
  index++;
527
641
 
528
- while (index < array_size(array)) {
529
- AST_NODE_T* child = array_get(array, index);
642
+ index = process_block_children(node, array, index, else_children, context, initial_type);
530
643
 
531
- if (!child) { break; }
532
-
533
- if (child->type == AST_ERB_CONTENT_NODE) {
534
- AST_ERB_CONTENT_NODE_T* child_erb = (AST_ERB_CONTENT_NODE_T*) child;
535
- control_type_t child_type = detect_control_type(child_erb);
536
-
537
- if (child_type == CONTROL_TYPE_END) { break; }
538
- }
539
-
540
- array_append(else_children, child);
541
- index++;
542
- }
644
+ hb_array_T* else_errors = next_erb->base.errors;
645
+ next_erb->base.errors = NULL;
543
646
 
544
647
  else_clause = ast_erb_else_node_init(
545
648
  next_erb->tag_opening,
546
649
  next_erb->content,
547
650
  next_erb->tag_closing,
548
651
  else_children,
549
- next_erb->tag_opening->location->start,
550
- next_erb->tag_closing->location->end,
551
- array_init(8)
652
+ next_erb->tag_opening->location.start,
653
+ next_erb->tag_closing->location.end,
654
+ else_errors
552
655
  );
656
+
657
+ ast_node_free((AST_NODE_T*) next_erb);
553
658
  }
554
659
  }
555
660
  }
556
661
 
557
662
  AST_ERB_END_NODE_T* end_node = NULL;
558
663
 
559
- if (index < array_size(array)) {
560
- 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);
561
666
 
562
667
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
563
668
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
564
669
 
565
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
+
566
674
  end_node = ast_erb_end_node_init(
567
675
  end_erb->tag_opening,
568
676
  end_erb->content,
569
677
  end_erb->tag_closing,
570
- end_erb->tag_opening->location->start,
571
- end_erb->tag_closing->location->end,
572
- end_erb->base.errors
678
+ end_erb->tag_opening->location.start,
679
+ end_erb->tag_closing->location.end,
680
+ end_errors
573
681
  );
574
682
 
683
+ ast_node_free((AST_NODE_T*) end_erb);
684
+
575
685
  index++;
576
686
  }
577
687
  }
578
688
  }
579
689
 
580
- position_T* start_position = erb_node->tag_opening->location->start;
581
- position_T* end_position = erb_node->tag_closing->location->end;
690
+ position_T start_position = erb_node->tag_opening->location.start;
691
+ position_T end_position = erb_node->tag_closing->location.end;
582
692
 
583
693
  if (end_node) {
584
- end_position = end_node->base.location->end;
694
+ end_position = end_node->base.location.end;
585
695
  } 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;
696
+ end_position = else_clause->base.location.end;
697
+ } else if (hb_array_size(when_conditions) > 0) {
698
+ AST_NODE_T* last_when = hb_array_last(when_conditions);
699
+ end_position = last_when->location.end;
700
+ } else if (hb_array_size(in_conditions) > 0) {
701
+ AST_NODE_T* last_in = hb_array_last(in_conditions);
702
+ end_position = last_in->location.end;
593
703
  }
594
704
 
595
- 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
+
596
709
  AST_ERB_CASE_MATCH_NODE_T* case_match_node = ast_erb_case_match_node_init(
597
710
  erb_node->tag_opening,
598
711
  erb_node->content,
@@ -603,13 +716,21 @@ static size_t process_control_structure(
603
716
  end_node,
604
717
  start_position,
605
718
  end_position,
606
- array_init(8)
719
+ case_match_errors
607
720
  );
608
721
 
609
- 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
+
610
728
  return index;
611
729
  }
612
730
 
731
+ hb_array_T* case_errors = erb_node->base.errors;
732
+ erb_node->base.errors = NULL;
733
+
613
734
  AST_ERB_CASE_NODE_T* case_node = ast_erb_case_node_init(
614
735
  erb_node->tag_opening,
615
736
  erb_node->content,
@@ -620,10 +741,15 @@ static size_t process_control_structure(
620
741
  end_node,
621
742
  start_position,
622
743
  end_position,
623
- array_init(8)
744
+ case_errors
624
745
  );
625
746
 
626
- 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
+
627
753
  return index;
628
754
  }
629
755
 
@@ -634,8 +760,8 @@ static size_t process_control_structure(
634
760
  AST_ERB_ELSE_NODE_T* else_clause = NULL;
635
761
  AST_ERB_ENSURE_NODE_T* ensure_clause = NULL;
636
762
 
637
- if (index < array_size(array)) {
638
- 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);
639
765
 
640
766
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
641
767
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -649,61 +775,52 @@ static size_t process_control_structure(
649
775
  }
650
776
  }
651
777
 
652
- if (index < array_size(array)) {
653
- 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);
654
780
 
655
781
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
656
782
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
657
783
  control_type_t next_type = detect_control_type(next_erb);
658
784
 
659
785
  if (next_type == CONTROL_TYPE_ELSE) {
660
- array_T* else_children = array_init(8);
786
+ hb_array_T* else_children = hb_array_init(8);
661
787
 
662
788
  index++;
663
789
 
664
- while (index < array_size(array)) {
665
- AST_NODE_T* child = array_get(array, index);
666
-
667
- if (!child) { break; }
668
-
669
- if (child->type == AST_ERB_CONTENT_NODE) {
670
- AST_ERB_CONTENT_NODE_T* child_erb = (AST_ERB_CONTENT_NODE_T*) child;
671
- control_type_t child_type = detect_control_type(child_erb);
672
-
673
- if (child_type == CONTROL_TYPE_ENSURE || child_type == CONTROL_TYPE_END) { break; }
674
- }
790
+ index = process_block_children(node, array, index, else_children, context, initial_type);
675
791
 
676
- array_append(else_children, child);
677
- index++;
678
- }
792
+ hb_array_T* else_errors = next_erb->base.errors;
793
+ next_erb->base.errors = NULL;
679
794
 
680
795
  else_clause = ast_erb_else_node_init(
681
796
  next_erb->tag_opening,
682
797
  next_erb->content,
683
798
  next_erb->tag_closing,
684
799
  else_children,
685
- next_erb->tag_opening->location->start,
686
- next_erb->tag_closing->location->end,
687
- array_init(8)
800
+ next_erb->tag_opening->location.start,
801
+ next_erb->tag_closing->location.end,
802
+ else_errors
688
803
  );
804
+
805
+ ast_node_free((AST_NODE_T*) next_erb);
689
806
  }
690
807
  }
691
808
  }
692
809
 
693
- if (index < array_size(array)) {
694
- 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);
695
812
 
696
813
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
697
814
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
698
815
  control_type_t next_type = detect_control_type(next_erb);
699
816
 
700
817
  if (next_type == CONTROL_TYPE_ENSURE) {
701
- array_T* ensure_children = array_init(8);
818
+ hb_array_T* ensure_children = hb_array_init(8);
702
819
 
703
820
  index++;
704
821
 
705
- while (index < array_size(array)) {
706
- 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);
707
824
 
708
825
  if (!child) { break; }
709
826
 
@@ -714,59 +831,72 @@ static size_t process_control_structure(
714
831
  if (child_type == CONTROL_TYPE_END) { break; }
715
832
  }
716
833
 
717
- array_append(ensure_children, child);
834
+ hb_array_append(ensure_children, child);
718
835
  index++;
719
836
  }
720
837
 
838
+ hb_array_T* ensure_errors = next_erb->base.errors;
839
+ next_erb->base.errors = NULL;
840
+
721
841
  ensure_clause = ast_erb_ensure_node_init(
722
842
  next_erb->tag_opening,
723
843
  next_erb->content,
724
844
  next_erb->tag_closing,
725
845
  ensure_children,
726
- next_erb->tag_opening->location->start,
727
- next_erb->tag_closing->location->end,
728
- array_init(8)
846
+ next_erb->tag_opening->location.start,
847
+ next_erb->tag_closing->location.end,
848
+ ensure_errors
729
849
  );
850
+
851
+ ast_node_free((AST_NODE_T*) next_erb);
730
852
  }
731
853
  }
732
854
  }
733
855
 
734
856
  AST_ERB_END_NODE_T* end_node = NULL;
735
857
 
736
- if (index < array_size(array)) {
737
- 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);
738
860
 
739
861
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
740
862
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
741
863
 
742
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
+
743
868
  end_node = ast_erb_end_node_init(
744
869
  end_erb->tag_opening,
745
870
  end_erb->content,
746
871
  end_erb->tag_closing,
747
- end_erb->tag_opening->location->start,
748
- end_erb->tag_closing->location->end,
749
- end_erb->base.errors
872
+ end_erb->tag_opening->location.start,
873
+ end_erb->tag_closing->location.end,
874
+ end_errors
750
875
  );
751
876
 
877
+ ast_node_free((AST_NODE_T*) end_erb);
878
+
752
879
  index++;
753
880
  }
754
881
  }
755
882
  }
756
883
 
757
- position_T* start_position = erb_node->tag_opening->location->start;
758
- position_T* end_position = erb_node->tag_closing->location->end;
884
+ position_T start_position = erb_node->tag_opening->location.start;
885
+ position_T end_position = erb_node->tag_closing->location.end;
759
886
 
760
887
  if (end_node) {
761
- end_position = end_node->base.location->end;
888
+ end_position = end_node->base.location.end;
762
889
  } else if (ensure_clause) {
763
- end_position = ensure_clause->base.location->end;
890
+ end_position = ensure_clause->base.location.end;
764
891
  } else if (else_clause) {
765
- end_position = else_clause->base.location->end;
892
+ end_position = else_clause->base.location.end;
766
893
  } else if (rescue_clause) {
767
- end_position = rescue_clause->base.location->end;
894
+ end_position = rescue_clause->base.location.end;
768
895
  }
769
896
 
897
+ hb_array_T* begin_errors = erb_node->base.errors;
898
+ erb_node->base.errors = NULL;
899
+
770
900
  AST_ERB_BEGIN_NODE_T* begin_node = ast_erb_begin_node_init(
771
901
  erb_node->tag_opening,
772
902
  erb_node->content,
@@ -778,10 +908,12 @@ static size_t process_control_structure(
778
908
  end_node,
779
909
  start_position,
780
910
  end_position,
781
- array_init(8)
911
+ begin_errors
782
912
  );
783
913
 
784
- 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);
785
917
  return index;
786
918
  }
787
919
 
@@ -790,38 +922,46 @@ static size_t process_control_structure(
790
922
 
791
923
  AST_ERB_END_NODE_T* end_node = NULL;
792
924
 
793
- if (index < array_size(array)) {
794
- 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);
795
927
 
796
928
  if (potential_close && potential_close->type == AST_ERB_CONTENT_NODE) {
797
929
  AST_ERB_CONTENT_NODE_T* close_erb = (AST_ERB_CONTENT_NODE_T*) potential_close;
798
930
  control_type_t close_type = detect_control_type(close_erb);
799
931
 
800
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
+
801
936
  end_node = ast_erb_end_node_init(
802
937
  close_erb->tag_opening,
803
938
  close_erb->content,
804
939
  close_erb->tag_closing,
805
- close_erb->tag_opening->location->start,
806
- close_erb->tag_closing->location->end,
807
- close_erb->base.errors
940
+ close_erb->tag_opening->location.start,
941
+ close_erb->tag_closing->location.end,
942
+ end_errors
808
943
  );
809
944
 
945
+ ast_node_free((AST_NODE_T*) close_erb);
946
+
810
947
  index++;
811
948
  }
812
949
  }
813
950
  }
814
951
 
815
- position_T* start_position = erb_node->tag_opening->location->start;
816
- position_T* end_position = erb_node->tag_closing->location->end;
952
+ position_T start_position = erb_node->tag_opening->location.start;
953
+ position_T end_position = erb_node->tag_closing->location.end;
817
954
 
818
955
  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;
956
+ end_position = end_node->base.location.end;
957
+ } else if (children && hb_array_size(children) > 0) {
958
+ AST_NODE_T* last_child = hb_array_last(children);
959
+ end_position = last_child->location.end;
823
960
  }
824
961
 
962
+ hb_array_T* block_errors = erb_node->base.errors;
963
+ erb_node->base.errors = NULL;
964
+
825
965
  AST_ERB_BLOCK_NODE_T* block_node = ast_erb_block_node_init(
826
966
  erb_node->tag_opening,
827
967
  erb_node->content,
@@ -830,10 +970,12 @@ static size_t process_control_structure(
830
970
  end_node,
831
971
  start_position,
832
972
  end_position,
833
- array_init(8)
973
+ block_errors
834
974
  );
835
975
 
836
- 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);
837
979
  return index;
838
980
  }
839
981
 
@@ -842,8 +984,8 @@ static size_t process_control_structure(
842
984
  AST_NODE_T* subsequent = NULL;
843
985
  AST_ERB_END_NODE_T* end_node = NULL;
844
986
 
845
- if (index < array_size(array)) {
846
- 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);
847
989
 
848
990
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
849
991
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -855,22 +997,27 @@ static size_t process_control_structure(
855
997
  }
856
998
  }
857
999
 
858
- if (index < array_size(array)) {
859
- 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);
860
1002
 
861
1003
  if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
862
1004
  AST_ERB_CONTENT_NODE_T* end_erb = (AST_ERB_CONTENT_NODE_T*) potential_end;
863
1005
 
864
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
+
865
1010
  end_node = ast_erb_end_node_init(
866
1011
  end_erb->tag_opening,
867
1012
  end_erb->content,
868
1013
  end_erb->tag_closing,
869
- end_erb->tag_opening->location->start,
870
- end_erb->tag_closing->location->end,
871
- end_erb->base.errors
1014
+ end_erb->tag_opening->location.start,
1015
+ end_erb->tag_closing->location.end,
1016
+ end_errors
872
1017
  );
873
1018
 
1019
+ ast_node_free((AST_NODE_T*) end_erb);
1020
+
874
1021
  index++;
875
1022
  }
876
1023
  }
@@ -878,22 +1025,27 @@ static size_t process_control_structure(
878
1025
 
879
1026
  AST_NODE_T* control_node = create_control_node(erb_node, children, subsequent, end_node, initial_type);
880
1027
 
881
- 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
+ }
882
1034
 
883
1035
  return index;
884
1036
  }
885
1037
 
886
1038
  static size_t process_subsequent_block(
887
1039
  AST_NODE_T* node,
888
- array_T* array,
1040
+ hb_array_T* array,
889
1041
  size_t index,
890
1042
  AST_NODE_T** subsequent_out,
891
1043
  analyze_ruby_context_T* context,
892
1044
  control_type_t parent_type
893
1045
  ) {
894
- 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);
895
1047
  control_type_t type = detect_control_type(erb_node);
896
- array_T* children = array_init(8);
1048
+ hb_array_T* children = hb_array_init(8);
897
1049
 
898
1050
  index++;
899
1051
 
@@ -901,8 +1053,14 @@ static size_t process_subsequent_block(
901
1053
 
902
1054
  AST_NODE_T* subsequent_node = create_control_node(erb_node, children, NULL, NULL, type);
903
1055
 
904
- if (index < array_size(array)) {
905
- 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);
906
1064
 
907
1065
  if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
908
1066
  AST_ERB_CONTENT_NODE_T* next_erb = (AST_ERB_CONTENT_NODE_T*) next_node;
@@ -953,19 +1111,19 @@ static size_t process_subsequent_block(
953
1111
 
954
1112
  static size_t process_block_children(
955
1113
  AST_NODE_T* node,
956
- array_T* array,
1114
+ hb_array_T* array,
957
1115
  size_t index,
958
- array_T* children_array,
1116
+ hb_array_T* children_array,
959
1117
  analyze_ruby_context_T* context,
960
1118
  control_type_t parent_type
961
1119
  ) {
962
- while (index < array_size(array)) {
963
- 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);
964
1122
 
965
1123
  if (!child) { break; }
966
1124
 
967
1125
  if (child->type != AST_ERB_CONTENT_NODE) {
968
- array_append(children_array, child);
1126
+ hb_array_append(children_array, child);
969
1127
  index++;
970
1128
  continue;
971
1129
  }
@@ -978,35 +1136,35 @@ static size_t process_block_children(
978
1136
  if (child_type == CONTROL_TYPE_IF || child_type == CONTROL_TYPE_CASE || child_type == CONTROL_TYPE_CASE_MATCH
979
1137
  || child_type == CONTROL_TYPE_BEGIN || child_type == CONTROL_TYPE_UNLESS || child_type == CONTROL_TYPE_WHILE
980
1138
  || child_type == CONTROL_TYPE_UNTIL || child_type == CONTROL_TYPE_FOR || child_type == CONTROL_TYPE_BLOCK) {
981
- array_T* temp_array = array_init(1);
1139
+ hb_array_T* temp_array = hb_array_init(1);
982
1140
  size_t new_index = process_control_structure(node, array, index, temp_array, context, child_type);
983
1141
 
984
- 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_first(temp_array)); }
985
1143
 
986
- array_free(&temp_array);
1144
+ hb_array_free(&temp_array);
987
1145
 
988
1146
  index = new_index;
989
1147
  continue;
990
1148
  }
991
1149
 
992
- array_append(children_array, child);
1150
+ hb_array_append(children_array, child);
993
1151
  index++;
994
1152
  }
995
1153
 
996
1154
  return index;
997
1155
  }
998
1156
 
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));
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));
1001
1159
  size_t index = 0;
1002
1160
 
1003
- while (index < array_size(array)) {
1004
- 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);
1005
1163
 
1006
1164
  if (!item) { break; }
1007
1165
 
1008
1166
  if (item->type != AST_ERB_CONTENT_NODE) {
1009
- array_append(new_array, item);
1167
+ hb_array_append(new_array, item);
1010
1168
  index++;
1011
1169
  continue;
1012
1170
  }
@@ -1028,12 +1186,13 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1028
1186
  continue;
1029
1187
 
1030
1188
  case CONTROL_TYPE_YIELD: {
1031
- 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);
1032
1190
 
1033
1191
  if (yield_node) {
1034
- array_append(new_array, yield_node);
1192
+ ast_node_free((AST_NODE_T*) erb_node);
1193
+ hb_array_append(new_array, yield_node);
1035
1194
  } else {
1036
- array_append(new_array, item);
1195
+ hb_array_append(new_array, item);
1037
1196
  }
1038
1197
 
1039
1198
  index++;
@@ -1041,7 +1200,7 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1041
1200
  }
1042
1201
 
1043
1202
  default:
1044
- array_append(new_array, item);
1203
+ hb_array_append(new_array, item);
1045
1204
  index++;
1046
1205
  break;
1047
1206
  }
@@ -1050,41 +1209,178 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
1050
1209
  return new_array;
1051
1210
  }
1052
1211
 
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;
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
+ }
1270
+
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;
1056
1338
 
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);
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
+ }
1062
1352
  }
1063
1353
 
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);
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);
1069
1358
  }
1070
1359
 
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);
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;
1076
1369
  }
1077
1370
 
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);
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;
1083
1376
  }
1084
1377
 
1085
- herb_visit_child_nodes(node, transform_erb_nodes, data);
1378
+ bool result = true;
1086
1379
 
1087
- return false;
1380
+ if (is_loop_node) { context->loop_depth--; }
1381
+ if (is_begin_node) { context->rescue_depth--; }
1382
+
1383
+ return result;
1088
1384
  }
1089
1385
 
1090
1386
  void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source) {
@@ -1093,19 +1389,31 @@ void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source)
1093
1389
  analyze_ruby_context_T* context = malloc(sizeof(analyze_ruby_context_T));
1094
1390
  context->document = document;
1095
1391
  context->parent = NULL;
1096
- context->ruby_context_stack = array_init(8);
1392
+ context->ruby_context_stack = hb_array_init(8);
1097
1393
 
1098
1394
  herb_visit_node((AST_NODE_T*) document, transform_erb_nodes, context);
1099
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
+
1100
1402
  herb_analyze_parse_errors(document, source);
1101
1403
 
1102
- 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
+
1103
1408
  free(context);
1409
+ free(invalid_context);
1104
1410
  }
1105
1411
 
1106
1412
  void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source) {
1107
1413
  char* extracted_ruby = herb_extract_ruby_with_semicolons(source);
1108
1414
 
1415
+ if (!extracted_ruby) { return; }
1416
+
1109
1417
  pm_parser_t parser;
1110
1418
  pm_options_t options = { 0, .partial_script = true };
1111
1419
  pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
@@ -1116,7 +1424,7 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source
1116
1424
  error = (const pm_diagnostic_t*) error->node.next) {
1117
1425
 
1118
1426
  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);
1427
+ hb_array_append(document->base.errors, parse_error);
1120
1428
  }
1121
1429
 
1122
1430
  pm_node_destroy(&parser, root);