herb 0.3.1-arm-linux-gnu → 0.4.2-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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +2 -2
  3. data/README.md +80 -115
  4. data/ext/herb/error_helpers.c +1 -1
  5. data/ext/herb/error_helpers.h +1 -1
  6. data/ext/herb/nodes.c +2 -2
  7. data/ext/herb/nodes.h +1 -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 +6 -1
  14. data/lib/herb/ast/nodes.rb +1 -1
  15. data/lib/herb/cli.rb +18 -2
  16. data/lib/herb/errors.rb +1 -1
  17. data/lib/herb/parse_result.rb +7 -2
  18. data/lib/herb/project.rb +79 -33
  19. data/lib/herb/version.rb +1 -1
  20. data/lib/herb/visitor.rb +1 -1
  21. data/sig/herb/ast/node.rbs +3 -0
  22. data/sig/herb/parse_result.rbs +3 -0
  23. data/sig/serialized_ast_errors.rbs +1 -1
  24. data/sig/serialized_ast_nodes.rbs +1 -1
  25. data/src/analyze.c +61 -16
  26. data/src/analyze_helpers.c +15 -6
  27. data/src/ast_nodes.c +1 -1
  28. data/src/ast_pretty_print.c +1 -1
  29. data/src/errors.c +1 -1
  30. data/src/extract.c +6 -2
  31. data/src/include/analyze_helpers.h +1 -1
  32. data/src/include/ast_nodes.h +1 -1
  33. data/src/include/ast_pretty_print.h +1 -1
  34. data/src/include/errors.h +1 -1
  35. data/src/include/parser_helpers.h +7 -2
  36. data/src/include/pretty_print.h +48 -8
  37. data/src/include/prism_helpers.h +4 -1
  38. data/src/include/token_struct.h +2 -1
  39. data/src/include/version.h +1 -1
  40. data/src/lexer.c +12 -2
  41. data/src/parser.c +13 -4
  42. data/src/parser_helpers.c +10 -3
  43. data/src/pretty_print.c +50 -10
  44. data/src/prism_helpers.c +4 -1
  45. data/src/token.c +1 -0
  46. data/src/visitor.c +1 -1
  47. metadata +2 -2
@@ -7,6 +7,9 @@ module Herb
7
7
  # : (Herb::AST::DocumentNode, String, Array[Herb::Warnings::Warning], Array[Herb::Errors::Error]) -> void
8
8
  def initialize: (Herb::AST::DocumentNode, String, Array[Herb::Warnings::Warning], Array[Herb::Errors::Error]) -> void
9
9
 
10
+ # : () -> Array[Herb::Errors::Error]
11
+ def errors: () -> Array[Herb::Errors::Error]
12
+
10
13
  # : () -> bool
11
14
  def failed?: () -> bool
12
15
 
@@ -2,7 +2,7 @@
2
2
  # typed: true
3
3
 
4
4
  # NOTE: This file is generated by the templates/template.rb script and should not be
5
- # modified manually. See /Users/marcoroth/Development/herb-release/templates/sig/serialized_ast_errors.rbs.erb
5
+ # modified manually. See /Users/marcoroth/Development/herb-release-6/templates/sig/serialized_ast_errors.rbs.erb
6
6
 
7
7
  module Herb
8
8
  type serialized_unexpected_error = serialized_error & {
@@ -2,7 +2,7 @@
2
2
  # typed: true
3
3
 
4
4
  # NOTE: This file is generated by the templates/template.rb script and should not be
5
- # modified manually. See /Users/marcoroth/Development/herb-release/templates/sig/serialized_ast_nodes.rbs.erb
5
+ # modified manually. See /Users/marcoroth/Development/herb-release-6/templates/sig/serialized_ast_nodes.rbs.erb
6
6
 
7
7
  module Herb
8
8
  type serialized_document_node = serialized_node & {
data/src/analyze.c CHANGED
@@ -39,7 +39,7 @@ static analyzed_ruby_T* herb_analyze_ruby(char* source) {
39
39
  search_in_nodes(analyzed);
40
40
  search_rescue_nodes(analyzed);
41
41
  search_ensure_nodes(analyzed);
42
- search_yield_nodes(analyzed);
42
+ search_yield_nodes(analyzed->root, analyzed);
43
43
  search_block_closing_nodes(analyzed);
44
44
 
45
45
  return analyzed;
@@ -49,13 +49,20 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
49
49
  if (node->type == AST_ERB_CONTENT_NODE) {
50
50
  AST_ERB_CONTENT_NODE_T* erb_content_node = (AST_ERB_CONTENT_NODE_T*) node;
51
51
 
52
- analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value);
52
+ const char* opening = erb_content_node->tag_opening->value;
53
+ if (strcmp(opening, "<%%") != 0 && strcmp(opening, "<%%=") != 0) {
54
+ analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value);
53
55
 
54
- if (false) { pretty_print_analyed_ruby(analyzed, erb_content_node->content->value); }
56
+ if (false) { pretty_print_analyed_ruby(analyzed, erb_content_node->content->value); }
55
57
 
56
- erb_content_node->parsed = true;
57
- erb_content_node->valid = analyzed->valid;
58
- erb_content_node->analyzed_ruby = analyzed;
58
+ erb_content_node->parsed = true;
59
+ erb_content_node->valid = analyzed->valid;
60
+ erb_content_node->analyzed_ruby = analyzed;
61
+ } else {
62
+ erb_content_node->parsed = false;
63
+ erb_content_node->valid = true;
64
+ erb_content_node->analyzed_ruby = NULL;
65
+ }
59
66
  }
60
67
 
61
68
  herb_visit_child_nodes(node, analyze_erb_content, data);
@@ -64,12 +71,20 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
64
71
  }
65
72
 
66
73
  static size_t process_block_children(
67
- AST_NODE_T* node, array_T* array, size_t index, array_T* children_array, analyze_ruby_context_T* context,
74
+ AST_NODE_T* node,
75
+ array_T* array,
76
+ size_t index,
77
+ array_T* children_array,
78
+ analyze_ruby_context_T* context,
68
79
  control_type_t parent_type
69
80
  );
70
81
 
71
82
  static size_t process_subsequent_block(
72
- AST_NODE_T* node, array_T* array, size_t index, AST_NODE_T** subsequent_out, analyze_ruby_context_T* context,
83
+ AST_NODE_T* node,
84
+ array_T* array,
85
+ size_t index,
86
+ AST_NODE_T** subsequent_out,
87
+ analyze_ruby_context_T* context,
73
88
  control_type_t parent_type
74
89
  );
75
90
 
@@ -80,8 +95,13 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
80
95
 
81
96
  if (!ruby) { return CONTROL_TYPE_UNKNOWN; }
82
97
 
83
- if (ruby->valid) { return CONTROL_TYPE_UNKNOWN; }
98
+ if (ruby->valid) {
99
+ if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
100
+ return CONTROL_TYPE_UNKNOWN;
101
+ }
84
102
 
103
+ if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
104
+ if (has_block_node(ruby)) { return CONTROL_TYPE_BLOCK; }
85
105
  if (has_if_node(ruby)) { return CONTROL_TYPE_IF; }
86
106
  if (has_elsif_node(ruby)) { return CONTROL_TYPE_ELSIF; }
87
107
  if (has_else_node(ruby)) { return CONTROL_TYPE_ELSE; }
@@ -97,8 +117,6 @@ static control_type_t detect_control_type(AST_ERB_CONTENT_NODE_T* erb_node) {
97
117
  if (has_while_node(ruby)) { return CONTROL_TYPE_WHILE; }
98
118
  if (has_until_node(ruby)) { return CONTROL_TYPE_UNTIL; }
99
119
  if (has_for_node(ruby)) { return CONTROL_TYPE_FOR; }
100
- if (has_block_node(ruby)) { return CONTROL_TYPE_BLOCK; }
101
- if (has_yield_node(ruby)) { return CONTROL_TYPE_YIELD; }
102
120
  if (has_block_closing(ruby)) { return CONTROL_TYPE_BLOCK_CLOSE; }
103
121
 
104
122
  return CONTROL_TYPE_UNKNOWN;
@@ -132,7 +150,10 @@ static bool is_terminator_type(control_type_t parent_type, control_type_t child_
132
150
  }
133
151
 
134
152
  static AST_NODE_T* create_control_node(
135
- AST_ERB_CONTENT_NODE_T* erb_node, array_T* children, AST_NODE_T* subsequent, AST_ERB_END_NODE_T* end_node,
153
+ AST_ERB_CONTENT_NODE_T* erb_node,
154
+ array_T* children,
155
+ AST_NODE_T* subsequent,
156
+ AST_ERB_END_NODE_T* end_node,
136
157
  control_type_t control_type
137
158
  ) {
138
159
  array_T* errors = array_init(8);
@@ -362,7 +383,11 @@ static AST_NODE_T* create_control_node(
362
383
  }
363
384
 
364
385
  static size_t process_control_structure(
365
- AST_NODE_T* node, array_T* array, size_t index, array_T* output_array, analyze_ruby_context_T* context,
386
+ AST_NODE_T* node,
387
+ array_T* array,
388
+ size_t index,
389
+ array_T* output_array,
390
+ analyze_ruby_context_T* context,
366
391
  control_type_t initial_type
367
392
  ) {
368
393
  AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
@@ -858,7 +883,11 @@ static size_t process_control_structure(
858
883
  }
859
884
 
860
885
  static size_t process_subsequent_block(
861
- AST_NODE_T* node, array_T* array, size_t index, AST_NODE_T** subsequent_out, analyze_ruby_context_T* context,
886
+ AST_NODE_T* node,
887
+ array_T* array,
888
+ size_t index,
889
+ AST_NODE_T** subsequent_out,
890
+ analyze_ruby_context_T* context,
862
891
  control_type_t parent_type
863
892
  ) {
864
893
  AST_ERB_CONTENT_NODE_T* erb_node = (AST_ERB_CONTENT_NODE_T*) array_get(array, index);
@@ -922,7 +951,11 @@ static size_t process_subsequent_block(
922
951
  }
923
952
 
924
953
  static size_t process_block_children(
925
- AST_NODE_T* node, array_T* array, size_t index, array_T* children_array, analyze_ruby_context_T* context,
954
+ AST_NODE_T* node,
955
+ array_T* array,
956
+ size_t index,
957
+ array_T* children_array,
958
+ analyze_ruby_context_T* context,
926
959
  control_type_t parent_type
927
960
  ) {
928
961
  while (index < array_size(array)) {
@@ -990,10 +1023,22 @@ static array_T* rewrite_node_array(AST_NODE_T* node, array_T* array, analyze_rub
990
1023
  case CONTROL_TYPE_UNTIL:
991
1024
  case CONTROL_TYPE_FOR:
992
1025
  case CONTROL_TYPE_BLOCK:
993
- case CONTROL_TYPE_YIELD:
994
1026
  index = process_control_structure(node, array, index, new_array, context, type);
995
1027
  continue;
996
1028
 
1029
+ case CONTROL_TYPE_YIELD: {
1030
+ AST_NODE_T* yield_node = create_control_node(erb_node, array_init(8), NULL, NULL, type);
1031
+
1032
+ if (yield_node) {
1033
+ array_append(new_array, yield_node);
1034
+ } else {
1035
+ array_append(new_array, item);
1036
+ }
1037
+
1038
+ index++;
1039
+ break;
1040
+ }
1041
+
997
1042
  default:
998
1043
  array_append(new_array, item);
999
1044
  index++;
@@ -89,12 +89,17 @@ bool search_if_nodes(const pm_node_t* node, void* data) {
89
89
  analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
90
90
 
91
91
  if (node->type == PM_IF_NODE) {
92
- analyzed->has_if_node = true;
93
- return true;
94
- } else {
95
- pm_visit_child_nodes(node, search_if_nodes, analyzed);
92
+ const pm_if_node_t* if_node = (const pm_if_node_t*) node;
93
+
94
+ // Handle ternary
95
+ if (if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL) {
96
+ analyzed->has_if_node = true;
97
+ return true;
98
+ }
96
99
  }
97
100
 
101
+ pm_visit_child_nodes(node, search_if_nodes, analyzed);
102
+
98
103
  return false;
99
104
  }
100
105
 
@@ -274,10 +279,14 @@ bool search_ensure_nodes(analyzed_ruby_T* analyzed) {
274
279
  return false;
275
280
  }
276
281
 
277
- bool search_yield_nodes(analyzed_ruby_T* analyzed) {
278
- if (has_error_message(analyzed, "Invalid yield")) {
282
+ bool search_yield_nodes(const pm_node_t* node, void* data) {
283
+ analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
284
+
285
+ if (node->type == PM_YIELD_NODE) {
279
286
  analyzed->has_yield_node = true;
280
287
  return true;
288
+ } else {
289
+ pm_visit_child_nodes(node, search_yield_nodes, analyzed);
281
290
  }
282
291
 
283
292
  return false;
data/src/ast_nodes.c CHANGED
@@ -1,5 +1,5 @@
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/templates/src/ast_nodes.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-6/templates/src/ast_nodes.c.erb
3
3
 
4
4
  #include <stdio.h>
5
5
  #include <stdbool.h>
@@ -1,5 +1,5 @@
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/templates/src/ast_pretty_print.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-6/templates/src/ast_pretty_print.c.erb
3
3
 
4
4
  #include "include/ast_node.h"
5
5
  #include "include/ast_nodes.h"
data/src/errors.c CHANGED
@@ -1,5 +1,5 @@
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/templates/src/errors.c.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-6/templates/src/errors.c.erb
3
3
 
4
4
  #include "include/array.h"
5
5
  #include "include/errors.h"
data/src/extract.c CHANGED
@@ -20,7 +20,9 @@ void herb_extract_ruby_to_buffer_with_semicolons(const char* source, buffer_T* o
20
20
  }
21
21
 
22
22
  case TOKEN_ERB_START: {
23
- if (strcmp(token->value, "<%#") == 0) { skip_erb_content = true; }
23
+ if (strcmp(token->value, "<%#") == 0 || strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0) {
24
+ skip_erb_content = true;
25
+ }
24
26
 
25
27
  buffer_append_whitespace(output, range_length(token->range));
26
28
  break;
@@ -67,7 +69,9 @@ void herb_extract_ruby_to_buffer(const char* source, buffer_T* output) {
67
69
  }
68
70
 
69
71
  case TOKEN_ERB_START: {
70
- if (strcmp(token->value, "<%#") == 0) { skip_erb_content = true; }
72
+ if (strcmp(token->value, "<%#") == 0 || strcmp(token->value, "<%%") == 0 || strcmp(token->value, "<%%=") == 0) {
73
+ skip_erb_content = true;
74
+ }
71
75
 
72
76
  buffer_append_whitespace(output, range_length(token->range));
73
77
  break;
@@ -44,6 +44,6 @@ bool search_when_nodes(analyzed_ruby_T* analyzed);
44
44
  bool search_in_nodes(analyzed_ruby_T* analyzed);
45
45
  bool search_rescue_nodes(analyzed_ruby_T* analyzed);
46
46
  bool search_ensure_nodes(analyzed_ruby_T* analyzed);
47
- bool search_yield_nodes(analyzed_ruby_T* analyzed);
47
+ bool search_yield_nodes(const pm_node_t* node, void* data);
48
48
 
49
49
  #endif
@@ -1,5 +1,5 @@
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/templates/src/include/ast_nodes.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-6/templates/src/include/ast_nodes.h.erb
3
3
 
4
4
  #ifndef HERB_AST_NODES_H
5
5
  #define HERB_AST_NODES_H
@@ -1,5 +1,5 @@
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/templates/src/include/ast_pretty_print.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-6/templates/src/include/ast_pretty_print.h.erb
3
3
 
4
4
  #ifndef HERB_AST_PRETTY_PRINT_H
5
5
  #define HERB_AST_PRETTY_PRINT_H
data/src/include/errors.h CHANGED
@@ -1,5 +1,5 @@
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/templates/src/include/errors.h.erb
2
+ // be modified manually. See /Users/marcoroth/Development/herb-release-6/templates/src/include/errors.h.erb
3
3
 
4
4
  #ifndef HERB_ERRORS_H
5
5
  #define HERB_ERRORS_H
@@ -16,7 +16,10 @@ void parser_append_unexpected_error(parser_T* parser, const char* description, c
16
16
  void parser_append_unexpected_token_error(parser_T* parser, token_type_T expected_type, array_T* errors);
17
17
 
18
18
  void parser_append_literal_node_from_buffer(
19
- const parser_T* parser, buffer_T* buffer, array_T* children, position_T* start
19
+ const parser_T* parser,
20
+ buffer_T* buffer,
21
+ array_T* children,
22
+ position_T* start
20
23
  );
21
24
 
22
25
  bool parser_in_svg_context(const parser_T* parser);
@@ -26,7 +29,9 @@ token_T* parser_consume_if_present(parser_T* parser, token_type_T type);
26
29
  token_T* parser_consume_expected(parser_T* parser, token_type_T type, array_T* array);
27
30
 
28
31
  AST_HTML_ELEMENT_NODE_T* parser_handle_missing_close_tag(
29
- AST_HTML_OPEN_TAG_NODE_T* open_tag, array_T* body, array_T* errors
32
+ AST_HTML_OPEN_TAG_NODE_T* open_tag,
33
+ array_T* body,
34
+ array_T* errors
30
35
  );
31
36
  void parser_handle_mismatched_tags(const parser_T* parser, const AST_HTML_CLOSE_TAG_NODE_T* close_tag, array_T* errors);
32
37
 
@@ -13,37 +13,77 @@ void pretty_print_newline(size_t indent, size_t relative_indent, buffer_T* buffe
13
13
  void pretty_print_label(const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer);
14
14
 
15
15
  void pretty_print_position_property(
16
- position_T* position, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
16
+ position_T* position,
17
+ const char* name,
18
+ size_t indent,
19
+ size_t relative_indent,
20
+ bool last_property,
21
+ buffer_T* buffer
17
22
  );
18
23
 
19
24
  void pretty_print_location(location_T* location, buffer_T* buffer);
20
25
 
21
26
  void pretty_print_property(
22
- const char* name, const char* value, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
27
+ const char* name,
28
+ const char* value,
29
+ size_t indent,
30
+ size_t relative_indent,
31
+ bool last_property,
32
+ buffer_T* buffer
23
33
  );
24
34
 
25
35
  void pretty_print_size_t_property(
26
- size_t value, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
36
+ size_t value,
37
+ const char* name,
38
+ size_t indent,
39
+ size_t relative_indent,
40
+ bool last_property,
41
+ buffer_T* buffer
27
42
  );
28
43
 
29
44
  void pretty_print_string_property(
30
- const char* string, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
45
+ const char* string,
46
+ const char* name,
47
+ size_t indent,
48
+ size_t relative_indent,
49
+ bool last_property,
50
+ buffer_T* buffer
31
51
  );
32
52
 
33
53
  void pretty_print_quoted_property(
34
- const char* name, const char* value, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
54
+ const char* name,
55
+ const char* value,
56
+ size_t indent,
57
+ size_t relative_indent,
58
+ bool last_property,
59
+ buffer_T* buffer
35
60
  );
36
61
 
37
62
  void pretty_print_boolean_property(
38
- const char* name, bool value, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
63
+ const char* name,
64
+ bool value,
65
+ size_t indent,
66
+ size_t relative_indent,
67
+ bool last_property,
68
+ buffer_T* buffer
39
69
  );
40
70
 
41
71
  void pretty_print_token_property(
42
- token_T* token, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
72
+ token_T* token,
73
+ const char* name,
74
+ size_t indent,
75
+ size_t relative_indent,
76
+ bool last_property,
77
+ buffer_T* buffer
43
78
  );
44
79
 
45
80
  void pretty_print_array(
46
- const char* name, array_T* array, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
81
+ const char* name,
82
+ array_T* array,
83
+ size_t indent,
84
+ size_t relative_indent,
85
+ bool last_property,
86
+ buffer_T* buffer
47
87
  );
48
88
 
49
89
  void pretty_print_errors(AST_NODE_T* node, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer);
@@ -10,7 +10,10 @@
10
10
  const char* pm_error_level_to_string(pm_error_level_t level);
11
11
 
12
12
  RUBY_PARSE_ERROR_T* ruby_parse_error_from_prism_error(
13
- const pm_diagnostic_t* error, const AST_NODE_T* node, const char* source, pm_parser_t* parser
13
+ const pm_diagnostic_t* error,
14
+ const AST_NODE_T* node,
15
+ const char* source,
16
+ pm_parser_t* parser
14
17
  );
15
18
 
16
19
  position_T* position_from_source_with_offset(const char* source, size_t offset);
@@ -20,7 +20,7 @@ typedef enum {
20
20
  TOKEN_HTML_COMMENT_START, // <!--
21
21
  TOKEN_HTML_COMMENT_END, // -->
22
22
 
23
- TOKEN_ERB_START, // <%, <%=, <%#, <%-, <%==, <%%
23
+ TOKEN_ERB_START, // <%, <%=, <%%=, <%#, <%-, <%==, <%%
24
24
  TOKEN_ERB_CONTENT, // Ruby Code
25
25
  TOKEN_ERB_END, // %>, -%>, %%>
26
26
 
@@ -33,6 +33,7 @@ typedef enum {
33
33
  TOKEN_EXCLAMATION, // !
34
34
  TOKEN_SEMICOLON, // ;
35
35
  TOKEN_COLON, // :
36
+ TOKEN_AT, // @
36
37
  TOKEN_PERCENT, // %
37
38
  TOKEN_AMPERSAND, // &
38
39
 
@@ -1,6 +1,6 @@
1
1
  #ifndef HERB_VERSION_H
2
2
  #define HERB_VERSION_H
3
3
 
4
- #define HERB_VERSION "0.3.1"
4
+ #define HERB_VERSION "0.4.2"
5
5
 
6
6
  #endif
data/src/lexer.c CHANGED
@@ -163,7 +163,7 @@ static token_T* lexer_parse_identifier(lexer_T* lexer) {
163
163
  // ===== ERB Parsing
164
164
 
165
165
  static token_T* lexer_parse_erb_open(lexer_T* lexer) {
166
- const char* erb_patterns[] = { "<%==", "<%=", "<%#", "<%-", "<%%", "<%" };
166
+ const char* erb_patterns[] = { "<%==", "<%%=", "<%=", "<%#", "<%-", "<%%", "<%" };
167
167
 
168
168
  lexer->state = STATE_ERB_CONTENT;
169
169
 
@@ -184,7 +184,16 @@ static token_T* lexer_parse_erb_content(lexer_T* lexer) {
184
184
  }
185
185
 
186
186
  buffer_append_char(&buffer, lexer->current_character);
187
- lexer_advance(lexer);
187
+
188
+ if (is_newline(lexer->current_character)) {
189
+ lexer->current_line++;
190
+ lexer->current_column = 0;
191
+ } else {
192
+ lexer->current_column++;
193
+ }
194
+
195
+ lexer->current_position++;
196
+ lexer->current_character = lexer->source[lexer->current_position];
188
197
  }
189
198
 
190
199
  lexer->state = STATE_ERB_CLOSE;
@@ -260,6 +269,7 @@ token_T* lexer_next_token(lexer_T* lexer) {
260
269
  case '>': return lexer_advance_current(lexer, TOKEN_HTML_TAG_END);
261
270
  case '_': return lexer_advance_current(lexer, TOKEN_UNDERSCORE);
262
271
  case ':': return lexer_advance_current(lexer, TOKEN_COLON);
272
+ case '@': return lexer_advance_current(lexer, TOKEN_AT);
263
273
  case ';': return lexer_advance_current(lexer, TOKEN_SEMICOLON);
264
274
  case '&': return lexer_advance_current(lexer, TOKEN_AMPERSAND);
265
275
  case '!': return lexer_advance_current(lexer, TOKEN_EXCLAMATION);
data/src/parser.c CHANGED
@@ -197,13 +197,19 @@ static AST_HTML_ATTRIBUTE_NAME_NODE_T* parser_parse_html_attribute_name(parser_T
197
197
  }
198
198
 
199
199
  static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value(
200
- parser_T* parser, array_T* children, array_T* errors
200
+ parser_T* parser,
201
+ array_T* children,
202
+ array_T* errors
201
203
  ) {
202
204
  buffer_T buffer = buffer_new();
203
205
  token_T* opening_quote = parser_consume_expected(parser, TOKEN_QUOTE, errors);
204
206
  position_T* start = position_copy(parser->current_token->location->start);
205
207
 
206
- while (token_is_none_of(parser, TOKEN_QUOTE, TOKEN_EOF)) {
208
+ while (!token_is(parser, TOKEN_EOF)
209
+ && !(
210
+ token_is(parser, TOKEN_QUOTE) && opening_quote != NULL
211
+ && strcmp(parser->current_token->value, opening_quote->value) == 0
212
+ )) {
207
213
  if (token_is(parser, TOKEN_ERB_START)) {
208
214
  parser_append_literal_node_from_buffer(parser, &buffer, children, start);
209
215
 
@@ -472,7 +478,8 @@ static AST_HTML_CLOSE_TAG_NODE_T* parser_parse_html_close_tag(parser_T* parser)
472
478
 
473
479
  // TODO: this should probably be AST_HTML_ELEMENT_NODE_T with a AST_HTML_SELF_CLOSING_TAG_NODE_T
474
480
  static AST_HTML_ELEMENT_NODE_T* parser_parse_html_self_closing_element(
475
- const parser_T* parser, AST_HTML_OPEN_TAG_NODE_T* open_tag
481
+ const parser_T* parser,
482
+ AST_HTML_OPEN_TAG_NODE_T* open_tag
476
483
  ) {
477
484
  return ast_html_element_node_init(
478
485
  open_tag,
@@ -487,7 +494,8 @@ static AST_HTML_ELEMENT_NODE_T* parser_parse_html_self_closing_element(
487
494
  }
488
495
 
489
496
  static AST_HTML_ELEMENT_NODE_T* parser_parse_html_regular_element(
490
- parser_T* parser, AST_HTML_OPEN_TAG_NODE_T* open_tag
497
+ parser_T* parser,
498
+ AST_HTML_OPEN_TAG_NODE_T* open_tag
491
499
  ) {
492
500
  array_T* errors = array_init(8);
493
501
  array_T* body = array_init(8);
@@ -618,6 +626,7 @@ static void parser_parse_in_data_state(parser_T* parser, array_T* children, arra
618
626
  TOKEN_IDENTIFIER,
619
627
  TOKEN_NEWLINE,
620
628
  TOKEN_PERCENT,
629
+ TOKEN_QUOTE,
621
630
  TOKEN_SEMICOLON,
622
631
  TOKEN_SLASH,
623
632
  TOKEN_UNDERSCORE,
data/src/parser_helpers.c CHANGED
@@ -80,7 +80,10 @@ void parser_append_unexpected_token_error(parser_T* parser, token_type_T expecte
80
80
  }
81
81
 
82
82
  void parser_append_literal_node_from_buffer(
83
- const parser_T* parser, buffer_T* buffer, array_T* children, position_T* start
83
+ const parser_T* parser,
84
+ buffer_T* buffer,
85
+ array_T* children,
86
+ position_T* start
84
87
  ) {
85
88
  if (buffer_length(buffer) == 0) { return; }
86
89
 
@@ -115,7 +118,9 @@ token_T* parser_consume_expected(parser_T* parser, const token_type_T expected_t
115
118
  }
116
119
 
117
120
  AST_HTML_ELEMENT_NODE_T* parser_handle_missing_close_tag(
118
- AST_HTML_OPEN_TAG_NODE_T* open_tag, array_T* body, array_T* errors
121
+ AST_HTML_OPEN_TAG_NODE_T* open_tag,
122
+ array_T* body,
123
+ array_T* errors
119
124
  ) {
120
125
  append_missing_closing_tag_error(
121
126
  open_tag->tag_name,
@@ -137,7 +142,9 @@ AST_HTML_ELEMENT_NODE_T* parser_handle_missing_close_tag(
137
142
  }
138
143
 
139
144
  void parser_handle_mismatched_tags(
140
- const parser_T* parser, const AST_HTML_CLOSE_TAG_NODE_T* close_tag, array_T* errors
145
+ const parser_T* parser,
146
+ const AST_HTML_CLOSE_TAG_NODE_T* close_tag,
147
+ array_T* errors
141
148
  ) {
142
149
  if (array_size(parser->open_tags_stack) > 0) {
143
150
  token_T* expected_tag = array_last(parser->open_tags_stack);