herb 0.8.6 → 0.8.8

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +7 -0
  3. data/config.yml +12 -0
  4. data/ext/herb/error_helpers.c +1 -1
  5. data/ext/herb/extconf.rb +0 -4
  6. data/ext/herb/extension_helpers.c +1 -1
  7. data/ext/herb/nodes.c +18 -10
  8. data/lib/herb/ast/nodes.rb +32 -8
  9. data/lib/herb/engine/debug_visitor.rb +1 -1
  10. data/lib/herb/version.rb +1 -1
  11. data/lib/herb.rb +30 -3
  12. data/sig/herb/ast/nodes.rbs +16 -8
  13. data/sig/serialized_ast_nodes.rbs +4 -0
  14. data/src/analyze.c +137 -42
  15. data/src/analyze_helpers.c +80 -12
  16. data/src/analyzed_ruby.c +1 -0
  17. data/src/ast_node.c +1 -1
  18. data/src/ast_nodes.c +65 -161
  19. data/src/ast_pretty_print.c +52 -0
  20. data/src/errors.c +5 -5
  21. data/src/extract.c +2 -2
  22. data/src/herb.c +2 -2
  23. data/src/include/analyze_helpers.h +7 -0
  24. data/src/include/analyzed_ruby.h +1 -0
  25. data/src/include/ast_nodes.h +8 -4
  26. data/src/include/location.h +4 -0
  27. data/src/include/prism_helpers.h +6 -0
  28. data/src/include/util/hb_narray.h +1 -0
  29. data/src/include/version.h +1 -1
  30. data/src/location.c +16 -0
  31. data/src/parser.c +9 -9
  32. data/src/parser_helpers.c +4 -4
  33. data/src/pretty_print.c +6 -6
  34. data/src/prism_helpers.c +188 -0
  35. data/src/util/hb_array.c +1 -0
  36. data/src/util/hb_narray.c +6 -0
  37. data/src/visitor.c +26 -26
  38. data/templates/ext/herb/error_helpers.c.erb +1 -1
  39. data/templates/ext/herb/nodes.c.erb +3 -1
  40. data/templates/java/error_helpers.c.erb +1 -1
  41. data/templates/java/nodes.c.erb +5 -3
  42. data/templates/java/org/herb/ast/Nodes.java.erb +11 -0
  43. data/templates/javascript/packages/core/src/nodes.ts.erb +14 -0
  44. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +1 -1
  45. data/templates/javascript/packages/node/extension/nodes.cpp.erb +10 -1
  46. data/templates/lib/herb/ast/nodes.rb.erb +4 -0
  47. data/templates/rust/src/ast/nodes.rs.erb +12 -2
  48. data/templates/rust/src/nodes.rs.erb +4 -0
  49. data/templates/src/ast_nodes.c.erb +7 -7
  50. data/templates/src/ast_pretty_print.c.erb +14 -0
  51. data/templates/src/errors.c.erb +5 -5
  52. data/templates/src/visitor.c.erb +1 -1
  53. data/templates/template.rb +11 -0
  54. data/templates/wasm/error_helpers.cpp.erb +1 -1
  55. data/templates/wasm/nodes.cpp.erb +7 -1
  56. data/vendor/prism/include/prism/version.h +2 -2
  57. data/vendor/prism/src/prism.c +48 -27
  58. data/vendor/prism/templates/java/org/prism/Loader.java.erb +1 -1
  59. data/vendor/prism/templates/javascript/src/deserialize.js.erb +1 -1
  60. data/vendor/prism/templates/lib/prism/compiler.rb.erb +2 -2
  61. data/vendor/prism/templates/lib/prism/node.rb.erb +24 -1
  62. data/vendor/prism/templates/lib/prism/serialize.rb.erb +1 -1
  63. data/vendor/prism/templates/lib/prism/visitor.rb.erb +2 -2
  64. data/vendor/prism/templates/sig/prism/node.rbs.erb +1 -0
  65. metadata +2 -2
@@ -51,7 +51,7 @@ unsafe fn convert_errors(errors_array: *mut hb_array_T) -> Vec<AnyError> {
51
51
  return Vec::new();
52
52
  }
53
53
 
54
- let count = (*errors_array).size;
54
+ let count = hb_array_size(errors_array);
55
55
  let mut errors = Vec::with_capacity(count);
56
56
 
57
57
  for index in 0..count {
@@ -105,12 +105,20 @@ unsafe fn convert_token_field(token_ptr: *mut token_T) -> Option<crate::Token> {
105
105
  }
106
106
  }
107
107
 
108
+ unsafe fn convert_location_field(location_ptr: *const location_T) -> Option<Location> {
109
+ if location_ptr.is_null() {
110
+ None
111
+ } else {
112
+ Some(convert_location(*location_ptr))
113
+ }
114
+ }
115
+
108
116
  unsafe fn convert_children(children_array: *mut hb_array_T) -> Vec<AnyNode> {
109
117
  if children_array.is_null() {
110
118
  return Vec::new();
111
119
  }
112
120
 
113
- let count = (*children_array).size;
121
+ let count = hb_array_size(children_array);
114
122
  let mut children = Vec::with_capacity(count);
115
123
 
116
124
  for index in 0..count {
@@ -212,6 +220,8 @@ unsafe fn convert_node(node_ptr: *const c_void) -> Option<AnyNode> {
212
220
  <%- else -%>
213
221
  <%= field.name %>: convert_node_field((*c_node_ptr).<%= field.name %> as *mut c_void),
214
222
  <%- end -%>
223
+ <%- when Herb::Template::LocationField -%>
224
+ <%= field.name %>: convert_location_field((*c_node_ptr).<%= field.name %>),
215
225
  <%- end -%>
216
226
  <%- end -%>
217
227
  })
@@ -253,6 +253,8 @@ pub struct <%= node.name %> {
253
253
  <%- end -%>
254
254
  <%- when Herb::Template::ElementSourceField -%>
255
255
  pub <%= field.name %>: String,
256
+ <%- when Herb::Template::LocationField -%>
257
+ pub <%= field.name %>: Option<Location>,
256
258
  <%- end -%>
257
259
  <%- end -%>
258
260
  }
@@ -361,6 +363,8 @@ impl Node for <%= node.name %> {
361
363
  output.push_str(&format!("{}{}: {}", "<%= symbol %>".white(), "<%= field.name %>".white(), format_array_value(&self.<%= field.name %>, &"<%= is_last ? " " : "│ " %>".white().to_string())));
362
364
  <%- when Herb::Template::NodeField -%>
363
365
  output.push_str(&format!("{}{}: {}", "<%= symbol %>".white(), "<%= field.name %>".white(), format_node_value(&self.<%= field.name %>, &"<%= is_last ? " " : "│ " %>".white().to_string(), <%= !is_last %>)));
366
+ <%- when Herb::Template::LocationField -%>
367
+ output.push_str(&format!("{}{}: {}\n", "<%= symbol %>".white(), "<%= field.name %>".white(), self.<%= field.name %>.as_ref().map(|l| format!("(location: {})", l).dimmed().to_string()).unwrap_or_else(|| "∅".magenta().to_string())));
364
368
  <%- end -%>
365
369
  <%- end -%>
366
370
  <%- else -%>
@@ -27,11 +27,7 @@
27
27
  <%- when Herb::Template::NodeField -%>
28
28
  <%= node.human %>-><%= field.name %> = <%= field.name %>;
29
29
  <%- when Herb::Template::ArrayField -%>
30
- if (<%= field.name %> == NULL) {
31
- <%= node.human %>-><%= field.name %> = hb_array_init(8);
32
- } else {
33
- <%= node.human %>-><%= field.name %> = <%= field.name %>;
34
- }
30
+ <%= node.human %>-><%= field.name %> = <%= field.name %>;
35
31
  <%- when Herb::Template::BooleanField -%>
36
32
  <%= node.human %>-><%= field.name %> = <%= field.name %>;
37
33
  <%- when Herb::Template::ElementSourceField -%>
@@ -44,6 +40,8 @@
44
40
  <%= node.human %>-><%= field.name %> = <%= field.name %>;
45
41
  <%- when Herb::Template::VoidPointerField -%>
46
42
  <%= node.human %>-><%= field.name %> = <%= field.name %>;
43
+ <%- when Herb::Template::LocationField -%>
44
+ <%= node.human %>-><%= field.name %> = <%= field.name %>;
47
45
  <%- else -%>
48
46
  <%= field.inspect %>
49
47
  <%- end -%>
@@ -77,7 +75,7 @@ void ast_free_base_node(AST_NODE_T* node) {
77
75
  if (node == NULL) { return; }
78
76
 
79
77
  if (node->errors) {
80
- for (size_t i = 0; i < node->errors->size; i++) {
78
+ for (size_t i = 0; i < hb_array_size(node->errors); i++) {
81
79
  ERROR_T* child = hb_array_get(node->errors, i);
82
80
  if (child != NULL) { error_free(child); }
83
81
  }
@@ -103,7 +101,7 @@ static void ast_free_<%= node.human %>(<%= node.struct_type %>* <%= node.human %
103
101
  ast_node_free((AST_NODE_T*) <%= node.human %>-><%= field.name %>);
104
102
  <%- when Herb::Template::ArrayField -%>
105
103
  if (<%= node.human %>-><%= field.name %> != NULL) {
106
- for (size_t i = 0; i < <%= node.human %>-><%= field.name %>->size; i++) {
104
+ for (size_t i = 0; i < hb_array_size(<%= node.human %>-><%= field.name %>); i++) {
107
105
  AST_NODE_T* child = hb_array_get(<%= node.human %>-><%= field.name %>, i);
108
106
  if (child) { ast_node_free(child); }
109
107
  }
@@ -127,6 +125,8 @@ static void ast_free_<%= node.human %>(<%= node.struct_type %>* <%= node.human %
127
125
  free(<%= node.human %>-><%= field.name %>);
128
126
  <%- when Herb::Template::BooleanField -%>
129
127
  <%- when Herb::Template::ElementSourceField -%>
128
+ <%- when Herb::Template::LocationField -%>
129
+ if (<%= node.human %>-><%= field.name %> != NULL) { free(<%= node.human %>-><%= field.name %>); }
130
130
  <%- else -%>
131
131
  <%= field.inspect %>
132
132
  <%- end -%>
@@ -87,6 +87,20 @@ void ast_pretty_print_node(AST_NODE_T* node, const size_t indent, const size_t r
87
87
  pretty_print_label(hb_string("<%= field.name %>"), indent, relative_indent, <%= last %>, buffer);
88
88
  hb_buffer_append(buffer, " ?\n");
89
89
 
90
+ <%- when Herb::Template::LocationField -%>
91
+ pretty_print_label(hb_string("<%= field.name %>"), indent, relative_indent, <%= last %>, buffer);
92
+ if (<%= node.human %>-><%= field.name %>) {
93
+ char <%= field.name %>_location_string[128];
94
+ sprintf(<%= field.name %>_location_string, " (location: (%u:%u)-(%u:%u))\n",
95
+ <%= node.human %>-><%= field.name %>->start.line,
96
+ <%= node.human %>-><%= field.name %>->start.column,
97
+ <%= node.human %>-><%= field.name %>->end.line,
98
+ <%= node.human %>-><%= field.name %>->end.column);
99
+ hb_buffer_append(buffer, <%= field.name %>_location_string);
100
+ } else {
101
+ hb_buffer_append(buffer, " ∅\n");
102
+ }
103
+
90
104
  <%- else -%>
91
105
  <%= field.inspect %>
92
106
  <%- end -%>
@@ -167,7 +167,7 @@ void error_pretty_print_array(
167
167
  return;
168
168
  }
169
169
 
170
- if (array->size == 0) {
170
+ if (hb_array_size(array) == 0) {
171
171
  pretty_print_property(hb_string(name), hb_string("[]"), indent, relative_indent, last_property, buffer);
172
172
 
173
173
  return;
@@ -178,17 +178,17 @@ void error_pretty_print_array(
178
178
  hb_buffer_append(buffer, "(");
179
179
 
180
180
  char count[16];
181
- sprintf(count, "%zu", array->size);
181
+ sprintf(count, "%zu", hb_array_size(array));
182
182
  hb_buffer_append(buffer, count);
183
183
  hb_buffer_append(buffer, ")\n");
184
184
 
185
185
  if (indent < 20) {
186
- for (size_t i = 0; i < array->size; i++) {
186
+ for (size_t i = 0; i < hb_array_size(array); i++) {
187
187
  ERROR_T* child = hb_array_get(array, i);
188
188
  pretty_print_indent(buffer, indent);
189
189
  pretty_print_indent(buffer, relative_indent + 1);
190
190
 
191
- if (i == array->size - 1) {
191
+ if (i == hb_array_size(array) - 1) {
192
192
  hb_buffer_append(buffer, "└── ");
193
193
  } else {
194
194
  hb_buffer_append(buffer, "├── ");
@@ -196,7 +196,7 @@ void error_pretty_print_array(
196
196
 
197
197
  error_pretty_print(child, indent + 1, relative_indent + 1, buffer);
198
198
 
199
- if (i != array->size - 1) { pretty_print_newline(indent + 1, relative_indent, buffer); }
199
+ if (i != hb_array_size(array) - 1) { pretty_print_newline(indent + 1, relative_indent, buffer); }
200
200
  }
201
201
  }
202
202
  }
@@ -31,7 +31,7 @@ void herb_visit_child_nodes(const AST_NODE_T *node, bool (*visitor)(const AST_NO
31
31
 
32
32
  <%- when Herb::Template::ArrayField -%>
33
33
  if (<%= node.human %>-><%= field.name %> != NULL) {
34
- for (size_t index = 0; index < <%= node.human %>-><%= field.name %>->size; index++) {
34
+ for (size_t index = 0; index < hb_array_size(<%= node.human %>-><%= field.name %>); index++) {
35
35
  herb_visit_node(hb_array_get(<%= node.human %>-><%= field.name %>, index), visitor, data);
36
36
  }
37
37
  }
@@ -117,6 +117,16 @@ module Herb
117
117
  end
118
118
  end
119
119
 
120
+ class LocationField < Field
121
+ def ruby_type
122
+ "Herb::Location"
123
+ end
124
+
125
+ def c_type
126
+ "location_T*"
127
+ end
128
+ end
129
+
120
130
  class IntegerField < Field
121
131
  def ruby_type
122
132
  "Integer"
@@ -210,6 +220,7 @@ module Herb
210
220
  when "token_type" then TokenTypeField
211
221
  when "string" then StringField
212
222
  when "position" then PositionField
223
+ when "location" then LocationField
213
224
  when "size_t" then SizeTField
214
225
  when "boolean" then BooleanField
215
226
  when "prism_node" then PrismNodeField
@@ -66,7 +66,7 @@ val ErrorsArrayFromCArray(hb_array_T* array) {
66
66
  val result = Array.new_();
67
67
 
68
68
  if (array) {
69
- for (size_t i = 0; i < array->size; i++) {
69
+ for (size_t i = 0; i < hb_array_size(array); i++) {
70
70
  ERROR_T* error = (ERROR_T*)hb_array_get(array, i);
71
71
  if (error) {
72
72
  result.call<void>("push", ErrorFromCStruct(error));
@@ -39,6 +39,12 @@ val <%= node.name %>FromCStruct(<%= node.struct_type %>* <%= node.human %>) {
39
39
  result.set("<%= field.name %>", NodesArrayFromCArray(<%= node.human %>-><%= field.name %>));
40
40
  <%- when Herb::Template::ElementSourceField -%>
41
41
  result.set("<%= field.name %>", CreateStringFromHbString(element_source_to_string(<%= node.human %>-><%= field.name %>)));
42
+ <%- when Herb::Template::LocationField -%>
43
+ if (<%= node.human %>-><%= field.name %>) {
44
+ result.set("<%= field.name %>", CreateLocation(*<%= node.human %>-><%= field.name %>));
45
+ } else {
46
+ result.set("<%= field.name %>", val::null());
47
+ }
42
48
  <%- else -%>
43
49
  result.set("<%= field.name %>", val::null());
44
50
  <%- end -%>
@@ -67,7 +73,7 @@ val NodesArrayFromCArray(hb_array_T* array) {
67
73
 
68
74
  val jsArray = val::array();
69
75
 
70
- for (size_t i = 0; i < array->size; i++) {
76
+ for (size_t i = 0; i < hb_array_size(array); i++) {
71
77
  AST_NODE_T* child_node = (AST_NODE_T*) hb_array_get(array, i);
72
78
 
73
79
  if (child_node) {
@@ -14,7 +14,7 @@
14
14
  /**
15
15
  * The minor version of the Prism library as an int.
16
16
  */
17
- #define PRISM_VERSION_MINOR 7
17
+ #define PRISM_VERSION_MINOR 8
18
18
 
19
19
  /**
20
20
  * The patch version of the Prism library as an int.
@@ -24,6 +24,6 @@
24
24
  /**
25
25
  * The version of the Prism library as a constant string.
26
26
  */
27
- #define PRISM_VERSION "1.7.0"
27
+ #define PRISM_VERSION "1.8.0"
28
28
 
29
29
  #endif
@@ -3962,9 +3962,13 @@ pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3962
3962
  memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
3963
3963
  pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
3964
3964
 
3965
+ size_t fract_length = 0;
3966
+ for (const uint8_t *fract = point; fract < end; ++fract) {
3967
+ if (*fract != '_') ++fract_length;
3968
+ }
3965
3969
  digits[0] = '1';
3966
- if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
3967
- pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
3970
+ if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
3971
+ pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
3968
3972
  xfree(digits);
3969
3973
 
3970
3974
  pm_integers_reduce(&node->numerator, &node->denominator);
@@ -12422,6 +12426,22 @@ expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ide
12422
12426
  }
12423
12427
  }
12424
12428
 
12429
+ /**
12430
+ * A special expect1 that attaches the error to the opening token location
12431
+ * rather than the current position. This is useful for errors about missing
12432
+ * closing tokens, where we want to point to the line with the opening token
12433
+ * (e.g., `def`, `class`, `if`, `{`) rather than the end of the file.
12434
+ */
12435
+ static void
12436
+ expect1_opening(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id, const pm_token_t *opening) {
12437
+ if (accept1(parser, type)) return;
12438
+
12439
+ pm_parser_err(parser, opening->start, opening->end, diag_id);
12440
+
12441
+ parser->previous.start = opening->end;
12442
+ parser->previous.type = PM_TOKEN_MISSING;
12443
+ }
12444
+
12425
12445
  static pm_node_t *
12426
12446
  parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth);
12427
12447
 
@@ -14764,7 +14784,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
14764
14784
  statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
14765
14785
  }
14766
14786
 
14767
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
14787
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
14768
14788
  } else {
14769
14789
  if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14770
14790
  if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
@@ -14779,7 +14799,7 @@ parse_block(pm_parser_t *parser, uint16_t depth) {
14779
14799
  }
14780
14800
  }
14781
14801
 
14782
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
14802
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
14783
14803
  }
14784
14804
 
14785
14805
  pm_constant_id_list_t locals;
@@ -15204,7 +15224,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
15204
15224
 
15205
15225
  accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15206
15226
  parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false, false);
15207
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
15227
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15208
15228
 
15209
15229
  pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
15210
15230
 
@@ -15221,7 +15241,7 @@ parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newl
15221
15241
  }
15222
15242
  } else {
15223
15243
  parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false);
15224
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
15244
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15225
15245
  }
15226
15246
 
15227
15247
  // Set the appropriate end location for all of the nodes in the subtree.
@@ -16202,7 +16222,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
16202
16222
  if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16203
16223
  inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16204
16224
  accept1(parser, PM_TOKEN_NEWLINE);
16205
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16225
+ expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16206
16226
  }
16207
16227
 
16208
16228
  closing = parser->previous;
@@ -16214,7 +16234,7 @@ parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures
16214
16234
  if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16215
16235
  inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16216
16236
  accept1(parser, PM_TOKEN_NEWLINE);
16217
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16237
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16218
16238
  }
16219
16239
 
16220
16240
  closing = parser->previous;
@@ -16594,7 +16614,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
16594
16614
  pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16595
16615
 
16596
16616
  accept1(parser, PM_TOKEN_NEWLINE);
16597
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
16617
+ expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16598
16618
  pm_token_t closing = parser->previous;
16599
16619
 
16600
16620
  switch (PM_NODE_TYPE(inner)) {
@@ -16672,7 +16692,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
16672
16692
  node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16673
16693
 
16674
16694
  accept1(parser, PM_TOKEN_NEWLINE);
16675
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
16695
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
16676
16696
  pm_token_t closing = parser->previous;
16677
16697
 
16678
16698
  node->base.location.start = opening.start;
@@ -16798,7 +16818,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm
16798
16818
  parser->pattern_matching_newlines = previous_pattern_matching_newlines;
16799
16819
 
16800
16820
  accept1(parser, PM_TOKEN_NEWLINE);
16801
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16821
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
16802
16822
  return UP(pm_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous));
16803
16823
  }
16804
16824
  default: {
@@ -16896,7 +16916,7 @@ parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, p
16896
16916
 
16897
16917
  pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16898
16918
  accept1(parser, PM_TOKEN_NEWLINE);
16899
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
16919
+ expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16900
16920
  pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
16901
16921
 
16902
16922
  if (!alternation) {
@@ -17748,7 +17768,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17748
17768
  pm_accepts_block_stack_push(parser, true);
17749
17769
  parser_lex(parser);
17750
17770
 
17751
- pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
17771
+ pm_token_t opening = parser->previous;
17772
+ pm_hash_node_t *node = pm_hash_node_create(parser, &opening);
17752
17773
 
17753
17774
  if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17754
17775
  if (current_hash_keys != NULL) {
@@ -17763,7 +17784,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
17763
17784
  }
17764
17785
 
17765
17786
  pm_accepts_block_stack_pop(parser);
17766
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
17787
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
17767
17788
  pm_hash_node_closing_loc_set(node, &parser->previous);
17768
17789
 
17769
17790
  return UP(node);
@@ -18380,7 +18401,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18380
18401
  }
18381
18402
 
18382
18403
  parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
18383
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
18404
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18384
18405
 
18385
18406
  if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18386
18407
  pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->previous);
@@ -18413,7 +18434,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18413
18434
 
18414
18435
  pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18415
18436
  parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18416
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
18437
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
18417
18438
 
18418
18439
  begin_node->base.location.end = parser->previous.end;
18419
18440
  pm_begin_node_end_keyword_set(begin_node, &parser->previous);
@@ -18438,7 +18459,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18438
18459
  pm_token_t opening = parser->previous;
18439
18460
  pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
18440
18461
 
18441
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
18462
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
18442
18463
  pm_context_t context = parser->current_context->context;
18443
18464
  if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
18444
18465
  pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
@@ -18568,7 +18589,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18568
18589
  parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
18569
18590
  }
18570
18591
 
18571
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18592
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18572
18593
 
18573
18594
  pm_constant_id_list_t locals;
18574
18595
  pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
@@ -18626,7 +18647,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18626
18647
  parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
18627
18648
  }
18628
18649
 
18629
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
18650
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18630
18651
 
18631
18652
  if (context_def_p(parser)) {
18632
18653
  pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
@@ -18936,7 +18957,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
18936
18957
  pm_accepts_block_stack_pop(parser);
18937
18958
  pm_do_loop_stack_pop(parser);
18938
18959
 
18939
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
18960
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18940
18961
  end_keyword = parser->previous;
18941
18962
  }
18942
18963
 
@@ -19030,7 +19051,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
19030
19051
  pm_token_t opening = parser->previous;
19031
19052
  pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
19032
19053
 
19033
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
19054
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19034
19055
  return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
19035
19056
  }
19036
19057
  case PM_TOKEN_KEYWORD_FALSE:
@@ -19094,7 +19115,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
19094
19115
  }
19095
19116
 
19096
19117
  parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false);
19097
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
19118
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19098
19119
 
19099
19120
  return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous));
19100
19121
  }
@@ -19245,7 +19266,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
19245
19266
  pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
19246
19267
 
19247
19268
  pm_parser_scope_pop(parser);
19248
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
19269
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19249
19270
 
19250
19271
  if (context_def_p(parser)) {
19251
19272
  pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
@@ -19311,7 +19332,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
19311
19332
  }
19312
19333
 
19313
19334
  parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
19314
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
19335
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19315
19336
 
19316
19337
  return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0));
19317
19338
  }
@@ -19345,7 +19366,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
19345
19366
  }
19346
19367
 
19347
19368
  parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
19348
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
19369
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19349
19370
 
19350
19371
  return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->previous, predicate, statements, 0));
19351
19372
  }
@@ -20091,7 +20112,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
20091
20112
  }
20092
20113
 
20093
20114
  parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
20094
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
20115
+ expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20095
20116
  } else {
20096
20117
  expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20097
20118
  opening = parser->previous;
@@ -20109,7 +20130,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
20109
20130
  parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
20110
20131
  }
20111
20132
 
20112
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
20133
+ expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &operator);
20113
20134
  }
20114
20135
 
20115
20136
  pm_constant_id_list_t locals;
@@ -101,7 +101,7 @@ public class Loader {
101
101
  expect((byte) 'M', "incorrect prism header");
102
102
 
103
103
  expect((byte) 1, "prism major version does not match");
104
- expect((byte) 7, "prism minor version does not match");
104
+ expect((byte) 8, "prism minor version does not match");
105
105
  expect((byte) 0, "prism patch version does not match");
106
106
 
107
107
  expect((byte) 1, "Loader.java requires no location fields in the serialized output");
@@ -1,7 +1,7 @@
1
1
  import * as nodes from "./nodes.js";
2
2
 
3
3
  const MAJOR_VERSION = 1;
4
- const MINOR_VERSION = 7;
4
+ const MINOR_VERSION = 8;
5
5
  const PATCH_VERSION = 0;
6
6
 
7
7
  // The DataView getFloat64 function takes an optional second argument that
@@ -29,14 +29,14 @@ module Prism
29
29
 
30
30
  # Visit the child nodes of the given node.
31
31
  def visit_child_nodes(node)
32
- node.compact_child_nodes.map { |node| node.accept(self) }
32
+ node.each_child_node.map { |node| node.accept(self) }
33
33
  end
34
34
 
35
35
  <%- nodes.each_with_index do |node, index| -%>
36
36
  <%= "\n" if index != 0 -%>
37
37
  # Compile a <%= node.name %> node
38
38
  def visit_<%= node.human %>(node)
39
- node.compact_child_nodes.map { |node| node.accept(self) }
39
+ node.each_child_node.map { |node| node.accept(self) }
40
40
  end
41
41
  <%- end -%>
42
42
  end
@@ -187,7 +187,7 @@ module Prism
187
187
  while (node = queue.shift)
188
188
  result << node
189
189
 
190
- node.compact_child_nodes.each do |child_node|
190
+ node.each_child_node do |child_node|
191
191
  child_location = child_node.location
192
192
 
193
193
  start_line = child_location.start_line
@@ -259,6 +259,13 @@ module Prism
259
259
 
260
260
  alias deconstruct child_nodes
261
261
 
262
+ # With a block given, yields each child node. Without a block, returns
263
+ # an enumerator that contains each child node. Excludes any `nil`s in
264
+ # the place of optional nodes that were not present.
265
+ def each_child_node
266
+ raise NoMethodError, "undefined method `each_child_node' for #{inspect}"
267
+ end
268
+
262
269
  # Returns an array of child nodes, excluding any `nil`s in the place of
263
270
  # optional nodes that were not present.
264
271
  def compact_child_nodes
@@ -335,6 +342,22 @@ module Prism
335
342
  }.compact.join(", ") %>]
336
343
  end
337
344
 
345
+ # def each_child_node: () { (Prism::node) -> void } -> void | () -> Enumerator[Prism::node]
346
+ def each_child_node
347
+ return to_enum(:each_child_node) unless block_given?
348
+
349
+ <%- node.fields.each do |field| -%>
350
+ <%- case field -%>
351
+ <%- when Prism::Template::NodeField -%>
352
+ yield <%= field.name %>
353
+ <%- when Prism::Template::OptionalNodeField -%>
354
+ yield <%= field.name %> if <%= field.name %>
355
+ <%- when Prism::Template::NodeListField -%>
356
+ <%= field.name %>.each { |node| yield node }
357
+ <%- end -%>
358
+ <%- end -%>
359
+ end
360
+
338
361
  # def compact_child_nodes: () -> Array[Node]
339
362
  def compact_child_nodes
340
363
  <%- if node.fields.any? { |field| field.is_a?(Prism::Template::OptionalNodeField) } -%>
@@ -10,7 +10,7 @@ module Prism
10
10
 
11
11
  # The minor version of prism that we are expecting to find in the serialized
12
12
  # strings.
13
- MINOR_VERSION = 7
13
+ MINOR_VERSION = 8
14
14
 
15
15
  # The patch version of prism that we are expecting to find in the serialized
16
16
  # strings.
@@ -20,7 +20,7 @@ module Prism
20
20
  # Visits the child nodes of `node` by calling `accept` on each one.
21
21
  def visit_child_nodes(node)
22
22
  # @type self: _Visitor
23
- node.compact_child_nodes.each { |node| node.accept(self) }
23
+ node.each_child_node { |node| node.accept(self) }
24
24
  end
25
25
  end
26
26
 
@@ -48,7 +48,7 @@ module Prism
48
48
  <%= "\n" if index != 0 -%>
49
49
  # Visit a <%= node.name %> node
50
50
  def visit_<%= node.human %>(node)
51
- node.compact_child_nodes.each { |node| node.accept(self) }
51
+ node.each_child_node { |node| node.accept(self) }
52
52
  end
53
53
  <%- end -%>
54
54
  end
@@ -12,6 +12,7 @@ module Prism
12
12
  def child_nodes: () -> Array[Prism::node?]
13
13
  def comment_targets: () -> Array[Prism::node | Location]
14
14
  def compact_child_nodes: () -> Array[Prism::node]
15
+ def each_child_node: () { (Prism::node) -> void } -> void | () -> Enumerator[Prism::node]
15
16
  def self.fields: () -> Array[Prism::Reflection::Field]
16
17
  def type: () -> Symbol
17
18
  def self.type: () -> Symbol
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: herb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 0.8.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Roth
@@ -323,7 +323,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
323
323
  - !ruby/object:Gem::Version
324
324
  version: '0'
325
325
  requirements: []
326
- rubygems_version: 3.6.9
326
+ rubygems_version: 4.0.3
327
327
  specification_version: 4
328
328
  summary: Powerful and seamless HTML-aware ERB parsing and tooling.
329
329
  test_files: []