herb 0.7.5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +8 -5
  3. data/config.yml +26 -6
  4. data/ext/herb/error_helpers.c +57 -3
  5. data/ext/herb/error_helpers.h +1 -1
  6. data/ext/herb/extconf.rb +1 -0
  7. data/ext/herb/extension.c +10 -24
  8. data/ext/herb/extension_helpers.c +3 -3
  9. data/ext/herb/extension_helpers.h +1 -1
  10. data/ext/herb/nodes.c +72 -37
  11. data/herb.gemspec +0 -2
  12. data/lib/herb/ast/helpers.rb +11 -0
  13. data/lib/herb/ast/node.rb +15 -6
  14. data/lib/herb/ast/nodes.rb +609 -392
  15. data/lib/herb/cli.rb +31 -0
  16. data/lib/herb/colors.rb +82 -0
  17. data/lib/herb/engine/compiler.rb +140 -14
  18. data/lib/herb/engine/debug_visitor.rb +1 -5
  19. data/lib/herb/engine/parser_error_overlay.rb +1 -1
  20. data/lib/herb/engine.rb +8 -14
  21. data/lib/herb/errors.rb +166 -56
  22. data/lib/herb/location.rb +2 -2
  23. data/lib/herb/project.rb +86 -21
  24. data/lib/herb/token.rb +14 -2
  25. data/lib/herb/version.rb +1 -1
  26. data/lib/herb.rb +1 -0
  27. data/sig/herb/ast/helpers.rbs +3 -0
  28. data/sig/herb/ast/node.rbs +12 -5
  29. data/sig/herb/ast/nodes.rbs +124 -62
  30. data/sig/herb/colors.rbs +35 -0
  31. data/sig/herb/engine/compiler.rbs +23 -1
  32. data/sig/herb/errors.rbs +74 -20
  33. data/sig/herb/token.rbs +8 -0
  34. data/sig/herb_c_extension.rbs +1 -1
  35. data/sig/serialized_ast_errors.rbs +8 -0
  36. data/src/analyze.c +420 -171
  37. data/src/analyze_helpers.c +5 -0
  38. data/src/analyze_missing_end.c +147 -0
  39. data/src/analyze_transform.c +196 -0
  40. data/src/analyzed_ruby.c +23 -2
  41. data/src/ast_node.c +5 -5
  42. data/src/ast_nodes.c +179 -179
  43. data/src/ast_pretty_print.c +232 -232
  44. data/src/element_source.c +7 -6
  45. data/src/errors.c +246 -126
  46. data/src/extract.c +92 -34
  47. data/src/herb.c +37 -49
  48. data/src/html_util.c +34 -96
  49. data/src/include/analyze.h +10 -2
  50. data/src/include/analyze_helpers.h +3 -0
  51. data/src/include/analyzed_ruby.h +4 -2
  52. data/src/include/ast_node.h +2 -2
  53. data/src/include/ast_nodes.h +67 -66
  54. data/src/include/ast_pretty_print.h +2 -2
  55. data/src/include/element_source.h +3 -1
  56. data/src/include/errors.h +30 -14
  57. data/src/include/extract.h +4 -4
  58. data/src/include/herb.h +6 -7
  59. data/src/include/html_util.h +4 -5
  60. data/src/include/lexer.h +1 -3
  61. data/src/include/lexer_peek_helpers.h +14 -14
  62. data/src/include/lexer_struct.h +3 -2
  63. data/src/include/macros.h +4 -0
  64. data/src/include/parser.h +12 -6
  65. data/src/include/parser_helpers.h +25 -15
  66. data/src/include/pretty_print.h +38 -28
  67. data/src/include/token.h +5 -8
  68. data/src/include/utf8.h +3 -2
  69. data/src/include/util/hb_arena.h +31 -0
  70. data/src/include/util/hb_arena_debug.h +8 -0
  71. data/src/include/util/hb_array.h +33 -0
  72. data/src/include/util/hb_buffer.h +34 -0
  73. data/src/include/util/hb_string.h +29 -0
  74. data/src/include/util/hb_system.h +9 -0
  75. data/src/include/util.h +3 -14
  76. data/src/include/version.h +1 -1
  77. data/src/include/visitor.h +1 -1
  78. data/src/io.c +7 -4
  79. data/src/lexer.c +61 -88
  80. data/src/lexer_peek_helpers.c +35 -37
  81. data/src/main.c +19 -23
  82. data/src/parser.c +282 -201
  83. data/src/parser_helpers.c +46 -40
  84. data/src/parser_match_tags.c +316 -0
  85. data/src/pretty_print.c +82 -106
  86. data/src/token.c +18 -65
  87. data/src/utf8.c +4 -4
  88. data/src/util/hb_arena.c +179 -0
  89. data/src/util/hb_arena_debug.c +237 -0
  90. data/src/{array.c → util/hb_array.c} +26 -27
  91. data/src/util/hb_buffer.c +203 -0
  92. data/src/util/hb_string.c +85 -0
  93. data/src/util/hb_system.c +30 -0
  94. data/src/util.c +29 -99
  95. data/src/visitor.c +54 -54
  96. data/templates/ext/herb/error_helpers.c.erb +3 -3
  97. data/templates/ext/herb/error_helpers.h.erb +1 -1
  98. data/templates/ext/herb/nodes.c.erb +11 -6
  99. data/templates/java/error_helpers.c.erb +75 -0
  100. data/templates/java/error_helpers.h.erb +20 -0
  101. data/templates/java/nodes.c.erb +97 -0
  102. data/templates/java/nodes.h.erb +23 -0
  103. data/templates/java/org/herb/ast/Errors.java.erb +121 -0
  104. data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
  105. data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
  106. data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
  107. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
  108. data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
  109. data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
  110. data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
  111. data/templates/lib/herb/ast/nodes.rb.erb +28 -16
  112. data/templates/lib/herb/errors.rb.erb +17 -12
  113. data/templates/rust/src/ast/nodes.rs.erb +220 -0
  114. data/templates/rust/src/errors.rs.erb +216 -0
  115. data/templates/rust/src/nodes.rs.erb +374 -0
  116. data/templates/src/analyze_missing_end.c.erb +36 -0
  117. data/templates/src/analyze_transform.c.erb +24 -0
  118. data/templates/src/ast_nodes.c.erb +14 -14
  119. data/templates/src/ast_pretty_print.c.erb +36 -36
  120. data/templates/src/errors.c.erb +31 -31
  121. data/templates/src/include/ast_nodes.h.erb +10 -9
  122. data/templates/src/include/ast_pretty_print.h.erb +2 -2
  123. data/templates/src/include/errors.h.erb +6 -6
  124. data/templates/src/parser_match_tags.c.erb +38 -0
  125. data/templates/src/visitor.c.erb +4 -4
  126. data/templates/template.rb +22 -3
  127. data/templates/wasm/error_helpers.cpp.erb +9 -9
  128. data/templates/wasm/error_helpers.h.erb +1 -1
  129. data/templates/wasm/nodes.cpp.erb +9 -9
  130. data/templates/wasm/nodes.h.erb +1 -1
  131. data/vendor/prism/Rakefile +4 -1
  132. data/vendor/prism/config.yml +2 -1
  133. data/vendor/prism/include/prism/ast.h +31 -1
  134. data/vendor/prism/include/prism/diagnostic.h +1 -0
  135. data/vendor/prism/include/prism/version.h +3 -3
  136. data/vendor/prism/src/diagnostic.c +3 -1
  137. data/vendor/prism/src/prism.c +130 -71
  138. data/vendor/prism/src/util/pm_string.c +6 -8
  139. data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
  140. data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
  141. data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
  142. data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
  143. data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
  144. data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
  145. metadata +34 -20
  146. data/lib/herb/libherb/array.rb +0 -51
  147. data/lib/herb/libherb/ast_node.rb +0 -50
  148. data/lib/herb/libherb/buffer.rb +0 -56
  149. data/lib/herb/libherb/extract_result.rb +0 -20
  150. data/lib/herb/libherb/lex_result.rb +0 -32
  151. data/lib/herb/libherb/libherb.rb +0 -52
  152. data/lib/herb/libherb/parse_result.rb +0 -20
  153. data/lib/herb/libherb/token.rb +0 -46
  154. data/lib/herb/libherb.rb +0 -35
  155. data/src/buffer.c +0 -241
  156. data/src/include/array.h +0 -33
  157. data/src/include/buffer.h +0 -39
  158. data/src/include/json.h +0 -28
  159. data/src/include/memory.h +0 -12
  160. data/src/json.c +0 -205
  161. data/src/memory.c +0 -53
data/src/extract.c CHANGED
@@ -1,53 +1,107 @@
1
- #include "include/array.h"
2
- #include "include/buffer.h"
3
1
  #include "include/herb.h"
4
2
  #include "include/io.h"
5
3
  #include "include/lexer.h"
4
+ #include "include/util/hb_array.h"
5
+ #include "include/util/hb_buffer.h"
6
6
 
7
7
  #include <stdlib.h>
8
+ #include <string.h>
8
9
 
9
- void herb_extract_ruby_to_buffer_with_semicolons(const char* source, buffer_T* output) {
10
- array_T* tokens = herb_lex(source);
10
+ void herb_extract_ruby_to_buffer_with_semicolons(const char* source, hb_buffer_T* output) {
11
+ hb_array_T* tokens = herb_lex(source);
11
12
  bool skip_erb_content = false;
13
+ bool is_comment_tag = false;
12
14
 
13
- for (size_t i = 0; i < array_size(tokens); i++) {
14
- const token_T* token = array_get(tokens, i);
15
+ for (size_t i = 0; i < hb_array_size(tokens); i++) {
16
+ const token_T* token = hb_array_get(tokens, i);
15
17
 
16
18
  switch (token->type) {
17
19
  case TOKEN_NEWLINE: {
18
- buffer_append(output, token->value);
20
+ hb_buffer_append(output, token->value);
19
21
  break;
20
22
  }
21
23
 
22
24
  case TOKEN_ERB_START: {
23
- if (strcmp(token->value, "<%#") == 0 || strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0) {
25
+ if (strcmp(token->value, "<%#") == 0) {
26
+ skip_erb_content = true;
27
+ is_comment_tag = true;
28
+ } else if (strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0) {
24
29
  skip_erb_content = true;
30
+ is_comment_tag = false;
31
+ } else {
32
+ skip_erb_content = false;
33
+ is_comment_tag = false;
25
34
  }
26
35
 
27
- buffer_append_whitespace(output, range_length(token->range));
36
+ hb_buffer_append_whitespace(output, range_length(token->range));
28
37
  break;
29
38
  }
30
39
 
31
40
  case TOKEN_ERB_CONTENT: {
32
41
  if (skip_erb_content == false) {
33
- buffer_append(output, token->value);
42
+ bool is_inline_comment = false;
43
+
44
+ if (!is_comment_tag && token->value != NULL) {
45
+ const char* content = token->value;
46
+
47
+ while (*content == ' ' || *content == '\t') {
48
+ content++;
49
+ }
50
+
51
+ if (*content == '#' && token->location.start.line == token->location.end.line) {
52
+ is_comment_tag = true;
53
+ is_inline_comment = true;
54
+ }
55
+ }
56
+
57
+ if (is_inline_comment) {
58
+ hb_buffer_append_whitespace(output, range_length(token->range));
59
+ } else {
60
+ hb_buffer_append(output, token->value);
61
+ }
34
62
  } else {
35
- buffer_append_whitespace(output, range_length(token->range));
63
+ hb_buffer_append_whitespace(output, range_length(token->range));
36
64
  }
37
65
 
38
66
  break;
39
67
  }
40
68
 
41
69
  case TOKEN_ERB_END: {
70
+ bool was_comment = is_comment_tag;
42
71
  skip_erb_content = false;
72
+ is_comment_tag = false;
73
+
74
+ if (was_comment) {
75
+ hb_buffer_append_whitespace(output, range_length(token->range));
76
+ break;
77
+ }
78
+
79
+ bool needs_semicolon = false;
80
+ uint32_t current_line = token->location.end.line;
81
+
82
+ for (size_t j = i + 1; j < hb_array_size(tokens); j++) {
83
+ const token_T* next_token = hb_array_get(tokens, j);
43
84
 
44
- buffer_append_char(output, ';');
45
- buffer_append_whitespace(output, range_length(token->range) - 1);
85
+ if (next_token->type == TOKEN_NEWLINE) { break; }
86
+
87
+ if (next_token->type == TOKEN_ERB_START && next_token->location.start.line == current_line) {
88
+ needs_semicolon = true;
89
+ break;
90
+ }
91
+ }
92
+
93
+ if (needs_semicolon) {
94
+ hb_buffer_append_char(output, ' ');
95
+ hb_buffer_append_char(output, ';');
96
+ hb_buffer_append_whitespace(output, range_length(token->range) - 2);
97
+ } else {
98
+ hb_buffer_append_whitespace(output, range_length(token->range));
99
+ }
46
100
  break;
47
101
  }
48
102
 
49
103
  default: {
50
- buffer_append_whitespace(output, range_length(token->range));
104
+ hb_buffer_append_whitespace(output, range_length(token->range));
51
105
  }
52
106
  }
53
107
  }
@@ -55,16 +109,16 @@ void herb_extract_ruby_to_buffer_with_semicolons(const char* source, buffer_T* o
55
109
  herb_free_tokens(&tokens);
56
110
  }
57
111
 
58
- void herb_extract_ruby_to_buffer(const char* source, buffer_T* output) {
59
- array_T* tokens = herb_lex(source);
112
+ void herb_extract_ruby_to_buffer(const char* source, hb_buffer_T* output) {
113
+ hb_array_T* tokens = herb_lex(source);
60
114
  bool skip_erb_content = false;
61
115
 
62
- for (size_t i = 0; i < array_size(tokens); i++) {
63
- const token_T* token = array_get(tokens, i);
116
+ for (size_t i = 0; i < hb_array_size(tokens); i++) {
117
+ const token_T* token = hb_array_get(tokens, i);
64
118
 
65
119
  switch (token->type) {
66
120
  case TOKEN_NEWLINE: {
67
- buffer_append(output, token->value);
121
+ hb_buffer_append(output, token->value);
68
122
  break;
69
123
  }
70
124
 
@@ -73,15 +127,15 @@ void herb_extract_ruby_to_buffer(const char* source, buffer_T* output) {
73
127
  skip_erb_content = true;
74
128
  }
75
129
 
76
- buffer_append_whitespace(output, range_length(token->range));
130
+ hb_buffer_append_whitespace(output, range_length(token->range));
77
131
  break;
78
132
  }
79
133
 
80
134
  case TOKEN_ERB_CONTENT: {
81
135
  if (skip_erb_content == false) {
82
- buffer_append(output, token->value);
136
+ hb_buffer_append(output, token->value);
83
137
  } else {
84
- buffer_append_whitespace(output, range_length(token->range));
138
+ hb_buffer_append_whitespace(output, range_length(token->range));
85
139
  }
86
140
 
87
141
  break;
@@ -90,12 +144,12 @@ void herb_extract_ruby_to_buffer(const char* source, buffer_T* output) {
90
144
  case TOKEN_ERB_END: {
91
145
  skip_erb_content = false;
92
146
 
93
- buffer_append_whitespace(output, range_length(token->range));
147
+ hb_buffer_append_whitespace(output, range_length(token->range));
94
148
  break;
95
149
  }
96
150
 
97
151
  default: {
98
- buffer_append_whitespace(output, range_length(token->range));
152
+ hb_buffer_append_whitespace(output, range_length(token->range));
99
153
  }
100
154
  }
101
155
  }
@@ -103,17 +157,17 @@ void herb_extract_ruby_to_buffer(const char* source, buffer_T* output) {
103
157
  herb_free_tokens(&tokens);
104
158
  }
105
159
 
106
- void herb_extract_html_to_buffer(const char* source, buffer_T* output) {
107
- array_T* tokens = herb_lex(source);
160
+ void herb_extract_html_to_buffer(const char* source, hb_buffer_T* output) {
161
+ hb_array_T* tokens = herb_lex(source);
108
162
 
109
- for (size_t i = 0; i < array_size(tokens); i++) {
110
- const token_T* token = array_get(tokens, i);
163
+ for (size_t i = 0; i < hb_array_size(tokens); i++) {
164
+ const token_T* token = hb_array_get(tokens, i);
111
165
 
112
166
  switch (token->type) {
113
167
  case TOKEN_ERB_START:
114
168
  case TOKEN_ERB_CONTENT:
115
- case TOKEN_ERB_END: buffer_append_whitespace(output, range_length(token->range)); break;
116
- default: buffer_append(output, token->value);
169
+ case TOKEN_ERB_END: hb_buffer_append_whitespace(output, range_length(token->range)); break;
170
+ default: hb_buffer_append(output, token->value);
117
171
  }
118
172
  }
119
173
 
@@ -121,8 +175,10 @@ void herb_extract_html_to_buffer(const char* source, buffer_T* output) {
121
175
  }
122
176
 
123
177
  char* herb_extract_ruby_with_semicolons(const char* source) {
124
- buffer_T output;
125
- buffer_init(&output);
178
+ if (!source) { return NULL; }
179
+
180
+ hb_buffer_T output;
181
+ hb_buffer_init(&output, strlen(source));
126
182
 
127
183
  herb_extract_ruby_to_buffer_with_semicolons(source, &output);
128
184
 
@@ -130,8 +186,10 @@ char* herb_extract_ruby_with_semicolons(const char* source) {
130
186
  }
131
187
 
132
188
  char* herb_extract(const char* source, const herb_extract_language_T language) {
133
- buffer_T output;
134
- buffer_init(&output);
189
+ if (!source) { return NULL; }
190
+
191
+ hb_buffer_T output;
192
+ hb_buffer_init(&output, strlen(source));
135
193
 
136
194
  switch (language) {
137
195
  case HERB_EXTRACT_LANGUAGE_RUBY: herb_extract_ruby_to_buffer(source, &output); break;
data/src/herb.c CHANGED
@@ -1,97 +1,85 @@
1
1
  #include "include/herb.h"
2
- #include "include/array.h"
3
- #include "include/buffer.h"
4
2
  #include "include/io.h"
5
- #include "include/json.h"
6
3
  #include "include/lexer.h"
7
4
  #include "include/parser.h"
8
5
  #include "include/token.h"
6
+ #include "include/util/hb_array.h"
7
+ #include "include/util/hb_buffer.h"
9
8
  #include "include/version.h"
10
9
 
11
10
  #include <prism.h>
12
11
  #include <stdlib.h>
13
12
 
14
- array_T* herb_lex(const char* source) {
15
- lexer_T* lexer = lexer_init(source);
13
+ hb_array_T* herb_lex(const char* source) {
14
+ lexer_T lexer = { 0 };
15
+ lexer_init(&lexer, source);
16
+
16
17
  token_T* token = NULL;
17
- array_T* tokens = array_init(128);
18
+ hb_array_T* tokens = hb_array_init(128);
18
19
 
19
- while ((token = lexer_next_token(lexer))->type != TOKEN_EOF) {
20
- array_append(tokens, token);
20
+ while ((token = lexer_next_token(&lexer))->type != TOKEN_EOF) {
21
+ hb_array_append(tokens, token);
21
22
  }
22
23
 
23
- array_append(tokens, token);
24
-
25
- lexer_free(lexer);
24
+ hb_array_append(tokens, token);
26
25
 
27
26
  return tokens;
28
27
  }
29
28
 
30
29
  AST_DOCUMENT_NODE_T* herb_parse(const char* source, parser_options_T* options) {
31
- lexer_T* lexer = lexer_init(source);
32
- parser_T* parser = herb_parser_init(lexer, options);
30
+ if (!source) { source = ""; }
31
+
32
+ lexer_T lexer = { 0 };
33
+ lexer_init(&lexer, source);
34
+ parser_T parser = { 0 };
35
+
36
+ parser_options_T parser_options = HERB_DEFAULT_PARSER_OPTIONS;
33
37
 
34
- AST_DOCUMENT_NODE_T* document = herb_parser_parse(parser);
38
+ if (options != NULL) { parser_options = *options; }
35
39
 
36
- parser_free(parser);
40
+ herb_parser_init(&parser, &lexer, parser_options);
41
+
42
+ AST_DOCUMENT_NODE_T* document = herb_parser_parse(&parser);
43
+
44
+ herb_parser_deinit(&parser);
37
45
 
38
46
  return document;
39
47
  }
40
48
 
41
- array_T* herb_lex_file(const char* path) {
49
+ hb_array_T* herb_lex_file(const char* path) {
42
50
  char* source = herb_read_file(path);
43
- array_T* tokens = herb_lex(source);
51
+ hb_array_T* tokens = herb_lex(source);
44
52
 
45
53
  free(source);
46
54
 
47
55
  return tokens;
48
56
  }
49
57
 
50
- void herb_lex_to_buffer(const char* source, buffer_T* output) {
51
- array_T* tokens = herb_lex(source);
52
-
53
- for (size_t i = 0; i < array_size(tokens); i++) {
54
- token_T* token = array_get(tokens, i);
58
+ void herb_lex_to_buffer(const char* source, hb_buffer_T* output) {
59
+ hb_array_T* tokens = herb_lex(source);
55
60
 
56
- char* type = token_to_string(token);
57
- buffer_append(output, type);
58
- free(type);
61
+ for (size_t i = 0; i < hb_array_size(tokens); i++) {
62
+ token_T* token = hb_array_get(tokens, i);
59
63
 
60
- buffer_append(output, "\n");
61
- }
62
-
63
- herb_free_tokens(&tokens);
64
- }
64
+ hb_string_T type = token_to_string(token);
65
+ hb_buffer_append_string(output, type);
66
+ free(type.data);
65
67
 
66
- void herb_lex_json_to_buffer(const char* source, buffer_T* output) {
67
- array_T* tokens = herb_lex(source);
68
-
69
- buffer_T json = buffer_new();
70
- json_start_root_array(&json);
71
-
72
- for (size_t i = 0; i < array_size(tokens); i++) {
73
- token_T* token = array_get(tokens, i);
74
- char* token_json = token_to_json(token);
75
- json_add_raw_string(&json, token_json);
76
- free(token_json);
68
+ hb_buffer_append(output, "\n");
77
69
  }
78
70
 
79
- json_end_array(&json);
80
- buffer_concat(output, &json);
81
-
82
- buffer_free(&json);
83
71
  herb_free_tokens(&tokens);
84
72
  }
85
73
 
86
- void herb_free_tokens(array_T** tokens) {
74
+ void herb_free_tokens(hb_array_T** tokens) {
87
75
  if (!tokens || !*tokens) { return; }
88
76
 
89
- for (size_t i = 0; i < array_size(*tokens); i++) {
90
- token_T* token = array_get(*tokens, i);
77
+ for (size_t i = 0; i < hb_array_size(*tokens); i++) {
78
+ token_T* token = hb_array_get(*tokens, i);
91
79
  if (token) { token_free(token); }
92
80
  }
93
81
 
94
- array_free(tokens);
82
+ hb_array_free(tokens);
95
83
  }
96
84
 
97
85
  const char* herb_version(void) {
data/src/html_util.c CHANGED
@@ -1,76 +1,31 @@
1
1
  #include "include/html_util.h"
2
2
  #include "include/util.h"
3
+ #include "include/util/hb_buffer.h"
4
+ #include "include/util/hb_string.h"
3
5
 
4
6
  #include <ctype.h>
5
7
  #include <stdbool.h>
6
8
  #include <stddef.h>
7
9
  #include <stdlib.h>
8
10
  #include <string.h>
9
- #include <strings.h>
10
11
 
11
12
  // https://developer.mozilla.org/en-US/docs/Glossary/Void_element
12
- bool is_void_element(const char* tag_name) {
13
- if (tag_name == NULL) { return false; }
13
+ bool is_void_element(hb_string_T tag_name) {
14
+ if (hb_string_is_empty(tag_name)) { return false; }
14
15
 
15
- const char* void_tags[] = {
16
- "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr",
16
+ hb_string_T void_tags[14] = {
17
+ hb_string("area"), hb_string("base"), hb_string("br"), hb_string("col"), hb_string("embed"),
18
+ hb_string("hr"), hb_string("img"), hb_string("input"), hb_string("link"), hb_string("meta"),
19
+ hb_string("param"), hb_string("source"), hb_string("track"), hb_string("wbr"),
17
20
  };
18
21
 
19
- for (size_t i = 0; i < sizeof(void_tags) / sizeof(char*); i++) {
20
- if (strcasecmp(tag_name, void_tags[i]) == 0) { return true; }
21
- }
22
-
23
- return false;
24
- }
25
-
26
- bool is_html4_void_element(const char* tag_name) {
27
- if (tag_name == NULL) { return false; }
28
-
29
- const char* html4_void_tags[] = {
30
- "basefont", "bgsound", "command", "frame", "image", "keygen",
31
- };
32
-
33
- for (size_t i = 0; i < sizeof(html4_void_tags) / sizeof(char*); i++) {
34
- if (strcasecmp(tag_name, html4_void_tags[i]) == 0) { return true; }
22
+ for (size_t i = 0; i < 14; i++) {
23
+ if (hb_string_equals_case_insensitive(tag_name, void_tags[i])) { return true; }
35
24
  }
36
25
 
37
26
  return false;
38
27
  }
39
28
 
40
- /**
41
- * @brief Creates an opening HTML tag string like "<tag_name>"
42
- *
43
- * @param tag_name The name of the HTML tag to be enclosed in a opening tag
44
- * @return A newly allocated string containing the opening tag, or NULL if memory allocation fails
45
- * @note The caller is responsible for freeing the returned string
46
- *
47
- * Example:
48
- * @code
49
- * char* tag = html_opening_tag_string("div");
50
- * if (tag) {
51
- * printf("%s\n", tag); // Prints: <div>
52
- * free(tag);
53
- * }
54
- * @endcode
55
- */
56
- char* html_opening_tag_string(const char* tag_name) {
57
- if (tag_name == NULL) { return herb_strdup("<>"); }
58
-
59
- size_t length = strlen(tag_name);
60
- char* result = (char*) malloc(length + 3); // +3 for '<', '>', and '\0'
61
-
62
- if (result == NULL) { return NULL; }
63
-
64
- result[0] = '<';
65
-
66
- memcpy(result + 1, tag_name, length);
67
-
68
- result[length + 1] = '>';
69
- result[length + 2] = '\0';
70
-
71
- return result;
72
- }
73
-
74
29
  /**
75
30
  * @brief Creates a closing HTML tag string like "</tag_name>"
76
31
  *
@@ -80,30 +35,22 @@ char* html_opening_tag_string(const char* tag_name) {
80
35
  *
81
36
  * Example:
82
37
  * @code
83
- * char* tag = html_closing_tag_string("div");
84
- * if (tag) {
85
- * printf("%s\n", tag); // Prints: </div>
86
- * free(tag);
87
- * }
38
+ * hb_string_T tag = html_closing_tag_string(hb_string("div"));
39
+ *
40
+ * printf("%.*s\n", tag.length, tag.data); // Prints: </div>
41
+ * free(tag.data);
88
42
  * @endcode
89
43
  */
90
- char* html_closing_tag_string(const char* tag_name) {
91
- if (tag_name == NULL) { return herb_strdup("</>"); }
44
+ hb_string_T html_closing_tag_string(hb_string_T tag_name) {
45
+ hb_buffer_T buffer;
46
+ hb_buffer_init(&buffer, tag_name.length + 3);
92
47
 
93
- size_t length = strlen(tag_name);
94
- char* result = (char*) malloc(length + 4); // +4 for '<', '/', '>', and '\0'
48
+ hb_buffer_append_char(&buffer, '<');
49
+ hb_buffer_append_char(&buffer, '/');
50
+ hb_buffer_append_string(&buffer, tag_name);
51
+ hb_buffer_append_char(&buffer, '>');
95
52
 
96
- if (result == NULL) { return NULL; }
97
-
98
- result[0] = '<';
99
- result[1] = '/';
100
-
101
- memcpy(result + 2, tag_name, length);
102
-
103
- result[length + 2] = '>';
104
- result[length + 3] = '\0';
105
-
106
- return result;
53
+ return hb_string(buffer.value);
107
54
  }
108
55
 
109
56
  /**
@@ -115,29 +62,20 @@ char* html_closing_tag_string(const char* tag_name) {
115
62
  *
116
63
  * Example:
117
64
  * @code
118
- * char* tag = html_self_closing_tag_string("br");
119
- * if (tag) {
120
- * printf("%s\n", tag); // Prints: <br />
121
- * free(tag);
122
- * }
65
+ * hb_string_T tag = html_self_closing_tag_string(hb_string("br"));
66
+ * printf("%.*s\n", tag.length, tag.data); // Prints: <br />
67
+ * free(tag);
123
68
  * @endcode
124
69
  */
125
- char* html_self_closing_tag_string(const char* tag_name) {
126
- if (tag_name == NULL) { return herb_strdup("< />"); }
127
-
128
- size_t length = strlen(tag_name);
129
- char* result = (char*) malloc(length + 5); // +5 for '<', ' ', '/', '>', and '\0'
130
-
131
- if (result == NULL) { return NULL; }
132
-
133
- result[0] = '<';
134
-
135
- memcpy(result + 1, tag_name, length);
70
+ hb_string_T html_self_closing_tag_string(hb_string_T tag_name) {
71
+ hb_buffer_T buffer;
72
+ hb_buffer_init(&buffer, tag_name.length + 4);
136
73
 
137
- result[length + 1] = ' ';
138
- result[length + 2] = '/';
139
- result[length + 3] = '>';
140
- result[length + 4] = '\0';
74
+ hb_buffer_append_char(&buffer, '<');
75
+ hb_buffer_append_string(&buffer, tag_name);
76
+ hb_buffer_append_char(&buffer, ' ');
77
+ hb_buffer_append_char(&buffer, '/');
78
+ hb_buffer_append_char(&buffer, '>');
141
79
 
142
- return result;
80
+ return hb_string(buffer.value);
143
81
  }
@@ -2,13 +2,13 @@
2
2
  #define HERB_ANALYZE_H
3
3
 
4
4
  #include "analyzed_ruby.h"
5
- #include "array.h"
6
5
  #include "ast_nodes.h"
6
+ #include "util/hb_array.h"
7
7
 
8
8
  typedef struct ANALYZE_RUBY_CONTEXT_STRUCT {
9
9
  AST_DOCUMENT_NODE_T* document;
10
10
  AST_NODE_T* parent;
11
- array_T* ruby_context_stack;
11
+ hb_array_T* ruby_context_stack;
12
12
  } analyze_ruby_context_T;
13
13
 
14
14
  typedef enum {
@@ -33,7 +33,15 @@ typedef enum {
33
33
  CONTROL_TYPE_UNKNOWN
34
34
  } control_type_t;
35
35
 
36
+ typedef struct {
37
+ int loop_depth;
38
+ int rescue_depth;
39
+ } invalid_erb_context_T;
40
+
36
41
  void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source);
37
42
  void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source);
38
43
 
44
+ hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby_context_T* context);
45
+ bool transform_erb_nodes(const AST_NODE_T* node, void* data);
46
+
39
47
  #endif
@@ -5,6 +5,7 @@
5
5
  #include <stdbool.h>
6
6
 
7
7
  #include "analyzed_ruby.h"
8
+ #include "ast_node.h"
8
9
 
9
10
  bool has_if_node(analyzed_ruby_T* analyzed);
10
11
  bool has_elsif_node(analyzed_ruby_T* analyzed);
@@ -46,4 +47,6 @@ bool search_rescue_nodes(analyzed_ruby_T* analyzed);
46
47
  bool search_ensure_nodes(analyzed_ruby_T* analyzed);
47
48
  bool search_yield_nodes(const pm_node_t* node, void* data);
48
49
 
50
+ void check_erb_node_for_missing_end(const AST_NODE_T* node);
51
+
49
52
  #endif
@@ -1,7 +1,8 @@
1
1
  #ifndef HERB_ANALYZED_RUBY_H
2
2
  #define HERB_ANALYZED_RUBY_H
3
3
 
4
- #include "array.h"
4
+ #include "util/hb_array.h"
5
+ #include "util/hb_string.h"
5
6
 
6
7
  #include <prism.h>
7
8
 
@@ -30,7 +31,8 @@ typedef struct ANALYZED_RUBY_STRUCT {
30
31
  bool has_yield_node;
31
32
  } analyzed_ruby_T;
32
33
 
33
- analyzed_ruby_T* init_analyzed_ruby(char* source);
34
+ analyzed_ruby_T* init_analyzed_ruby(hb_string_T source);
34
35
  void free_analyzed_ruby(analyzed_ruby_T* analyzed);
36
+ const char* erb_keyword_from_analyzed_ruby(const analyzed_ruby_T* analyzed);
35
37
 
36
38
  #endif
@@ -6,7 +6,7 @@
6
6
  #include "position.h"
7
7
  #include "token_struct.h"
8
8
 
9
- void ast_node_init(AST_NODE_T* node, ast_node_type_T type, position_T start, position_T end, array_T* errors);
9
+ void ast_node_init(AST_NODE_T* node, ast_node_type_T type, position_T start, position_T end, hb_array_T* errors);
10
10
  void ast_node_free(AST_NODE_T* node);
11
11
 
12
12
  AST_LITERAL_NODE_T* ast_literal_node_init_from_token(const token_T* token);
@@ -22,7 +22,7 @@ void ast_node_set_start(AST_NODE_T* node, position_T position);
22
22
  void ast_node_set_end(AST_NODE_T* node, position_T position);
23
23
 
24
24
  size_t ast_node_errors_count(const AST_NODE_T* node);
25
- array_T* ast_node_errors(const AST_NODE_T* node);
25
+ hb_array_T* ast_node_errors(const AST_NODE_T* node);
26
26
  void ast_node_append_error(const AST_NODE_T* node, ERROR_T* error);
27
27
 
28
28
  void ast_node_set_start_from_token(AST_NODE_T* node, const token_T* token);