herb 0.1.1-x86_64-linux-gnu → 0.2.0-x86_64-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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +20 -2
  3. data/ext/herb/extension.c +46 -14
  4. data/ext/herb/extension.h +9 -0
  5. data/ext/herb/extension_helpers.c +9 -27
  6. data/ext/herb/nodes.c +104 -1
  7. data/herb.gemspec +2 -1
  8. data/lib/herb/3.0/herb.so +0 -0
  9. data/lib/herb/3.1/herb.so +0 -0
  10. data/lib/herb/3.2/herb.so +0 -0
  11. data/lib/herb/3.3/herb.so +0 -0
  12. data/lib/herb/3.4/herb.so +0 -0
  13. data/lib/herb/ast/node.rb +40 -4
  14. data/lib/herb/ast/nodes.rb +892 -140
  15. data/lib/herb/ast.rb +1 -0
  16. data/lib/herb/cli.rb +4 -1
  17. data/lib/herb/errors.rb +84 -33
  18. data/lib/herb/lex_result.rb +4 -1
  19. data/lib/herb/libherb/array.rb +3 -0
  20. data/lib/herb/libherb/ast_node.rb +3 -0
  21. data/lib/herb/libherb/buffer.rb +3 -0
  22. data/lib/herb/libherb/extract_result.rb +3 -0
  23. data/lib/herb/libherb/lex_result.rb +3 -0
  24. data/lib/herb/libherb/libherb.rb +3 -0
  25. data/lib/herb/libherb/parse_result.rb +3 -0
  26. data/lib/herb/libherb/token.rb +3 -0
  27. data/lib/herb/libherb.rb +3 -0
  28. data/lib/herb/location.rb +15 -6
  29. data/lib/herb/parse_result.rb +10 -1
  30. data/lib/herb/position.rb +17 -8
  31. data/lib/herb/project.rb +13 -4
  32. data/lib/herb/range.rb +18 -8
  33. data/lib/herb/result.rb +7 -1
  34. data/lib/herb/token.rb +14 -4
  35. data/lib/herb/token_list.rb +10 -1
  36. data/lib/herb/version.rb +2 -1
  37. data/lib/herb/visitor.rb +175 -0
  38. data/lib/herb/warnings.rb +43 -0
  39. data/lib/herb.rb +6 -1
  40. data/sig/herb/ast/node.rbs +48 -0
  41. data/sig/herb/ast/nodes.rbs +941 -0
  42. data/sig/herb/ast.rbs +6 -0
  43. data/sig/herb/errors.rbs +193 -0
  44. data/sig/herb/lex_result.rbs +16 -0
  45. data/sig/herb/location.rbs +30 -0
  46. data/sig/herb/parse_result.rbs +22 -0
  47. data/sig/herb/position.rbs +30 -0
  48. data/sig/herb/range.rbs +33 -0
  49. data/sig/herb/result.rbs +20 -0
  50. data/sig/herb/token.rbs +31 -0
  51. data/sig/herb/token_list.rbs +13 -0
  52. data/sig/herb/version.rbs +5 -0
  53. data/sig/herb/visitor.rbs +104 -0
  54. data/sig/herb/warnings.rbs +28 -0
  55. data/sig/herb.rbs +4 -0
  56. data/sig/serialized.rbs +9 -0
  57. data/sig/serialized_ast_errors.rbs +53 -0
  58. data/sig/serialized_ast_nodes.rbs +221 -0
  59. data/src/analyze.c +138 -43
  60. data/src/analyze_helpers.c +44 -1
  61. data/src/analyzed_ruby.c +10 -1
  62. data/src/ast_nodes.c +103 -1
  63. data/src/ast_pretty_print.c +60 -0
  64. data/src/buffer.c +60 -27
  65. data/src/extract.c +57 -20
  66. data/src/include/analyze.h +3 -0
  67. data/src/include/analyze_helpers.h +6 -0
  68. data/src/include/analyzed_ruby.h +3 -0
  69. data/src/include/ast_nodes.h +32 -0
  70. data/src/include/buffer.h +5 -2
  71. data/src/include/lexer_peek_helpers.h +2 -2
  72. data/src/include/macros.h +2 -2
  73. data/src/include/version.h +1 -1
  74. data/src/lexer.c +1 -1
  75. data/src/parser.c +17 -7
  76. data/src/token.c +1 -1
  77. data/src/util.c +3 -1
  78. data/src/visitor.c +36 -0
  79. metadata +24 -3
  80. /data/{License.txt → LICENSE.txt} +0 -0
@@ -35,6 +35,7 @@ typedef enum {
35
35
  AST_ERB_BLOCK_NODE,
36
36
  AST_ERB_WHEN_NODE,
37
37
  AST_ERB_CASE_NODE,
38
+ AST_ERB_CASE_MATCH_NODE,
38
39
  AST_ERB_WHILE_NODE,
39
40
  AST_ERB_UNTIL_NODE,
40
41
  AST_ERB_FOR_NODE,
@@ -42,6 +43,8 @@ typedef enum {
42
43
  AST_ERB_ENSURE_NODE,
43
44
  AST_ERB_BEGIN_NODE,
44
45
  AST_ERB_UNLESS_NODE,
46
+ AST_ERB_YIELD_NODE,
47
+ AST_ERB_IN_NODE,
45
48
  } ast_node_type_T;
46
49
 
47
50
  typedef struct AST_NODE_STRUCT {
@@ -203,6 +206,17 @@ typedef struct AST_ERB_CASE_NODE_STRUCT {
203
206
  struct AST_ERB_END_NODE_STRUCT* end_node;
204
207
  } AST_ERB_CASE_NODE_T;
205
208
 
209
+ typedef struct AST_ERB_CASE_MATCH_NODE_STRUCT {
210
+ AST_NODE_T base;
211
+ token_T* tag_opening;
212
+ token_T* content;
213
+ token_T* tag_closing;
214
+ array_T* children;
215
+ array_T* conditions;
216
+ struct AST_ERB_ELSE_NODE_STRUCT* else_clause;
217
+ struct AST_ERB_END_NODE_STRUCT* end_node;
218
+ } AST_ERB_CASE_MATCH_NODE_T;
219
+
206
220
  typedef struct AST_ERB_WHILE_NODE_STRUCT {
207
221
  AST_NODE_T base;
208
222
  token_T* tag_opening;
@@ -269,6 +283,21 @@ typedef struct AST_ERB_UNLESS_NODE_STRUCT {
269
283
  struct AST_ERB_END_NODE_STRUCT* end_node;
270
284
  } AST_ERB_UNLESS_NODE_T;
271
285
 
286
+ typedef struct AST_ERB_YIELD_NODE_STRUCT {
287
+ AST_NODE_T base;
288
+ token_T* tag_opening;
289
+ token_T* content;
290
+ token_T* tag_closing;
291
+ } AST_ERB_YIELD_NODE_T;
292
+
293
+ typedef struct AST_ERB_IN_NODE_STRUCT {
294
+ AST_NODE_T base;
295
+ token_T* tag_opening;
296
+ token_T* content;
297
+ token_T* tag_closing;
298
+ array_T* statements;
299
+ } AST_ERB_IN_NODE_T;
300
+
272
301
  AST_DOCUMENT_NODE_T* ast_document_node_init(array_T* children, position_T* start_position, position_T* end_position, array_T* errors);
273
302
  AST_LITERAL_NODE_T* ast_literal_node_init(const char* content, position_T* start_position, position_T* end_position, array_T* errors);
274
303
  AST_HTML_OPEN_TAG_NODE_T* ast_html_open_tag_node_init(token_T* tag_opening, token_T* tag_name, token_T* tag_closing, array_T* children, bool is_void, position_T* start_position, position_T* end_position, array_T* errors);
@@ -289,6 +318,7 @@ AST_ERB_IF_NODE_T* ast_erb_if_node_init(token_T* tag_opening, token_T* content,
289
318
  AST_ERB_BLOCK_NODE_T* ast_erb_block_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* body, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
290
319
  AST_ERB_WHEN_NODE_T* ast_erb_when_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, position_T* start_position, position_T* end_position, array_T* errors);
291
320
  AST_ERB_CASE_NODE_T* ast_erb_case_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* children, array_T* conditions, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
321
+ AST_ERB_CASE_MATCH_NODE_T* ast_erb_case_match_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* children, array_T* conditions, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
292
322
  AST_ERB_WHILE_NODE_T* ast_erb_while_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
293
323
  AST_ERB_UNTIL_NODE_T* ast_erb_until_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
294
324
  AST_ERB_FOR_NODE_T* ast_erb_for_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
@@ -296,6 +326,8 @@ AST_ERB_RESCUE_NODE_T* ast_erb_rescue_node_init(token_T* tag_opening, token_T* c
296
326
  AST_ERB_ENSURE_NODE_T* ast_erb_ensure_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, position_T* start_position, position_T* end_position, array_T* errors);
297
327
  AST_ERB_BEGIN_NODE_T* ast_erb_begin_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, struct AST_ERB_RESCUE_NODE_STRUCT* rescue_clause, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_ENSURE_NODE_STRUCT* ensure_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
298
328
  AST_ERB_UNLESS_NODE_T* ast_erb_unless_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T* start_position, position_T* end_position, array_T* errors);
329
+ AST_ERB_YIELD_NODE_T* ast_erb_yield_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, position_T* start_position, position_T* end_position, array_T* errors);
330
+ AST_ERB_IN_NODE_T* ast_erb_in_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, array_T* statements, position_T* start_position, position_T* end_position, array_T* errors);
299
331
 
300
332
  const char* ast_node_type_to_string(AST_NODE_T* node);
301
333
  const char* ast_node_human_type(AST_NODE_T* node);
data/src/include/buffer.h CHANGED
@@ -13,8 +13,11 @@ typedef struct BUFFER_STRUCT {
13
13
  bool buffer_init(buffer_T* buffer);
14
14
  buffer_T buffer_new(void);
15
15
 
16
- bool buffer_increase_capacity(buffer_T* buffer, size_t required_length);
17
- bool buffer_reserve(buffer_T* buffer, size_t min_capacity);
16
+ bool buffer_increase_capacity(buffer_T* buffer, size_t additional_capacity);
17
+ bool buffer_has_capacity(buffer_T* buffer, size_t required_length);
18
+ bool buffer_expand_capacity(buffer_T* buffer);
19
+ bool buffer_expand_if_needed(buffer_T* buffer, size_t required_length);
20
+ bool buffer_resize(buffer_T* buffer, size_t new_capacity);
18
21
 
19
22
  void buffer_append(buffer_T* buffer, const char* text);
20
23
  void buffer_append_with_length(buffer_T* buffer, const char* text, size_t length);
@@ -1,5 +1,5 @@
1
- #ifndef HERB_LEXER_PEEK_H
2
- #define HERB_LEXER_PEEK_H
1
+ #ifndef HERB_LEXER_PEEK_HELPERS_H
2
+ #define HERB_LEXER_PEEK_HELPERS_H
3
3
 
4
4
  #include "lexer_struct.h"
5
5
 
data/src/include/macros.h CHANGED
@@ -1,9 +1,9 @@
1
1
  #ifndef HERB_MACROS_H
2
2
  #define HERB_MACROS_H
3
3
 
4
- #define MAX(a, b) (a) > (b) ? (a) : (b)
4
+ #define MAX(a, b) ((a) > (b) ? (a) : (b))
5
5
 
6
- #define MIN(a, b) (a) < (b) ? (a) : (b)
6
+ #define MIN(a, b) ((a) < (b) ? (a) : (b))
7
7
 
8
8
  #define unlikely(x) __builtin_expect(!!(x), 0)
9
9
 
@@ -1,6 +1,6 @@
1
1
  #ifndef HERB_VERSION_H
2
2
  #define HERB_VERSION_H
3
3
 
4
- #define HERB_VERSION "0.1.1"
4
+ #define HERB_VERSION "0.2.0"
5
5
 
6
6
  #endif
data/src/lexer.c CHANGED
@@ -72,7 +72,7 @@ token_T* lexer_error(lexer_T* lexer, const char* message) {
72
72
  lexer->current_column
73
73
  );
74
74
 
75
- return token_init(herb_strdup(error_message), TOKEN_ERROR, lexer);
75
+ return token_init(error_message, TOKEN_ERROR, lexer);
76
76
  }
77
77
 
78
78
  static void lexer_advance(lexer_T* lexer) {
data/src/parser.c CHANGED
@@ -124,10 +124,9 @@ static AST_HTML_DOCTYPE_NODE_T* parser_parse_html_doctype(parser_T* parser) {
124
124
  return doctype;
125
125
  }
126
126
 
127
- static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser) {
127
+ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, array_T* document_errors) {
128
128
  position_T* start = position_copy(parser->current_token->location->start);
129
129
 
130
- array_T* errors = array_init(8);
131
130
  buffer_T content = buffer_new();
132
131
 
133
132
  while (token_is_none_of(
@@ -142,16 +141,18 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser) {
142
141
  if (token_is(parser, TOKEN_ERROR)) {
143
142
  buffer_free(&content);
144
143
 
145
- token_T* token = parser_consume_expected(parser, TOKEN_ERROR, errors);
144
+ token_T* token = parser_consume_expected(parser, TOKEN_ERROR, document_errors);
146
145
  append_unexpected_error(
147
146
  "Token Error",
148
147
  "not TOKEN_ERROR",
149
148
  token->value,
150
149
  token->location->start,
151
150
  token->location->end,
152
- errors
151
+ document_errors
153
152
  );
153
+
154
154
  token_free(token);
155
+ position_free(start);
155
156
 
156
157
  return NULL;
157
158
  }
@@ -161,6 +162,8 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser) {
161
162
  token_free(token);
162
163
  }
163
164
 
165
+ array_T* errors = array_init(8);
166
+
164
167
  if (buffer_length(&content) > 0) {
165
168
  AST_HTML_TEXT_NODE_T* text_node =
166
169
  ast_html_text_node_init(buffer_value(&content), start, parser->current_token->location->start, errors);
@@ -265,7 +268,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser
265
268
  false,
266
269
  erb_node->base.location->start,
267
270
  erb_node->base.location->end,
268
- NULL
271
+ errors
269
272
  );
270
273
  }
271
274
 
@@ -284,7 +287,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser
284
287
  false,
285
288
  literal->base.location->start,
286
289
  literal->base.location->end,
287
- NULL
290
+ errors
288
291
  );
289
292
  }
290
293
 
@@ -400,6 +403,9 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
400
403
  token_free(tag_start);
401
404
  token_free(tag_name);
402
405
 
406
+ array_free(&children);
407
+ array_free(&errors);
408
+
403
409
  return NULL;
404
410
  }
405
411
 
@@ -617,7 +623,7 @@ static void parser_parse_in_data_state(parser_T* parser, array_T* children, arra
617
623
  TOKEN_UNDERSCORE,
618
624
  TOKEN_WHITESPACE
619
625
  )) {
620
- array_append(children, parser_parse_text_content(parser));
626
+ array_append(children, parser_parse_text_content(parser, errors));
621
627
  continue;
622
628
  }
623
629
 
@@ -650,6 +656,10 @@ static void parser_parse_stray_closing_tags(parser_T* parser, array_T* children,
650
656
  while (token_is_not(parser, TOKEN_EOF)) {
651
657
  if (token_is_not(parser, TOKEN_HTML_TAG_START_CLOSE)) {
652
658
  parser_append_unexpected_token_error(parser, TOKEN_HTML_TAG_START_CLOSE, errors);
659
+
660
+ token_T* unexpected = parser_advance(parser);
661
+ token_free(unexpected);
662
+
653
663
  continue;
654
664
  }
655
665
 
data/src/token.c CHANGED
@@ -72,7 +72,7 @@ const char* token_type_to_string(const token_type_T type) {
72
72
  case TOKEN_EOF: return "TOKEN_EOF";
73
73
  }
74
74
 
75
- return "Unkown token_type_T";
75
+ return "Unknown token_type_T";
76
76
  }
77
77
 
78
78
  char* token_to_string(const token_T* token) {
data/src/util.c CHANGED
@@ -43,13 +43,15 @@ int count_newlines(const char* string) {
43
43
  }
44
44
 
45
45
  char* replace_char(char* string, const char find, const char replace) {
46
+ char* original_string = string;
47
+
46
48
  while (*string != '\0') {
47
49
  if (*string == find) { *string = replace; }
48
50
 
49
51
  string++;
50
52
  }
51
53
 
52
- return string;
54
+ return original_string;
53
55
  }
54
56
 
55
57
  char* escape_newlines(const char* input) {
data/src/visitor.c CHANGED
@@ -199,6 +199,31 @@ void herb_visit_child_nodes(const AST_NODE_T *node, bool (*visitor)(const AST_NO
199
199
 
200
200
  } break;
201
201
 
202
+ case AST_ERB_CASE_MATCH_NODE: {
203
+ const AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node = ((const AST_ERB_CASE_MATCH_NODE_T *) node);
204
+
205
+ if (erb_case_match_node->children != NULL) {
206
+ for (size_t index = 0; index < array_size(erb_case_match_node->children); index++) {
207
+ herb_visit_node(array_get(erb_case_match_node->children, index), visitor, data);
208
+ }
209
+ }
210
+
211
+ if (erb_case_match_node->conditions != NULL) {
212
+ for (size_t index = 0; index < array_size(erb_case_match_node->conditions); index++) {
213
+ herb_visit_node(array_get(erb_case_match_node->conditions, index), visitor, data);
214
+ }
215
+ }
216
+
217
+ if (erb_case_match_node->else_clause != NULL) {
218
+ herb_visit_node((AST_NODE_T *) erb_case_match_node->else_clause, visitor, data);
219
+ }
220
+
221
+ if (erb_case_match_node->end_node != NULL) {
222
+ herb_visit_node((AST_NODE_T *) erb_case_match_node->end_node, visitor, data);
223
+ }
224
+
225
+ } break;
226
+
202
227
  case AST_ERB_WHILE_NODE: {
203
228
  const AST_ERB_WHILE_NODE_T* erb_while_node = ((const AST_ERB_WHILE_NODE_T *) node);
204
229
 
@@ -316,6 +341,17 @@ void herb_visit_child_nodes(const AST_NODE_T *node, bool (*visitor)(const AST_NO
316
341
 
317
342
  } break;
318
343
 
344
+ case AST_ERB_IN_NODE: {
345
+ const AST_ERB_IN_NODE_T* erb_in_node = ((const AST_ERB_IN_NODE_T *) node);
346
+
347
+ if (erb_in_node->statements != NULL) {
348
+ for (size_t index = 0; index < array_size(erb_in_node->statements); index++) {
349
+ herb_visit_node(array_get(erb_in_node->statements, index), visitor, data);
350
+ }
351
+ }
352
+
353
+ } break;
354
+
319
355
  default: break;
320
356
  }
321
357
  }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: herb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: x86_64-linux-gnu
6
6
  authors:
7
7
  - Marco Roth
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-20 00:00:00.000000000 Z
10
+ date: 2025-06-12 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Powerful and seamless HTML-aware ERB parsing and tooling.
13
13
  email:
@@ -17,7 +17,7 @@ executables:
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - License.txt
20
+ - LICENSE.txt
21
21
  - Makefile
22
22
  - README.md
23
23
  - Rakefile
@@ -62,6 +62,27 @@ files:
62
62
  - lib/herb/token.rb
63
63
  - lib/herb/token_list.rb
64
64
  - lib/herb/version.rb
65
+ - lib/herb/visitor.rb
66
+ - lib/herb/warnings.rb
67
+ - sig/herb.rbs
68
+ - sig/herb/ast.rbs
69
+ - sig/herb/ast/node.rbs
70
+ - sig/herb/ast/nodes.rbs
71
+ - sig/herb/errors.rbs
72
+ - sig/herb/lex_result.rbs
73
+ - sig/herb/location.rbs
74
+ - sig/herb/parse_result.rbs
75
+ - sig/herb/position.rbs
76
+ - sig/herb/range.rbs
77
+ - sig/herb/result.rbs
78
+ - sig/herb/token.rbs
79
+ - sig/herb/token_list.rbs
80
+ - sig/herb/version.rbs
81
+ - sig/herb/visitor.rbs
82
+ - sig/herb/warnings.rbs
83
+ - sig/serialized.rbs
84
+ - sig/serialized_ast_errors.rbs
85
+ - sig/serialized_ast_nodes.rbs
65
86
  - src/analyze.c
66
87
  - src/analyze_helpers.c
67
88
  - src/analyzed_ruby.c
File without changes