@herb-tools/node 0.8.10 → 0.9.1
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/binding.gyp +27 -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 +598 -73
- package/extension/error_helpers.h +20 -3
- package/extension/extension_helpers.cpp +40 -35
- package/extension/extension_helpers.h +2 -2
- package/extension/herb.cpp +194 -64
- package/extension/libherb/analyze/action_view/attribute_extraction_helpers.c +303 -0
- package/extension/libherb/analyze/action_view/attribute_extraction_helpers.h +36 -0
- package/extension/libherb/analyze/action_view/content_tag.c +78 -0
- package/extension/libherb/analyze/action_view/link_to.c +167 -0
- package/extension/libherb/analyze/action_view/registry.c +83 -0
- package/extension/libherb/analyze/action_view/tag.c +70 -0
- package/extension/libherb/analyze/action_view/tag_helper_handler.h +43 -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 +815 -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 +885 -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} +48 -23
- package/extension/libherb/{analyze_helpers.h → analyze/helpers.h} +4 -2
- 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 +399 -0
- package/extension/libherb/analyze/prism_annotate.h +16 -0
- package/extension/libherb/analyze/render_nodes.c +761 -0
- package/extension/libherb/analyze/render_nodes.h +11 -0
- package/extension/libherb/{analyze_transform.c → analyze/transform.c} +24 -3
- package/extension/libherb/ast_node.c +17 -7
- package/extension/libherb/ast_node.h +11 -5
- package/extension/libherb/ast_nodes.c +760 -388
- package/extension/libherb/ast_nodes.h +155 -39
- package/extension/libherb/ast_pretty_print.c +265 -7
- package/extension/libherb/ast_pretty_print.h +6 -1
- package/extension/libherb/element_source.h +3 -8
- package/extension/libherb/errors.c +1455 -520
- package/extension/libherb/errors.h +207 -56
- package/extension/libherb/extract.c +145 -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 +43 -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} +4 -2
- package/extension/libherb/include/analyze/invalid_structures.h +11 -0
- package/extension/libherb/include/analyze/prism_annotate.h +16 -0
- package/extension/libherb/include/analyze/render_nodes.h +11 -0
- package/extension/libherb/include/ast_node.h +11 -5
- package/extension/libherb/include/ast_nodes.h +155 -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 +207 -56
- 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 +28 -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.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 +53 -28
- package/extension/libherb/parser.c +784 -247
- package/extension/libherb/parser.h +28 -2
- package/extension/libherb/parser_helpers.c +110 -23
- package/extension/libherb/parser_helpers.h +19 -3
- package/extension/libherb/parser_match_tags.c +130 -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.c +21 -11
- package/extension/libherb/util.h +6 -3
- package/extension/libherb/version.h +1 -1
- package/extension/libherb/visitor.c +68 -1
- package/extension/nodes.cpp +593 -6
- package/extension/nodes.h +10 -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 -1608
- 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
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
// NOTE: This file is generated by the templates/template.rb script and should not
|
|
2
|
-
// be modified manually. See /Users/marcoroth/Development/herb-release-0.
|
|
2
|
+
// be modified manually. See /Users/marcoroth/Development/herb-release-0.9.1/templates/src/analyze/missing_end.c.erb
|
|
3
3
|
|
|
4
|
-
#include "include/
|
|
5
|
-
#include "include/errors.h"
|
|
4
|
+
#include "../include/analyze/helpers.h"
|
|
5
|
+
#include "../include/errors.h"
|
|
6
|
+
#include "../include/util/hb_allocator.h"
|
|
7
|
+
#include "../include/util/hb_string.h"
|
|
6
8
|
|
|
7
9
|
|
|
8
|
-
void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
10
|
+
void check_erb_node_for_missing_end(const AST_NODE_T* node, hb_allocator_T* allocator) {
|
|
9
11
|
switch (node->type) {
|
|
10
12
|
case AST_ERB_IF_NODE: {
|
|
11
13
|
const AST_ERB_IF_NODE_T* erb_if_node = (const AST_ERB_IF_NODE_T*) node;
|
|
12
14
|
|
|
13
15
|
if (erb_if_node->end_node == NULL) {
|
|
14
|
-
|
|
15
|
-
"`<" "%" " if " "%" ">`",
|
|
16
|
+
append_missing_erb_end_tag_error(
|
|
17
|
+
hb_string("`<" "%" " if " "%" ">`"),
|
|
16
18
|
erb_if_node->tag_opening->location.start,
|
|
17
19
|
erb_if_node->tag_closing->location.end,
|
|
20
|
+
allocator,
|
|
18
21
|
node->errors
|
|
19
22
|
);
|
|
20
23
|
}
|
|
@@ -26,10 +29,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
26
29
|
const AST_ERB_BLOCK_NODE_T* erb_block_node = (const AST_ERB_BLOCK_NODE_T*) node;
|
|
27
30
|
|
|
28
31
|
if (erb_block_node->end_node == NULL) {
|
|
29
|
-
|
|
30
|
-
"ERB block",
|
|
32
|
+
append_missing_erb_end_tag_error(
|
|
33
|
+
hb_string("ERB block"),
|
|
31
34
|
erb_block_node->tag_opening->location.start,
|
|
32
35
|
erb_block_node->tag_closing->location.end,
|
|
36
|
+
allocator,
|
|
33
37
|
node->errors
|
|
34
38
|
);
|
|
35
39
|
}
|
|
@@ -41,10 +45,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
41
45
|
const AST_ERB_CASE_NODE_T* erb_case_node = (const AST_ERB_CASE_NODE_T*) node;
|
|
42
46
|
|
|
43
47
|
if (erb_case_node->end_node == NULL) {
|
|
44
|
-
|
|
45
|
-
"`<" "%" " case " "%" ">`",
|
|
48
|
+
append_missing_erb_end_tag_error(
|
|
49
|
+
hb_string("`<" "%" " case " "%" ">`"),
|
|
46
50
|
erb_case_node->tag_opening->location.start,
|
|
47
51
|
erb_case_node->tag_closing->location.end,
|
|
52
|
+
allocator,
|
|
48
53
|
node->errors
|
|
49
54
|
);
|
|
50
55
|
}
|
|
@@ -56,10 +61,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
56
61
|
const AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node = (const AST_ERB_CASE_MATCH_NODE_T*) node;
|
|
57
62
|
|
|
58
63
|
if (erb_case_match_node->end_node == NULL) {
|
|
59
|
-
|
|
60
|
-
"`<" "%" " case " "%" ">`",
|
|
64
|
+
append_missing_erb_end_tag_error(
|
|
65
|
+
hb_string("`<" "%" " case " "%" ">`"),
|
|
61
66
|
erb_case_match_node->tag_opening->location.start,
|
|
62
67
|
erb_case_match_node->tag_closing->location.end,
|
|
68
|
+
allocator,
|
|
63
69
|
node->errors
|
|
64
70
|
);
|
|
65
71
|
}
|
|
@@ -71,10 +77,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
71
77
|
const AST_ERB_WHILE_NODE_T* erb_while_node = (const AST_ERB_WHILE_NODE_T*) node;
|
|
72
78
|
|
|
73
79
|
if (erb_while_node->end_node == NULL) {
|
|
74
|
-
|
|
75
|
-
"`<" "%" " while " "%" ">`",
|
|
80
|
+
append_missing_erb_end_tag_error(
|
|
81
|
+
hb_string("`<" "%" " while " "%" ">`"),
|
|
76
82
|
erb_while_node->tag_opening->location.start,
|
|
77
83
|
erb_while_node->tag_closing->location.end,
|
|
84
|
+
allocator,
|
|
78
85
|
node->errors
|
|
79
86
|
);
|
|
80
87
|
}
|
|
@@ -86,10 +93,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
86
93
|
const AST_ERB_UNTIL_NODE_T* erb_until_node = (const AST_ERB_UNTIL_NODE_T*) node;
|
|
87
94
|
|
|
88
95
|
if (erb_until_node->end_node == NULL) {
|
|
89
|
-
|
|
90
|
-
"`<" "%" " until " "%" ">`",
|
|
96
|
+
append_missing_erb_end_tag_error(
|
|
97
|
+
hb_string("`<" "%" " until " "%" ">`"),
|
|
91
98
|
erb_until_node->tag_opening->location.start,
|
|
92
99
|
erb_until_node->tag_closing->location.end,
|
|
100
|
+
allocator,
|
|
93
101
|
node->errors
|
|
94
102
|
);
|
|
95
103
|
}
|
|
@@ -101,10 +109,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
101
109
|
const AST_ERB_FOR_NODE_T* erb_for_node = (const AST_ERB_FOR_NODE_T*) node;
|
|
102
110
|
|
|
103
111
|
if (erb_for_node->end_node == NULL) {
|
|
104
|
-
|
|
105
|
-
"`<" "%" " for " "%" ">`",
|
|
112
|
+
append_missing_erb_end_tag_error(
|
|
113
|
+
hb_string("`<" "%" " for " "%" ">`"),
|
|
106
114
|
erb_for_node->tag_opening->location.start,
|
|
107
115
|
erb_for_node->tag_closing->location.end,
|
|
116
|
+
allocator,
|
|
108
117
|
node->errors
|
|
109
118
|
);
|
|
110
119
|
}
|
|
@@ -116,10 +125,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
116
125
|
const AST_ERB_BEGIN_NODE_T* erb_begin_node = (const AST_ERB_BEGIN_NODE_T*) node;
|
|
117
126
|
|
|
118
127
|
if (erb_begin_node->end_node == NULL) {
|
|
119
|
-
|
|
120
|
-
"`<" "%" " begin " "%" ">`",
|
|
128
|
+
append_missing_erb_end_tag_error(
|
|
129
|
+
hb_string("`<" "%" " begin " "%" ">`"),
|
|
121
130
|
erb_begin_node->tag_opening->location.start,
|
|
122
131
|
erb_begin_node->tag_closing->location.end,
|
|
132
|
+
allocator,
|
|
123
133
|
node->errors
|
|
124
134
|
);
|
|
125
135
|
}
|
|
@@ -131,10 +141,11 @@ void check_erb_node_for_missing_end(const AST_NODE_T* node) {
|
|
|
131
141
|
const AST_ERB_UNLESS_NODE_T* erb_unless_node = (const AST_ERB_UNLESS_NODE_T*) node;
|
|
132
142
|
|
|
133
143
|
if (erb_unless_node->end_node == NULL) {
|
|
134
|
-
|
|
135
|
-
"`<" "%" " unless " "%" ">`",
|
|
144
|
+
append_missing_erb_end_tag_error(
|
|
145
|
+
hb_string("`<" "%" " unless " "%" ">`"),
|
|
136
146
|
erb_unless_node->tag_opening->location.start,
|
|
137
147
|
erb_unless_node->tag_closing->location.end,
|
|
148
|
+
allocator,
|
|
138
149
|
node->errors
|
|
139
150
|
);
|
|
140
151
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#include "../include/analyze/analyze.h"
|
|
2
|
+
#include "../include/ast_node.h"
|
|
3
|
+
#include "../include/ast_nodes.h"
|
|
4
|
+
#include "../include/errors.h"
|
|
5
|
+
#include "../include/extract.h"
|
|
6
|
+
#include "../include/prism_helpers.h"
|
|
7
|
+
#include "../include/util/hb_allocator.h"
|
|
8
|
+
#include "../include/util/hb_string.h"
|
|
9
|
+
|
|
10
|
+
#include <prism.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
#include <string.h>
|
|
13
|
+
|
|
14
|
+
static void parse_erb_content_errors(AST_NODE_T* erb_node, const char* source, hb_allocator_T* allocator) {
|
|
15
|
+
if (!erb_node || erb_node->type != AST_ERB_CONTENT_NODE) { return; }
|
|
16
|
+
AST_ERB_CONTENT_NODE_T* content_node = (AST_ERB_CONTENT_NODE_T*) erb_node;
|
|
17
|
+
|
|
18
|
+
if (!content_node->content || hb_string_is_empty(content_node->content->value)) { return; }
|
|
19
|
+
|
|
20
|
+
char* content = hb_string_to_c_string_using_malloc(content_node->content->value);
|
|
21
|
+
if (!content) { return; }
|
|
22
|
+
|
|
23
|
+
pm_parser_t parser;
|
|
24
|
+
pm_options_t options = { 0, .partial_script = true };
|
|
25
|
+
pm_parser_init(&parser, (const uint8_t*) content, strlen(content), &options);
|
|
26
|
+
|
|
27
|
+
pm_node_t* root = pm_parse(&parser);
|
|
28
|
+
|
|
29
|
+
const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head;
|
|
30
|
+
|
|
31
|
+
if (error != NULL) {
|
|
32
|
+
RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error_with_positions(
|
|
33
|
+
error,
|
|
34
|
+
erb_node->location.start,
|
|
35
|
+
erb_node->location.end,
|
|
36
|
+
allocator
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
hb_array_append(erb_node->errors, parse_error);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pm_node_destroy(&parser, root);
|
|
43
|
+
pm_parser_free(&parser);
|
|
44
|
+
pm_options_free(&options);
|
|
45
|
+
free(content);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source, hb_allocator_T* allocator) {
|
|
49
|
+
char* extracted_ruby = herb_extract_ruby_with_semicolons(source, allocator);
|
|
50
|
+
|
|
51
|
+
if (!extracted_ruby) { return; }
|
|
52
|
+
|
|
53
|
+
pm_parser_t parser;
|
|
54
|
+
pm_options_t options = { 0, .partial_script = true };
|
|
55
|
+
pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
|
|
56
|
+
|
|
57
|
+
pm_node_t* root = pm_parse(&parser);
|
|
58
|
+
|
|
59
|
+
for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) parser.error_list.head; error != NULL;
|
|
60
|
+
error = (const pm_diagnostic_t*) error->node.next) {
|
|
61
|
+
size_t error_offset = (size_t) (error->location.start - parser.start);
|
|
62
|
+
|
|
63
|
+
if (strstr(error->message, "unexpected ';'") != NULL) {
|
|
64
|
+
if (error_offset < strlen(extracted_ruby) && extracted_ruby[error_offset] == ';') {
|
|
65
|
+
if (error_offset >= strlen(source) || source[error_offset] != ';') {
|
|
66
|
+
AST_NODE_T* erb_node = find_erb_content_at_offset(document, source, error_offset);
|
|
67
|
+
|
|
68
|
+
if (erb_node) { parse_erb_content_errors(erb_node, source, allocator); }
|
|
69
|
+
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
RUBY_PARSE_ERROR_T* parse_error =
|
|
76
|
+
ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser, allocator);
|
|
77
|
+
hb_array_append(document->base.errors, parse_error);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pm_node_destroy(&parser, root);
|
|
81
|
+
pm_parser_free(&parser);
|
|
82
|
+
pm_options_free(&options);
|
|
83
|
+
hb_allocator_dealloc(allocator, extracted_ruby);
|
|
84
|
+
}
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#include "../include/analyze/prism_annotate.h"
|
|
2
|
+
#include "../include/ast_node.h"
|
|
3
|
+
#include "../include/ast_nodes.h"
|
|
4
|
+
#include "../include/extract.h"
|
|
5
|
+
#include "../include/herb_prism_node.h"
|
|
6
|
+
#include "../include/prism_context.h"
|
|
7
|
+
#include "../include/util/hb_allocator.h"
|
|
8
|
+
#include "../include/util/hb_buffer.h"
|
|
9
|
+
#include "../include/util/hb_narray.h"
|
|
10
|
+
#include "../include/visitor.h"
|
|
11
|
+
|
|
12
|
+
#include <prism.h>
|
|
13
|
+
#include <string.h>
|
|
14
|
+
|
|
15
|
+
typedef struct {
|
|
16
|
+
uint32_t from;
|
|
17
|
+
uint32_t to;
|
|
18
|
+
} content_range_T;
|
|
19
|
+
|
|
20
|
+
typedef struct {
|
|
21
|
+
pm_parser_t* parser;
|
|
22
|
+
pm_parser_t* structural_parser;
|
|
23
|
+
hb_narray_T* node_list;
|
|
24
|
+
hb_narray_T* structural_node_list;
|
|
25
|
+
bool prism_nodes_deep;
|
|
26
|
+
} prism_annotate_context_T;
|
|
27
|
+
|
|
28
|
+
static void collect_prism_nodes(pm_node_t* node, hb_narray_T* list);
|
|
29
|
+
|
|
30
|
+
static void collect_from_statements(pm_statements_node_t* statements, hb_narray_T* list) {
|
|
31
|
+
if (!statements) { return; }
|
|
32
|
+
|
|
33
|
+
for (size_t i = 0; i < statements->body.size; i++) {
|
|
34
|
+
hb_narray_push(list, &statements->body.nodes[i]);
|
|
35
|
+
collect_prism_nodes(statements->body.nodes[i], list);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static void collect_prism_nodes(pm_node_t* node, hb_narray_T* list) {
|
|
40
|
+
if (!node) { return; }
|
|
41
|
+
|
|
42
|
+
switch (PM_NODE_TYPE(node)) {
|
|
43
|
+
case PM_PROGRAM_NODE: {
|
|
44
|
+
collect_from_statements(((pm_program_node_t*) node)->statements, list);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
case PM_IF_NODE: {
|
|
49
|
+
pm_if_node_t* if_node = (pm_if_node_t*) node;
|
|
50
|
+
collect_from_statements(if_node->statements, list);
|
|
51
|
+
if (if_node->subsequent) { collect_prism_nodes(if_node->subsequent, list); }
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
case PM_UNLESS_NODE: {
|
|
56
|
+
pm_unless_node_t* unless_node = (pm_unless_node_t*) node;
|
|
57
|
+
collect_from_statements(unless_node->statements, list);
|
|
58
|
+
if (unless_node->else_clause) { collect_prism_nodes((pm_node_t*) unless_node->else_clause, list); }
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
case PM_ELSE_NODE: {
|
|
63
|
+
collect_from_statements(((pm_else_node_t*) node)->statements, list);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
case PM_WHILE_NODE: {
|
|
68
|
+
collect_from_statements(((pm_while_node_t*) node)->statements, list);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case PM_UNTIL_NODE: {
|
|
73
|
+
collect_from_statements(((pm_until_node_t*) node)->statements, list);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
case PM_FOR_NODE: {
|
|
78
|
+
collect_from_statements(((pm_for_node_t*) node)->statements, list);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
case PM_CASE_NODE: {
|
|
83
|
+
pm_case_node_t* case_node = (pm_case_node_t*) node;
|
|
84
|
+
|
|
85
|
+
for (size_t i = 0; i < case_node->conditions.size; i++) {
|
|
86
|
+
collect_prism_nodes(case_node->conditions.nodes[i], list);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (case_node->else_clause) { collect_prism_nodes((pm_node_t*) case_node->else_clause, list); }
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
case PM_CASE_MATCH_NODE: {
|
|
94
|
+
pm_case_match_node_t* case_match_node = (pm_case_match_node_t*) node;
|
|
95
|
+
|
|
96
|
+
for (size_t i = 0; i < case_match_node->conditions.size; i++) {
|
|
97
|
+
collect_prism_nodes(case_match_node->conditions.nodes[i], list);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (case_match_node->else_clause) { collect_prism_nodes((pm_node_t*) case_match_node->else_clause, list); }
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
case PM_WHEN_NODE: {
|
|
105
|
+
collect_from_statements(((pm_when_node_t*) node)->statements, list);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
case PM_IN_NODE: {
|
|
110
|
+
collect_from_statements(((pm_in_node_t*) node)->statements, list);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
case PM_BEGIN_NODE: {
|
|
115
|
+
pm_begin_node_t* begin_node = (pm_begin_node_t*) node;
|
|
116
|
+
|
|
117
|
+
collect_from_statements(begin_node->statements, list);
|
|
118
|
+
|
|
119
|
+
if (begin_node->rescue_clause) { collect_prism_nodes((pm_node_t*) begin_node->rescue_clause, list); }
|
|
120
|
+
if (begin_node->else_clause) { collect_prism_nodes((pm_node_t*) begin_node->else_clause, list); }
|
|
121
|
+
if (begin_node->ensure_clause) { collect_prism_nodes((pm_node_t*) begin_node->ensure_clause, list); }
|
|
122
|
+
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
case PM_RESCUE_NODE: {
|
|
127
|
+
pm_rescue_node_t* rescue_node = (pm_rescue_node_t*) node;
|
|
128
|
+
|
|
129
|
+
collect_from_statements(rescue_node->statements, list);
|
|
130
|
+
|
|
131
|
+
if (rescue_node->subsequent) { collect_prism_nodes((pm_node_t*) rescue_node->subsequent, list); }
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
case PM_ENSURE_NODE: {
|
|
136
|
+
collect_from_statements(((pm_ensure_node_t*) node)->statements, list);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
case PM_CALL_NODE: {
|
|
141
|
+
pm_call_node_t* call_node = (pm_call_node_t*) node;
|
|
142
|
+
|
|
143
|
+
if (call_node->block && PM_NODE_TYPE(call_node->block) == PM_BLOCK_NODE) {
|
|
144
|
+
pm_block_node_t* block = (pm_block_node_t*) call_node->block;
|
|
145
|
+
|
|
146
|
+
if (block->body && PM_NODE_TYPE(block->body) == PM_STATEMENTS_NODE) {
|
|
147
|
+
collect_from_statements((pm_statements_node_t*) block->body, list);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
case PM_LAMBDA_NODE: {
|
|
155
|
+
pm_lambda_node_t* lambda_node = (pm_lambda_node_t*) node;
|
|
156
|
+
|
|
157
|
+
if (lambda_node->body && PM_NODE_TYPE(lambda_node->body) == PM_STATEMENTS_NODE) {
|
|
158
|
+
collect_from_statements((pm_statements_node_t*) lambda_node->body, list);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
default: break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static token_T* get_content_token(const AST_NODE_T* node) {
|
|
169
|
+
switch (node->type) {
|
|
170
|
+
case AST_ERB_CONTENT_NODE: return ((AST_ERB_CONTENT_NODE_T*) node)->content;
|
|
171
|
+
case AST_ERB_RENDER_NODE: return ((AST_ERB_RENDER_NODE_T*) node)->content;
|
|
172
|
+
case AST_ERB_IF_NODE: return ((AST_ERB_IF_NODE_T*) node)->content;
|
|
173
|
+
case AST_ERB_BLOCK_NODE: return ((AST_ERB_BLOCK_NODE_T*) node)->content;
|
|
174
|
+
case AST_ERB_CASE_NODE: return ((AST_ERB_CASE_NODE_T*) node)->content;
|
|
175
|
+
case AST_ERB_CASE_MATCH_NODE: return ((AST_ERB_CASE_MATCH_NODE_T*) node)->content;
|
|
176
|
+
case AST_ERB_WHILE_NODE: return ((AST_ERB_WHILE_NODE_T*) node)->content;
|
|
177
|
+
case AST_ERB_UNTIL_NODE: return ((AST_ERB_UNTIL_NODE_T*) node)->content;
|
|
178
|
+
case AST_ERB_FOR_NODE: return ((AST_ERB_FOR_NODE_T*) node)->content;
|
|
179
|
+
case AST_ERB_BEGIN_NODE: return ((AST_ERB_BEGIN_NODE_T*) node)->content;
|
|
180
|
+
case AST_ERB_UNLESS_NODE: return ((AST_ERB_UNLESS_NODE_T*) node)->content;
|
|
181
|
+
default: return NULL;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
static void set_prism_node(AST_NODE_T* node, herb_prism_node_T prism_ref) {
|
|
186
|
+
switch (node->type) {
|
|
187
|
+
case AST_ERB_CONTENT_NODE: ((AST_ERB_CONTENT_NODE_T*) node)->prism_node = prism_ref; break;
|
|
188
|
+
case AST_ERB_RENDER_NODE: ((AST_ERB_RENDER_NODE_T*) node)->prism_node = prism_ref; break;
|
|
189
|
+
case AST_ERB_IF_NODE: ((AST_ERB_IF_NODE_T*) node)->prism_node = prism_ref; break;
|
|
190
|
+
case AST_ERB_BLOCK_NODE: ((AST_ERB_BLOCK_NODE_T*) node)->prism_node = prism_ref; break;
|
|
191
|
+
case AST_ERB_CASE_NODE: ((AST_ERB_CASE_NODE_T*) node)->prism_node = prism_ref; break;
|
|
192
|
+
case AST_ERB_CASE_MATCH_NODE: ((AST_ERB_CASE_MATCH_NODE_T*) node)->prism_node = prism_ref; break;
|
|
193
|
+
case AST_ERB_WHILE_NODE: ((AST_ERB_WHILE_NODE_T*) node)->prism_node = prism_ref; break;
|
|
194
|
+
case AST_ERB_UNTIL_NODE: ((AST_ERB_UNTIL_NODE_T*) node)->prism_node = prism_ref; break;
|
|
195
|
+
case AST_ERB_FOR_NODE: ((AST_ERB_FOR_NODE_T*) node)->prism_node = prism_ref; break;
|
|
196
|
+
case AST_ERB_BEGIN_NODE: ((AST_ERB_BEGIN_NODE_T*) node)->prism_node = prism_ref; break;
|
|
197
|
+
case AST_ERB_UNLESS_NODE: ((AST_ERB_UNLESS_NODE_T*) node)->prism_node = prism_ref; break;
|
|
198
|
+
default: break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
static herb_prism_node_T find_prism_node_for_herb_node(
|
|
203
|
+
pm_parser_t* parser,
|
|
204
|
+
hb_narray_T* node_list,
|
|
205
|
+
const AST_NODE_T* node
|
|
206
|
+
) {
|
|
207
|
+
herb_prism_node_T result = HERB_PRISM_NODE_EMPTY;
|
|
208
|
+
|
|
209
|
+
token_T* content = get_content_token(node);
|
|
210
|
+
if (!content || hb_string_is_empty(content->value)) { return result; }
|
|
211
|
+
|
|
212
|
+
uint32_t content_from = content->range.from;
|
|
213
|
+
uint32_t content_to = content->range.to;
|
|
214
|
+
|
|
215
|
+
for (size_t i = 0; i < hb_narray_size(node_list); i++) {
|
|
216
|
+
pm_node_t* prism_node = *(pm_node_t**) hb_narray_get(node_list, i);
|
|
217
|
+
size_t prism_start = (size_t) (prism_node->location.start - parser->start);
|
|
218
|
+
|
|
219
|
+
if (prism_start >= content_from && prism_start < content_to) {
|
|
220
|
+
result.node = prism_node;
|
|
221
|
+
result.parser = parser;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static bool annotate_visitor(const AST_NODE_T* node, void* data) {
|
|
230
|
+
prism_annotate_context_T* context = (prism_annotate_context_T*) data;
|
|
231
|
+
|
|
232
|
+
if (!get_content_token(node)) { return true; }
|
|
233
|
+
|
|
234
|
+
pm_parser_t* parser;
|
|
235
|
+
hb_narray_T* node_list;
|
|
236
|
+
|
|
237
|
+
if (node->type == AST_ERB_CONTENT_NODE || node->type == AST_ERB_RENDER_NODE || context->prism_nodes_deep) {
|
|
238
|
+
parser = context->parser;
|
|
239
|
+
node_list = context->node_list;
|
|
240
|
+
} else {
|
|
241
|
+
parser = context->structural_parser;
|
|
242
|
+
node_list = context->structural_node_list;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
herb_prism_node_T prism_ref = find_prism_node_for_herb_node(parser, node_list, node);
|
|
246
|
+
|
|
247
|
+
if (prism_ref.node) { set_prism_node((AST_NODE_T*) node, prism_ref); }
|
|
248
|
+
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
static bool collect_content_ranges_visitor(const AST_NODE_T* node, void* data) {
|
|
253
|
+
if (node->type != AST_ERB_CONTENT_NODE && node->type != AST_ERB_RENDER_NODE) { return true; }
|
|
254
|
+
|
|
255
|
+
hb_narray_T* ranges = (hb_narray_T*) data;
|
|
256
|
+
token_T* content = get_content_token(node);
|
|
257
|
+
|
|
258
|
+
if (!content || hb_string_is_empty(content->value)) { return true; }
|
|
259
|
+
|
|
260
|
+
content_range_T range = { .from = content->range.from, .to = content->range.to };
|
|
261
|
+
hb_narray_push(ranges, &range);
|
|
262
|
+
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
void herb_annotate_prism_nodes(
|
|
267
|
+
AST_DOCUMENT_NODE_T* document,
|
|
268
|
+
const char* source,
|
|
269
|
+
bool prism_nodes,
|
|
270
|
+
bool prism_nodes_deep,
|
|
271
|
+
bool prism_program,
|
|
272
|
+
hb_allocator_T* allocator
|
|
273
|
+
) {
|
|
274
|
+
if (!document || !source) { return; }
|
|
275
|
+
|
|
276
|
+
size_t source_len = strlen(source);
|
|
277
|
+
|
|
278
|
+
herb_prism_context_T* context = hb_allocator_alloc(allocator, sizeof(herb_prism_context_T));
|
|
279
|
+
if (!context) { return; }
|
|
280
|
+
|
|
281
|
+
memset(context, 0, sizeof(herb_prism_context_T));
|
|
282
|
+
|
|
283
|
+
context->allocator = allocator;
|
|
284
|
+
context->has_structural = false;
|
|
285
|
+
|
|
286
|
+
if (!hb_buffer_init(&context->ruby_buf, source_len, allocator)) {
|
|
287
|
+
hb_allocator_dealloc(allocator, context);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
herb_extract_ruby_options_T extract_options = {
|
|
292
|
+
.semicolons = true,
|
|
293
|
+
.comments = false,
|
|
294
|
+
.preserve_positions = true,
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
herb_extract_ruby_to_buffer_with_options(source, &context->ruby_buf, &extract_options, allocator);
|
|
298
|
+
|
|
299
|
+
if (!context->ruby_buf.value || context->ruby_buf.length == 0) {
|
|
300
|
+
hb_buffer_free(&context->ruby_buf);
|
|
301
|
+
hb_allocator_dealloc(allocator, context);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
memset(&context->pm_opts, 0, sizeof(pm_options_t));
|
|
306
|
+
pm_options_partial_script_set(&context->pm_opts, true);
|
|
307
|
+
pm_parser_init(
|
|
308
|
+
&context->parser,
|
|
309
|
+
(const uint8_t*) context->ruby_buf.value,
|
|
310
|
+
context->ruby_buf.length,
|
|
311
|
+
&context->pm_opts
|
|
312
|
+
);
|
|
313
|
+
context->root = pm_parse(&context->parser);
|
|
314
|
+
|
|
315
|
+
if (!context->root || context->root->type != PM_PROGRAM_NODE) {
|
|
316
|
+
pm_node_destroy(&context->parser, context->root);
|
|
317
|
+
context->root = NULL;
|
|
318
|
+
|
|
319
|
+
pm_parser_free(&context->parser);
|
|
320
|
+
pm_options_free(&context->pm_opts);
|
|
321
|
+
|
|
322
|
+
hb_buffer_free(&context->ruby_buf);
|
|
323
|
+
hb_allocator_dealloc(allocator, context);
|
|
324
|
+
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
document->prism_context = context;
|
|
329
|
+
|
|
330
|
+
if (prism_program) {
|
|
331
|
+
herb_prism_node_T program_ref = {
|
|
332
|
+
.node = context->root,
|
|
333
|
+
.parser = &context->parser,
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
document->prism_node = program_ref;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
hb_narray_T node_list;
|
|
340
|
+
hb_narray_pointer_init(&node_list, 32, allocator);
|
|
341
|
+
|
|
342
|
+
hb_narray_T structural_node_list;
|
|
343
|
+
hb_narray_pointer_init(&structural_node_list, 32, allocator);
|
|
344
|
+
|
|
345
|
+
if (prism_nodes) {
|
|
346
|
+
collect_prism_nodes(context->root, &node_list);
|
|
347
|
+
|
|
348
|
+
if (!prism_nodes_deep) {
|
|
349
|
+
hb_narray_T content_ranges;
|
|
350
|
+
hb_narray_init(&content_ranges, sizeof(content_range_T), 32, allocator);
|
|
351
|
+
herb_visit_node((AST_NODE_T*) document, collect_content_ranges_visitor, &content_ranges);
|
|
352
|
+
|
|
353
|
+
if (hb_buffer_init(&context->structural_buf, context->ruby_buf.length, allocator)) {
|
|
354
|
+
memcpy(context->structural_buf.value, context->ruby_buf.value, context->ruby_buf.length);
|
|
355
|
+
context->structural_buf.length = context->ruby_buf.length;
|
|
356
|
+
|
|
357
|
+
for (size_t i = 0; i < hb_narray_size(&content_ranges); i++) {
|
|
358
|
+
content_range_T* range = (content_range_T*) hb_narray_get(&content_ranges, i);
|
|
359
|
+
|
|
360
|
+
for (uint32_t j = range->from; j < range->to && j < context->structural_buf.length; j++) {
|
|
361
|
+
context->structural_buf.value[j] = ' ';
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
memset(&context->structural_pm_opts, 0, sizeof(pm_options_t));
|
|
366
|
+
pm_options_partial_script_set(&context->structural_pm_opts, true);
|
|
367
|
+
|
|
368
|
+
pm_parser_init(
|
|
369
|
+
&context->structural_parser,
|
|
370
|
+
(const uint8_t*) context->structural_buf.value,
|
|
371
|
+
context->structural_buf.length,
|
|
372
|
+
&context->structural_pm_opts
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
context->structural_root = pm_parse(&context->structural_parser);
|
|
376
|
+
context->has_structural = true;
|
|
377
|
+
|
|
378
|
+
if (context->structural_root && context->structural_root->type == PM_PROGRAM_NODE) {
|
|
379
|
+
collect_prism_nodes(context->structural_root, &structural_node_list);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
hb_narray_deinit(&content_ranges);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
prism_annotate_context_T annotate_context = {
|
|
387
|
+
.parser = &context->parser,
|
|
388
|
+
.structural_parser = prism_nodes_deep ? &context->parser : &context->structural_parser,
|
|
389
|
+
.node_list = &node_list,
|
|
390
|
+
.structural_node_list = prism_nodes_deep ? &node_list : &structural_node_list,
|
|
391
|
+
.prism_nodes_deep = prism_nodes_deep,
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
herb_visit_node((AST_NODE_T*) document, annotate_visitor, &annotate_context);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
hb_narray_deinit(&node_list);
|
|
398
|
+
hb_narray_deinit(&structural_node_list);
|
|
399
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#ifndef HERB_PRISM_ANNOTATE_H
|
|
2
|
+
#define HERB_PRISM_ANNOTATE_H
|
|
3
|
+
|
|
4
|
+
#include "../ast_nodes.h"
|
|
5
|
+
#include "../util/hb_allocator.h"
|
|
6
|
+
|
|
7
|
+
void herb_annotate_prism_nodes(
|
|
8
|
+
AST_DOCUMENT_NODE_T* document,
|
|
9
|
+
const char* source,
|
|
10
|
+
bool prism_nodes,
|
|
11
|
+
bool prism_nodes_deep,
|
|
12
|
+
bool prism_program,
|
|
13
|
+
hb_allocator_T* allocator
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
#endif
|