herb 0.7.4-aarch64-linux-gnu → 0.8.0-aarch64-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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +8 -5
  3. data/config.yml +40 -20
  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 +12 -18
  9. data/ext/herb/extension_helpers.h +4 -4
  10. data/ext/herb/nodes.c +72 -37
  11. data/herb.gemspec +0 -2
  12. data/lib/herb/3.0/herb.so +0 -0
  13. data/lib/herb/3.1/herb.so +0 -0
  14. data/lib/herb/3.2/herb.so +0 -0
  15. data/lib/herb/3.3/herb.so +0 -0
  16. data/lib/herb/3.4/herb.so +0 -0
  17. data/lib/herb/ast/helpers.rb +11 -0
  18. data/lib/herb/ast/node.rb +15 -6
  19. data/lib/herb/ast/nodes.rb +609 -392
  20. data/lib/herb/cli.rb +31 -0
  21. data/lib/herb/colors.rb +82 -0
  22. data/lib/herb/engine/compiler.rb +140 -14
  23. data/lib/herb/engine/debug_visitor.rb +1 -5
  24. data/lib/herb/engine/parser_error_overlay.rb +1 -1
  25. data/lib/herb/engine.rb +18 -20
  26. data/lib/herb/errors.rb +166 -56
  27. data/lib/herb/location.rb +2 -2
  28. data/lib/herb/project.rb +86 -21
  29. data/lib/herb/token.rb +14 -2
  30. data/lib/herb/version.rb +1 -1
  31. data/lib/herb.rb +1 -0
  32. data/sig/herb/ast/helpers.rbs +3 -0
  33. data/sig/herb/ast/node.rbs +12 -5
  34. data/sig/herb/ast/nodes.rbs +124 -62
  35. data/sig/herb/colors.rbs +35 -0
  36. data/sig/herb/engine/compiler.rbs +23 -1
  37. data/sig/herb/errors.rbs +74 -20
  38. data/sig/herb/token.rbs +8 -0
  39. data/sig/herb_c_extension.rbs +1 -1
  40. data/sig/serialized_ast_errors.rbs +8 -0
  41. data/src/analyze.c +461 -249
  42. data/src/analyze_helpers.c +5 -0
  43. data/src/analyze_missing_end.c +147 -0
  44. data/src/analyze_transform.c +196 -0
  45. data/src/analyzed_ruby.c +23 -2
  46. data/src/ast_node.c +14 -17
  47. data/src/ast_nodes.c +179 -181
  48. data/src/ast_pretty_print.c +232 -232
  49. data/src/element_source.c +7 -6
  50. data/src/errors.c +272 -152
  51. data/src/extract.c +92 -34
  52. data/src/herb.c +37 -49
  53. data/src/html_util.c +34 -96
  54. data/src/include/analyze.h +10 -2
  55. data/src/include/analyze_helpers.h +3 -0
  56. data/src/include/analyzed_ruby.h +4 -2
  57. data/src/include/ast_node.h +4 -4
  58. data/src/include/ast_nodes.h +68 -67
  59. data/src/include/ast_pretty_print.h +2 -2
  60. data/src/include/element_source.h +3 -1
  61. data/src/include/errors.h +42 -26
  62. data/src/include/extract.h +4 -4
  63. data/src/include/herb.h +6 -7
  64. data/src/include/html_util.h +4 -5
  65. data/src/include/lexer.h +1 -3
  66. data/src/include/lexer_peek_helpers.h +21 -19
  67. data/src/include/lexer_struct.h +12 -10
  68. data/src/include/location.h +10 -13
  69. data/src/include/macros.h +4 -0
  70. data/src/include/parser.h +12 -6
  71. data/src/include/parser_helpers.h +26 -16
  72. data/src/include/position.h +3 -14
  73. data/src/include/pretty_print.h +38 -28
  74. data/src/include/prism_helpers.h +1 -1
  75. data/src/include/range.h +4 -13
  76. data/src/include/token.h +5 -11
  77. data/src/include/token_struct.h +2 -2
  78. data/src/include/utf8.h +3 -2
  79. data/src/include/util/hb_arena.h +31 -0
  80. data/src/include/util/hb_arena_debug.h +8 -0
  81. data/src/include/util/hb_array.h +33 -0
  82. data/src/include/util/hb_buffer.h +34 -0
  83. data/src/include/util/hb_string.h +29 -0
  84. data/src/include/util/hb_system.h +9 -0
  85. data/src/include/util.h +3 -14
  86. data/src/include/version.h +1 -1
  87. data/src/include/visitor.h +1 -1
  88. data/src/io.c +7 -4
  89. data/src/lexer.c +62 -88
  90. data/src/lexer_peek_helpers.c +42 -38
  91. data/src/location.c +9 -37
  92. data/src/main.c +19 -23
  93. data/src/parser.c +373 -313
  94. data/src/parser_helpers.c +60 -54
  95. data/src/parser_match_tags.c +316 -0
  96. data/src/pretty_print.c +88 -117
  97. data/src/prism_helpers.c +7 -7
  98. data/src/range.c +2 -35
  99. data/src/token.c +36 -87
  100. data/src/utf8.c +4 -4
  101. data/src/util/hb_arena.c +179 -0
  102. data/src/util/hb_arena_debug.c +237 -0
  103. data/src/{array.c → util/hb_array.c} +26 -27
  104. data/src/util/hb_buffer.c +203 -0
  105. data/src/util/hb_string.c +85 -0
  106. data/src/util/hb_system.c +30 -0
  107. data/src/util.c +29 -99
  108. data/src/visitor.c +54 -54
  109. data/templates/ext/herb/error_helpers.c.erb +3 -3
  110. data/templates/ext/herb/error_helpers.h.erb +1 -1
  111. data/templates/ext/herb/nodes.c.erb +11 -6
  112. data/templates/java/error_helpers.c.erb +75 -0
  113. data/templates/java/error_helpers.h.erb +20 -0
  114. data/templates/java/nodes.c.erb +97 -0
  115. data/templates/java/nodes.h.erb +23 -0
  116. data/templates/java/org/herb/ast/Errors.java.erb +121 -0
  117. data/templates/java/org/herb/ast/NodeVisitor.java.erb +14 -0
  118. data/templates/java/org/herb/ast/Nodes.java.erb +220 -0
  119. data/templates/java/org/herb/ast/Visitor.java.erb +56 -0
  120. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -1
  121. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +8 -8
  122. data/templates/javascript/packages/node/extension/error_helpers.h.erb +1 -1
  123. data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -9
  124. data/templates/javascript/packages/node/extension/nodes.h.erb +1 -1
  125. data/templates/lib/herb/ast/nodes.rb.erb +28 -16
  126. data/templates/lib/herb/errors.rb.erb +17 -12
  127. data/templates/rust/src/ast/nodes.rs.erb +220 -0
  128. data/templates/rust/src/errors.rs.erb +216 -0
  129. data/templates/rust/src/nodes.rs.erb +374 -0
  130. data/templates/src/analyze_missing_end.c.erb +36 -0
  131. data/templates/src/analyze_transform.c.erb +24 -0
  132. data/templates/src/ast_nodes.c.erb +14 -16
  133. data/templates/src/ast_pretty_print.c.erb +36 -36
  134. data/templates/src/errors.c.erb +36 -38
  135. data/templates/src/include/ast_nodes.h.erb +11 -10
  136. data/templates/src/include/ast_pretty_print.h.erb +2 -2
  137. data/templates/src/include/errors.h.erb +9 -9
  138. data/templates/src/parser_match_tags.c.erb +38 -0
  139. data/templates/src/visitor.c.erb +4 -4
  140. data/templates/template.rb +22 -3
  141. data/templates/wasm/error_helpers.cpp.erb +9 -9
  142. data/templates/wasm/error_helpers.h.erb +1 -1
  143. data/templates/wasm/nodes.cpp.erb +9 -9
  144. data/templates/wasm/nodes.h.erb +1 -1
  145. data/vendor/prism/Rakefile +4 -1
  146. data/vendor/prism/config.yml +2 -1
  147. data/vendor/prism/include/prism/ast.h +31 -1
  148. data/vendor/prism/include/prism/diagnostic.h +1 -0
  149. data/vendor/prism/include/prism/version.h +3 -3
  150. data/vendor/prism/src/diagnostic.c +3 -1
  151. data/vendor/prism/src/prism.c +130 -71
  152. data/vendor/prism/src/util/pm_string.c +6 -8
  153. data/vendor/prism/templates/include/prism/ast.h.erb +2 -0
  154. data/vendor/prism/templates/java/org/prism/Loader.java.erb +2 -2
  155. data/vendor/prism/templates/javascript/src/deserialize.js.erb +2 -2
  156. data/vendor/prism/templates/lib/prism/serialize.rb.erb +2 -2
  157. data/vendor/prism/templates/sig/prism.rbs.erb +4 -0
  158. data/vendor/prism/templates/src/diagnostic.c.erb +1 -0
  159. metadata +34 -21
  160. data/lib/herb/libherb/array.rb +0 -51
  161. data/lib/herb/libherb/ast_node.rb +0 -50
  162. data/lib/herb/libherb/buffer.rb +0 -56
  163. data/lib/herb/libherb/extract_result.rb +0 -20
  164. data/lib/herb/libherb/lex_result.rb +0 -32
  165. data/lib/herb/libherb/libherb.rb +0 -52
  166. data/lib/herb/libherb/parse_result.rb +0 -20
  167. data/lib/herb/libherb/token.rb +0 -46
  168. data/lib/herb/libherb.rb +0 -35
  169. data/src/buffer.c +0 -232
  170. data/src/include/array.h +0 -33
  171. data/src/include/buffer.h +0 -39
  172. data/src/include/json.h +0 -28
  173. data/src/include/memory.h +0 -12
  174. data/src/json.c +0 -205
  175. data/src/memory.c +0 -53
  176. data/src/position.c +0 -33
@@ -0,0 +1,121 @@
1
+ package org.herb.ast;
2
+
3
+ import org.herb.Location;
4
+ import org.herb.Token;
5
+
6
+ /**
7
+ * Base class for all Herb parsing errors.
8
+ */
9
+ abstract class HerbError {
10
+ private final String type;
11
+ private final String message;
12
+ private final Location location;
13
+
14
+ public HerbError(String type, String message, Location location) {
15
+ this.type = type;
16
+ this.message = message;
17
+ this.location = location;
18
+ }
19
+
20
+ public String getType() {
21
+ return type;
22
+ }
23
+
24
+ public String getMessage() {
25
+ return message;
26
+ }
27
+
28
+ public Location getLocation() {
29
+ return location;
30
+ }
31
+
32
+ @Override
33
+ public String toString() {
34
+ return String.format("HerbError{type='%s', message='%s', location=%s}", type, message, location);
35
+ }
36
+
37
+ public abstract String inspect();
38
+
39
+ protected String indent(String str, int level) {
40
+ if (level == 0) return str;
41
+ String prefix = " ".repeat(level);
42
+ return str.lines()
43
+ .map(line -> prefix + line)
44
+ .collect(java.util.stream.Collectors.joining("\n"));
45
+ }
46
+ }
47
+
48
+ <%- errors.each do |error| -%>
49
+ /**
50
+ * <%= error.name %>: <%= error.message_template %>
51
+ */
52
+ class <%= error.name %> extends HerbError {
53
+ <%- error.fields.each do |field| -%>
54
+ <%- case field -%>
55
+ <%- when Herb::Template::StringField -%>
56
+ private final String <%= field.name %>;
57
+ <%- when Herb::Template::TokenField -%>
58
+ private final Token <%= field.name %>;
59
+ <%- when Herb::Template::TokenTypeField -%>
60
+ private final String <%= field.name %>;
61
+ <%- else -%>
62
+ // Unsupported field type: <%= field.class %>
63
+ <%- end -%>
64
+ <%- end -%>
65
+
66
+ public <%= error.name %>(String type, String message, Location location<%- error.fields.each do |field| -%><%- case field -%><%- when Herb::Template::StringField -%>, String <%= field.name %><%- when Herb::Template::TokenField -%>, Token <%= field.name %><%- when Herb::Template::TokenTypeField -%>, String <%= field.name %><%- end -%><%- end -%>) {
67
+ super(type, message, location);
68
+ <%- error.fields.each do |field| -%>
69
+ this.<%= field.name %> = <%= field.name %>;
70
+ <%- end -%>
71
+ }
72
+
73
+ <%- error.fields.each do |field| -%>
74
+ <%- case field -%>
75
+ <%- when Herb::Template::StringField -%>
76
+ public String get<%= field.name.capitalize %>() {
77
+ return <%= field.name %>;
78
+ }
79
+
80
+ <%- when Herb::Template::TokenField -%>
81
+ public Token get<%= field.name.capitalize %>() {
82
+ return <%= field.name %>;
83
+ }
84
+
85
+ <%- when Herb::Template::TokenTypeField -%>
86
+ public String get<%= field.name.capitalize %>() {
87
+ return <%= field.name %>;
88
+ }
89
+
90
+ <%- end -%>
91
+ <%- end -%>
92
+ @Override
93
+ public String inspect() {
94
+ StringBuilder output = new StringBuilder();
95
+
96
+ output.append("@ <%= error.name %> ");
97
+ output.append(getLocation() != null ? "(location: " + getLocation().toString() + ")" : "no-location");
98
+ output.append("\n");
99
+ <%- symbol = error.fields.any? ? "├──" : "└──" -%>
100
+ output.append("<%= symbol %> message: ");
101
+ output.append("\"").append(getMessage()).append("\"");
102
+ output.append("\n");
103
+ <%- error.fields.each do |field| -%>
104
+ <%- symbol = error.fields.last == field ? "└──" : "├──" -%>
105
+ <%- case field -%>
106
+ <%- when Herb::Template::StringField, Herb::Template::TokenTypeField -%>
107
+ output.append("<%= symbol %> <%= field.name %>: ");
108
+ output.append("\"").append(<%= field.name %>).append("\"");
109
+ output.append("\n");
110
+ <%- when Herb::Template::TokenField -%>
111
+ output.append("<%= symbol %> <%= field.name %>: ");
112
+ output.append(<%= field.name %> != null ? <%= field.name %>.inspect() : "∅");
113
+ output.append("\n");
114
+ <%- end -%>
115
+ <%- end -%>
116
+
117
+ return output.toString();
118
+ }
119
+ }
120
+
121
+ <%- end -%>
@@ -0,0 +1,14 @@
1
+ package org.herb.ast;
2
+
3
+ /**
4
+ * Visitor interface for traversing AST nodes.
5
+ *
6
+ * @param <R> the return type
7
+ * @param <C> the context type
8
+ */
9
+ public interface NodeVisitor<R, C> {
10
+ R visitNode(Node node, C context);
11
+ <%- nodes.each do |node| -%>
12
+ R visit<%= node.name %>(<%=node.name %> node, C context);
13
+ <%- end -%>
14
+ }
@@ -0,0 +1,220 @@
1
+ package org.herb.ast;
2
+
3
+ import org.herb.Location;
4
+ import org.herb.Token;
5
+
6
+ import java.util.ArrayList;
7
+ import java.util.List;
8
+
9
+ <%- nodes.each do |node| -%>
10
+ class <%= node.name %> extends BaseNode {
11
+ <%- if node.fields.any? -%>
12
+ <%- node.fields.each do |field| -%>
13
+ <%- if field.is_a?(Herb::Template::StringField) -%>
14
+ private final String <%= field.name %>;
15
+ <%- elsif field.is_a?(Herb::Template::TokenField) -%>
16
+ private final Token <%= field.name %>;
17
+ <%- elsif field.is_a?(Herb::Template::BooleanField) -%>
18
+ private final boolean <%= field.name %>;
19
+ <%- elsif field.is_a?(Herb::Template::ArrayField) -%>
20
+ private final List<Node> <%= field.name %>;
21
+ <%- elsif field.is_a?(Herb::Template::NodeField) -%>
22
+ <%- if field.specific_kind -%>
23
+ private final <%= field.specific_kind %> <%= field.name %>;
24
+ <%- else -%>
25
+ private final Node <%= field.name %>;
26
+ <%- end -%>
27
+ <%- elsif field.is_a?(Herb::Template::ElementSourceField) -%>
28
+ private final String <%= field.name %>;
29
+ <%- else -%>
30
+ // private final Object <%= field.name %>;
31
+ <%- end -%>
32
+ <%- end -%>
33
+ <%- end -%>
34
+
35
+ public <%= node.name %>(
36
+ String type,
37
+ Location location,
38
+ List<Node> errors<%- if node.fields.any? %>,<% end %>
39
+ <%- if node.fields.any? -%>
40
+ <%- node.fields.each do |field| -%>
41
+ <%- if field.is_a?(Herb::Template::StringField) -%>
42
+ String <%= field.name %><%- if node.fields.last != field %>,<% end %>
43
+ <%- elsif field.is_a?(Herb::Template::TokenField) -%>
44
+ Token <%= field.name %><%- if node.fields.last != field %>,<% end %>
45
+ <%- elsif field.is_a?(Herb::Template::BooleanField) -%>
46
+ boolean <%= field.name %><%- if node.fields.last != field %>,<% end %>
47
+ <%- elsif field.is_a?(Herb::Template::ArrayField) -%>
48
+ List<Node> <%= field.name %><%- if node.fields.last != field %>,<% end %>
49
+ <%- elsif field.is_a?(Herb::Template::NodeField) -%>
50
+ <%= field.specific_kind || 'Node' %> <%= field.name %><%- if node.fields.last != field %>,<% end %>
51
+ <%- elsif field.is_a?(Herb::Template::ElementSourceField) -%>
52
+ String <%= field.name %><%- if node.fields.last != field %>,<% end %>
53
+ <%- else -%>
54
+ // <%= field.c_type %> <%= field.name %>
55
+ <%- end -%>
56
+ <%- end -%>
57
+ <%- end -%>
58
+ ) {
59
+ super(type, location, errors);
60
+
61
+ <%- if node.fields.any? -%>
62
+ <%- node.fields.each do |field| -%>
63
+ <%- unless field.is_a?(Herb::Template::AnalyzedRubyField) || field.is_a?(Herb::Template::PrismNodeField) -%>
64
+ this.<%= field.name %> = <%= field.name %>;
65
+ <%- else -%>
66
+ // this.<%= field.name %> = <%= field.name %>;
67
+ <%- end -%>
68
+ <%- end -%>
69
+ <%- end -%>
70
+ }
71
+
72
+ <%- if node.fields.any? -%>
73
+ <%- node.fields.each do |field| -%>
74
+ <%- if field.is_a?(Herb::Template::StringField) -%>
75
+ public String get<%= field.name.split('_').map(&:capitalize).join %>() {
76
+ return <%= field.name %>;
77
+ }
78
+
79
+ <%- elsif field.is_a?(Herb::Template::TokenField) -%>
80
+ public Token get<%= field.name.split('_').map(&:capitalize).join %>() {
81
+ return <%= field.name %>;
82
+ }
83
+
84
+ <%- elsif field.is_a?(Herb::Template::BooleanField) -%>
85
+ public boolean is<%= field.name.split('_').map(&:capitalize).join %>() {
86
+ return <%= field.name %>;
87
+ }
88
+
89
+ <%- elsif field.is_a?(Herb::Template::ArrayField) -%>
90
+ public List<Node> get<%= field.name.split('_').map(&:capitalize).join %>() {
91
+ return <%= field.name %>;
92
+ }
93
+
94
+ <%- elsif field.is_a?(Herb::Template::NodeField) -%>
95
+ public <%= field.specific_kind || 'Node' %> get<%= field.name.split('_').map(&:capitalize).join %>() {
96
+ return <%= field.name %>;
97
+ }
98
+
99
+ <%- elsif field.is_a?(Herb::Template::ElementSourceField) -%>
100
+ public String get<%= field.name.split('_').map(&:capitalize).join %>() {
101
+ return <%= field.name %>;
102
+ }
103
+
104
+ <%- else -%>
105
+ /*
106
+ public Object get<%= field.name.split('_').map(&:capitalize).join %>() {
107
+ return <%= field.name %>;
108
+ }
109
+ */
110
+
111
+ <%- end -%>
112
+ <%- end -%>
113
+ @Override
114
+ public <R, C> R accept(NodeVisitor<R, C> visitor, C context) {
115
+ return visitor.visit<%= node.name %>(this, context);
116
+ }
117
+
118
+ @Override
119
+ public <R, C> void visitChildren(NodeVisitor<R, C> visitor, C context) {
120
+ <%- if node.fields.any? -%>
121
+ <%- node.fields.each do |field| -%>
122
+ <%- if field.is_a?(Herb::Template::ArrayField) -%>
123
+ if (<%= field.name %> != null) {
124
+ for (Node child : <%= field.name %>) {
125
+ if (child != null) child.accept(visitor, context);
126
+ }
127
+ }
128
+
129
+ <%- elsif field.is_a?(Herb::Template::NodeField) -%>
130
+ if (<%= field.name %> != null) <%= field.name %>.accept(visitor, context);
131
+
132
+ <%- end -%>
133
+ <%- end -%>
134
+ <%- else -%>
135
+ // No children to visit
136
+ <%- end -%>
137
+ }
138
+
139
+ @Override
140
+ public String inspect() {
141
+ StringBuilder output = new StringBuilder();
142
+
143
+ output.append("@ <%= node.name %> ").append(location != null ? "(location: " + location.toString() + ")" : "no-location").append("\n");
144
+ <%- if node.fields.any? -%>
145
+ output.append(inspectErrors("│ "));
146
+ <%- else -%>
147
+ output.append(inspectErrors(" "));
148
+ <%- end -%>
149
+ <%- if node.fields.any? -%>
150
+ <%- node.fields.each_with_index do |field, index| -%>
151
+ <%- is_last = index == node.fields.length - 1 -%>
152
+ <%- symbol = is_last ? "└── " : "├── " -%>
153
+ <%- prefix = is_last ? " " : "│ " -%>
154
+ <%- if field.is_a?(Herb::Template::StringField) || field.is_a?(Herb::Template::ElementSourceField) -%>
155
+ output.append("<%= symbol %><%= field.name %>: ").append(<%= field.name %> != null ? "\"" + <%= field.name %>.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t").replace("\"", "\\\"") + "\"" : "∅").append("\n");
156
+ <%- elsif field.is_a?(Herb::Template::TokenField) -%>
157
+ output.append("<%= symbol %><%= field.name %>: ").append(<%= field.name %> != null ? <%= field.name %>.treeInspect() : "∅").append("\n");
158
+ <%- elsif field.is_a?(Herb::Template::BooleanField) -%>
159
+ output.append("<%= symbol %><%= field.name %>: ").append(<%= field.name %>).append("\n");
160
+ <%- elsif field.is_a?(Herb::Template::ArrayField) -%>
161
+ output.append("<%= symbol %><%= field.name %>: ").append(inspectArray(<%= field.name %>, "<%= prefix %>"));
162
+ <%- elsif field.is_a?(Herb::Template::NodeField) -%>
163
+ if (<%= field.name %> != null) {
164
+ output.append("<%= symbol %><%= field.name %>:\n");
165
+ output.append("<%= prefix %>").append(inspectNode(<%= field.name %>, "<%= prefix %>"));
166
+ <%- unless is_last -%>
167
+ output.append("<%= prefix %>").append("\n");
168
+ <%- end -%>
169
+ } else {
170
+ output.append("<%= symbol %><%= field.name %>: ∅\n");
171
+ }
172
+ <%- end -%>
173
+ <%- end -%>
174
+ <%- else -%>
175
+ output.append("└── (no fields)\n");
176
+ <%- end -%>
177
+
178
+ return output.toString();
179
+ }
180
+
181
+ @Override
182
+ public List<Node> recursiveErrors() {
183
+ List<Node> result = new ArrayList<>();
184
+
185
+ if (errors != null) {
186
+ result.addAll(errors);
187
+ }
188
+
189
+ <%- if node.fields.any? -%>
190
+ <%- node.fields.each do |field| -%>
191
+ <%- if field.is_a?(Herb::Template::ArrayField) -%>
192
+
193
+ if (<%= field.name %> != null) {
194
+ for (Node child : <%= field.name %>) {
195
+ if (child != null) {
196
+ result.addAll(child.recursiveErrors());
197
+ }
198
+ }
199
+ }
200
+
201
+ <%- elsif field.is_a?(Herb::Template::NodeField) -%>
202
+ if (<%= field.name %> != null) {
203
+ result.addAll(<%= field.name %>.recursiveErrors());
204
+ }
205
+
206
+ <%- end -%>
207
+ <%- end -%>
208
+ <%- end -%>
209
+
210
+ return result;
211
+ }
212
+
213
+ @Override
214
+ public String toString() {
215
+ return "<%= node.name %> {}";
216
+ }
217
+ }
218
+
219
+ <%- end -%>
220
+ <%- end -%>
@@ -0,0 +1,56 @@
1
+ package org.herb.ast;
2
+
3
+ import java.util.List;
4
+
5
+ /**
6
+ * Abstract base class for node visitors that provides default implementations.
7
+ * Subclasses can override specific visit methods to customize behavior.
8
+ *
9
+ * @param <R> the return type
10
+ * @param <C> the context type
11
+ */
12
+ public abstract class Visitor<R, C> implements NodeVisitor<R, C> {
13
+
14
+ /**
15
+ * Default visit method that can be overridden by subclasses.
16
+ */
17
+ @Override
18
+ public R visitNode(Node node, C context) {
19
+ visitChildNodes(node, context);
20
+
21
+ return null;
22
+ }
23
+
24
+ /**
25
+ * Visit all child nodes of a given node.
26
+ * Subclasses can call this to recursively visit children.
27
+ */
28
+ protected void visitChildNodes(Node node, C context) {
29
+ if (node != null) {
30
+ node.visitChildren(this, context);
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Visit a list of nodes.
36
+ */
37
+ protected void visitAll(List<Node> nodes, C context) {
38
+ if (nodes == null) return;
39
+
40
+ for (Node node : nodes) {
41
+ if (node != null) node.accept(this, context);
42
+ }
43
+ }
44
+
45
+ <%- nodes.each do |node| -%>
46
+ /**
47
+ * Default implementation for <%= node.name %>.
48
+ * Delegates to visitNode by default.
49
+ */
50
+ @Override
51
+ public R visit<%= node.name %>(<%= node.name %> node, C context) {
52
+ return visitNode(node, context);
53
+ }
54
+
55
+ <%- end -%>
56
+ }
@@ -1,11 +1,27 @@
1
1
  import {
2
2
  Node,
3
+ ERBNode,
3
4
  <%- nodes.each do |node| -%>
4
5
  <%= node.name %>,
5
6
  <%- end -%>
6
7
  } from "./nodes.js"
7
8
 
8
- export class Visitor {
9
+ /**
10
+ * Interface that enforces all node visit methods are implemented
11
+ * This ensures that any class implementing IVisitor must have a visit method for every node type
12
+ */
13
+ export interface IVisitor {
14
+ visit(node: Node | null | undefined): void
15
+ visitAll(nodes: (Node | null | undefined)[]): void
16
+ visitChildNodes(node: Node): void
17
+ <%- nodes.each do |node| -%>
18
+ visit<%= node.name %>(node: <%= node.name %>): void
19
+ <%- end -%>
20
+ visitNode(node: Node): void
21
+ visitERBNode(node: ERBNode): void
22
+ }
23
+
24
+ export class Visitor implements IVisitor {
9
25
  visit(node: Node | null | undefined): void {
10
26
  if (!node) return
11
27
 
@@ -20,8 +36,20 @@ export class Visitor {
20
36
  node.compactChildNodes().forEach(node => node.accept(this))
21
37
  }
22
38
 
39
+ visitNode(_node: Node): void {
40
+ // Default implementation does nothing
41
+ }
42
+
43
+ visitERBNode(_node: ERBNode): void {
44
+ // Default implementation does nothing
45
+ }
46
+
23
47
  <%- nodes.each do |node| -%>
24
48
  visit<%= node.name %>(node: <%= node.name %>): void {
49
+ this.visitNode(node)
50
+ <%- if node.name.start_with?("ERB") -%>
51
+ this.visitERBNode(node)
52
+ <%- end -%>
25
53
  this.visitChildNodes(node)
26
54
  }
27
55
 
@@ -4,16 +4,16 @@
4
4
  #include "nodes.h"
5
5
 
6
6
  extern "C" {
7
- #include "../extension/libherb/include/herb.h"
8
- #include "../extension/libherb/include/token.h"
9
- #include "../extension/libherb/include/array.h"
10
- #include "../extension/libherb/include/errors.h"
11
7
  #include "../extension/libherb/include/ast_node.h"
12
8
  #include "../extension/libherb/include/ast_nodes.h"
9
+ #include "../extension/libherb/include/errors.h"
10
+ #include "../extension/libherb/include/herb.h"
11
+ #include "../extension/libherb/include/token.h"
12
+ #include "../extension/libherb/include/util/hb_array.h"
13
13
  }
14
14
 
15
15
  napi_value ErrorFromCStruct(napi_env env, ERROR_T* error);
16
- napi_value ErrorsArrayFromCArray(napi_env env, array_T* array);
16
+ napi_value ErrorsArrayFromCArray(napi_env env, hb_array_T* array);
17
17
 
18
18
  <%- errors.each do |error| -%>
19
19
  napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>* <%= error.human %>) {
@@ -75,13 +75,13 @@ napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>*
75
75
 
76
76
  <%- end -%>
77
77
 
78
- napi_value ErrorsArrayFromCArray(napi_env env, array_T* array) {
78
+ napi_value ErrorsArrayFromCArray(napi_env env, hb_array_T* array) {
79
79
  napi_value result;
80
80
  napi_create_array(env, &result);
81
81
 
82
82
  if (array) {
83
- for (size_t i = 0; i < array_size(array); i++) {
84
- ERROR_T* error = (ERROR_T*) array_get(array, i);
83
+ for (size_t i = 0; i < hb_array_size(array); i++) {
84
+ ERROR_T* error = (ERROR_T*) hb_array_get(array, i);
85
85
  if (error) {
86
86
  napi_value js_error = ErrorFromCStruct(env, error);
87
87
  napi_set_element(env, result, i, js_error);
@@ -8,7 +8,7 @@ extern "C" {
8
8
  }
9
9
 
10
10
  napi_value ErrorFromCStruct(napi_env env, ERROR_T* error);
11
- napi_value ErrorsArrayFromCArray(napi_env env, array_T* array);
11
+ napi_value ErrorsArrayFromCArray(napi_env env, hb_array_T* array);
12
12
 
13
13
  <%- errors.each do |error| -%>
14
14
  napi_value <%= error.name %>FromCStruct(napi_env env, <%= error.struct_type %>* <%= error.human %>);
@@ -4,15 +4,15 @@
4
4
  #include "nodes.h"
5
5
 
6
6
  extern "C" {
7
- #include "../extension/libherb/include/herb.h"
8
- #include "../extension/libherb/include/token.h"
9
- #include "../extension/libherb/include/array.h"
10
7
  #include "../extension/libherb/include/ast_node.h"
11
8
  #include "../extension/libherb/include/ast_nodes.h"
9
+ #include "../extension/libherb/include/herb.h"
10
+ #include "../extension/libherb/include/token.h"
11
+ #include "../extension/libherb/include/util/hb_array.h"
12
12
  }
13
13
 
14
14
  napi_value NodeFromCStruct(napi_env env, AST_NODE_T* node);
15
- napi_value NodesArrayFromCArray(napi_env env, array_T* array);
15
+ napi_value NodesArrayFromCArray(napi_env env, hb_array_T* array);
16
16
 
17
17
  <%- nodes.each do |node| -%>
18
18
  napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %>* <%= node.human %>) {
@@ -25,7 +25,7 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
25
25
  napi_value result;
26
26
  napi_create_object(env, &result);
27
27
 
28
- napi_value type = CreateString(env, ast_node_type_to_string(&<%= node.human %>->base));
28
+ napi_value type = CreateStringFromHbString(env, ast_node_type_to_string(&<%= node.human %>->base));
29
29
  napi_set_named_property(env, result, "type", type);
30
30
 
31
31
  napi_value location = CreateLocation(env, <%= node.human %>->base.location);
@@ -58,7 +58,7 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
58
58
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
59
59
 
60
60
  <%- when Herb::Template::ElementSourceField -%>
61
- napi_value <%= field.name %> = CreateString(env, element_source_to_string(<%= node.human %>-><%= field.name %>));
61
+ napi_value <%= field.name %> = CreateStringFromHbString(env, element_source_to_string(<%= node.human %>-><%= field.name %>));
62
62
  napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
63
63
 
64
64
  <%- else -%>
@@ -73,13 +73,13 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
73
73
  }
74
74
  <%- end -%>
75
75
 
76
- napi_value NodesArrayFromCArray(napi_env env, array_T* array) {
76
+ napi_value NodesArrayFromCArray(napi_env env, hb_array_T* array) {
77
77
  napi_value result;
78
78
  napi_create_array(env, &result);
79
79
 
80
80
  if (array) {
81
- for (size_t i = 0; i < array_size(array); i++) {
82
- AST_NODE_T* child_node = (AST_NODE_T*) array_get(array, i);
81
+ for (size_t i = 0; i < hb_array_size(array); i++) {
82
+ AST_NODE_T* child_node = (AST_NODE_T*) hb_array_get(array, i);
83
83
  if (child_node) {
84
84
  napi_value js_child = NodeFromCStruct(env, child_node);
85
85
  napi_set_element(env, result, i, js_child);
@@ -8,7 +8,7 @@ extern "C" {
8
8
  }
9
9
 
10
10
  napi_value NodeFromCStruct(napi_env env, AST_NODE_T* node);
11
- napi_value NodesArrayFromCArray(napi_env env, array_T* array);
11
+ napi_value NodesArrayFromCArray(napi_env env, hb_array_T* array);
12
12
 
13
13
  <%- nodes.each do |node| -%>
14
14
  napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %>* <%= node.human %>);
@@ -2,6 +2,8 @@ module Herb
2
2
  module AST
3
3
  <%- nodes.each do |node| -%>
4
4
  class <%= node.name -%> < Node
5
+ include Colors
6
+
5
7
  <%- node.fields.each do |field| -%>
6
8
  attr_reader :<%= field.name %> #: <%= field.ruby_type %>
7
9
  <%- end -%>
@@ -55,38 +57,42 @@ module Herb
55
57
  tree_inspect.rstrip.gsub(/\s+$/, "")
56
58
  end
57
59
 
58
- #: (?Integer) -> String
59
- def tree_inspect(indent = 0)
60
+ #: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
61
+ def tree_inspect(indent: 0, depth: 0, depth_limit: 10)
60
62
  output = +""
61
63
 
62
- output += "@ #{node_name} "
63
- output += location.tree_inspect
64
+ output += white("@ #{bold(yellow(node_name.to_s))} #{dimmed("(location: #{location.tree_inspect})")}")
64
65
  output += "\n"
65
66
 
67
+ if depth >= depth_limit
68
+ output += dimmed("└── [depth limit reached ...]\n\n")
69
+
70
+ return output.gsub(/^/, " " * indent)
71
+ end
72
+
66
73
  output += inspect_errors(prefix: "<%= node.fields.any? ? "│ " : " " %>")
67
74
 
68
75
  <%- node.fields.each do |field| -%>
69
76
  <%- symbol = node.fields.last == field ? "└──" : "├──" -%>
70
- <%- name = "#{symbol} #{field.name}: " -%>
71
77
  <%- case field -%>
72
78
  <%- when Herb::Template::StringField -%>
73
- output += %(<%= name %>#{<%= field.name %>.inspect}\n)
79
+ output += white("<%= symbol %> <%= field.name %>: ") + green("#{<%= field.name %>.inspect}\n")
74
80
  <%- when Herb::Template::TokenField -%>
75
- output += "<%= name %>"
76
- output += <%= field.name %> ? <%= field.name %>.tree_inspect : "∅"
81
+ output += white("<%= symbol %> <%= field.name %>: ")
82
+ output += <%= field.name %> ? <%= field.name %>.tree_inspect : magenta("∅")
77
83
  output += "\n"
78
84
  <%- when Herb::Template::BooleanField -%>
79
- output += "<%= name %>"
80
- output += [true, false].include?(<%= field.name %>) ? <%= field.name %>.to_s : "∅"
85
+ output += white("<%= symbol %> <%= field.name %>: ")
86
+ output += [true, false].include?(<%= field.name %>) ? bold(magenta(<%= field.name %>.to_s)) : magenta("∅")
81
87
  output += "\n"
82
88
  <%- when Herb::Template::ElementSourceField -%>
83
- output += %(<%= name %>#{<%= field.name %>.inspect}\n)
89
+ output += white("<%= symbol %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
84
90
  <%- when Herb::Template::PrismNodeField -%>
85
91
  # no-op for <%= field.name %>
86
92
  <%- when Herb::Template::AnalyzedRubyField -%>
87
93
  # no-op for <%= field.name %>
88
94
  <%- when Herb::Template::NodeField -%>
89
- output += "<%= name %>"
95
+ output += white("<%= symbol %> <%= field.name %>: ")
90
96
  if <%= field.name %>
91
97
  <%- prefix = (node.fields.last == field) ? " " : "│ " -%>
92
98
  output += "\n"
@@ -95,13 +101,19 @@ module Herb
95
101
  <%- else -%>
96
102
  output += "│ └── "
97
103
  <%- end -%>
98
- output += <%= field.name %>.tree_inspect(indent).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "<%= prefix %>").delete_prefix("<%= prefix %>")
104
+ output += <%= field.name %>.tree_inspect(indent: indent, depth: depth + 1, depth_limit: depth_limit).gsub(/^/, " " * (indent + 1)).lstrip.gsub(/^/, "<%= prefix %>").delete_prefix("<%= prefix %>")
105
+ <%- if false -%>
106
+ <%- unless node.fields.last == field -%>
107
+ output += "\n"
108
+ output += white("<%= prefix %>\n")
109
+ <%- end -%>
110
+ <%- end -%>
99
111
  else
100
- output += "∅\n"
112
+ output += magenta("∅\n")
101
113
  end
102
114
  <%- when Herb::Template::ArrayField -%>
103
- output += "<%= name %>"
104
- output += inspect_array(<%= field.name %>, prefix: "<%= (node.fields.last == field) ? " " : "│ " %>")
115
+ output += white("<%= symbol %> <%= field.name %>: ")
116
+ output += inspect_array(<%= field.name %>, prefix: "<%= (node.fields.last == field) ? " " : "│ " %>", indent: indent, depth: depth + 1, depth_limit: depth_limit)
105
117
  <%- else -%>
106
118
  <%- raise "Unhandled type: #{field.class}" -%>
107
119
  <%- end -%>