herb 0.7.5 → 0.8.0

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