herb 0.8.6-x86_64-linux-gnu → 0.8.8-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.
- checksums.yaml +4 -4
- data/Rakefile +7 -0
- data/config.yml +12 -0
- data/ext/herb/error_helpers.c +1 -1
- data/ext/herb/extconf.rb +0 -4
- data/ext/herb/extension_helpers.c +1 -1
- data/ext/herb/nodes.c +18 -10
- data/lib/herb/3.0/herb.so +0 -0
- data/lib/herb/3.1/herb.so +0 -0
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/4.0/herb.so +0 -0
- data/lib/herb/ast/nodes.rb +32 -8
- data/lib/herb/engine/debug_visitor.rb +1 -1
- data/lib/herb/version.rb +1 -1
- data/lib/herb.rb +30 -3
- data/sig/herb/ast/nodes.rbs +16 -8
- data/sig/serialized_ast_nodes.rbs +4 -0
- data/src/analyze.c +137 -42
- data/src/analyze_helpers.c +80 -12
- data/src/analyzed_ruby.c +1 -0
- data/src/ast_node.c +1 -1
- data/src/ast_nodes.c +65 -161
- data/src/ast_pretty_print.c +52 -0
- data/src/errors.c +5 -5
- data/src/extract.c +2 -2
- data/src/herb.c +2 -2
- data/src/include/analyze_helpers.h +7 -0
- data/src/include/analyzed_ruby.h +1 -0
- data/src/include/ast_nodes.h +8 -4
- data/src/include/location.h +4 -0
- data/src/include/prism_helpers.h +6 -0
- data/src/include/util/hb_narray.h +1 -0
- data/src/include/version.h +1 -1
- data/src/location.c +16 -0
- data/src/parser.c +9 -9
- data/src/parser_helpers.c +4 -4
- data/src/pretty_print.c +6 -6
- data/src/prism_helpers.c +188 -0
- data/src/util/hb_array.c +1 -0
- data/src/util/hb_narray.c +6 -0
- data/src/visitor.c +26 -26
- data/templates/ext/herb/error_helpers.c.erb +1 -1
- data/templates/ext/herb/nodes.c.erb +3 -1
- data/templates/java/error_helpers.c.erb +1 -1
- data/templates/java/nodes.c.erb +5 -3
- data/templates/java/org/herb/ast/Nodes.java.erb +11 -0
- data/templates/javascript/packages/core/src/nodes.ts.erb +14 -0
- data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +1 -1
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +10 -1
- data/templates/lib/herb/ast/nodes.rb.erb +4 -0
- data/templates/rust/src/ast/nodes.rs.erb +12 -2
- data/templates/rust/src/nodes.rs.erb +4 -0
- data/templates/src/ast_nodes.c.erb +7 -7
- data/templates/src/ast_pretty_print.c.erb +14 -0
- data/templates/src/errors.c.erb +5 -5
- data/templates/src/visitor.c.erb +1 -1
- data/templates/template.rb +11 -0
- data/templates/wasm/error_helpers.cpp.erb +1 -1
- data/templates/wasm/nodes.cpp.erb +7 -1
- data/vendor/prism/include/prism/version.h +2 -2
- data/vendor/prism/src/prism.c +48 -27
- data/vendor/prism/templates/java/org/prism/Loader.java.erb +1 -1
- data/vendor/prism/templates/javascript/src/deserialize.js.erb +1 -1
- data/vendor/prism/templates/lib/prism/compiler.rb.erb +2 -2
- data/vendor/prism/templates/lib/prism/node.rb.erb +24 -1
- data/vendor/prism/templates/lib/prism/serialize.rb.erb +1 -1
- data/vendor/prism/templates/lib/prism/visitor.rb.erb +2 -2
- data/vendor/prism/templates/sig/prism/node.rbs.erb +1 -0
- metadata +2 -2
data/src/analyze.c
CHANGED
|
@@ -43,6 +43,7 @@ static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source) {
|
|
|
43
43
|
search_rescue_nodes(analyzed);
|
|
44
44
|
search_ensure_nodes(analyzed);
|
|
45
45
|
search_yield_nodes(analyzed->root, analyzed);
|
|
46
|
+
search_then_keywords(analyzed->root, analyzed);
|
|
46
47
|
search_block_closing_nodes(analyzed);
|
|
47
48
|
|
|
48
49
|
if (!analyzed->valid) { pm_visit_node(analyzed->root, search_unclosed_control_flows, analyzed); }
|
|
@@ -112,6 +113,14 @@ typedef struct {
|
|
|
112
113
|
const uint8_t* source_start;
|
|
113
114
|
} location_walker_context_t;
|
|
114
115
|
|
|
116
|
+
static bool control_type_is_block(control_type_t type) {
|
|
117
|
+
return type == CONTROL_TYPE_BLOCK;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static bool control_type_is_yield(control_type_t type) {
|
|
121
|
+
return type == CONTROL_TYPE_YIELD;
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* data) {
|
|
116
125
|
if (!node) { return true; }
|
|
117
126
|
|
|
@@ -194,14 +203,12 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
|
|
|
194
203
|
|
|
195
204
|
if (call->block != NULL && call->block->type == PM_BLOCK_NODE) {
|
|
196
205
|
pm_block_node_t* block_node = (pm_block_node_t*) call->block;
|
|
197
|
-
|
|
198
|
-
bool has_do_opening =
|
|
199
|
-
|
|
200
|
-
bool
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (has_do_opening || (has_brace_opening && !has_closing_location)) {
|
|
206
|
+
|
|
207
|
+
bool has_do_opening = is_do_block(block_node->opening_loc);
|
|
208
|
+
bool has_brace_opening = is_brace_block(block_node->opening_loc);
|
|
209
|
+
bool has_valid_brace_closing = is_closing_brace(block_node->closing_loc);
|
|
210
|
+
|
|
211
|
+
if (has_do_opening || (has_brace_opening && !has_valid_brace_closing)) {
|
|
205
212
|
current_type = CONTROL_TYPE_BLOCK;
|
|
206
213
|
keyword_offset = (uint32_t) (node->location.start - context->source_start);
|
|
207
214
|
}
|
|
@@ -221,7 +228,17 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da
|
|
|
221
228
|
}
|
|
222
229
|
|
|
223
230
|
if (keyword_offset != UINT32_MAX) {
|
|
224
|
-
|
|
231
|
+
bool should_update = !result->found;
|
|
232
|
+
|
|
233
|
+
if (result->found) {
|
|
234
|
+
if (control_type_is_block(current_type) && control_type_is_yield(result->type)) {
|
|
235
|
+
should_update = true;
|
|
236
|
+
} else if (!(control_type_is_yield(current_type) && control_type_is_block(result->type))) {
|
|
237
|
+
should_update = keyword_offset < result->offset;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (should_update) {
|
|
225
242
|
result->type = current_type;
|
|
226
243
|
result->offset = keyword_offset;
|
|
227
244
|
result->found = true;
|
|
@@ -308,7 +325,7 @@ static AST_NODE_T* create_control_node(
|
|
|
308
325
|
|
|
309
326
|
if (end_node) {
|
|
310
327
|
end_position = end_node->base.location.end;
|
|
311
|
-
} else if (children
|
|
328
|
+
} else if (hb_array_size(children) > 0) {
|
|
312
329
|
AST_NODE_T* last_child = hb_array_last(children);
|
|
313
330
|
end_position = last_child->location.end;
|
|
314
331
|
} else if (subsequent) {
|
|
@@ -319,6 +336,34 @@ static AST_NODE_T* create_control_node(
|
|
|
319
336
|
token_T* content = erb_node->content;
|
|
320
337
|
token_T* tag_closing = erb_node->tag_closing;
|
|
321
338
|
|
|
339
|
+
location_T* then_keyword = NULL;
|
|
340
|
+
|
|
341
|
+
if (control_type == CONTROL_TYPE_IF || control_type == CONTROL_TYPE_ELSIF || control_type == CONTROL_TYPE_UNLESS
|
|
342
|
+
|| control_type == CONTROL_TYPE_WHEN || control_type == CONTROL_TYPE_IN) {
|
|
343
|
+
const char* source = content ? content->value : NULL;
|
|
344
|
+
|
|
345
|
+
if (control_type == CONTROL_TYPE_WHEN || control_type == CONTROL_TYPE_IN) {
|
|
346
|
+
if (source != NULL && strstr(source, "then") != NULL) {
|
|
347
|
+
then_keyword = get_then_keyword_location_wrapped(source, control_type == CONTROL_TYPE_IN);
|
|
348
|
+
}
|
|
349
|
+
} else if (control_type == CONTROL_TYPE_ELSIF) {
|
|
350
|
+
if (source != NULL && strstr(source, "then") != NULL) {
|
|
351
|
+
then_keyword = get_then_keyword_location_elsif_wrapped(source);
|
|
352
|
+
}
|
|
353
|
+
} else {
|
|
354
|
+
then_keyword = get_then_keyword_location(erb_node->analyzed_ruby, source);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (then_keyword != NULL && content != NULL) {
|
|
358
|
+
position_T content_start = content->location.start;
|
|
359
|
+
|
|
360
|
+
then_keyword->start.line = content_start.line + then_keyword->start.line - 1;
|
|
361
|
+
then_keyword->start.column = content_start.column + then_keyword->start.column;
|
|
362
|
+
then_keyword->end.line = content_start.line + then_keyword->end.line - 1;
|
|
363
|
+
then_keyword->end.column = content_start.column + then_keyword->end.column;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
322
367
|
switch (control_type) {
|
|
323
368
|
case CONTROL_TYPE_IF:
|
|
324
369
|
case CONTROL_TYPE_ELSIF: {
|
|
@@ -326,6 +371,7 @@ static AST_NODE_T* create_control_node(
|
|
|
326
371
|
tag_opening,
|
|
327
372
|
content,
|
|
328
373
|
tag_closing,
|
|
374
|
+
then_keyword,
|
|
329
375
|
children,
|
|
330
376
|
subsequent,
|
|
331
377
|
end_node,
|
|
@@ -350,7 +396,7 @@ static AST_NODE_T* create_control_node(
|
|
|
350
396
|
hb_array_T* in_conditions = hb_array_init(8);
|
|
351
397
|
hb_array_T* non_when_non_in_children = hb_array_init(8);
|
|
352
398
|
|
|
353
|
-
for (size_t i = 0; i < children
|
|
399
|
+
for (size_t i = 0; i < hb_array_size(children); i++) {
|
|
354
400
|
AST_NODE_T* child = hb_array_get(children, i);
|
|
355
401
|
|
|
356
402
|
if (child && child->type == AST_ERB_WHEN_NODE) {
|
|
@@ -364,7 +410,7 @@ static AST_NODE_T* create_control_node(
|
|
|
364
410
|
|
|
365
411
|
hb_array_free(&children);
|
|
366
412
|
|
|
367
|
-
if (in_conditions
|
|
413
|
+
if (hb_array_size(in_conditions) > 0) {
|
|
368
414
|
hb_array_free(&when_conditions);
|
|
369
415
|
|
|
370
416
|
return (AST_NODE_T*) ast_erb_case_match_node_init(
|
|
@@ -398,15 +444,29 @@ static AST_NODE_T* create_control_node(
|
|
|
398
444
|
}
|
|
399
445
|
|
|
400
446
|
case CONTROL_TYPE_WHEN: {
|
|
401
|
-
return (
|
|
402
|
-
|
|
403
|
-
|
|
447
|
+
return (AST_NODE_T*) ast_erb_when_node_init(
|
|
448
|
+
tag_opening,
|
|
449
|
+
content,
|
|
450
|
+
tag_closing,
|
|
451
|
+
then_keyword,
|
|
452
|
+
children,
|
|
453
|
+
start_position,
|
|
454
|
+
end_position,
|
|
455
|
+
errors
|
|
456
|
+
);
|
|
404
457
|
}
|
|
405
458
|
|
|
406
459
|
case CONTROL_TYPE_IN: {
|
|
407
|
-
return (
|
|
408
|
-
|
|
409
|
-
|
|
460
|
+
return (AST_NODE_T*) ast_erb_in_node_init(
|
|
461
|
+
tag_opening,
|
|
462
|
+
content,
|
|
463
|
+
tag_closing,
|
|
464
|
+
then_keyword,
|
|
465
|
+
children,
|
|
466
|
+
start_position,
|
|
467
|
+
end_position,
|
|
468
|
+
errors
|
|
469
|
+
);
|
|
410
470
|
}
|
|
411
471
|
|
|
412
472
|
case CONTROL_TYPE_BEGIN: {
|
|
@@ -471,6 +531,7 @@ static AST_NODE_T* create_control_node(
|
|
|
471
531
|
tag_opening,
|
|
472
532
|
content,
|
|
473
533
|
tag_closing,
|
|
534
|
+
then_keyword,
|
|
474
535
|
children,
|
|
475
536
|
else_clause,
|
|
476
537
|
end_node,
|
|
@@ -560,7 +621,7 @@ static size_t process_control_structure(
|
|
|
560
621
|
hb_array_T* in_conditions = hb_array_init(8);
|
|
561
622
|
hb_array_T* non_when_non_in_children = hb_array_init(8);
|
|
562
623
|
|
|
563
|
-
while (index < array
|
|
624
|
+
while (index < hb_array_size(array)) {
|
|
564
625
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
565
626
|
|
|
566
627
|
if (!next_node) { break; }
|
|
@@ -576,7 +637,7 @@ static size_t process_control_structure(
|
|
|
576
637
|
index++;
|
|
577
638
|
}
|
|
578
639
|
|
|
579
|
-
while (index < array
|
|
640
|
+
while (index < hb_array_size(array)) {
|
|
580
641
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
581
642
|
|
|
582
643
|
if (!next_node) { break; }
|
|
@@ -599,10 +660,27 @@ static size_t process_control_structure(
|
|
|
599
660
|
hb_array_T* when_errors = erb_content->base.errors;
|
|
600
661
|
erb_content->base.errors = NULL;
|
|
601
662
|
|
|
663
|
+
location_T* then_keyword = NULL;
|
|
664
|
+
const char* source = erb_content->content ? erb_content->content->value : NULL;
|
|
665
|
+
|
|
666
|
+
if (source != NULL && strstr(source, "then") != NULL) {
|
|
667
|
+
then_keyword = get_then_keyword_location_wrapped(source, false);
|
|
668
|
+
|
|
669
|
+
if (then_keyword != NULL && erb_content->content != NULL) {
|
|
670
|
+
position_T content_start = erb_content->content->location.start;
|
|
671
|
+
|
|
672
|
+
then_keyword->start.line = content_start.line + then_keyword->start.line - 1;
|
|
673
|
+
then_keyword->start.column = content_start.column + then_keyword->start.column;
|
|
674
|
+
then_keyword->end.line = content_start.line + then_keyword->end.line - 1;
|
|
675
|
+
then_keyword->end.column = content_start.column + then_keyword->end.column;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
602
679
|
AST_ERB_WHEN_NODE_T* when_node = ast_erb_when_node_init(
|
|
603
680
|
erb_content->tag_opening,
|
|
604
681
|
erb_content->content,
|
|
605
682
|
erb_content->tag_closing,
|
|
683
|
+
then_keyword,
|
|
606
684
|
when_statements,
|
|
607
685
|
erb_content->tag_opening->location.start,
|
|
608
686
|
erb_content->tag_closing->location.end,
|
|
@@ -623,10 +701,27 @@ static size_t process_control_structure(
|
|
|
623
701
|
hb_array_T* in_errors = erb_content->base.errors;
|
|
624
702
|
erb_content->base.errors = NULL;
|
|
625
703
|
|
|
704
|
+
location_T* in_then_keyword = NULL;
|
|
705
|
+
const char* in_source = erb_content->content ? erb_content->content->value : NULL;
|
|
706
|
+
|
|
707
|
+
if (in_source != NULL && strstr(in_source, "then") != NULL) {
|
|
708
|
+
in_then_keyword = get_then_keyword_location_wrapped(in_source, true);
|
|
709
|
+
|
|
710
|
+
if (in_then_keyword != NULL && erb_content->content != NULL) {
|
|
711
|
+
position_T content_start = erb_content->content->location.start;
|
|
712
|
+
|
|
713
|
+
in_then_keyword->start.line = content_start.line + in_then_keyword->start.line - 1;
|
|
714
|
+
in_then_keyword->start.column = content_start.column + in_then_keyword->start.column;
|
|
715
|
+
in_then_keyword->end.line = content_start.line + in_then_keyword->end.line - 1;
|
|
716
|
+
in_then_keyword->end.column = content_start.column + in_then_keyword->end.column;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
626
720
|
AST_ERB_IN_NODE_T* in_node = ast_erb_in_node_init(
|
|
627
721
|
erb_content->tag_opening,
|
|
628
722
|
erb_content->content,
|
|
629
723
|
erb_content->tag_closing,
|
|
724
|
+
in_then_keyword,
|
|
630
725
|
in_statements,
|
|
631
726
|
erb_content->tag_opening->location.start,
|
|
632
727
|
erb_content->tag_closing->location.end,
|
|
@@ -648,7 +743,7 @@ static size_t process_control_structure(
|
|
|
648
743
|
|
|
649
744
|
AST_ERB_ELSE_NODE_T* else_clause = NULL;
|
|
650
745
|
|
|
651
|
-
if (index < array
|
|
746
|
+
if (index < hb_array_size(array)) {
|
|
652
747
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
653
748
|
|
|
654
749
|
if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -682,7 +777,7 @@ static size_t process_control_structure(
|
|
|
682
777
|
|
|
683
778
|
AST_ERB_END_NODE_T* end_node = NULL;
|
|
684
779
|
|
|
685
|
-
if (index < array
|
|
780
|
+
if (index < hb_array_size(array)) {
|
|
686
781
|
AST_NODE_T* potential_end = hb_array_get(array, index);
|
|
687
782
|
|
|
688
783
|
if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -715,15 +810,15 @@ static size_t process_control_structure(
|
|
|
715
810
|
end_position = end_node->base.location.end;
|
|
716
811
|
} else if (else_clause) {
|
|
717
812
|
end_position = else_clause->base.location.end;
|
|
718
|
-
} else if (when_conditions
|
|
813
|
+
} else if (hb_array_size(when_conditions) > 0) {
|
|
719
814
|
AST_NODE_T* last_when = hb_array_last(when_conditions);
|
|
720
815
|
end_position = last_when->location.end;
|
|
721
|
-
} else if (in_conditions
|
|
816
|
+
} else if (hb_array_size(in_conditions) > 0) {
|
|
722
817
|
AST_NODE_T* last_in = hb_array_last(in_conditions);
|
|
723
818
|
end_position = last_in->location.end;
|
|
724
819
|
}
|
|
725
820
|
|
|
726
|
-
if (in_conditions
|
|
821
|
+
if (hb_array_size(in_conditions) > 0) {
|
|
727
822
|
hb_array_T* case_match_errors = erb_node->base.errors;
|
|
728
823
|
erb_node->base.errors = NULL;
|
|
729
824
|
|
|
@@ -781,7 +876,7 @@ static size_t process_control_structure(
|
|
|
781
876
|
AST_ERB_ELSE_NODE_T* else_clause = NULL;
|
|
782
877
|
AST_ERB_ENSURE_NODE_T* ensure_clause = NULL;
|
|
783
878
|
|
|
784
|
-
if (index < array
|
|
879
|
+
if (index < hb_array_size(array)) {
|
|
785
880
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
786
881
|
|
|
787
882
|
if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -796,7 +891,7 @@ static size_t process_control_structure(
|
|
|
796
891
|
}
|
|
797
892
|
}
|
|
798
893
|
|
|
799
|
-
if (index < array
|
|
894
|
+
if (index < hb_array_size(array)) {
|
|
800
895
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
801
896
|
|
|
802
897
|
if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -828,7 +923,7 @@ static size_t process_control_structure(
|
|
|
828
923
|
}
|
|
829
924
|
}
|
|
830
925
|
|
|
831
|
-
if (index < array
|
|
926
|
+
if (index < hb_array_size(array)) {
|
|
832
927
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
833
928
|
|
|
834
929
|
if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -840,7 +935,7 @@ static size_t process_control_structure(
|
|
|
840
935
|
|
|
841
936
|
index++;
|
|
842
937
|
|
|
843
|
-
while (index < array
|
|
938
|
+
while (index < hb_array_size(array)) {
|
|
844
939
|
AST_NODE_T* child = hb_array_get(array, index);
|
|
845
940
|
|
|
846
941
|
if (!child) { break; }
|
|
@@ -876,7 +971,7 @@ static size_t process_control_structure(
|
|
|
876
971
|
|
|
877
972
|
AST_ERB_END_NODE_T* end_node = NULL;
|
|
878
973
|
|
|
879
|
-
if (index < array
|
|
974
|
+
if (index < hb_array_size(array)) {
|
|
880
975
|
AST_NODE_T* potential_end = hb_array_get(array, index);
|
|
881
976
|
|
|
882
977
|
if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -943,7 +1038,7 @@ static size_t process_control_structure(
|
|
|
943
1038
|
|
|
944
1039
|
AST_ERB_END_NODE_T* end_node = NULL;
|
|
945
1040
|
|
|
946
|
-
if (index < array
|
|
1041
|
+
if (index < hb_array_size(array)) {
|
|
947
1042
|
AST_NODE_T* potential_close = hb_array_get(array, index);
|
|
948
1043
|
|
|
949
1044
|
if (potential_close && potential_close->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -975,7 +1070,7 @@ static size_t process_control_structure(
|
|
|
975
1070
|
|
|
976
1071
|
if (end_node) {
|
|
977
1072
|
end_position = end_node->base.location.end;
|
|
978
|
-
} else if (children
|
|
1073
|
+
} else if (hb_array_size(children) > 0) {
|
|
979
1074
|
AST_NODE_T* last_child = hb_array_last(children);
|
|
980
1075
|
end_position = last_child->location.end;
|
|
981
1076
|
}
|
|
@@ -1005,7 +1100,7 @@ static size_t process_control_structure(
|
|
|
1005
1100
|
AST_NODE_T* subsequent = NULL;
|
|
1006
1101
|
AST_ERB_END_NODE_T* end_node = NULL;
|
|
1007
1102
|
|
|
1008
|
-
if (index < array
|
|
1103
|
+
if (index < hb_array_size(array)) {
|
|
1009
1104
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
1010
1105
|
|
|
1011
1106
|
if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -1018,7 +1113,7 @@ static size_t process_control_structure(
|
|
|
1018
1113
|
}
|
|
1019
1114
|
}
|
|
1020
1115
|
|
|
1021
|
-
if (index < array
|
|
1116
|
+
if (index < hb_array_size(array)) {
|
|
1022
1117
|
AST_NODE_T* potential_end = hb_array_get(array, index);
|
|
1023
1118
|
|
|
1024
1119
|
if (potential_end && potential_end->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -1080,7 +1175,7 @@ static size_t process_subsequent_block(
|
|
|
1080
1175
|
hb_array_free(&children);
|
|
1081
1176
|
}
|
|
1082
1177
|
|
|
1083
|
-
if (index < array
|
|
1178
|
+
if (index < hb_array_size(array)) {
|
|
1084
1179
|
AST_NODE_T* next_node = hb_array_get(array, index);
|
|
1085
1180
|
|
|
1086
1181
|
if (next_node && next_node->type == AST_ERB_CONTENT_NODE) {
|
|
@@ -1138,7 +1233,7 @@ static size_t process_block_children(
|
|
|
1138
1233
|
analyze_ruby_context_T* context,
|
|
1139
1234
|
control_type_t parent_type
|
|
1140
1235
|
) {
|
|
1141
|
-
while (index < array
|
|
1236
|
+
while (index < hb_array_size(array)) {
|
|
1142
1237
|
AST_NODE_T* child = hb_array_get(array, index);
|
|
1143
1238
|
|
|
1144
1239
|
if (!child) { break; }
|
|
@@ -1160,7 +1255,7 @@ static size_t process_block_children(
|
|
|
1160
1255
|
hb_array_T* temp_array = hb_array_init(1);
|
|
1161
1256
|
size_t new_index = process_control_structure(node, array, index, temp_array, context, child_type);
|
|
1162
1257
|
|
|
1163
|
-
if (temp_array
|
|
1258
|
+
if (hb_array_size(temp_array) > 0) { hb_array_append(children_array, hb_array_first(temp_array)); }
|
|
1164
1259
|
|
|
1165
1260
|
hb_array_free(&temp_array);
|
|
1166
1261
|
|
|
@@ -1176,10 +1271,10 @@ static size_t process_block_children(
|
|
|
1176
1271
|
}
|
|
1177
1272
|
|
|
1178
1273
|
hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby_context_T* context) {
|
|
1179
|
-
hb_array_T* new_array = hb_array_init(array
|
|
1274
|
+
hb_array_T* new_array = hb_array_init(hb_array_size(array));
|
|
1180
1275
|
size_t index = 0;
|
|
1181
1276
|
|
|
1182
|
-
while (index < array
|
|
1277
|
+
while (index < hb_array_size(array)) {
|
|
1183
1278
|
AST_NODE_T* item = hb_array_get(array, index);
|
|
1184
1279
|
|
|
1185
1280
|
if (!item) { break; }
|
|
@@ -1314,7 +1409,7 @@ static bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data) {
|
|
|
1314
1409
|
if (if_node->end_node == NULL) { check_erb_node_for_missing_end(node); }
|
|
1315
1410
|
|
|
1316
1411
|
if (if_node->statements != NULL) {
|
|
1317
|
-
for (size_t i = 0; i < if_node->statements
|
|
1412
|
+
for (size_t i = 0; i < hb_array_size(if_node->statements); i++) {
|
|
1318
1413
|
AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(if_node->statements, i);
|
|
1319
1414
|
|
|
1320
1415
|
if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
|
|
@@ -1346,7 +1441,7 @@ static bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data) {
|
|
|
1346
1441
|
const AST_ERB_IF_NODE_T* elsif_node = (const AST_ERB_IF_NODE_T*) subsequent;
|
|
1347
1442
|
|
|
1348
1443
|
if (elsif_node->statements != NULL) {
|
|
1349
|
-
for (size_t i = 0; i < elsif_node->statements
|
|
1444
|
+
for (size_t i = 0; i < hb_array_size(elsif_node->statements); i++) {
|
|
1350
1445
|
AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(elsif_node->statements, i);
|
|
1351
1446
|
|
|
1352
1447
|
if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
|
|
@@ -1358,7 +1453,7 @@ static bool detect_invalid_erb_structures(const AST_NODE_T* node, void* data) {
|
|
|
1358
1453
|
const AST_ERB_ELSE_NODE_T* else_node = (const AST_ERB_ELSE_NODE_T*) subsequent;
|
|
1359
1454
|
|
|
1360
1455
|
if (else_node->statements != NULL) {
|
|
1361
|
-
for (size_t i = 0; i < else_node->statements
|
|
1456
|
+
for (size_t i = 0; i < hb_array_size(else_node->statements); i++) {
|
|
1362
1457
|
AST_NODE_T* statement = (AST_NODE_T*) hb_array_get(else_node->statements, i);
|
|
1363
1458
|
|
|
1364
1459
|
if (statement != NULL) { herb_visit_node(statement, detect_invalid_erb_structures, context); }
|
data/src/analyze_helpers.c
CHANGED
|
@@ -76,6 +76,10 @@ bool has_yield_node(analyzed_ruby_T* analyzed) {
|
|
|
76
76
|
return analyzed->yield_node_count > 0;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
bool has_then_keyword(analyzed_ruby_T* analyzed) {
|
|
80
|
+
return analyzed->then_keyword_count > 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
79
83
|
bool has_error_message(analyzed_ruby_T* anlayzed, const char* message) {
|
|
80
84
|
for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) anlayzed->parser.error_list.head; error != NULL;
|
|
81
85
|
error = (const pm_diagnostic_t*) error->node.next) {
|
|
@@ -102,13 +106,13 @@ bool search_if_nodes(const pm_node_t* node, void* data) {
|
|
|
102
106
|
return false;
|
|
103
107
|
}
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
bool is_do_block(pm_location_t opening_location) {
|
|
106
110
|
size_t length = opening_location.end - opening_location.start;
|
|
107
111
|
|
|
108
112
|
return length == 2 && opening_location.start[0] == 'd' && opening_location.start[1] == 'o';
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
|
|
115
|
+
bool is_brace_block(pm_location_t opening_location) {
|
|
112
116
|
size_t length = opening_location.end - opening_location.start;
|
|
113
117
|
|
|
114
118
|
return length == 1 && opening_location.start[0] == '{';
|
|
@@ -118,6 +122,32 @@ static bool has_location(pm_location_t location) {
|
|
|
118
122
|
return location.start != NULL && location.end != NULL && (location.end - location.start) > 0;
|
|
119
123
|
}
|
|
120
124
|
|
|
125
|
+
static bool is_end_keyword(pm_location_t location) {
|
|
126
|
+
if (location.start == NULL || location.end == NULL) { return false; }
|
|
127
|
+
|
|
128
|
+
size_t length = location.end - location.start;
|
|
129
|
+
|
|
130
|
+
return length == 3 && location.start[0] == 'e' && location.start[1] == 'n' && location.start[2] == 'd';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
bool is_closing_brace(pm_location_t location) {
|
|
134
|
+
if (location.start == NULL || location.end == NULL) { return false; }
|
|
135
|
+
|
|
136
|
+
size_t length = location.end - location.start;
|
|
137
|
+
|
|
138
|
+
return length == 1 && location.start[0] == '}';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc) {
|
|
142
|
+
if (is_do_block(opening_loc)) {
|
|
143
|
+
return is_end_keyword(closing_loc);
|
|
144
|
+
} else if (is_brace_block(opening_loc)) {
|
|
145
|
+
return is_closing_brace(closing_loc);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
121
151
|
bool search_block_nodes(const pm_node_t* node, void* data) {
|
|
122
152
|
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
123
153
|
|
|
@@ -125,7 +155,7 @@ bool search_block_nodes(const pm_node_t* node, void* data) {
|
|
|
125
155
|
pm_block_node_t* block_node = (pm_block_node_t*) node;
|
|
126
156
|
|
|
127
157
|
bool has_opening = is_do_block(block_node->opening_loc) || is_brace_block(block_node->opening_loc);
|
|
128
|
-
bool is_unclosed = !
|
|
158
|
+
bool is_unclosed = !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc);
|
|
129
159
|
|
|
130
160
|
if (has_opening && is_unclosed) { analyzed->block_node_count++; }
|
|
131
161
|
}
|
|
@@ -299,6 +329,42 @@ bool search_yield_nodes(const pm_node_t* node, void* data) {
|
|
|
299
329
|
return false;
|
|
300
330
|
}
|
|
301
331
|
|
|
332
|
+
bool search_then_keywords(const pm_node_t* node, void* data) {
|
|
333
|
+
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
334
|
+
|
|
335
|
+
switch (node->type) {
|
|
336
|
+
case PM_IF_NODE: {
|
|
337
|
+
const pm_if_node_t* if_node = (const pm_if_node_t*) node;
|
|
338
|
+
if (if_node->then_keyword_loc.start != NULL && if_node->then_keyword_loc.end != NULL) {
|
|
339
|
+
analyzed->then_keyword_count++;
|
|
340
|
+
}
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
case PM_UNLESS_NODE: {
|
|
345
|
+
const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
|
|
346
|
+
if (unless_node->then_keyword_loc.start != NULL && unless_node->then_keyword_loc.end != NULL) {
|
|
347
|
+
analyzed->then_keyword_count++;
|
|
348
|
+
}
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
case PM_WHEN_NODE: {
|
|
353
|
+
const pm_when_node_t* when_node = (const pm_when_node_t*) node;
|
|
354
|
+
if (when_node->then_keyword_loc.start != NULL && when_node->then_keyword_loc.end != NULL) {
|
|
355
|
+
analyzed->then_keyword_count++;
|
|
356
|
+
}
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
default: break;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
pm_visit_child_nodes(node, search_then_keywords, analyzed);
|
|
364
|
+
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
|
|
302
368
|
static bool is_postfix_conditional(const pm_statements_node_t* statements, pm_location_t keyword_location) {
|
|
303
369
|
if (statements == NULL) { return false; }
|
|
304
370
|
|
|
@@ -314,7 +380,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
314
380
|
case PM_IF_NODE: {
|
|
315
381
|
const pm_if_node_t* if_node = (const pm_if_node_t*) node;
|
|
316
382
|
|
|
317
|
-
if (has_location(if_node->if_keyword_loc) && !
|
|
383
|
+
if (has_location(if_node->if_keyword_loc) && !is_end_keyword(if_node->end_keyword_loc)) {
|
|
318
384
|
if (!is_postfix_conditional(if_node->statements, if_node->if_keyword_loc)) {
|
|
319
385
|
analyzed->unclosed_control_flow_count++;
|
|
320
386
|
}
|
|
@@ -326,7 +392,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
326
392
|
case PM_UNLESS_NODE: {
|
|
327
393
|
const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
|
|
328
394
|
|
|
329
|
-
if (has_location(unless_node->keyword_loc) && !
|
|
395
|
+
if (has_location(unless_node->keyword_loc) && !is_end_keyword(unless_node->end_keyword_loc)) {
|
|
330
396
|
if (!is_postfix_conditional(unless_node->statements, unless_node->keyword_loc)) {
|
|
331
397
|
analyzed->unclosed_control_flow_count++;
|
|
332
398
|
}
|
|
@@ -338,7 +404,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
338
404
|
case PM_CASE_NODE: {
|
|
339
405
|
const pm_case_node_t* case_node = (const pm_case_node_t*) node;
|
|
340
406
|
|
|
341
|
-
if (has_location(case_node->case_keyword_loc) && !
|
|
407
|
+
if (has_location(case_node->case_keyword_loc) && !is_end_keyword(case_node->end_keyword_loc)) {
|
|
342
408
|
analyzed->unclosed_control_flow_count++;
|
|
343
409
|
}
|
|
344
410
|
|
|
@@ -348,7 +414,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
348
414
|
case PM_CASE_MATCH_NODE: {
|
|
349
415
|
const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
|
|
350
416
|
|
|
351
|
-
if (has_location(case_match_node->case_keyword_loc) && !
|
|
417
|
+
if (has_location(case_match_node->case_keyword_loc) && !is_end_keyword(case_match_node->end_keyword_loc)) {
|
|
352
418
|
analyzed->unclosed_control_flow_count++;
|
|
353
419
|
}
|
|
354
420
|
|
|
@@ -358,7 +424,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
358
424
|
case PM_WHILE_NODE: {
|
|
359
425
|
const pm_while_node_t* while_node = (const pm_while_node_t*) node;
|
|
360
426
|
|
|
361
|
-
if (has_location(while_node->keyword_loc) && !
|
|
427
|
+
if (has_location(while_node->keyword_loc) && !is_end_keyword(while_node->closing_loc)) {
|
|
362
428
|
analyzed->unclosed_control_flow_count++;
|
|
363
429
|
}
|
|
364
430
|
|
|
@@ -368,7 +434,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
368
434
|
case PM_UNTIL_NODE: {
|
|
369
435
|
const pm_until_node_t* until_node = (const pm_until_node_t*) node;
|
|
370
436
|
|
|
371
|
-
if (has_location(until_node->keyword_loc) && !
|
|
437
|
+
if (has_location(until_node->keyword_loc) && !is_end_keyword(until_node->closing_loc)) {
|
|
372
438
|
analyzed->unclosed_control_flow_count++;
|
|
373
439
|
}
|
|
374
440
|
|
|
@@ -378,7 +444,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
378
444
|
case PM_FOR_NODE: {
|
|
379
445
|
const pm_for_node_t* for_node = (const pm_for_node_t*) node;
|
|
380
446
|
|
|
381
|
-
if (has_location(for_node->for_keyword_loc) && !
|
|
447
|
+
if (has_location(for_node->for_keyword_loc) && !is_end_keyword(for_node->end_keyword_loc)) {
|
|
382
448
|
analyzed->unclosed_control_flow_count++;
|
|
383
449
|
}
|
|
384
450
|
|
|
@@ -388,7 +454,7 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
388
454
|
case PM_BEGIN_NODE: {
|
|
389
455
|
const pm_begin_node_t* begin_node = (const pm_begin_node_t*) node;
|
|
390
456
|
|
|
391
|
-
if (has_location(begin_node->begin_keyword_loc) && !
|
|
457
|
+
if (has_location(begin_node->begin_keyword_loc) && !is_end_keyword(begin_node->end_keyword_loc)) {
|
|
392
458
|
analyzed->unclosed_control_flow_count++;
|
|
393
459
|
}
|
|
394
460
|
|
|
@@ -399,7 +465,9 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
399
465
|
const pm_block_node_t* block_node = (const pm_block_node_t*) node;
|
|
400
466
|
bool has_opening = is_do_block(block_node->opening_loc) || is_brace_block(block_node->opening_loc);
|
|
401
467
|
|
|
402
|
-
if (has_opening && !
|
|
468
|
+
if (has_opening && !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc)) {
|
|
469
|
+
analyzed->unclosed_control_flow_count++;
|
|
470
|
+
}
|
|
403
471
|
break;
|
|
404
472
|
}
|
|
405
473
|
|
data/src/analyzed_ruby.c
CHANGED
|
@@ -30,6 +30,7 @@ analyzed_ruby_T* init_analyzed_ruby(hb_string_T source) {
|
|
|
30
30
|
analyzed->ensure_node_count = 0;
|
|
31
31
|
analyzed->unless_node_count = 0;
|
|
32
32
|
analyzed->yield_node_count = 0;
|
|
33
|
+
analyzed->then_keyword_count = 0;
|
|
33
34
|
analyzed->unclosed_control_flow_count = 0;
|
|
34
35
|
|
|
35
36
|
return analyzed;
|
data/src/ast_node.c
CHANGED