herb 0.9.2-arm-linux-gnu → 0.9.4-arm-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/config.yml +125 -0
  4. data/ext/herb/error_helpers.c +172 -2
  5. data/ext/herb/extconf.rb +6 -0
  6. data/ext/herb/extension.c +16 -2
  7. data/ext/herb/extension_helpers.c +6 -5
  8. data/ext/herb/extension_helpers.h +4 -4
  9. data/ext/herb/nodes.c +89 -3
  10. data/lib/herb/3.0/herb.so +0 -0
  11. data/lib/herb/3.1/herb.so +0 -0
  12. data/lib/herb/3.2/herb.so +0 -0
  13. data/lib/herb/3.3/herb.so +0 -0
  14. data/lib/herb/3.4/herb.so +0 -0
  15. data/lib/herb/4.0/herb.so +0 -0
  16. data/lib/herb/ast/erb_content_node.rb +32 -0
  17. data/lib/herb/ast/nodes.rb +244 -3
  18. data/lib/herb/cli.rb +12 -2
  19. data/lib/herb/engine/compiler.rb +166 -75
  20. data/lib/herb/engine/validators/security_validator.rb +40 -0
  21. data/lib/herb/engine.rb +3 -0
  22. data/lib/herb/errors.rb +268 -0
  23. data/lib/herb/parser_options.rb +7 -2
  24. data/lib/herb/project.rb +58 -17
  25. data/lib/herb/version.rb +1 -1
  26. data/lib/herb/visitor.rb +82 -0
  27. data/lib/herb.rb +1 -0
  28. data/sig/herb/ast/erb_content_node.rbs +13 -0
  29. data/sig/herb/ast/nodes.rbs +98 -2
  30. data/sig/herb/engine/compiler.rbs +31 -2
  31. data/sig/herb/engine/validators/security_validator.rbs +4 -0
  32. data/sig/herb/engine.rbs +3 -0
  33. data/sig/herb/errors.rbs +122 -0
  34. data/sig/herb/parser_options.rbs +6 -2
  35. data/sig/herb/visitor.rbs +12 -0
  36. data/sig/serialized_ast_errors.rbs +29 -0
  37. data/sig/serialized_ast_nodes.rbs +19 -0
  38. data/src/analyze/action_view/attribute_extraction_helpers.c +420 -91
  39. data/src/analyze/action_view/image_tag.c +87 -0
  40. data/src/analyze/action_view/javascript_include_tag.c +22 -12
  41. data/src/analyze/action_view/registry.c +6 -3
  42. data/src/analyze/action_view/tag.c +19 -2
  43. data/src/analyze/action_view/tag_helper_node_builders.c +105 -36
  44. data/src/analyze/action_view/tag_helpers.c +792 -44
  45. data/src/analyze/analyze.c +167 -13
  46. data/src/analyze/{helpers.c → analyze_helpers.c} +1 -1
  47. data/src/analyze/analyzed_ruby.c +1 -1
  48. data/src/analyze/builders.c +11 -8
  49. data/src/analyze/conditional_elements.c +6 -7
  50. data/src/analyze/conditional_open_tags.c +6 -7
  51. data/src/analyze/control_type.c +4 -2
  52. data/src/analyze/invalid_structures.c +5 -5
  53. data/src/analyze/missing_end.c +2 -2
  54. data/src/analyze/parse_errors.c +47 -6
  55. data/src/analyze/prism_annotate.c +7 -7
  56. data/src/analyze/render_nodes.c +6 -26
  57. data/src/analyze/strict_locals.c +651 -0
  58. data/src/analyze/transform.c +7 -0
  59. data/src/{ast_node.c → ast/ast_node.c} +8 -8
  60. data/src/{ast_nodes.c → ast/ast_nodes.c} +82 -11
  61. data/src/{ast_pretty_print.c → ast/ast_pretty_print.c} +113 -9
  62. data/src/{pretty_print.c → ast/pretty_print.c} +9 -9
  63. data/src/errors.c +398 -8
  64. data/src/extract.c +5 -5
  65. data/src/herb.c +15 -5
  66. data/src/include/analyze/action_view/attribute_extraction_helpers.h +3 -1
  67. data/src/include/analyze/action_view/tag_helper_handler.h +3 -3
  68. data/src/include/analyze/action_view/tag_helper_node_builders.h +34 -5
  69. data/src/include/analyze/action_view/tag_helpers.h +4 -3
  70. data/src/include/analyze/analyze.h +12 -5
  71. data/src/include/analyze/analyzed_ruby.h +2 -2
  72. data/src/include/analyze/builders.h +4 -4
  73. data/src/include/analyze/conditional_elements.h +2 -2
  74. data/src/include/analyze/conditional_open_tags.h +2 -2
  75. data/src/include/analyze/control_type.h +1 -1
  76. data/src/include/analyze/helpers.h +2 -2
  77. data/src/include/analyze/invalid_structures.h +1 -1
  78. data/src/include/analyze/prism_annotate.h +2 -2
  79. data/src/include/analyze/render_nodes.h +1 -1
  80. data/src/include/analyze/strict_locals.h +11 -0
  81. data/src/include/{ast_node.h → ast/ast_node.h} +4 -4
  82. data/src/include/{ast_nodes.h → ast/ast_nodes.h} +38 -14
  83. data/src/include/{ast_pretty_print.h → ast/ast_pretty_print.h} +3 -3
  84. data/src/include/{pretty_print.h → ast/pretty_print.h} +4 -4
  85. data/src/include/errors.h +65 -7
  86. data/src/include/extract.h +2 -2
  87. data/src/include/herb.h +5 -5
  88. data/src/include/{lex_helpers.h → lexer/lex_helpers.h} +5 -5
  89. data/src/include/{lexer.h → lexer/lexer.h} +1 -1
  90. data/src/include/{lexer_peek_helpers.h → lexer/lexer_peek_helpers.h} +2 -2
  91. data/src/include/{lexer_struct.h → lexer/lexer_struct.h} +2 -2
  92. data/src/include/{token.h → lexer/token.h} +3 -3
  93. data/src/include/{token_matchers.h → lexer/token_matchers.h} +1 -1
  94. data/src/include/{token_struct.h → lexer/token_struct.h} +3 -3
  95. data/src/include/{util → lib}/hb_foreach.h +1 -1
  96. data/src/include/{util → lib}/hb_string.h +5 -1
  97. data/src/include/{location.h → location/location.h} +1 -1
  98. data/src/include/parser/dot_notation.h +12 -0
  99. data/src/include/{parser.h → parser/parser.h} +11 -4
  100. data/src/include/{parser_helpers.h → parser/parser_helpers.h} +6 -6
  101. data/src/include/{prism_context.h → prism/prism_context.h} +2 -2
  102. data/src/include/{prism_helpers.h → prism/prism_helpers.h} +6 -6
  103. data/src/include/{html_util.h → util/html_util.h} +1 -1
  104. data/src/include/util/ruby_util.h +9 -0
  105. data/src/include/{utf8.h → util/utf8.h} +1 -1
  106. data/src/include/{util.h → util/util.h} +1 -1
  107. data/src/include/version.h +1 -1
  108. data/src/include/visitor.h +3 -3
  109. data/src/{lexer_peek_helpers.c → lexer/lexer_peek_helpers.c} +3 -3
  110. data/src/{token.c → lexer/token.c} +8 -8
  111. data/src/{token_matchers.c → lexer/token_matchers.c} +2 -2
  112. data/src/lexer.c +6 -6
  113. data/src/{util → lib}/hb_allocator.c +2 -2
  114. data/src/{util → lib}/hb_arena.c +1 -1
  115. data/src/{util → lib}/hb_arena_debug.c +2 -2
  116. data/src/{util → lib}/hb_array.c +2 -2
  117. data/src/{util → lib}/hb_buffer.c +2 -2
  118. data/src/{util → lib}/hb_narray.c +1 -1
  119. data/src/{util → lib}/hb_string.c +2 -2
  120. data/src/{location.c → location/location.c} +2 -2
  121. data/src/{position.c → location/position.c} +2 -2
  122. data/src/{range.c → location/range.c} +1 -1
  123. data/src/main.c +11 -11
  124. data/src/parser/dot_notation.c +100 -0
  125. data/src/{parser_match_tags.c → parser/match_tags.c} +34 -5
  126. data/src/{parser_helpers.c → parser/parser_helpers.c} +10 -10
  127. data/src/parser.c +68 -32
  128. data/src/{prism_helpers.c → prism/prism_helpers.c} +7 -7
  129. data/src/{ruby_parser.c → prism/ruby_parser.c} +1 -1
  130. data/src/{html_util.c → util/html_util.c} +4 -4
  131. data/src/{io.c → util/io.c} +3 -3
  132. data/src/util/ruby_util.c +42 -0
  133. data/src/{utf8.c → util/utf8.c} +2 -2
  134. data/src/{util.c → util/util.c} +4 -4
  135. data/src/visitor.c +35 -3
  136. data/templates/ext/herb/error_helpers.c.erb +2 -2
  137. data/templates/ext/herb/nodes.c.erb +1 -1
  138. data/templates/java/error_helpers.c.erb +1 -1
  139. data/templates/java/error_helpers.h.erb +2 -2
  140. data/templates/java/nodes.c.erb +4 -4
  141. data/templates/java/nodes.h.erb +1 -1
  142. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +4 -4
  143. data/templates/javascript/packages/node/extension/nodes.cpp.erb +4 -4
  144. data/templates/lib/herb/visitor.rb.erb +14 -0
  145. data/templates/src/analyze/missing_end.c.erb +2 -2
  146. data/templates/src/{ast_nodes.c.erb → ast/ast_nodes.c.erb} +9 -9
  147. data/templates/src/{ast_pretty_print.c.erb → ast/ast_pretty_print.c.erb} +8 -8
  148. data/templates/src/errors.c.erb +8 -8
  149. data/templates/src/include/{ast_nodes.h.erb → ast/ast_nodes.h.erb} +11 -12
  150. data/templates/src/include/{ast_pretty_print.h.erb → ast/ast_pretty_print.h.erb} +2 -2
  151. data/templates/src/include/errors.h.erb +7 -7
  152. data/templates/src/{parser_match_tags.c.erb → parser/match_tags.c.erb} +4 -4
  153. data/templates/src/visitor.c.erb +3 -3
  154. data/templates/wasm/error_helpers.cpp.erb +4 -4
  155. data/templates/wasm/nodes.cpp.erb +5 -5
  156. metadata +76 -68
  157. data/src/include/element_source.h +0 -10
  158. /data/src/include/{util → lib}/hb_allocator.h +0 -0
  159. /data/src/include/{util → lib}/hb_arena.h +0 -0
  160. /data/src/include/{util → lib}/hb_arena_debug.h +0 -0
  161. /data/src/include/{util → lib}/hb_array.h +0 -0
  162. /data/src/include/{util → lib}/hb_buffer.h +0 -0
  163. /data/src/include/{util → lib}/hb_narray.h +0 -0
  164. /data/src/include/{util → lib}/string.h +0 -0
  165. /data/src/include/{position.h → location/position.h} +0 -0
  166. /data/src/include/{range.h → location/range.h} +0 -0
  167. /data/src/include/{herb_prism_node.h → prism/herb_prism_node.h} +0 -0
  168. /data/src/include/{prism_serialized.h → prism/prism_serialized.h} +0 -0
  169. /data/src/include/{ruby_parser.h → prism/ruby_parser.h} +0 -0
  170. /data/src/include/{io.h → util/io.h} +0 -0
  171. /data/templates/src/include/{util → lib}/hb_foreach.h.erb +0 -0
@@ -0,0 +1,87 @@
1
+ #include <prism.h>
2
+ #include <stdbool.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+
6
+ #include "../../include/analyze/action_view/tag_helper_handler.h"
7
+ #include "../../include/lib/hb_buffer.h"
8
+
9
+ bool detect_image_tag(pm_call_node_t* call_node, pm_parser_t* parser) {
10
+ if (!call_node || !call_node->name) { return false; }
11
+
12
+ pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
13
+ return constant && constant->length == 9 && strncmp((const char*) constant->start, "image_tag", 9) == 0;
14
+ }
15
+
16
+ char* extract_image_tag_name(pm_call_node_t* _call_node, pm_parser_t* _parser, hb_allocator_T* allocator) {
17
+ return hb_allocator_strdup(allocator, "img");
18
+ }
19
+
20
+ char* extract_image_tag_content(pm_call_node_t* _call_node, pm_parser_t* _parser, hb_allocator_T* _allocator) {
21
+ return NULL;
22
+ }
23
+
24
+ char* extract_image_tag_src(pm_call_node_t* call_node, pm_parser_t* _parser, hb_allocator_T* allocator) {
25
+ if (!call_node || !call_node->arguments) { return NULL; }
26
+
27
+ pm_arguments_node_t* arguments = call_node->arguments;
28
+ if (!arguments->arguments.size) { return NULL; }
29
+
30
+ pm_node_t* first_argument = arguments->arguments.nodes[0];
31
+
32
+ if (first_argument->type == PM_STRING_NODE) {
33
+ pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
34
+ size_t length = pm_string_length(&string_node->unescaped);
35
+
36
+ return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
37
+ }
38
+
39
+ size_t source_length = first_argument->location.end - first_argument->location.start;
40
+ return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
41
+ }
42
+
43
+ bool image_tag_source_is_url(const char* source, size_t length) {
44
+ if (!source || length == 0) { return false; }
45
+
46
+ if (length >= 2 && source[0] == '/' && source[1] == '/') { return true; }
47
+ if (strstr(source, "://") != NULL) { return true; }
48
+
49
+ return false;
50
+ }
51
+
52
+ char* wrap_in_image_path(
53
+ const char* source,
54
+ size_t source_length,
55
+ const char* path_options,
56
+ hb_allocator_T* allocator
57
+ ) {
58
+ hb_buffer_T buffer;
59
+ hb_buffer_init(&buffer, source_length + 32, allocator);
60
+
61
+ hb_buffer_append(&buffer, "image_path(");
62
+ hb_buffer_append_with_length(&buffer, source, source_length);
63
+
64
+ if (path_options && strlen(path_options) > 0) {
65
+ hb_buffer_append(&buffer, ", ");
66
+ hb_buffer_append(&buffer, path_options);
67
+ }
68
+
69
+ hb_buffer_append(&buffer, ")");
70
+
71
+ char* result = hb_allocator_strdup(allocator, hb_buffer_value(&buffer));
72
+ hb_buffer_free(&buffer);
73
+
74
+ return result;
75
+ }
76
+
77
+ bool image_tag_supports_block(void) {
78
+ return false;
79
+ }
80
+
81
+ const tag_helper_handler_T image_tag_handler = { .name = "image_tag",
82
+ .source =
83
+ HB_STRING_LITERAL("ActionView::Helpers::AssetTagHelper#image_tag"),
84
+ .detect = detect_image_tag,
85
+ .extract_tag_name = extract_image_tag_name,
86
+ .extract_content = extract_image_tag_content,
87
+ .supports_block = image_tag_supports_block };
@@ -1,4 +1,5 @@
1
1
  #include "../../include/analyze/action_view/tag_helper_handler.h"
2
+ #include "../../include/lib/hb_buffer.h"
2
3
 
3
4
  #include <prism.h>
4
5
  #include <stdbool.h>
@@ -62,18 +63,27 @@ bool javascript_include_tag_source_is_url(const char* source, size_t length) {
62
63
  return false;
63
64
  }
64
65
 
65
- char* wrap_in_javascript_path(const char* source, size_t source_length, hb_allocator_T* allocator) {
66
- const char* prefix = "javascript_path(";
67
- const char* suffix = ")";
68
- size_t prefix_length = strlen(prefix);
69
- size_t suffix_length = strlen(suffix);
70
- size_t total_length = prefix_length + source_length + suffix_length;
71
- char* result = hb_allocator_alloc(allocator, total_length + 1);
72
-
73
- memcpy(result, prefix, prefix_length);
74
- memcpy(result + prefix_length, source, source_length);
75
- memcpy(result + prefix_length + source_length, suffix, suffix_length);
76
- result[total_length] = '\0';
66
+ char* wrap_in_javascript_path(
67
+ const char* source,
68
+ size_t source_length,
69
+ const char* path_options,
70
+ hb_allocator_T* allocator
71
+ ) {
72
+ hb_buffer_T buffer;
73
+ hb_buffer_init(&buffer, source_length + 32, allocator);
74
+
75
+ hb_buffer_append(&buffer, "javascript_path(");
76
+ hb_buffer_append_with_length(&buffer, source, source_length);
77
+
78
+ if (path_options && strlen(path_options) > 0) {
79
+ hb_buffer_append(&buffer, ", ");
80
+ hb_buffer_append(&buffer, path_options);
81
+ }
82
+
83
+ hb_buffer_append(&buffer, ")");
84
+
85
+ char* result = hb_allocator_strdup(allocator, hb_buffer_value(&buffer));
86
+ hb_buffer_free(&buffer);
77
87
 
78
88
  return result;
79
89
  }
@@ -1,5 +1,5 @@
1
1
  #include "../../include/analyze/action_view/tag_helper_handler.h"
2
- #include "../../include/util/hb_allocator.h"
2
+ #include "../../include/lib/hb_allocator.h"
3
3
 
4
4
  #include <stdbool.h>
5
5
  #include <stdlib.h>
@@ -10,8 +10,9 @@ extern const tag_helper_handler_T link_to_handler;
10
10
  extern const tag_helper_handler_T turbo_frame_tag_handler;
11
11
  extern const tag_helper_handler_T javascript_tag_handler;
12
12
  extern const tag_helper_handler_T javascript_include_tag_handler;
13
+ extern const tag_helper_handler_T image_tag_handler;
13
14
 
14
- static size_t handlers_count = 6;
15
+ static size_t handlers_count = 7;
15
16
 
16
17
  tag_helper_info_T* tag_helper_info_init(hb_allocator_T* allocator) {
17
18
  tag_helper_info_T* info = hb_allocator_alloc(allocator, sizeof(tag_helper_info_T));
@@ -43,7 +44,7 @@ void tag_helper_info_free(tag_helper_info_T** info) {
43
44
  }
44
45
 
45
46
  tag_helper_handler_T* get_tag_helper_handlers(void) {
46
- static tag_helper_handler_T static_handlers[6];
47
+ static tag_helper_handler_T static_handlers[7];
47
48
  static bool initialized = false;
48
49
 
49
50
  if (!initialized) {
@@ -53,6 +54,8 @@ tag_helper_handler_T* get_tag_helper_handlers(void) {
53
54
  static_handlers[3] = turbo_frame_tag_handler;
54
55
  static_handlers[4] = javascript_tag_handler;
55
56
  static_handlers[5] = javascript_include_tag_handler;
57
+ static_handlers[6] = image_tag_handler;
58
+
56
59
  initialized = true;
57
60
  }
58
61
 
@@ -1,4 +1,5 @@
1
1
  #include "../../include/analyze/action_view/tag_helper_handler.h"
2
+ #include "../../include/util/ruby_util.h"
2
3
 
3
4
  #include <prism.h>
4
5
  #include <stdbool.h>
@@ -23,6 +24,10 @@ char* extract_tag_dot_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_al
23
24
  pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
24
25
  if (!constant) { return NULL; }
25
26
 
27
+ if (is_ruby_introspection_method(hb_string_from_data((const char*) constant->start, constant->length))) {
28
+ return NULL;
29
+ }
30
+
26
31
  char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
27
32
 
28
33
  for (size_t i = 0; i < constant->length && name[i] != '\0'; i++) {
@@ -34,10 +39,17 @@ char* extract_tag_dot_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_al
34
39
 
35
40
  // TODO: this should probably be an array of nodes
36
41
  char* extract_tag_dot_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
37
- (void) parser;
38
-
39
42
  if (!call_node) { return NULL; }
40
43
 
44
+ if (call_node->name) {
45
+ pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
46
+
47
+ if (constant
48
+ && is_ruby_introspection_method(hb_string_from_data((const char*) constant->start, constant->length))) {
49
+ return NULL;
50
+ }
51
+ }
52
+
41
53
  char* block_content = extract_inline_block_content(call_node, allocator);
42
54
  if (block_content) { return block_content; }
43
55
 
@@ -47,11 +59,16 @@ char* extract_tag_dot_content(pm_call_node_t* call_node, pm_parser_t* parser, hb
47
59
  if (arguments->arguments.size) {
48
60
  pm_node_t* first_argument = arguments->arguments.nodes[0];
49
61
 
62
+ if (first_argument->type == PM_KEYWORD_HASH_NODE) { return NULL; }
63
+
50
64
  if (first_argument->type == PM_STRING_NODE) {
51
65
  pm_string_node_t* string_node = (pm_string_node_t*) first_argument;
52
66
  size_t length = pm_string_length(&string_node->unescaped);
53
67
  return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
54
68
  }
69
+
70
+ size_t source_length = first_argument->location.end - first_argument->location.start;
71
+ return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
55
72
  }
56
73
  }
57
74
 
@@ -1,12 +1,12 @@
1
1
  #include "../../include/analyze/action_view/tag_helper_node_builders.h"
2
- #include "../../include/ast_nodes.h"
3
- #include "../../include/location.h"
4
- #include "../../include/position.h"
5
- #include "../../include/range.h"
6
- #include "../../include/token_struct.h"
7
- #include "../../include/util/hb_allocator.h"
8
- #include "../../include/util/hb_array.h"
9
- #include "../../include/util/hb_string.h"
2
+ #include "../../include/ast/ast_nodes.h"
3
+ #include "../../include/lexer/token_struct.h"
4
+ #include "../../include/lib/hb_allocator.h"
5
+ #include "../../include/lib/hb_array.h"
6
+ #include "../../include/lib/hb_string.h"
7
+ #include "../../include/location/location.h"
8
+ #include "../../include/location/position.h"
9
+ #include "../../include/location/range.h"
10
10
 
11
11
  #include <prism.h>
12
12
  #include <stdbool.h>
@@ -26,7 +26,7 @@ token_T* create_synthetic_token(
26
26
  if (value) {
27
27
  size_t length = strlen(value);
28
28
  char* copied = hb_allocator_strndup(allocator, value, length);
29
- token->value = (hb_string_T) { .data = copied, .length = (uint32_t) length };
29
+ token->value = hb_string_from_data(copied, length);
30
30
  } else {
31
31
  token->value = HB_STRING_EMPTY;
32
32
  }
@@ -76,33 +76,47 @@ hb_array_T* prepend_attribute(hb_array_T* attributes, AST_NODE_T* attribute, hb_
76
76
  return new_attributes;
77
77
  }
78
78
 
79
- AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_node(
79
+ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_node_precise(
80
80
  const char* name_string,
81
81
  const char* value_string,
82
- position_T start_position,
83
- position_T end_position,
82
+ attribute_positions_T* positions,
84
83
  hb_allocator_T* allocator
85
84
  ) {
86
85
  if (!name_string) { return NULL; }
87
86
 
88
87
  AST_HTML_ATTRIBUTE_NAME_NODE_T* name_node =
89
- create_attribute_name_node(name_string, start_position, end_position, allocator);
88
+ create_attribute_name_node(name_string, positions->name_start, positions->name_end, allocator);
89
+
90
+ token_T* equals_token = value_string ? create_synthetic_token(
91
+ allocator,
92
+ positions->separator_string,
93
+ positions->separator_type,
94
+ positions->separator_start,
95
+ positions->separator_end
96
+ )
97
+ : NULL;
90
98
 
91
- token_T* equals_token =
92
- value_string ? create_synthetic_token(allocator, "=", TOKEN_EQUALS, start_position, end_position) : NULL;
93
99
  AST_HTML_ATTRIBUTE_VALUE_NODE_T* value_node = NULL;
94
100
 
95
101
  if (value_string) {
96
- token_T* open_quote = create_synthetic_token(allocator, "\"", TOKEN_QUOTE, start_position, end_position);
97
- token_T* close_quote = create_synthetic_token(allocator, "\"", TOKEN_QUOTE, end_position, end_position);
102
+ token_T* open_quote =
103
+ positions->quoted
104
+ ? create_synthetic_token(allocator, "\"", TOKEN_QUOTE, positions->value_start, positions->content_start)
105
+ : NULL;
106
+
107
+ token_T* close_quote =
108
+ positions->quoted
109
+ ? create_synthetic_token(allocator, "\"", TOKEN_QUOTE, positions->content_end, positions->value_end)
110
+ : NULL;
98
111
 
99
112
  AST_LITERAL_NODE_T* value_literal = ast_literal_node_init(
100
113
  hb_string_from_c_string(value_string),
101
- start_position,
102
- end_position,
114
+ positions->content_start,
115
+ positions->content_end,
103
116
  hb_array_init(0, allocator),
104
117
  allocator
105
118
  );
119
+
106
120
  hb_array_T* value_children = hb_array_init(1, allocator);
107
121
  hb_array_append(value_children, (AST_NODE_T*) value_literal);
108
122
 
@@ -110,43 +124,50 @@ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_node(
110
124
  open_quote,
111
125
  value_children,
112
126
  close_quote,
113
- true,
114
- start_position,
115
- end_position,
127
+ positions->quoted,
128
+ positions->value_start,
129
+ positions->value_end,
116
130
  hb_array_init(0, allocator),
117
131
  allocator
118
132
  );
119
133
  }
120
134
 
135
+ position_T attribute_end = value_string ? positions->value_end : positions->name_end;
136
+
121
137
  return ast_html_attribute_node_init(
122
138
  name_node,
123
139
  equals_token,
124
140
  value_node,
125
- start_position,
126
- end_position,
141
+ positions->name_start,
142
+ attribute_end,
127
143
  hb_array_init(0, allocator),
128
144
  allocator
129
145
  );
130
146
  }
131
147
 
132
- AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_with_ruby_literal(
148
+ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_with_ruby_literal_precise(
133
149
  const char* name_string,
134
150
  const char* ruby_content,
135
- position_T start_position,
136
- position_T end_position,
151
+ attribute_positions_T* positions,
137
152
  hb_allocator_T* allocator
138
153
  ) {
139
154
  if (!name_string || !ruby_content) { return NULL; }
140
155
 
141
156
  AST_HTML_ATTRIBUTE_NAME_NODE_T* name_node =
142
- create_attribute_name_node(name_string, start_position, end_position, allocator);
143
-
144
- token_T* equals_token = create_synthetic_token(allocator, ":", TOKEN_COLON, start_position, end_position);
157
+ create_attribute_name_node(name_string, positions->name_start, positions->name_end, allocator);
158
+
159
+ token_T* equals_token = create_synthetic_token(
160
+ allocator,
161
+ positions->separator_string,
162
+ positions->separator_type,
163
+ positions->separator_start,
164
+ positions->separator_end
165
+ );
145
166
 
146
167
  AST_RUBY_LITERAL_NODE_T* ruby_node = ast_ruby_literal_node_init(
147
168
  hb_string_from_c_string(ruby_content),
148
- start_position,
149
- end_position,
169
+ positions->content_start,
170
+ positions->content_end,
150
171
  hb_array_init(0, allocator),
151
172
  allocator
152
173
  );
@@ -159,8 +180,8 @@ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_with_ruby_literal(
159
180
  value_children,
160
181
  NULL,
161
182
  false,
162
- start_position,
163
- end_position,
183
+ positions->content_start,
184
+ positions->content_end,
164
185
  hb_array_init(0, allocator),
165
186
  allocator
166
187
  );
@@ -169,13 +190,61 @@ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_with_ruby_literal(
169
190
  name_node,
170
191
  equals_token,
171
192
  value_node,
172
- start_position,
173
- end_position,
193
+ positions->name_start,
194
+ positions->content_end,
174
195
  hb_array_init(0, allocator),
175
196
  allocator
176
197
  );
177
198
  }
178
199
 
200
+ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_node(
201
+ const char* name_string,
202
+ const char* value_string,
203
+ position_T start_position,
204
+ position_T end_position,
205
+ hb_allocator_T* allocator
206
+ ) {
207
+ attribute_positions_T positions = {
208
+ .name_start = start_position,
209
+ .name_end = end_position,
210
+ .separator_string = "=",
211
+ .separator_type = TOKEN_EQUALS,
212
+ .separator_start = start_position,
213
+ .separator_end = end_position,
214
+ .value_start = start_position,
215
+ .value_end = end_position,
216
+ .content_start = start_position,
217
+ .content_end = end_position,
218
+ .quoted = true,
219
+ };
220
+
221
+ return create_html_attribute_node_precise(name_string, value_string, &positions, allocator);
222
+ }
223
+
224
+ AST_HTML_ATTRIBUTE_NODE_T* create_html_attribute_with_ruby_literal(
225
+ const char* name_string,
226
+ const char* ruby_content,
227
+ position_T start_position,
228
+ position_T end_position,
229
+ hb_allocator_T* allocator
230
+ ) {
231
+ attribute_positions_T positions = {
232
+ .name_start = start_position,
233
+ .name_end = end_position,
234
+ .separator_string = ":",
235
+ .separator_type = TOKEN_COLON,
236
+ .separator_start = start_position,
237
+ .separator_end = end_position,
238
+ .value_start = start_position,
239
+ .value_end = end_position,
240
+ .content_start = start_position,
241
+ .content_end = end_position,
242
+ .quoted = false,
243
+ };
244
+
245
+ return create_html_attribute_with_ruby_literal_precise(name_string, ruby_content, &positions, allocator);
246
+ }
247
+
179
248
  static AST_HTML_ATTRIBUTE_VALUE_NODE_T* create_interpolated_attribute_value(
180
249
  pm_interpolated_string_node_t* interpolated_node,
181
250
  position_T start_position,