@herb-tools/node 0.8.9 → 0.9.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.
- package/CHANGELOG.md +19 -0
- package/binding.gyp +26 -8
- package/dist/herb-node.cjs +41 -12
- package/dist/herb-node.cjs.map +1 -1
- package/dist/herb-node.esm.js +8 -1
- package/dist/herb-node.esm.js.map +1 -1
- package/dist/types/node-backend.d.ts +3 -1
- package/extension/error_helpers.cpp +419 -71
- package/extension/error_helpers.h +14 -3
- package/extension/extension_helpers.cpp +38 -35
- package/extension/extension_helpers.h +2 -2
- package/extension/herb.cpp +183 -64
- package/extension/libherb/analyze/action_view/attribute_extraction_helpers.c +290 -0
- package/extension/libherb/analyze/action_view/attribute_extraction_helpers.h +36 -0
- package/extension/libherb/analyze/action_view/content_tag.c +70 -0
- package/extension/libherb/analyze/action_view/link_to.c +143 -0
- package/extension/libherb/analyze/action_view/registry.c +60 -0
- package/extension/libherb/analyze/action_view/tag.c +64 -0
- package/extension/libherb/analyze/action_view/tag_helper_handler.h +41 -0
- package/extension/libherb/analyze/action_view/tag_helper_node_builders.c +305 -0
- package/extension/libherb/analyze/action_view/tag_helper_node_builders.h +70 -0
- package/extension/libherb/analyze/action_view/tag_helpers.c +748 -0
- package/extension/libherb/analyze/action_view/tag_helpers.h +38 -0
- package/extension/libherb/analyze/action_view/turbo_frame_tag.c +88 -0
- package/extension/libherb/analyze/analyze.c +882 -0
- package/extension/libherb/{include → analyze}/analyze.h +14 -4
- package/extension/libherb/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
- package/extension/libherb/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
- package/extension/libherb/analyze/builders.c +343 -0
- package/extension/libherb/analyze/builders.h +27 -0
- package/extension/libherb/analyze/conditional_elements.c +594 -0
- package/extension/libherb/analyze/conditional_elements.h +9 -0
- package/extension/libherb/analyze/conditional_open_tags.c +640 -0
- package/extension/libherb/analyze/conditional_open_tags.h +9 -0
- package/extension/libherb/analyze/control_type.c +250 -0
- package/extension/libherb/analyze/control_type.h +14 -0
- package/extension/libherb/{analyze_helpers.c → analyze/helpers.c} +79 -31
- package/extension/libherb/{analyze_helpers.h → analyze/helpers.h} +22 -17
- package/extension/libherb/analyze/invalid_structures.c +193 -0
- package/extension/libherb/analyze/invalid_structures.h +11 -0
- package/extension/libherb/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
- package/extension/libherb/analyze/parse_errors.c +84 -0
- package/extension/libherb/analyze/prism_annotate.c +397 -0
- package/extension/libherb/analyze/prism_annotate.h +16 -0
- package/extension/libherb/{analyze_transform.c → analyze/transform.c} +17 -3
- package/extension/libherb/ast_node.c +17 -7
- package/extension/libherb/ast_node.h +11 -5
- package/extension/libherb/ast_nodes.c +663 -388
- package/extension/libherb/ast_nodes.h +118 -39
- package/extension/libherb/ast_pretty_print.c +191 -7
- package/extension/libherb/ast_pretty_print.h +6 -1
- package/extension/libherb/element_source.h +3 -8
- package/extension/libherb/errors.c +1100 -507
- package/extension/libherb/errors.h +155 -54
- package/extension/libherb/extract.c +148 -49
- package/extension/libherb/extract.h +21 -5
- package/extension/libherb/herb.c +52 -34
- package/extension/libherb/herb.h +18 -6
- package/extension/libherb/herb_prism_node.h +13 -0
- package/extension/libherb/html_util.c +241 -12
- package/extension/libherb/html_util.h +7 -2
- package/extension/libherb/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
- package/extension/libherb/include/analyze/action_view/tag_helper_handler.h +41 -0
- package/extension/libherb/include/analyze/action_view/tag_helper_node_builders.h +70 -0
- package/extension/libherb/include/analyze/action_view/tag_helpers.h +38 -0
- package/extension/libherb/{analyze.h → include/analyze/analyze.h} +14 -4
- package/extension/libherb/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
- package/extension/libherb/include/analyze/builders.h +27 -0
- package/extension/libherb/include/analyze/conditional_elements.h +9 -0
- package/extension/libherb/include/analyze/conditional_open_tags.h +9 -0
- package/extension/libherb/include/analyze/control_type.h +14 -0
- package/extension/libherb/include/{analyze_helpers.h → analyze/helpers.h} +22 -17
- package/extension/libherb/include/analyze/invalid_structures.h +11 -0
- package/extension/libherb/include/analyze/prism_annotate.h +16 -0
- package/extension/libherb/include/ast_node.h +11 -5
- package/extension/libherb/include/ast_nodes.h +118 -39
- package/extension/libherb/include/ast_pretty_print.h +6 -1
- package/extension/libherb/include/element_source.h +3 -8
- package/extension/libherb/include/errors.h +155 -54
- package/extension/libherb/include/extract.h +21 -5
- package/extension/libherb/include/herb.h +18 -6
- package/extension/libherb/include/herb_prism_node.h +13 -0
- package/extension/libherb/include/html_util.h +7 -2
- package/extension/libherb/include/io.h +3 -1
- package/extension/libherb/include/lex_helpers.h +29 -0
- package/extension/libherb/include/lexer.h +1 -1
- package/extension/libherb/include/lexer_peek_helpers.h +87 -13
- package/extension/libherb/include/lexer_struct.h +2 -0
- package/extension/libherb/include/location.h +2 -1
- package/extension/libherb/include/parser.h +27 -2
- package/extension/libherb/include/parser_helpers.h +19 -3
- package/extension/libherb/include/pretty_print.h +10 -5
- package/extension/libherb/include/prism_context.h +45 -0
- package/extension/libherb/include/prism_helpers.h +10 -7
- package/extension/libherb/include/prism_serialized.h +12 -0
- package/extension/libherb/include/token.h +16 -4
- package/extension/libherb/include/token_struct.h +10 -3
- package/extension/libherb/include/utf8.h +2 -1
- package/extension/libherb/include/util/hb_allocator.h +78 -0
- package/extension/libherb/include/util/hb_arena.h +6 -1
- package/extension/libherb/include/util/hb_arena_debug.h +12 -1
- package/extension/libherb/include/util/hb_array.h +7 -3
- package/extension/libherb/include/util/hb_buffer.h +6 -4
- package/extension/libherb/include/util/hb_foreach.h +79 -0
- package/extension/libherb/include/util/hb_narray.h +8 -4
- package/extension/libherb/include/util/hb_string.h +56 -9
- package/extension/libherb/include/util/string.h +11 -0
- package/extension/libherb/include/util.h +6 -3
- package/extension/libherb/include/version.h +1 -1
- package/extension/libherb/io.c +3 -2
- package/extension/libherb/io.h +3 -1
- package/extension/libherb/lex_helpers.h +29 -0
- package/extension/libherb/lexer.c +42 -30
- package/extension/libherb/lexer.h +1 -1
- package/extension/libherb/lexer_peek_helpers.c +12 -74
- package/extension/libherb/lexer_peek_helpers.h +87 -13
- package/extension/libherb/lexer_struct.h +2 -0
- package/extension/libherb/location.c +2 -2
- package/extension/libherb/location.h +2 -1
- package/extension/libherb/main.c +79 -66
- package/extension/libherb/parser.c +784 -247
- package/extension/libherb/parser.h +27 -2
- package/extension/libherb/parser_helpers.c +110 -23
- package/extension/libherb/parser_helpers.h +19 -3
- package/extension/libherb/parser_match_tags.c +110 -49
- package/extension/libherb/pretty_print.c +29 -24
- package/extension/libherb/pretty_print.h +10 -5
- package/extension/libherb/prism_context.h +45 -0
- package/extension/libherb/prism_helpers.c +30 -27
- package/extension/libherb/prism_helpers.h +10 -7
- package/extension/libherb/prism_serialized.h +12 -0
- package/extension/libherb/ruby_parser.c +2 -0
- package/extension/libherb/token.c +151 -66
- package/extension/libherb/token.h +16 -4
- package/extension/libherb/token_matchers.c +0 -1
- package/extension/libherb/token_struct.h +10 -3
- package/extension/libherb/utf8.c +7 -6
- package/extension/libherb/utf8.h +2 -1
- package/extension/libherb/util/hb_allocator.c +341 -0
- package/extension/libherb/util/hb_allocator.h +78 -0
- package/extension/libherb/util/hb_arena.c +81 -56
- package/extension/libherb/util/hb_arena.h +6 -1
- package/extension/libherb/util/hb_arena_debug.c +32 -17
- package/extension/libherb/util/hb_arena_debug.h +12 -1
- package/extension/libherb/util/hb_array.c +30 -15
- package/extension/libherb/util/hb_array.h +7 -3
- package/extension/libherb/util/hb_buffer.c +17 -21
- package/extension/libherb/util/hb_buffer.h +6 -4
- package/extension/libherb/util/hb_foreach.h +79 -0
- package/extension/libherb/util/hb_narray.c +22 -7
- package/extension/libherb/util/hb_narray.h +8 -4
- package/extension/libherb/util/hb_string.c +49 -35
- package/extension/libherb/util/hb_string.h +56 -9
- package/extension/libherb/util/string.h +11 -0
- package/extension/libherb/util.c +21 -11
- package/extension/libherb/util.h +6 -3
- package/extension/libherb/version.h +1 -1
- package/extension/libherb/visitor.c +48 -1
- package/extension/nodes.cpp +451 -6
- package/extension/nodes.h +8 -1
- package/extension/prism/include/prism/ast.h +4 -4
- package/extension/prism/include/prism/version.h +2 -2
- package/extension/prism/src/prism.c +1 -1
- package/package.json +12 -8
- package/src/node-backend.ts +11 -1
- package/dist/types/index-cjs.d.cts +0 -1
- package/extension/libherb/analyze.c +0 -1594
- package/extension/libherb/element_source.c +0 -12
- package/extension/libherb/include/util/hb_system.h +0 -9
- package/extension/libherb/util/hb_system.c +0 -30
- package/extension/libherb/util/hb_system.h +0 -9
- package/src/index-cjs.cts +0 -22
- /package/dist/types/{index-esm.d.mts → index.d.ts} +0 -0
- /package/src/{index-esm.mts → index.ts} +0 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#include "../include/analyze/control_type.h"
|
|
2
|
+
#include "../include/analyze/analyze.h"
|
|
3
|
+
#include "../include/analyze/analyzed_ruby.h"
|
|
4
|
+
#include "../include/analyze/helpers.h"
|
|
5
|
+
#include "../include/ast_node.h"
|
|
6
|
+
|
|
7
|
+
#include <prism.h>
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
#include <stdint.h>
|
|
10
|
+
|
|
11
|
+
typedef struct {
|
|
12
|
+
control_type_t type;
|
|
13
|
+
uint32_t offset;
|
|
14
|
+
bool found;
|
|
15
|
+
} earliest_control_keyword_T;
|
|
16
|
+
|
|
17
|
+
typedef struct {
|
|
18
|
+
earliest_control_keyword_T* result;
|
|
19
|
+
const uint8_t* source_start;
|
|
20
|
+
} location_walker_context_T;
|
|
21
|
+
|
|
22
|
+
static bool control_type_is_block(control_type_t type) {
|
|
23
|
+
return type == CONTROL_TYPE_BLOCK;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static bool control_type_is_yield(control_type_t type) {
|
|
27
|
+
return type == CONTROL_TYPE_YIELD;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* data) {
|
|
31
|
+
if (!node) { return true; }
|
|
32
|
+
|
|
33
|
+
location_walker_context_T* context = (location_walker_context_T*) data;
|
|
34
|
+
earliest_control_keyword_T* result = context->result;
|
|
35
|
+
|
|
36
|
+
control_type_t current_type = CONTROL_TYPE_UNKNOWN;
|
|
37
|
+
uint32_t keyword_offset = UINT32_MAX;
|
|
38
|
+
|
|
39
|
+
switch (node->type) {
|
|
40
|
+
case PM_IF_NODE: {
|
|
41
|
+
pm_if_node_t* if_node = (pm_if_node_t*) node;
|
|
42
|
+
current_type = CONTROL_TYPE_IF;
|
|
43
|
+
keyword_offset = (uint32_t) (if_node->if_keyword_loc.start - context->source_start);
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
case PM_UNLESS_NODE: {
|
|
48
|
+
pm_unless_node_t* unless_node = (pm_unless_node_t*) node;
|
|
49
|
+
current_type = CONTROL_TYPE_UNLESS;
|
|
50
|
+
keyword_offset = (uint32_t) (unless_node->keyword_loc.start - context->source_start);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
case PM_CASE_NODE: {
|
|
55
|
+
pm_case_node_t* case_node = (pm_case_node_t*) node;
|
|
56
|
+
current_type = CONTROL_TYPE_CASE;
|
|
57
|
+
keyword_offset = (uint32_t) (case_node->case_keyword_loc.start - context->source_start);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
case PM_CASE_MATCH_NODE: {
|
|
62
|
+
pm_case_match_node_t* case_match_node = (pm_case_match_node_t*) node;
|
|
63
|
+
current_type = CONTROL_TYPE_CASE_MATCH;
|
|
64
|
+
keyword_offset = (uint32_t) (case_match_node->case_keyword_loc.start - context->source_start);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
case PM_WHILE_NODE: {
|
|
69
|
+
pm_while_node_t* while_node = (pm_while_node_t*) node;
|
|
70
|
+
current_type = CONTROL_TYPE_WHILE;
|
|
71
|
+
keyword_offset = (uint32_t) (while_node->keyword_loc.start - context->source_start);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
case PM_UNTIL_NODE: {
|
|
76
|
+
pm_until_node_t* until_node = (pm_until_node_t*) node;
|
|
77
|
+
current_type = CONTROL_TYPE_UNTIL;
|
|
78
|
+
keyword_offset = (uint32_t) (until_node->keyword_loc.start - context->source_start);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
case PM_FOR_NODE: {
|
|
83
|
+
pm_for_node_t* for_node = (pm_for_node_t*) node;
|
|
84
|
+
current_type = CONTROL_TYPE_FOR;
|
|
85
|
+
keyword_offset = (uint32_t) (for_node->for_keyword_loc.start - context->source_start);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
case PM_BEGIN_NODE: {
|
|
90
|
+
pm_begin_node_t* begin_node = (pm_begin_node_t*) node;
|
|
91
|
+
current_type = CONTROL_TYPE_BEGIN;
|
|
92
|
+
|
|
93
|
+
if (begin_node->begin_keyword_loc.start != NULL) {
|
|
94
|
+
keyword_offset = (uint32_t) (begin_node->begin_keyword_loc.start - context->source_start);
|
|
95
|
+
} else {
|
|
96
|
+
keyword_offset = (uint32_t) (node->location.start - context->source_start);
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case PM_YIELD_NODE: {
|
|
102
|
+
current_type = CONTROL_TYPE_YIELD;
|
|
103
|
+
keyword_offset = (uint32_t) (node->location.start - context->source_start);
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
case PM_CALL_NODE: {
|
|
108
|
+
pm_call_node_t* call = (pm_call_node_t*) node;
|
|
109
|
+
|
|
110
|
+
if (call->block != NULL && call->block->type == PM_BLOCK_NODE) {
|
|
111
|
+
pm_block_node_t* block_node = (pm_block_node_t*) call->block;
|
|
112
|
+
|
|
113
|
+
bool has_do_opening = is_do_block(block_node->opening_loc);
|
|
114
|
+
bool has_brace_opening = is_brace_block(block_node->opening_loc);
|
|
115
|
+
bool has_valid_brace_closing = is_closing_brace(block_node->closing_loc);
|
|
116
|
+
|
|
117
|
+
if (has_do_opening || (has_brace_opening && !has_valid_brace_closing)) {
|
|
118
|
+
current_type = CONTROL_TYPE_BLOCK;
|
|
119
|
+
keyword_offset = (uint32_t) (node->location.start - context->source_start);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
case PM_LAMBDA_NODE: {
|
|
126
|
+
pm_lambda_node_t* lambda = (pm_lambda_node_t*) node;
|
|
127
|
+
|
|
128
|
+
bool has_do_opening = is_do_block(lambda->opening_loc);
|
|
129
|
+
bool has_brace_opening = is_brace_block(lambda->opening_loc);
|
|
130
|
+
bool has_valid_brace_closing = is_closing_brace(lambda->closing_loc);
|
|
131
|
+
|
|
132
|
+
if (has_do_opening || (has_brace_opening && !has_valid_brace_closing)) {
|
|
133
|
+
current_type = CONTROL_TYPE_BLOCK;
|
|
134
|
+
keyword_offset = (uint32_t) (node->location.start - context->source_start);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
case PM_NEXT_NODE:
|
|
141
|
+
case PM_BREAK_NODE:
|
|
142
|
+
case PM_RETURN_NODE: {
|
|
143
|
+
current_type = CONTROL_TYPE_UNKNOWN;
|
|
144
|
+
keyword_offset = (uint32_t) (node->location.start - context->source_start);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
default: break;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (keyword_offset != UINT32_MAX) {
|
|
152
|
+
bool should_update = !result->found;
|
|
153
|
+
|
|
154
|
+
if (result->found) {
|
|
155
|
+
if (control_type_is_block(current_type) && control_type_is_yield(result->type)) {
|
|
156
|
+
should_update = true;
|
|
157
|
+
} else if (!(control_type_is_yield(current_type) && control_type_is_block(result->type))) {
|
|
158
|
+
should_update = keyword_offset < result->offset;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (should_update) {
|
|
163
|
+
result->type = current_type;
|
|
164
|
+
result->offset = keyword_offset;
|
|
165
|
+
result->found = true;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static control_type_t find_earliest_control_keyword(pm_node_t* root, const uint8_t* source_start) {
|
|
173
|
+
if (!root) { return CONTROL_TYPE_UNKNOWN; }
|
|
174
|
+
|
|
175
|
+
earliest_control_keyword_T result = { .type = CONTROL_TYPE_UNKNOWN, .offset = UINT32_MAX, .found = false };
|
|
176
|
+
|
|
177
|
+
location_walker_context_T context = { .result = &result, .source_start = source_start };
|
|
178
|
+
|
|
179
|
+
pm_visit_node(root, find_earliest_control_keyword_walker, &context);
|
|
180
|
+
|
|
181
|
+
return result.found ? result.type : CONTROL_TYPE_UNKNOWN;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
|
|
185
|
+
if (!erb_node || erb_node->base.type != AST_ERB_CONTENT_NODE) { return CONTROL_TYPE_UNKNOWN; }
|
|
186
|
+
if (erb_node->tag_closing == NULL) { return CONTROL_TYPE_UNKNOWN; }
|
|
187
|
+
|
|
188
|
+
analyzed_ruby_T* ruby = erb_node->analyzed_ruby;
|
|
189
|
+
|
|
190
|
+
if (!ruby) { return CONTROL_TYPE_UNKNOWN; }
|
|
191
|
+
if (ruby->valid) { return CONTROL_TYPE_UNKNOWN; }
|
|
192
|
+
|
|
193
|
+
pm_node_t* root = ruby->root;
|
|
194
|
+
|
|
195
|
+
if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
|
|
196
|
+
if (has_else_node(ruby)) { return CONTROL_TYPE_ELSE; }
|
|
197
|
+
if (has_end(ruby)) { return CONTROL_TYPE_END; }
|
|
198
|
+
if (has_when_node(ruby) && !has_case_node(ruby)) { return CONTROL_TYPE_WHEN; }
|
|
199
|
+
if (has_in_node(ruby) && !has_case_match_node(ruby)) { return CONTROL_TYPE_IN; }
|
|
200
|
+
if (has_rescue_node(ruby)) { return CONTROL_TYPE_RESCUE; }
|
|
201
|
+
if (has_ensure_node(ruby)) { return CONTROL_TYPE_ENSURE; }
|
|
202
|
+
if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
|
|
203
|
+
|
|
204
|
+
if (ruby->unclosed_control_flow_count == 0 && !has_yield_node(ruby)) { return CONTROL_TYPE_UNKNOWN; }
|
|
205
|
+
|
|
206
|
+
return find_earliest_control_keyword(root, ruby->parser.start);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
bool is_subsequent_type(control_type_t parent_type, control_type_t child_type) {
|
|
210
|
+
switch (parent_type) {
|
|
211
|
+
case CONTROL_TYPE_IF:
|
|
212
|
+
case CONTROL_TYPE_ELSIF: return child_type == CONTROL_TYPE_ELSIF || child_type == CONTROL_TYPE_ELSE;
|
|
213
|
+
case CONTROL_TYPE_CASE:
|
|
214
|
+
case CONTROL_TYPE_CASE_MATCH: return child_type == CONTROL_TYPE_WHEN || child_type == CONTROL_TYPE_ELSE;
|
|
215
|
+
case CONTROL_TYPE_BEGIN:
|
|
216
|
+
return child_type == CONTROL_TYPE_RESCUE || child_type == CONTROL_TYPE_ELSE || child_type == CONTROL_TYPE_ENSURE;
|
|
217
|
+
case CONTROL_TYPE_RESCUE: return child_type == CONTROL_TYPE_RESCUE;
|
|
218
|
+
case CONTROL_TYPE_UNLESS: return child_type == CONTROL_TYPE_ELSE;
|
|
219
|
+
|
|
220
|
+
default: return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
bool is_terminator_type(control_type_t parent_type, control_type_t child_type) {
|
|
225
|
+
if (child_type == CONTROL_TYPE_END) { return true; }
|
|
226
|
+
|
|
227
|
+
switch (parent_type) {
|
|
228
|
+
case CONTROL_TYPE_WHEN: return child_type == CONTROL_TYPE_WHEN || child_type == CONTROL_TYPE_ELSE;
|
|
229
|
+
case CONTROL_TYPE_IN: return child_type == CONTROL_TYPE_IN || child_type == CONTROL_TYPE_ELSE;
|
|
230
|
+
case CONTROL_TYPE_BLOCK: return child_type == CONTROL_TYPE_BLOCK_CLOSE;
|
|
231
|
+
|
|
232
|
+
default: return is_subsequent_type(parent_type, child_type);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
bool is_compound_control_type(control_type_t type) {
|
|
237
|
+
switch (type) {
|
|
238
|
+
case CONTROL_TYPE_IF:
|
|
239
|
+
case CONTROL_TYPE_CASE:
|
|
240
|
+
case CONTROL_TYPE_CASE_MATCH:
|
|
241
|
+
case CONTROL_TYPE_BEGIN:
|
|
242
|
+
case CONTROL_TYPE_UNLESS:
|
|
243
|
+
case CONTROL_TYPE_WHILE:
|
|
244
|
+
case CONTROL_TYPE_UNTIL:
|
|
245
|
+
case CONTROL_TYPE_FOR:
|
|
246
|
+
case CONTROL_TYPE_BLOCK: return true;
|
|
247
|
+
|
|
248
|
+
default: return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#ifndef HERB_ANALYZE_CONTROL_TYPE_H
|
|
2
|
+
#define HERB_ANALYZE_CONTROL_TYPE_H
|
|
3
|
+
|
|
4
|
+
#include "../ast_nodes.h"
|
|
5
|
+
#include "analyze.h"
|
|
6
|
+
|
|
7
|
+
#include <stdbool.h>
|
|
8
|
+
|
|
9
|
+
control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node);
|
|
10
|
+
bool is_subsequent_type(control_type_t parent_type, control_type_t child_type);
|
|
11
|
+
bool is_terminator_type(control_type_t parent_type, control_type_t child_type);
|
|
12
|
+
bool is_compound_control_type(control_type_t type);
|
|
13
|
+
|
|
14
|
+
#endif
|
|
@@ -2,88 +2,94 @@
|
|
|
2
2
|
#include <stdbool.h>
|
|
3
3
|
#include <string.h>
|
|
4
4
|
|
|
5
|
-
#include "include/analyzed_ruby.h"
|
|
5
|
+
#include "../include/analyze/analyzed_ruby.h"
|
|
6
|
+
#include "../include/util/string.h"
|
|
6
7
|
|
|
7
8
|
bool has_if_node(analyzed_ruby_T* analyzed) {
|
|
8
|
-
return analyzed->if_node_count > 0;
|
|
9
|
+
return analyzed && analyzed->if_node_count > 0;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
bool has_elsif_node(analyzed_ruby_T* analyzed) {
|
|
12
|
-
return analyzed->elsif_node_count > 0;
|
|
13
|
+
return analyzed && analyzed->elsif_node_count > 0;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
bool has_else_node(analyzed_ruby_T* analyzed) {
|
|
16
|
-
return analyzed->else_node_count > 0;
|
|
17
|
+
return analyzed && analyzed->else_node_count > 0;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
bool has_end(analyzed_ruby_T* analyzed) {
|
|
20
|
-
return analyzed->end_count > 0;
|
|
21
|
+
return analyzed && analyzed->end_count > 0;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
bool has_block_node(analyzed_ruby_T* analyzed) {
|
|
24
|
-
return analyzed->block_node_count > 0;
|
|
25
|
+
return analyzed && analyzed->block_node_count > 0;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
bool has_block_closing(analyzed_ruby_T* analyzed) {
|
|
28
|
-
return analyzed->block_closing_count > 0;
|
|
29
|
+
return analyzed && analyzed->block_closing_count > 0;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
bool has_case_node(analyzed_ruby_T* analyzed) {
|
|
32
|
-
return analyzed->case_node_count > 0;
|
|
33
|
+
return analyzed && analyzed->case_node_count > 0;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
bool has_case_match_node(analyzed_ruby_T* analyzed) {
|
|
36
|
-
return analyzed->case_match_node_count > 0;
|
|
37
|
+
return analyzed && analyzed->case_match_node_count > 0;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
bool has_when_node(analyzed_ruby_T* analyzed) {
|
|
40
|
-
return analyzed->when_node_count > 0;
|
|
41
|
+
return analyzed && analyzed->when_node_count > 0;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
bool has_in_node(analyzed_ruby_T* analyzed) {
|
|
44
|
-
return analyzed->in_node_count > 0;
|
|
45
|
+
return analyzed && analyzed->in_node_count > 0;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
bool has_for_node(analyzed_ruby_T* analyzed) {
|
|
48
|
-
return analyzed->for_node_count > 0;
|
|
49
|
+
return analyzed && analyzed->for_node_count > 0;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
bool has_while_node(analyzed_ruby_T* analyzed) {
|
|
52
|
-
return analyzed->while_node_count > 0;
|
|
53
|
+
return analyzed && analyzed->while_node_count > 0;
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
bool has_until_node(analyzed_ruby_T* analyzed) {
|
|
56
|
-
return analyzed->until_node_count > 0;
|
|
57
|
+
return analyzed && analyzed->until_node_count > 0;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
bool has_begin_node(analyzed_ruby_T* analyzed) {
|
|
60
|
-
return analyzed->begin_node_count > 0;
|
|
61
|
+
return analyzed && analyzed->begin_node_count > 0;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
bool has_rescue_node(analyzed_ruby_T* analyzed) {
|
|
64
|
-
return analyzed->rescue_node_count > 0;
|
|
65
|
+
return analyzed && analyzed->rescue_node_count > 0;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
bool has_ensure_node(analyzed_ruby_T* analyzed) {
|
|
68
|
-
return analyzed->ensure_node_count > 0;
|
|
69
|
+
return analyzed && analyzed->ensure_node_count > 0;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
bool has_unless_node(analyzed_ruby_T* analyzed) {
|
|
72
|
-
return analyzed->unless_node_count > 0;
|
|
73
|
+
return analyzed && analyzed->unless_node_count > 0;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
bool has_yield_node(analyzed_ruby_T* analyzed) {
|
|
76
|
-
return analyzed->yield_node_count > 0;
|
|
77
|
+
return analyzed && analyzed->yield_node_count > 0;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
bool has_then_keyword(analyzed_ruby_T* analyzed) {
|
|
80
|
-
return analyzed->then_keyword_count > 0;
|
|
81
|
+
return analyzed && analyzed->then_keyword_count > 0;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
bool
|
|
84
|
-
|
|
84
|
+
bool has_inline_case_condition(analyzed_ruby_T* analyzed) {
|
|
85
|
+
return (has_case_node(analyzed) && has_when_node(analyzed))
|
|
86
|
+
|| (has_case_match_node(analyzed) && has_in_node(analyzed));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
bool has_error_message(analyzed_ruby_T* analyzed, const char* message) {
|
|
90
|
+
for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) analyzed->parser.error_list.head; error != NULL;
|
|
85
91
|
error = (const pm_diagnostic_t*) error->node.next) {
|
|
86
|
-
if (
|
|
92
|
+
if (string_equals(error->message, message)) { return true; }
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
return false;
|
|
@@ -160,6 +166,15 @@ bool search_block_nodes(const pm_node_t* node, void* data) {
|
|
|
160
166
|
if (has_opening && is_unclosed) { analyzed->block_node_count++; }
|
|
161
167
|
}
|
|
162
168
|
|
|
169
|
+
if (node->type == PM_LAMBDA_NODE) {
|
|
170
|
+
pm_lambda_node_t* lambda_node = (pm_lambda_node_t*) node;
|
|
171
|
+
|
|
172
|
+
bool has_opening = is_do_block(lambda_node->opening_loc) || is_brace_block(lambda_node->opening_loc);
|
|
173
|
+
bool is_unclosed = !has_valid_block_closing(lambda_node->opening_loc, lambda_node->closing_loc);
|
|
174
|
+
|
|
175
|
+
if (has_opening && is_unclosed) { analyzed->block_node_count++; }
|
|
176
|
+
}
|
|
177
|
+
|
|
163
178
|
pm_visit_child_nodes(node, search_block_nodes, analyzed);
|
|
164
179
|
|
|
165
180
|
return false;
|
|
@@ -242,7 +257,28 @@ bool search_unless_nodes(const pm_node_t* node, void* data) {
|
|
|
242
257
|
return false;
|
|
243
258
|
}
|
|
244
259
|
|
|
245
|
-
bool
|
|
260
|
+
bool search_when_nodes(const pm_node_t* node, void* data) {
|
|
261
|
+
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
262
|
+
|
|
263
|
+
if (node->type == PM_WHEN_NODE) { analyzed->when_node_count++; }
|
|
264
|
+
|
|
265
|
+
pm_visit_child_nodes(node, search_when_nodes, analyzed);
|
|
266
|
+
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
bool search_in_nodes(const pm_node_t* node, void* data) {
|
|
271
|
+
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
272
|
+
|
|
273
|
+
if (node->type == PM_IN_NODE) { analyzed->in_node_count++; }
|
|
274
|
+
if (node->type == PM_MATCH_PREDICATE_NODE) { analyzed->in_node_count++; }
|
|
275
|
+
|
|
276
|
+
pm_visit_child_nodes(node, search_in_nodes, analyzed);
|
|
277
|
+
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed) {
|
|
246
282
|
if (has_error_message(analyzed, "unexpected 'elsif', ignoring it")) {
|
|
247
283
|
analyzed->elsif_node_count++;
|
|
248
284
|
return true;
|
|
@@ -251,7 +287,7 @@ bool search_elsif_nodes(analyzed_ruby_T* analyzed) {
|
|
|
251
287
|
return false;
|
|
252
288
|
}
|
|
253
289
|
|
|
254
|
-
bool
|
|
290
|
+
bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed) {
|
|
255
291
|
if (has_error_message(analyzed, "unexpected 'else', ignoring it")) {
|
|
256
292
|
analyzed->else_node_count++;
|
|
257
293
|
return true;
|
|
@@ -260,7 +296,7 @@ bool search_else_nodes(analyzed_ruby_T* analyzed) {
|
|
|
260
296
|
return false;
|
|
261
297
|
}
|
|
262
298
|
|
|
263
|
-
bool
|
|
299
|
+
bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed) {
|
|
264
300
|
if (has_error_message(analyzed, "unexpected 'end', ignoring it")) {
|
|
265
301
|
if (has_error_message(analyzed, "unexpected '=', ignoring it")) {
|
|
266
302
|
// `=end`
|
|
@@ -274,7 +310,7 @@ bool search_end_nodes(analyzed_ruby_T* analyzed) {
|
|
|
274
310
|
return false;
|
|
275
311
|
}
|
|
276
312
|
|
|
277
|
-
bool
|
|
313
|
+
bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed) {
|
|
278
314
|
if (has_error_message(analyzed, "unexpected '}', ignoring it")) {
|
|
279
315
|
analyzed->block_closing_count++;
|
|
280
316
|
return true;
|
|
@@ -283,7 +319,7 @@ bool search_block_closing_nodes(analyzed_ruby_T* analyzed) {
|
|
|
283
319
|
return false;
|
|
284
320
|
}
|
|
285
321
|
|
|
286
|
-
bool
|
|
322
|
+
bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed) {
|
|
287
323
|
if (has_error_message(analyzed, "unexpected 'when', ignoring it")) {
|
|
288
324
|
analyzed->when_node_count++;
|
|
289
325
|
return true;
|
|
@@ -292,7 +328,7 @@ bool search_when_nodes(analyzed_ruby_T* analyzed) {
|
|
|
292
328
|
return false;
|
|
293
329
|
}
|
|
294
330
|
|
|
295
|
-
bool
|
|
331
|
+
bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed) {
|
|
296
332
|
if (has_error_message(analyzed, "unexpected 'in', ignoring it")) {
|
|
297
333
|
analyzed->in_node_count++;
|
|
298
334
|
return true;
|
|
@@ -301,7 +337,7 @@ bool search_in_nodes(analyzed_ruby_T* analyzed) {
|
|
|
301
337
|
return false;
|
|
302
338
|
}
|
|
303
339
|
|
|
304
|
-
bool
|
|
340
|
+
bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed) {
|
|
305
341
|
if (has_error_message(analyzed, "unexpected 'rescue', ignoring it")) {
|
|
306
342
|
analyzed->rescue_node_count++;
|
|
307
343
|
return true;
|
|
@@ -310,7 +346,7 @@ bool search_rescue_nodes(analyzed_ruby_T* analyzed) {
|
|
|
310
346
|
return false;
|
|
311
347
|
}
|
|
312
348
|
|
|
313
|
-
bool
|
|
349
|
+
bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed) {
|
|
314
350
|
if (has_error_message(analyzed, "unexpected 'ensure', ignoring it")) {
|
|
315
351
|
analyzed->ensure_node_count++;
|
|
316
352
|
return true;
|
|
@@ -468,6 +504,18 @@ bool search_unclosed_control_flows(const pm_node_t* node, void* data) {
|
|
|
468
504
|
if (has_opening && !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc)) {
|
|
469
505
|
analyzed->unclosed_control_flow_count++;
|
|
470
506
|
}
|
|
507
|
+
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
case PM_LAMBDA_NODE: {
|
|
512
|
+
const pm_lambda_node_t* lambda_node = (const pm_lambda_node_t*) node;
|
|
513
|
+
bool has_opening = is_do_block(lambda_node->opening_loc) || is_brace_block(lambda_node->opening_loc);
|
|
514
|
+
|
|
515
|
+
if (has_opening && !has_valid_block_closing(lambda_node->opening_loc, lambda_node->closing_loc)) {
|
|
516
|
+
analyzed->unclosed_control_flow_count++;
|
|
517
|
+
}
|
|
518
|
+
|
|
471
519
|
break;
|
|
472
520
|
}
|
|
473
521
|
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
#include <prism.h>
|
|
5
5
|
#include <stdbool.h>
|
|
6
6
|
|
|
7
|
+
#include "../ast_node.h"
|
|
8
|
+
#include "../util/hb_allocator.h"
|
|
7
9
|
#include "analyzed_ruby.h"
|
|
8
|
-
#include "ast_node.h"
|
|
9
10
|
|
|
10
11
|
bool has_if_node(analyzed_ruby_T* analyzed);
|
|
11
12
|
bool has_elsif_node(analyzed_ruby_T* analyzed);
|
|
@@ -26,6 +27,7 @@ bool has_ensure_node(analyzed_ruby_T* analyzed);
|
|
|
26
27
|
bool has_unless_node(analyzed_ruby_T* analyzed);
|
|
27
28
|
bool has_yield_node(analyzed_ruby_T* analyzed);
|
|
28
29
|
bool has_then_keyword(analyzed_ruby_T* analyzed);
|
|
30
|
+
bool has_inline_case_condition(analyzed_ruby_T* analyzed);
|
|
29
31
|
|
|
30
32
|
bool has_error_message(analyzed_ruby_T* anlayzed, const char* message);
|
|
31
33
|
|
|
@@ -34,27 +36,30 @@ bool is_brace_block(pm_location_t opening_location);
|
|
|
34
36
|
bool is_closing_brace(pm_location_t location);
|
|
35
37
|
bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc);
|
|
36
38
|
|
|
37
|
-
bool
|
|
39
|
+
bool search_begin_nodes(const pm_node_t* node, void* data);
|
|
38
40
|
bool search_block_nodes(const pm_node_t* node, void* data);
|
|
39
|
-
bool search_case_nodes(const pm_node_t* node, void* data);
|
|
40
41
|
bool search_case_match_nodes(const pm_node_t* node, void* data);
|
|
41
|
-
bool
|
|
42
|
+
bool search_case_nodes(const pm_node_t* node, void* data);
|
|
42
43
|
bool search_for_nodes(const pm_node_t* node, void* data);
|
|
43
|
-
bool
|
|
44
|
-
bool
|
|
45
|
-
bool search_unless_nodes(const pm_node_t* node, void* data);
|
|
46
|
-
bool search_elsif_nodes(analyzed_ruby_T* analyzed);
|
|
47
|
-
bool search_else_nodes(analyzed_ruby_T* analyzed);
|
|
48
|
-
bool search_end_nodes(analyzed_ruby_T* analyzed);
|
|
49
|
-
bool search_block_closing_nodes(analyzed_ruby_T* analyzed);
|
|
50
|
-
bool search_when_nodes(analyzed_ruby_T* analyzed);
|
|
51
|
-
bool search_in_nodes(analyzed_ruby_T* analyzed);
|
|
52
|
-
bool search_rescue_nodes(analyzed_ruby_T* analyzed);
|
|
53
|
-
bool search_ensure_nodes(analyzed_ruby_T* analyzed);
|
|
54
|
-
bool search_yield_nodes(const pm_node_t* node, void* data);
|
|
44
|
+
bool search_if_nodes(const pm_node_t* node, void* data);
|
|
45
|
+
bool search_in_nodes(const pm_node_t* node, void* data);
|
|
55
46
|
bool search_then_keywords(const pm_node_t* node, void* data);
|
|
56
47
|
bool search_unclosed_control_flows(const pm_node_t* node, void* data);
|
|
48
|
+
bool search_unless_nodes(const pm_node_t* node, void* data);
|
|
49
|
+
bool search_until_nodes(const pm_node_t* node, void* data);
|
|
50
|
+
bool search_when_nodes(const pm_node_t* node, void* data);
|
|
51
|
+
bool search_while_nodes(const pm_node_t* node, void* data);
|
|
52
|
+
bool search_yield_nodes(const pm_node_t* node, void* data);
|
|
53
|
+
|
|
54
|
+
bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed);
|
|
55
|
+
bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed);
|
|
56
|
+
bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed);
|
|
57
|
+
bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed);
|
|
58
|
+
bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed);
|
|
59
|
+
bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed);
|
|
60
|
+
bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed);
|
|
61
|
+
bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed);
|
|
57
62
|
|
|
58
|
-
void check_erb_node_for_missing_end(const AST_NODE_T* node);
|
|
63
|
+
void check_erb_node_for_missing_end(const AST_NODE_T* node, hb_allocator_T* allocator);
|
|
59
64
|
|
|
60
65
|
#endif
|