herb 0.9.3-arm-linux-gnu → 0.9.5-arm-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/config.yml +57 -21
- data/ext/herb/nodes.c +93 -55
- 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 +212 -78
- data/lib/herb/engine/compiler.rb +52 -26
- data/lib/herb/engine.rb +3 -0
- data/lib/herb/project.rb +58 -17
- data/lib/herb/version.rb +1 -1
- data/lib/herb/visitor.rb +8 -2
- data/sig/herb/ast/nodes.rbs +85 -34
- data/sig/herb/engine/compiler.rbs +16 -0
- data/sig/herb/engine.rbs +3 -0
- data/sig/herb/visitor.rbs +5 -2
- data/sig/serialized_ast_nodes.rbs +20 -9
- data/src/analyze/action_view/javascript_tag.c +38 -0
- data/src/analyze/action_view/tag_helper_node_builders.c +23 -2
- data/src/analyze/action_view/tag_helpers.c +53 -14
- data/src/analyze/analyze.c +23 -3
- data/src/analyze/analyze_helpers.c +406 -0
- data/src/analyze/builders.c +1 -0
- data/src/analyze/missing_end.c +16 -0
- data/src/analyze/parse_errors.c +43 -1
- data/src/analyze/render_nodes.c +231 -35
- data/src/analyze/strict_locals.c +22 -324
- data/src/analyze/transform.c +23 -2
- data/src/ast/ast_nodes.c +114 -57
- data/src/ast/ast_pretty_print.c +109 -25
- data/src/include/analyze/action_view/tag_helper_handler.h +3 -0
- data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
- data/src/include/analyze/analyze.h +6 -1
- data/src/include/analyze/helpers.h +18 -0
- data/src/include/ast/ast_nodes.h +27 -13
- data/src/include/version.h +1 -1
- data/src/parser/match_tags.c +37 -6
- data/src/parser.c +8 -0
- data/src/visitor.c +50 -7
- metadata +1 -1
|
@@ -639,7 +639,15 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
639
639
|
id_is_ruby_expression ? create_html_attribute_with_ruby_literal("id", id_value, id_start, id_end, allocator)
|
|
640
640
|
: create_html_attribute_node("id", id_value, id_start, id_end, allocator);
|
|
641
641
|
|
|
642
|
-
if (id_attribute) {
|
|
642
|
+
if (id_attribute) {
|
|
643
|
+
AST_NODE_T* src_node = remove_attribute_by_name(attributes, "src");
|
|
644
|
+
AST_NODE_T* target_node = remove_attribute_by_name(attributes, "target");
|
|
645
|
+
|
|
646
|
+
hb_array_append(attributes, (AST_NODE_T*) id_attribute);
|
|
647
|
+
|
|
648
|
+
if (src_node) { hb_array_append(attributes, src_node); }
|
|
649
|
+
if (target_node) { hb_array_append(attributes, target_node); }
|
|
650
|
+
}
|
|
643
651
|
|
|
644
652
|
hb_allocator_dealloc(allocator, id_value);
|
|
645
653
|
}
|
|
@@ -679,7 +687,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
679
687
|
? create_html_attribute_node("src", source_attribute_value, source_start, source_end, allocator)
|
|
680
688
|
: create_html_attribute_with_ruby_literal("src", source_attribute_value, source_start, source_end, allocator);
|
|
681
689
|
|
|
682
|
-
if (source_attribute) {
|
|
690
|
+
if (source_attribute) { hb_array_append(attributes, (AST_NODE_T*) source_attribute); }
|
|
683
691
|
|
|
684
692
|
if (source_attribute_value != source_value) { hb_allocator_dealloc(allocator, source_attribute_value); }
|
|
685
693
|
hb_allocator_dealloc(allocator, source_value);
|
|
@@ -723,7 +731,7 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
723
731
|
? create_html_attribute_node("src", source_attribute_value, source_start, source_end, allocator)
|
|
724
732
|
: create_html_attribute_with_ruby_literal("src", source_attribute_value, source_start, source_end, allocator);
|
|
725
733
|
|
|
726
|
-
if (source_attribute) {
|
|
734
|
+
if (source_attribute) { hb_array_append(attributes, (AST_NODE_T*) source_attribute); }
|
|
727
735
|
if (source_attribute_value != source_value) { hb_allocator_dealloc(allocator, source_attribute_value); }
|
|
728
736
|
|
|
729
737
|
hb_allocator_dealloc(allocator, source_value);
|
|
@@ -798,14 +806,37 @@ static AST_NODE_T* transform_tag_helper_with_attributes(
|
|
|
798
806
|
);
|
|
799
807
|
}
|
|
800
808
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
+
if (string_equals(handler->name, "javascript_tag")) {
|
|
810
|
+
hb_array_T* cdata_children = hb_array_init(1, allocator);
|
|
811
|
+
|
|
812
|
+
append_body_content_node(
|
|
813
|
+
cdata_children,
|
|
814
|
+
helper_content,
|
|
815
|
+
content_is_ruby_expression,
|
|
816
|
+
erb_node->base.location.start,
|
|
817
|
+
erb_node->base.location.end,
|
|
818
|
+
allocator
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
AST_CDATA_NODE_T* cdata_node = create_javascript_cdata_node(
|
|
822
|
+
cdata_children,
|
|
823
|
+
erb_node->base.location.start,
|
|
824
|
+
erb_node->base.location.end,
|
|
825
|
+
allocator
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
if (cdata_node) { hb_array_append(body, (AST_NODE_T*) cdata_node); }
|
|
829
|
+
} else {
|
|
830
|
+
append_body_content_node(
|
|
831
|
+
body,
|
|
832
|
+
helper_content,
|
|
833
|
+
content_is_ruby_expression,
|
|
834
|
+
erb_node->base.location.start,
|
|
835
|
+
erb_node->base.location.end,
|
|
836
|
+
allocator
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
|
|
809
840
|
hb_allocator_dealloc(allocator, helper_content);
|
|
810
841
|
}
|
|
811
842
|
|
|
@@ -1117,7 +1148,7 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
|
|
|
1117
1148
|
AST_HTML_ATTRIBUTE_NODE_T* href_attribute =
|
|
1118
1149
|
create_href_attribute(href, href_is_ruby_expression, href_start, href_end, allocator);
|
|
1119
1150
|
|
|
1120
|
-
if (href_attribute) {
|
|
1151
|
+
if (href_attribute) { hb_array_append(attributes, (AST_NODE_T*) href_attribute); }
|
|
1121
1152
|
|
|
1122
1153
|
hb_allocator_dealloc(allocator, href);
|
|
1123
1154
|
}
|
|
@@ -1138,7 +1169,15 @@ static AST_NODE_T* transform_erb_block_to_tag_helper(
|
|
|
1138
1169
|
id_is_ruby_expression ? create_html_attribute_with_ruby_literal("id", id_value, id_start, id_end, allocator)
|
|
1139
1170
|
: create_html_attribute_node("id", id_value, id_start, id_end, allocator);
|
|
1140
1171
|
|
|
1141
|
-
if (id_attribute) {
|
|
1172
|
+
if (id_attribute) {
|
|
1173
|
+
AST_NODE_T* src_node = remove_attribute_by_name(attributes, "src");
|
|
1174
|
+
AST_NODE_T* target_node = remove_attribute_by_name(attributes, "target");
|
|
1175
|
+
|
|
1176
|
+
hb_array_append(attributes, (AST_NODE_T*) id_attribute);
|
|
1177
|
+
|
|
1178
|
+
if (src_node) { hb_array_append(attributes, src_node); }
|
|
1179
|
+
if (target_node) { hb_array_append(attributes, target_node); }
|
|
1180
|
+
}
|
|
1142
1181
|
|
|
1143
1182
|
hb_allocator_dealloc(allocator, id_value);
|
|
1144
1183
|
}
|
|
@@ -1395,7 +1434,7 @@ static AST_NODE_T* transform_link_to_helper(
|
|
|
1395
1434
|
AST_HTML_ATTRIBUTE_NODE_T* href_attribute =
|
|
1396
1435
|
create_href_attribute(href, href_is_ruby_expression, href_start, href_end, allocator);
|
|
1397
1436
|
|
|
1398
|
-
if (href_attribute) {
|
|
1437
|
+
if (href_attribute) { hb_array_append(attributes, (AST_NODE_T*) href_attribute); }
|
|
1399
1438
|
if (!info->content) {
|
|
1400
1439
|
href_for_body = hb_allocator_strdup(allocator, href);
|
|
1401
1440
|
href_for_body_is_ruby_expression = href_is_ruby_expression;
|
data/src/analyze/analyze.c
CHANGED
|
@@ -75,8 +75,7 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
|
|
|
75
75
|
|
|
76
76
|
hb_string_T opening = erb_content_node->tag_opening->value;
|
|
77
77
|
|
|
78
|
-
if (!hb_string_equals(opening, hb_string("
|
|
79
|
-
&& !hb_string_equals(opening, hb_string("<%#")) && !hb_string_equals(opening, hb_string("<%graphql"))) {
|
|
78
|
+
if (!hb_string_equals(opening, hb_string("<%#")) && !hb_string_equals(opening, hb_string("<%graphql"))) {
|
|
80
79
|
analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value);
|
|
81
80
|
|
|
82
81
|
erb_content_node->parsed = true;
|
|
@@ -737,12 +736,32 @@ static size_t process_block_structure(
|
|
|
737
736
|
hb_array_T* block_errors = erb_node->base.errors;
|
|
738
737
|
erb_node->base.errors = NULL;
|
|
739
738
|
|
|
739
|
+
// Filter out "incomplete block" Prism errors since we've matched the block with its end tag.
|
|
740
|
+
if (block_errors) {
|
|
741
|
+
for (size_t error_index = hb_array_size(block_errors); error_index > 0; error_index--) {
|
|
742
|
+
ERROR_T* error = hb_array_get(block_errors, error_index - 1);
|
|
743
|
+
if (!error || error->type != RUBY_PARSE_ERROR) { continue; }
|
|
744
|
+
|
|
745
|
+
RUBY_PARSE_ERROR_T* parse_error = (RUBY_PARSE_ERROR_T*) error;
|
|
746
|
+
|
|
747
|
+
if (string_equals(parse_error->diagnostic_id.data, "block_term_end")
|
|
748
|
+
|| string_equals(parse_error->diagnostic_id.data, "block_term_brace")
|
|
749
|
+
|| string_equals(parse_error->diagnostic_id.data, "unexpected_token_close_context")) {
|
|
750
|
+
hb_array_remove(block_errors, error_index - 1);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
hb_array_T* block_arguments =
|
|
756
|
+
extract_block_arguments_from_erb_node(erb_node, context->source, block_errors, allocator);
|
|
757
|
+
|
|
740
758
|
AST_ERB_BLOCK_NODE_T* block_node = ast_erb_block_node_init(
|
|
741
759
|
erb_node->tag_opening,
|
|
742
760
|
erb_node->content,
|
|
743
761
|
erb_node->tag_closing,
|
|
744
762
|
HERB_PRISM_NODE_EMPTY,
|
|
745
763
|
children,
|
|
764
|
+
block_arguments,
|
|
746
765
|
rescue_clause,
|
|
747
766
|
else_clause,
|
|
748
767
|
ensure_clause,
|
|
@@ -943,6 +962,7 @@ hb_array_T* get_node_children_array(const AST_NODE_T* node) {
|
|
|
943
962
|
case AST_ERB_ENSURE_NODE: return ((AST_ERB_ENSURE_NODE_T*) node)->statements;
|
|
944
963
|
case AST_ERB_CASE_NODE: return ((AST_ERB_CASE_NODE_T*) node)->children;
|
|
945
964
|
case AST_ERB_WHEN_NODE: return ((AST_ERB_WHEN_NODE_T*) node)->statements;
|
|
965
|
+
case AST_ERB_RENDER_NODE: return ((AST_ERB_RENDER_NODE_T*) node)->body;
|
|
946
966
|
default: return NULL;
|
|
947
967
|
}
|
|
948
968
|
}
|
|
@@ -1032,7 +1052,7 @@ void herb_analyze_parse_tree(
|
|
|
1032
1052
|
|
|
1033
1053
|
herb_visit_node((AST_NODE_T*) document, detect_invalid_erb_structures, &invalid_context);
|
|
1034
1054
|
|
|
1035
|
-
herb_analyze_parse_errors(document, source, allocator);
|
|
1055
|
+
herb_analyze_parse_errors(document, source, options, allocator);
|
|
1036
1056
|
|
|
1037
1057
|
herb_parser_match_html_tags_post_analyze(document, options, allocator);
|
|
1038
1058
|
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
#include <stdbool.h>
|
|
3
3
|
#include <string.h>
|
|
4
4
|
|
|
5
|
+
#include "../include/analyze/action_view/tag_helper_node_builders.h"
|
|
6
|
+
#include "../include/analyze/action_view/tag_helpers.h"
|
|
5
7
|
#include "../include/analyze/analyzed_ruby.h"
|
|
8
|
+
#include "../include/analyze/helpers.h"
|
|
9
|
+
#include "../include/ast/ast_nodes.h"
|
|
10
|
+
#include "../include/lib/hb_array.h"
|
|
6
11
|
#include "../include/lib/string.h"
|
|
12
|
+
#include "../include/prism/prism_helpers.h"
|
|
7
13
|
|
|
8
14
|
bool has_if_node(analyzed_ruby_T* analyzed) {
|
|
9
15
|
return analyzed && analyzed->if_node_count > 0;
|
|
@@ -526,3 +532,403 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
526
532
|
|
|
527
533
|
return false;
|
|
528
534
|
}
|
|
535
|
+
|
|
536
|
+
static pm_block_node_t* find_first_block_node(pm_node_t* node) {
|
|
537
|
+
if (!node) { return NULL; }
|
|
538
|
+
|
|
539
|
+
if (node->type == PM_CALL_NODE) {
|
|
540
|
+
pm_call_node_t* call = (pm_call_node_t*) node;
|
|
541
|
+
|
|
542
|
+
if (call->block && call->block->type == PM_BLOCK_NODE) { return (pm_block_node_t*) call->block; }
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (node->type == PM_PROGRAM_NODE) {
|
|
546
|
+
pm_program_node_t* program = (pm_program_node_t*) node;
|
|
547
|
+
|
|
548
|
+
if (program->statements && program->statements->body.size > 0) {
|
|
549
|
+
return find_first_block_node(program->statements->body.nodes[0]);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (node->type == PM_STATEMENTS_NODE) {
|
|
554
|
+
pm_statements_node_t* statements = (pm_statements_node_t*) node;
|
|
555
|
+
|
|
556
|
+
if (statements->body.size > 0) { return find_first_block_node(statements->body.nodes[0]); }
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return NULL;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
static position_T prism_to_source_position(
|
|
563
|
+
const uint8_t* prism_pointer,
|
|
564
|
+
const uint8_t* prism_source_start,
|
|
565
|
+
size_t source_base_offset,
|
|
566
|
+
const char* source
|
|
567
|
+
) {
|
|
568
|
+
if (!source || !prism_source_start) { return (position_T) { .line = 1, .column = 0 }; }
|
|
569
|
+
|
|
570
|
+
size_t prism_offset = (size_t) (prism_pointer - prism_source_start);
|
|
571
|
+
return byte_offset_to_position(source, source_base_offset + prism_offset);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
static token_T* create_parameter_name_token(
|
|
575
|
+
pm_location_t location,
|
|
576
|
+
const char* name,
|
|
577
|
+
const uint8_t* prism_source_start,
|
|
578
|
+
size_t source_base_offset,
|
|
579
|
+
const char* source,
|
|
580
|
+
hb_allocator_T* allocator
|
|
581
|
+
) {
|
|
582
|
+
position_T start = prism_to_source_position(location.start, prism_source_start, source_base_offset, source);
|
|
583
|
+
position_T end = prism_to_source_position(location.end, prism_source_start, source_base_offset, source);
|
|
584
|
+
|
|
585
|
+
return create_synthetic_token(allocator, name, TOKEN_IDENTIFIER, start, end);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
static void append_parameter(
|
|
589
|
+
hb_array_T* result,
|
|
590
|
+
token_T* name_token,
|
|
591
|
+
AST_RUBY_LITERAL_NODE_T* default_value,
|
|
592
|
+
const char* kind,
|
|
593
|
+
bool required,
|
|
594
|
+
position_T start,
|
|
595
|
+
position_T end,
|
|
596
|
+
hb_allocator_T* allocator
|
|
597
|
+
) {
|
|
598
|
+
hb_array_append(
|
|
599
|
+
result,
|
|
600
|
+
ast_ruby_parameter_node_init(
|
|
601
|
+
name_token,
|
|
602
|
+
default_value,
|
|
603
|
+
hb_string(kind),
|
|
604
|
+
required,
|
|
605
|
+
start,
|
|
606
|
+
end,
|
|
607
|
+
hb_array_init(0, allocator),
|
|
608
|
+
allocator
|
|
609
|
+
)
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
hb_array_T* extract_parameters_from_prism(
|
|
614
|
+
pm_parameters_node_t* parameters,
|
|
615
|
+
pm_parser_t* parser,
|
|
616
|
+
const char* source,
|
|
617
|
+
size_t source_base_offset,
|
|
618
|
+
const uint8_t* prism_source_start,
|
|
619
|
+
hb_allocator_T* allocator
|
|
620
|
+
) {
|
|
621
|
+
if (!parameters) { return hb_array_init(0, allocator); }
|
|
622
|
+
|
|
623
|
+
size_t count = parameters->requireds.size + parameters->optionals.size + parameters->keywords.size;
|
|
624
|
+
if (parameters->rest) { count++; }
|
|
625
|
+
if (parameters->keyword_rest) { count++; }
|
|
626
|
+
if (parameters->block) { count++; }
|
|
627
|
+
|
|
628
|
+
hb_array_T* result = hb_array_init(count, allocator);
|
|
629
|
+
|
|
630
|
+
// Required positional: |item|
|
|
631
|
+
for (size_t index = 0; index < parameters->requireds.size; index++) {
|
|
632
|
+
pm_node_t* node = parameters->requireds.nodes[index];
|
|
633
|
+
if (node->type != PM_REQUIRED_PARAMETER_NODE) { continue; }
|
|
634
|
+
|
|
635
|
+
pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) node;
|
|
636
|
+
pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
|
|
637
|
+
if (!constant) { continue; }
|
|
638
|
+
|
|
639
|
+
char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
|
|
640
|
+
position_T start = prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source);
|
|
641
|
+
position_T end = prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source);
|
|
642
|
+
|
|
643
|
+
append_parameter(
|
|
644
|
+
result,
|
|
645
|
+
create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
|
|
646
|
+
NULL,
|
|
647
|
+
"positional",
|
|
648
|
+
true,
|
|
649
|
+
start,
|
|
650
|
+
end,
|
|
651
|
+
allocator
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
hb_allocator_dealloc(allocator, name);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Optional positional: |item = nil|
|
|
658
|
+
for (size_t index = 0; index < parameters->optionals.size; index++) {
|
|
659
|
+
pm_node_t* node = parameters->optionals.nodes[index];
|
|
660
|
+
if (node->type != PM_OPTIONAL_PARAMETER_NODE) { continue; }
|
|
661
|
+
|
|
662
|
+
pm_optional_parameter_node_t* optional = (pm_optional_parameter_node_t*) node;
|
|
663
|
+
size_t name_length = (size_t) (optional->name_loc.end - optional->name_loc.start);
|
|
664
|
+
char* name = hb_allocator_strndup(allocator, (const char*) optional->name_loc.start, name_length);
|
|
665
|
+
|
|
666
|
+
position_T start = prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source);
|
|
667
|
+
position_T end = prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source);
|
|
668
|
+
|
|
669
|
+
AST_RUBY_LITERAL_NODE_T* default_value = NULL;
|
|
670
|
+
|
|
671
|
+
if (optional->value) {
|
|
672
|
+
size_t value_length = (size_t) (optional->value->location.end - optional->value->location.start);
|
|
673
|
+
char* value_string = hb_allocator_strndup(allocator, (const char*) optional->value->location.start, value_length);
|
|
674
|
+
position_T value_start =
|
|
675
|
+
prism_to_source_position(optional->value->location.start, prism_source_start, source_base_offset, source);
|
|
676
|
+
position_T value_end =
|
|
677
|
+
prism_to_source_position(optional->value->location.end, prism_source_start, source_base_offset, source);
|
|
678
|
+
|
|
679
|
+
default_value = ast_ruby_literal_node_init(
|
|
680
|
+
hb_string_from_c_string(value_string),
|
|
681
|
+
value_start,
|
|
682
|
+
value_end,
|
|
683
|
+
hb_array_init(0, allocator),
|
|
684
|
+
allocator
|
|
685
|
+
);
|
|
686
|
+
hb_allocator_dealloc(allocator, value_string);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
append_parameter(
|
|
690
|
+
result,
|
|
691
|
+
create_parameter_name_token(optional->name_loc, name, prism_source_start, source_base_offset, source, allocator),
|
|
692
|
+
default_value,
|
|
693
|
+
"positional",
|
|
694
|
+
false,
|
|
695
|
+
start,
|
|
696
|
+
end,
|
|
697
|
+
allocator
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
hb_allocator_dealloc(allocator, name);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// Rest: |*items|
|
|
704
|
+
if (parameters->rest && parameters->rest->type == PM_REST_PARAMETER_NODE) {
|
|
705
|
+
pm_rest_parameter_node_t* rest = (pm_rest_parameter_node_t*) parameters->rest;
|
|
706
|
+
|
|
707
|
+
if (rest->name) {
|
|
708
|
+
size_t name_length = (size_t) (rest->name_loc.end - rest->name_loc.start);
|
|
709
|
+
char* name = hb_allocator_strndup(allocator, (const char*) rest->name_loc.start, name_length);
|
|
710
|
+
|
|
711
|
+
position_T start =
|
|
712
|
+
prism_to_source_position(parameters->rest->location.start, prism_source_start, source_base_offset, source);
|
|
713
|
+
position_T end =
|
|
714
|
+
prism_to_source_position(parameters->rest->location.end, prism_source_start, source_base_offset, source);
|
|
715
|
+
|
|
716
|
+
append_parameter(
|
|
717
|
+
result,
|
|
718
|
+
create_parameter_name_token(rest->name_loc, name, prism_source_start, source_base_offset, source, allocator),
|
|
719
|
+
NULL,
|
|
720
|
+
"rest",
|
|
721
|
+
false,
|
|
722
|
+
start,
|
|
723
|
+
end,
|
|
724
|
+
allocator
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
hb_allocator_dealloc(allocator, name);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Keywords: |name:| or |title: "default"|
|
|
732
|
+
for (size_t index = 0; index < parameters->keywords.size; index++) {
|
|
733
|
+
pm_node_t* keyword = parameters->keywords.nodes[index];
|
|
734
|
+
|
|
735
|
+
pm_location_t name_location;
|
|
736
|
+
bool is_required = false;
|
|
737
|
+
AST_RUBY_LITERAL_NODE_T* default_value = NULL;
|
|
738
|
+
|
|
739
|
+
if (keyword->type == PM_REQUIRED_KEYWORD_PARAMETER_NODE) {
|
|
740
|
+
name_location = ((pm_required_keyword_parameter_node_t*) keyword)->name_loc;
|
|
741
|
+
is_required = true;
|
|
742
|
+
} else if (keyword->type == PM_OPTIONAL_KEYWORD_PARAMETER_NODE) {
|
|
743
|
+
pm_optional_keyword_parameter_node_t* optional_keyword = (pm_optional_keyword_parameter_node_t*) keyword;
|
|
744
|
+
name_location = optional_keyword->name_loc;
|
|
745
|
+
|
|
746
|
+
if (optional_keyword->value) {
|
|
747
|
+
size_t value_length =
|
|
748
|
+
(size_t) (optional_keyword->value->location.end - optional_keyword->value->location.start);
|
|
749
|
+
char* value_string =
|
|
750
|
+
hb_allocator_strndup(allocator, (const char*) optional_keyword->value->location.start, value_length);
|
|
751
|
+
|
|
752
|
+
position_T value_start = prism_to_source_position(
|
|
753
|
+
optional_keyword->value->location.start,
|
|
754
|
+
prism_source_start,
|
|
755
|
+
source_base_offset,
|
|
756
|
+
source
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
position_T value_end = prism_to_source_position(
|
|
760
|
+
optional_keyword->value->location.end,
|
|
761
|
+
prism_source_start,
|
|
762
|
+
source_base_offset,
|
|
763
|
+
source
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
default_value = ast_ruby_literal_node_init(
|
|
767
|
+
hb_string_from_c_string(value_string),
|
|
768
|
+
value_start,
|
|
769
|
+
value_end,
|
|
770
|
+
hb_array_init(0, allocator),
|
|
771
|
+
allocator
|
|
772
|
+
);
|
|
773
|
+
|
|
774
|
+
hb_allocator_dealloc(allocator, value_string);
|
|
775
|
+
}
|
|
776
|
+
} else {
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
size_t name_length = (size_t) (name_location.end - name_location.start);
|
|
781
|
+
if (name_length > 0 && name_location.start[name_length - 1] == ':') { name_length--; }
|
|
782
|
+
char* name = hb_allocator_strndup(allocator, (const char*) name_location.start, name_length);
|
|
783
|
+
|
|
784
|
+
position_T start =
|
|
785
|
+
prism_to_source_position(keyword->location.start, prism_source_start, source_base_offset, source);
|
|
786
|
+
position_T end = prism_to_source_position(keyword->location.end, prism_source_start, source_base_offset, source);
|
|
787
|
+
|
|
788
|
+
append_parameter(
|
|
789
|
+
result,
|
|
790
|
+
create_parameter_name_token(name_location, name, prism_source_start, source_base_offset, source, allocator),
|
|
791
|
+
default_value,
|
|
792
|
+
"keyword",
|
|
793
|
+
is_required,
|
|
794
|
+
start,
|
|
795
|
+
end,
|
|
796
|
+
allocator
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
hb_allocator_dealloc(allocator, name);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// Keyword rest: |**opts| or |**|
|
|
803
|
+
if (parameters->keyword_rest && parameters->keyword_rest->type == PM_KEYWORD_REST_PARAMETER_NODE) {
|
|
804
|
+
pm_keyword_rest_parameter_node_t* keyword_rest = (pm_keyword_rest_parameter_node_t*) parameters->keyword_rest;
|
|
805
|
+
|
|
806
|
+
position_T start = prism_to_source_position(
|
|
807
|
+
parameters->keyword_rest->location.start,
|
|
808
|
+
prism_source_start,
|
|
809
|
+
source_base_offset,
|
|
810
|
+
source
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
position_T end =
|
|
814
|
+
prism_to_source_position(parameters->keyword_rest->location.end, prism_source_start, source_base_offset, source);
|
|
815
|
+
|
|
816
|
+
if (keyword_rest->name) {
|
|
817
|
+
size_t name_length = (size_t) (keyword_rest->name_loc.end - keyword_rest->name_loc.start);
|
|
818
|
+
char* name = hb_allocator_strndup(allocator, (const char*) keyword_rest->name_loc.start, name_length);
|
|
819
|
+
|
|
820
|
+
append_parameter(
|
|
821
|
+
result,
|
|
822
|
+
create_parameter_name_token(
|
|
823
|
+
keyword_rest->name_loc,
|
|
824
|
+
name,
|
|
825
|
+
prism_source_start,
|
|
826
|
+
source_base_offset,
|
|
827
|
+
source,
|
|
828
|
+
allocator
|
|
829
|
+
),
|
|
830
|
+
NULL,
|
|
831
|
+
"keyword_rest",
|
|
832
|
+
false,
|
|
833
|
+
start,
|
|
834
|
+
end,
|
|
835
|
+
allocator
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
hb_allocator_dealloc(allocator, name);
|
|
839
|
+
} else {
|
|
840
|
+
// Anonymous **
|
|
841
|
+
append_parameter(result, NULL, NULL, "keyword_rest", false, start, end, allocator);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Block: |&blk|
|
|
846
|
+
if (parameters->block) {
|
|
847
|
+
pm_block_parameter_node_t* block_param = parameters->block;
|
|
848
|
+
|
|
849
|
+
if (block_param->name) {
|
|
850
|
+
size_t name_length = (size_t) (block_param->name_loc.end - block_param->name_loc.start);
|
|
851
|
+
char* name = hb_allocator_strndup(allocator, (const char*) block_param->name_loc.start, name_length);
|
|
852
|
+
|
|
853
|
+
position_T start =
|
|
854
|
+
prism_to_source_position(block_param->base.location.start, prism_source_start, source_base_offset, source);
|
|
855
|
+
position_T end =
|
|
856
|
+
prism_to_source_position(block_param->base.location.end, prism_source_start, source_base_offset, source);
|
|
857
|
+
|
|
858
|
+
append_parameter(
|
|
859
|
+
result,
|
|
860
|
+
create_parameter_name_token(
|
|
861
|
+
block_param->name_loc,
|
|
862
|
+
name,
|
|
863
|
+
prism_source_start,
|
|
864
|
+
source_base_offset,
|
|
865
|
+
source,
|
|
866
|
+
allocator
|
|
867
|
+
),
|
|
868
|
+
NULL,
|
|
869
|
+
"block",
|
|
870
|
+
false,
|
|
871
|
+
start,
|
|
872
|
+
end,
|
|
873
|
+
allocator
|
|
874
|
+
);
|
|
875
|
+
|
|
876
|
+
hb_allocator_dealloc(allocator, name);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
hb_array_T* extract_block_arguments_from_erb_node(
|
|
884
|
+
const AST_ERB_CONTENT_NODE_T* erb_node,
|
|
885
|
+
const char* source,
|
|
886
|
+
hb_array_T* errors,
|
|
887
|
+
hb_allocator_T* allocator
|
|
888
|
+
) {
|
|
889
|
+
if (!erb_node || !erb_node->analyzed_ruby || !erb_node->analyzed_ruby->parsed) { return hb_array_init(0, allocator); }
|
|
890
|
+
|
|
891
|
+
pm_parser_t* parser = &erb_node->analyzed_ruby->parser;
|
|
892
|
+
pm_block_node_t* block_node = find_first_block_node(erb_node->analyzed_ruby->root);
|
|
893
|
+
|
|
894
|
+
if (!block_node || !block_node->parameters) { return hb_array_init(0, allocator); }
|
|
895
|
+
if (block_node->parameters->type != PM_BLOCK_PARAMETERS_NODE) { return hb_array_init(0, allocator); }
|
|
896
|
+
|
|
897
|
+
pm_block_parameters_node_t* block_parameters = (pm_block_parameters_node_t*) block_node->parameters;
|
|
898
|
+
size_t erb_content_offset = 0;
|
|
899
|
+
|
|
900
|
+
if (source && erb_node->content) {
|
|
901
|
+
erb_content_offset = calculate_byte_offset_from_position(source, erb_node->content->location.start);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
const uint8_t* prism_source_start = (const uint8_t*) parser->start;
|
|
905
|
+
|
|
906
|
+
if (errors) {
|
|
907
|
+
for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser->error_list.head; error != NULL;
|
|
908
|
+
error = (const pm_diagnostic_t*) error->node.next) {
|
|
909
|
+
if (error->diag_id == PM_ERR_BLOCK_TERM_END) { continue; }
|
|
910
|
+
if (error->diag_id == PM_ERR_BLOCK_TERM_BRACE) { continue; }
|
|
911
|
+
if (error->diag_id == PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) { continue; }
|
|
912
|
+
|
|
913
|
+
size_t error_start_offset = (size_t) (error->location.start - prism_source_start);
|
|
914
|
+
size_t error_end_offset = (size_t) (error->location.end - prism_source_start);
|
|
915
|
+
|
|
916
|
+
position_T error_start = byte_offset_to_position(source, erb_content_offset + error_start_offset);
|
|
917
|
+
position_T error_end = byte_offset_to_position(source, erb_content_offset + error_end_offset);
|
|
918
|
+
|
|
919
|
+
RUBY_PARSE_ERROR_T* parse_error =
|
|
920
|
+
ruby_parse_error_from_prism_error_with_positions(error, error_start, error_end, allocator);
|
|
921
|
+
|
|
922
|
+
hb_array_append(errors, parse_error);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
return extract_parameters_from_prism(
|
|
927
|
+
block_parameters->parameters,
|
|
928
|
+
parser,
|
|
929
|
+
source,
|
|
930
|
+
erb_content_offset,
|
|
931
|
+
prism_source_start,
|
|
932
|
+
allocator
|
|
933
|
+
);
|
|
934
|
+
}
|
data/src/analyze/builders.c
CHANGED
data/src/analyze/missing_end.c
CHANGED
|
@@ -153,6 +153,22 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node, hb_allocator_T* allo
|
|
|
153
153
|
break;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
case AST_ERB_RENDER_NODE: {
|
|
157
|
+
const AST_ERB_RENDER_NODE_T* erb_render_node = (const AST_ERB_RENDER_NODE_T*) node;
|
|
158
|
+
|
|
159
|
+
if (erb_render_node->end_node == NULL) {
|
|
160
|
+
append_missing_erb_end_tag_error(
|
|
161
|
+
hb_string("`<" "%" " render " "%" ">`"),
|
|
162
|
+
erb_render_node->tag_opening->location.start,
|
|
163
|
+
erb_render_node->tag_closing->location.end,
|
|
164
|
+
allocator,
|
|
165
|
+
node->errors
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
|
|
156
172
|
default: break;
|
|
157
173
|
}
|
|
158
174
|
}
|