@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.
Files changed (171) hide show
  1. package/binding.gyp +27 -8
  2. package/dist/herb-node.cjs +41 -12
  3. package/dist/herb-node.cjs.map +1 -1
  4. package/dist/herb-node.esm.js +8 -1
  5. package/dist/herb-node.esm.js.map +1 -1
  6. package/dist/types/node-backend.d.ts +3 -1
  7. package/extension/error_helpers.cpp +598 -73
  8. package/extension/error_helpers.h +20 -3
  9. package/extension/extension_helpers.cpp +40 -35
  10. package/extension/extension_helpers.h +2 -2
  11. package/extension/herb.cpp +194 -64
  12. package/extension/libherb/analyze/action_view/attribute_extraction_helpers.c +303 -0
  13. package/extension/libherb/analyze/action_view/attribute_extraction_helpers.h +36 -0
  14. package/extension/libherb/analyze/action_view/content_tag.c +78 -0
  15. package/extension/libherb/analyze/action_view/link_to.c +167 -0
  16. package/extension/libherb/analyze/action_view/registry.c +83 -0
  17. package/extension/libherb/analyze/action_view/tag.c +70 -0
  18. package/extension/libherb/analyze/action_view/tag_helper_handler.h +43 -0
  19. package/extension/libherb/analyze/action_view/tag_helper_node_builders.c +305 -0
  20. package/extension/libherb/analyze/action_view/tag_helper_node_builders.h +70 -0
  21. package/extension/libherb/analyze/action_view/tag_helpers.c +815 -0
  22. package/extension/libherb/analyze/action_view/tag_helpers.h +38 -0
  23. package/extension/libherb/analyze/action_view/turbo_frame_tag.c +88 -0
  24. package/extension/libherb/analyze/analyze.c +885 -0
  25. package/extension/libherb/{include → analyze}/analyze.h +14 -4
  26. package/extension/libherb/{analyzed_ruby.c → analyze/analyzed_ruby.c} +13 -11
  27. package/extension/libherb/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  28. package/extension/libherb/analyze/builders.c +343 -0
  29. package/extension/libherb/analyze/builders.h +27 -0
  30. package/extension/libherb/analyze/conditional_elements.c +594 -0
  31. package/extension/libherb/analyze/conditional_elements.h +9 -0
  32. package/extension/libherb/analyze/conditional_open_tags.c +640 -0
  33. package/extension/libherb/analyze/conditional_open_tags.h +9 -0
  34. package/extension/libherb/analyze/control_type.c +250 -0
  35. package/extension/libherb/analyze/control_type.h +14 -0
  36. package/extension/libherb/{analyze_helpers.c → analyze/helpers.c} +48 -23
  37. package/extension/libherb/{analyze_helpers.h → analyze/helpers.h} +4 -2
  38. package/extension/libherb/analyze/invalid_structures.c +193 -0
  39. package/extension/libherb/analyze/invalid_structures.h +11 -0
  40. package/extension/libherb/{analyze_missing_end.c → analyze/missing_end.c} +33 -22
  41. package/extension/libherb/analyze/parse_errors.c +84 -0
  42. package/extension/libherb/analyze/prism_annotate.c +399 -0
  43. package/extension/libherb/analyze/prism_annotate.h +16 -0
  44. package/extension/libherb/analyze/render_nodes.c +761 -0
  45. package/extension/libherb/analyze/render_nodes.h +11 -0
  46. package/extension/libherb/{analyze_transform.c → analyze/transform.c} +24 -3
  47. package/extension/libherb/ast_node.c +17 -7
  48. package/extension/libherb/ast_node.h +11 -5
  49. package/extension/libherb/ast_nodes.c +760 -388
  50. package/extension/libherb/ast_nodes.h +155 -39
  51. package/extension/libherb/ast_pretty_print.c +265 -7
  52. package/extension/libherb/ast_pretty_print.h +6 -1
  53. package/extension/libherb/element_source.h +3 -8
  54. package/extension/libherb/errors.c +1455 -520
  55. package/extension/libherb/errors.h +207 -56
  56. package/extension/libherb/extract.c +145 -49
  57. package/extension/libherb/extract.h +21 -5
  58. package/extension/libherb/herb.c +52 -34
  59. package/extension/libherb/herb.h +18 -6
  60. package/extension/libherb/herb_prism_node.h +13 -0
  61. package/extension/libherb/html_util.c +241 -12
  62. package/extension/libherb/html_util.h +7 -2
  63. package/extension/libherb/include/analyze/action_view/attribute_extraction_helpers.h +36 -0
  64. package/extension/libherb/include/analyze/action_view/tag_helper_handler.h +43 -0
  65. package/extension/libherb/include/analyze/action_view/tag_helper_node_builders.h +70 -0
  66. package/extension/libherb/include/analyze/action_view/tag_helpers.h +38 -0
  67. package/extension/libherb/{analyze.h → include/analyze/analyze.h} +14 -4
  68. package/extension/libherb/include/{analyzed_ruby.h → analyze/analyzed_ruby.h} +3 -3
  69. package/extension/libherb/include/analyze/builders.h +27 -0
  70. package/extension/libherb/include/analyze/conditional_elements.h +9 -0
  71. package/extension/libherb/include/analyze/conditional_open_tags.h +9 -0
  72. package/extension/libherb/include/analyze/control_type.h +14 -0
  73. package/extension/libherb/include/{analyze_helpers.h → analyze/helpers.h} +4 -2
  74. package/extension/libherb/include/analyze/invalid_structures.h +11 -0
  75. package/extension/libherb/include/analyze/prism_annotate.h +16 -0
  76. package/extension/libherb/include/analyze/render_nodes.h +11 -0
  77. package/extension/libherb/include/ast_node.h +11 -5
  78. package/extension/libherb/include/ast_nodes.h +155 -39
  79. package/extension/libherb/include/ast_pretty_print.h +6 -1
  80. package/extension/libherb/include/element_source.h +3 -8
  81. package/extension/libherb/include/errors.h +207 -56
  82. package/extension/libherb/include/extract.h +21 -5
  83. package/extension/libherb/include/herb.h +18 -6
  84. package/extension/libherb/include/herb_prism_node.h +13 -0
  85. package/extension/libherb/include/html_util.h +7 -2
  86. package/extension/libherb/include/io.h +3 -1
  87. package/extension/libherb/include/lex_helpers.h +29 -0
  88. package/extension/libherb/include/lexer.h +1 -1
  89. package/extension/libherb/include/lexer_peek_helpers.h +87 -13
  90. package/extension/libherb/include/lexer_struct.h +2 -0
  91. package/extension/libherb/include/location.h +2 -1
  92. package/extension/libherb/include/parser.h +28 -2
  93. package/extension/libherb/include/parser_helpers.h +19 -3
  94. package/extension/libherb/include/pretty_print.h +10 -5
  95. package/extension/libherb/include/prism_context.h +45 -0
  96. package/extension/libherb/include/prism_helpers.h +10 -7
  97. package/extension/libherb/include/prism_serialized.h +12 -0
  98. package/extension/libherb/include/token.h +16 -4
  99. package/extension/libherb/include/token_struct.h +10 -3
  100. package/extension/libherb/include/utf8.h +2 -1
  101. package/extension/libherb/include/util/hb_allocator.h +78 -0
  102. package/extension/libherb/include/util/hb_arena.h +6 -1
  103. package/extension/libherb/include/util/hb_arena_debug.h +12 -1
  104. package/extension/libherb/include/util/hb_array.h +7 -3
  105. package/extension/libherb/include/util/hb_buffer.h +6 -4
  106. package/extension/libherb/include/util/hb_foreach.h +79 -0
  107. package/extension/libherb/include/util/hb_narray.h +8 -4
  108. package/extension/libherb/include/util/hb_string.h +56 -9
  109. package/extension/libherb/include/util.h +6 -3
  110. package/extension/libherb/include/version.h +1 -1
  111. package/extension/libherb/io.c +3 -2
  112. package/extension/libherb/io.h +3 -1
  113. package/extension/libherb/lex_helpers.h +29 -0
  114. package/extension/libherb/lexer.c +42 -30
  115. package/extension/libherb/lexer.h +1 -1
  116. package/extension/libherb/lexer_peek_helpers.c +12 -74
  117. package/extension/libherb/lexer_peek_helpers.h +87 -13
  118. package/extension/libherb/lexer_struct.h +2 -0
  119. package/extension/libherb/location.c +2 -2
  120. package/extension/libherb/location.h +2 -1
  121. package/extension/libherb/main.c +53 -28
  122. package/extension/libherb/parser.c +784 -247
  123. package/extension/libherb/parser.h +28 -2
  124. package/extension/libherb/parser_helpers.c +110 -23
  125. package/extension/libherb/parser_helpers.h +19 -3
  126. package/extension/libherb/parser_match_tags.c +130 -49
  127. package/extension/libherb/pretty_print.c +29 -24
  128. package/extension/libherb/pretty_print.h +10 -5
  129. package/extension/libherb/prism_context.h +45 -0
  130. package/extension/libherb/prism_helpers.c +30 -27
  131. package/extension/libherb/prism_helpers.h +10 -7
  132. package/extension/libherb/prism_serialized.h +12 -0
  133. package/extension/libherb/ruby_parser.c +2 -0
  134. package/extension/libherb/token.c +151 -66
  135. package/extension/libherb/token.h +16 -4
  136. package/extension/libherb/token_matchers.c +0 -1
  137. package/extension/libherb/token_struct.h +10 -3
  138. package/extension/libherb/utf8.c +7 -6
  139. package/extension/libherb/utf8.h +2 -1
  140. package/extension/libherb/util/hb_allocator.c +341 -0
  141. package/extension/libherb/util/hb_allocator.h +78 -0
  142. package/extension/libherb/util/hb_arena.c +81 -56
  143. package/extension/libherb/util/hb_arena.h +6 -1
  144. package/extension/libherb/util/hb_arena_debug.c +32 -17
  145. package/extension/libherb/util/hb_arena_debug.h +12 -1
  146. package/extension/libherb/util/hb_array.c +30 -15
  147. package/extension/libherb/util/hb_array.h +7 -3
  148. package/extension/libherb/util/hb_buffer.c +17 -21
  149. package/extension/libherb/util/hb_buffer.h +6 -4
  150. package/extension/libherb/util/hb_foreach.h +79 -0
  151. package/extension/libherb/util/hb_narray.c +22 -7
  152. package/extension/libherb/util/hb_narray.h +8 -4
  153. package/extension/libherb/util/hb_string.c +49 -35
  154. package/extension/libherb/util/hb_string.h +56 -9
  155. package/extension/libherb/util.c +21 -11
  156. package/extension/libherb/util.h +6 -3
  157. package/extension/libherb/version.h +1 -1
  158. package/extension/libherb/visitor.c +68 -1
  159. package/extension/nodes.cpp +593 -6
  160. package/extension/nodes.h +10 -1
  161. package/package.json +12 -8
  162. package/src/node-backend.ts +11 -1
  163. package/dist/types/index-cjs.d.cts +0 -1
  164. package/extension/libherb/analyze.c +0 -1608
  165. package/extension/libherb/element_source.c +0 -12
  166. package/extension/libherb/include/util/hb_system.h +0 -9
  167. package/extension/libherb/util/hb_system.c +0 -30
  168. package/extension/libherb/util/hb_system.h +0 -9
  169. package/src/index-cjs.cts +0 -22
  170. /package/dist/types/{index-esm.d.mts → index.d.ts} +0 -0
  171. /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.8.10/templates/src/analyze_missing_end.c.erb
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/analyze_helpers.h"
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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
- append_missingerb_end_tag_error(
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