herb 0.11.1 → 0.11.2

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 (247) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -2
  3. data/config.yml +6 -0
  4. data/ext/herb/extconf.rb +8 -31
  5. data/ext/herb/nodes.c +75 -75
  6. data/ext/herb/parser_options_helpers.c +26 -0
  7. data/lib/herb/analysis/partial_index.rb +1 -1
  8. data/lib/herb/analysis/partial_resolution.rb +27 -0
  9. data/lib/herb/ast/helpers.rb +1 -1
  10. data/lib/herb/configuration.rb +11 -1
  11. data/lib/herb/dev/classifier.rb +1 -1
  12. data/lib/herb/engine/compiler.rb +5 -8
  13. data/lib/herb/engine/slots/dynamics_compiler.rb +53 -14
  14. data/lib/herb/engine/slots/subtree_compiler.rb +1 -1
  15. data/lib/herb/engine/slots/visitor.rb +32 -4
  16. data/lib/herb/engine/visitors/instrumentation_visitor.rb +18 -6
  17. data/lib/herb/parser_options.rb +6 -3
  18. data/lib/herb/project.rb +19 -8
  19. data/lib/herb/version.rb +1 -1
  20. data/lib/herb.rb +1 -1
  21. data/sig/herb/analysis/partial_resolution.rbs +8 -0
  22. data/sig/herb/configuration.rbs +3 -0
  23. data/sig/herb/engine/slots/dynamics_compiler.rbs +24 -7
  24. data/sig/herb/engine/slots/visitor.rbs +14 -0
  25. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +5 -1
  26. data/sig/herb/parser_options.rbs +6 -4
  27. data/sig/herb.rbs +2 -2
  28. data/src/analyze/action_view/attribute_extraction_helpers.c +40 -21
  29. data/src/analyze/action_view/generated_handlers.c +36 -36
  30. data/src/analyze/action_view/image_tag.c +7 -3
  31. data/src/analyze/action_view/javascript_include_tag.c +6 -3
  32. data/src/analyze/action_view/link_to.c +23 -23
  33. data/src/analyze/action_view/registry.c +7 -3
  34. data/src/analyze/action_view/tag_helper_node_builders.c +6 -13
  35. data/src/analyze/action_view/tag_helpers.c +139 -90
  36. data/src/analyze/action_view/turbo_frame_tag.c +5 -4
  37. data/src/analyze/analyze.c +35 -19
  38. data/src/analyze/analyze_helpers.c +161 -188
  39. data/src/analyze/analyzed_ruby.c +8 -7
  40. data/src/analyze/control_type.c +29 -22
  41. data/src/analyze/herb_directives.c +16 -20
  42. data/src/analyze/iteration_nodes.c +69 -24
  43. data/src/analyze/parse_errors.c +32 -22
  44. data/src/analyze/postfix_conditionals.c +23 -13
  45. data/src/analyze/prism_annotate.c +29 -28
  46. data/src/analyze/render_nodes.c +51 -41
  47. data/src/analyze/strict_locals.c +14 -15
  48. data/src/analyze/ternary_conditionals.c +14 -10
  49. data/src/herb.c +10 -8
  50. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  51. data/src/include/analyze/action_view/tag_helper_node_builders.h +1 -0
  52. data/src/include/analyze/action_view/tag_helpers.h +1 -1
  53. data/src/include/analyze/analyze.h +3 -2
  54. data/src/include/analyze/analyzed_ruby.h +4 -2
  55. data/src/include/analyze/helpers.h +6 -6
  56. data/src/include/herb.h +3 -2
  57. data/src/include/parser/parser_options.h +5 -0
  58. data/src/include/prism/prism_context.h +12 -12
  59. data/src/include/prism/prism_helpers.h +30 -0
  60. data/src/include/prism_version.h +11 -0
  61. data/src/include/version.h +1 -1
  62. data/src/parser/parser_helpers.c +1 -2
  63. data/src/parser.c +6 -7
  64. data/src/parser_options_defaults.c +1 -0
  65. data/src/prism/prism_helpers.c +84 -50
  66. data/src/prism/ruby_parser.c +20 -20
  67. data/templates/ext/herb/nodes.c.erb +5 -5
  68. data/templates/ext/herb/parser_options_helpers.c.erb +33 -0
  69. data/templates/java/nodes.c.erb +6 -6
  70. data/templates/java/parser_options_helpers.c.erb +41 -2
  71. data/templates/java/parser_options_helpers.h.erb +2 -1
  72. data/templates/javascript/packages/node/extension/nodes.cpp.erb +5 -5
  73. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +34 -2
  74. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +1 -1
  75. data/templates/lib/herb/parser_options.rb.erb +1 -1
  76. data/templates/rust/src/prism/generated_deserialize.rs.erb +90 -44
  77. data/templates/rust/src/prism/generated_prettyprint.rs.erb +18 -27
  78. data/templates/src/analyze/action_view/generated_handlers.c.erb +23 -22
  79. data/templates/src/include/parser/parser_options.h.erb +10 -0
  80. data/templates/src/include/prism_version.h.erb +17 -0
  81. data/templates/src/parser_options_defaults.c.erb +1 -1
  82. data/templates/template.rb +17 -2
  83. data/templates/wasm/nodes.cpp.erb +5 -5
  84. data/templates/wasm/parser_options_helpers.cpp.erb +24 -0
  85. data/vendor/prism/Rakefile +76 -7
  86. data/vendor/prism/config.yml +174 -161
  87. data/vendor/prism/include/prism/arena.h +45 -0
  88. data/vendor/prism/include/prism/arena.hpp +42 -0
  89. data/vendor/prism/include/prism/ast.h +2738 -611
  90. data/vendor/prism/include/prism/ast.hpp +641 -0
  91. data/vendor/prism/include/prism/buffer.h +60 -0
  92. data/vendor/prism/include/prism/buffer.hpp +55 -0
  93. data/vendor/prism/include/prism/comments.h +72 -0
  94. data/vendor/prism/include/prism/compiler/accel.h +26 -0
  95. data/vendor/prism/include/prism/compiler/align.h +36 -0
  96. data/vendor/prism/include/prism/compiler/assume.h +25 -0
  97. data/vendor/prism/include/prism/compiler/branch.h +26 -0
  98. data/vendor/prism/include/prism/compiler/bswap.h +46 -0
  99. data/vendor/prism/include/prism/compiler/cplusplus.hpp +16 -0
  100. data/vendor/prism/include/prism/compiler/endianness.h +34 -0
  101. data/vendor/prism/include/prism/compiler/exceptions.hpp +17 -0
  102. data/vendor/prism/include/prism/compiler/exported.h +24 -0
  103. data/vendor/prism/include/prism/compiler/fallthrough.h +22 -0
  104. data/vendor/prism/include/prism/compiler/filesystem.h +32 -0
  105. data/vendor/prism/include/prism/compiler/flex_array.h +19 -0
  106. data/vendor/prism/include/prism/compiler/force_inline.h +21 -0
  107. data/vendor/prism/include/prism/compiler/format.h +27 -0
  108. data/vendor/prism/include/prism/compiler/inline.h +17 -0
  109. data/vendor/prism/include/prism/compiler/lifetimebound.hpp +25 -0
  110. data/vendor/prism/include/prism/compiler/nodiscard.h +22 -0
  111. data/vendor/prism/include/prism/compiler/nonnull.h +18 -0
  112. data/vendor/prism/include/prism/compiler/unused.h +18 -0
  113. data/vendor/prism/include/prism/constant_pool.h +106 -0
  114. data/vendor/prism/include/prism/diagnostic.h +55 -402
  115. data/vendor/prism/include/prism/errors_format.h +61 -0
  116. data/vendor/prism/include/prism/excludes.h +29 -0
  117. data/vendor/prism/include/prism/integer.h +41 -0
  118. data/vendor/prism/include/prism/internal/allocator.h +68 -0
  119. data/vendor/prism/include/prism/internal/allocator_debug.h +88 -0
  120. data/vendor/prism/include/prism/internal/arena.h +108 -0
  121. data/vendor/prism/include/prism/internal/bit.h +42 -0
  122. data/vendor/prism/include/prism/internal/buffer.h +94 -0
  123. data/vendor/prism/include/prism/internal/char.h +145 -0
  124. data/vendor/prism/include/prism/internal/comments.h +54 -0
  125. data/vendor/prism/include/prism/internal/constant_pool.h +152 -0
  126. data/vendor/prism/include/prism/internal/diagnostic.h +389 -0
  127. data/vendor/prism/include/prism/{encoding.h → internal/encoding.h} +27 -68
  128. data/vendor/prism/include/prism/internal/integer.h +68 -0
  129. data/vendor/prism/include/prism/internal/isinf.h +16 -0
  130. data/vendor/prism/include/prism/internal/line_offset_list.h +34 -0
  131. data/vendor/prism/include/prism/{util/pm_list.h → internal/list.h} +11 -52
  132. data/vendor/prism/include/prism/internal/magic_comments.h +23 -0
  133. data/vendor/prism/include/prism/internal/memchr.h +15 -0
  134. data/vendor/prism/include/prism/internal/node.h +42 -0
  135. data/vendor/prism/include/prism/internal/options.h +232 -0
  136. data/vendor/prism/include/prism/internal/parser.h +1015 -0
  137. data/vendor/prism/include/prism/internal/regexp.h +26 -0
  138. data/vendor/prism/include/prism/internal/serialize.h +39 -0
  139. data/vendor/prism/include/prism/internal/source.h +72 -0
  140. data/vendor/prism/include/prism/internal/static_literals.h +60 -0
  141. data/vendor/prism/include/prism/internal/stringy.h +30 -0
  142. data/vendor/prism/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
  143. data/vendor/prism/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
  144. data/vendor/prism/include/prism/internal/tokens.h +11 -0
  145. data/vendor/prism/include/prism/internal/xxh3.h +16 -0
  146. data/vendor/prism/include/prism/json.h +40 -0
  147. data/vendor/prism/include/prism/line_offset_list.h +69 -0
  148. data/vendor/prism/include/prism/magic_comments.h +53 -0
  149. data/vendor/prism/include/prism/node.h +59 -49
  150. data/vendor/prism/include/prism/node.hpp +272 -0
  151. data/vendor/prism/include/prism/node_type.hpp +38 -0
  152. data/vendor/prism/include/prism/options.h +154 -279
  153. data/vendor/prism/include/prism/options.hpp +43 -0
  154. data/vendor/prism/include/prism/parser.h +367 -870
  155. data/vendor/prism/include/prism/parser.hpp +274 -0
  156. data/vendor/prism/include/prism/prettyprint.h +14 -9
  157. data/vendor/prism/include/prism/serialize.h +123 -0
  158. data/vendor/prism/include/prism/source.h +163 -0
  159. data/vendor/prism/include/prism/stream.h +36 -0
  160. data/vendor/prism/include/prism/string_query.h +82 -0
  161. data/vendor/prism/include/prism/stringy.h +61 -0
  162. data/vendor/prism/include/prism/stringy.hpp +31 -0
  163. data/vendor/prism/include/prism/version.h +20 -3
  164. data/vendor/prism/include/prism.h +35 -320
  165. data/vendor/prism/include/prism.hpp +24 -0
  166. data/vendor/prism/src/arena.c +122 -0
  167. data/vendor/prism/src/{util/pm_buffer.c → buffer.c} +53 -21
  168. data/vendor/prism/src/{util/pm_char.c → char.c} +28 -57
  169. data/vendor/prism/src/comments.c +455 -0
  170. data/vendor/prism/src/constant_pool.c +406 -0
  171. data/vendor/prism/src/diagnostic.c +120 -68
  172. data/vendor/prism/src/encoding.c +8 -3
  173. data/vendor/prism/src/errors_format.c +519 -0
  174. data/vendor/prism/src/{util/pm_integer.c → integer.c} +38 -22
  175. data/vendor/prism/src/json.c +5733 -0
  176. data/vendor/prism/src/line_offset_list.c +100 -0
  177. data/vendor/prism/src/list.c +24 -0
  178. data/vendor/prism/src/{util/pm_memchr.c → memchr.c} +8 -6
  179. data/vendor/prism/src/node.c +3465 -7787
  180. data/vendor/prism/src/options.c +161 -54
  181. data/vendor/prism/src/parser.c +371 -0
  182. data/vendor/prism/src/prettyprint.c +421 -354
  183. data/vendor/prism/src/prism.c +8522 -7280
  184. data/vendor/prism/src/regexp.c +960 -45
  185. data/vendor/prism/src/serialize.c +2434 -2048
  186. data/vendor/prism/src/source.c +524 -0
  187. data/vendor/prism/src/static_literals.c +303 -360
  188. data/vendor/prism/src/string_query.c +180 -0
  189. data/vendor/prism/src/stringy.c +61 -0
  190. data/vendor/prism/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
  191. data/vendor/prism/src/strpbrk.c +447 -0
  192. data/vendor/prism/src/{token_type.c → tokens.c} +39 -18
  193. data/vendor/prism/src/xxh3.c +292 -0
  194. data/vendor/prism/templates/ext/prism/api_node.c.erb +58 -44
  195. data/vendor/prism/templates/include/prism/ast.h.erb +67 -17
  196. data/vendor/prism/templates/include/prism/ast.hpp.erb +31 -0
  197. data/vendor/prism/templates/include/prism/internal/diagnostic.h.erb +60 -0
  198. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/AbstractNodeVisitor.java.erb +1 -1
  199. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Loader.java.erb +232 -133
  200. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Nodes.java.erb +62 -23
  201. data/vendor/prism/templates/javascript/src/deserialize.js.erb +153 -146
  202. data/vendor/prism/templates/javascript/src/nodes.js.erb +4 -9
  203. data/vendor/prism/templates/lib/prism/compiler.rb.erb +14 -5
  204. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +20 -12
  205. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +37 -11
  206. data/vendor/prism/templates/lib/prism/dsl.rb.erb +43 -4
  207. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +26 -10
  208. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +5 -2
  209. data/vendor/prism/templates/lib/prism/node.rb.erb +283 -105
  210. data/vendor/prism/templates/lib/prism/reflection.rb.erb +11 -2
  211. data/vendor/prism/templates/lib/prism/serialize.rb.erb +291 -134
  212. data/vendor/prism/templates/lib/prism/visitor.rb.erb +18 -0
  213. data/vendor/prism/templates/src/diagnostic.c.erb +114 -63
  214. data/vendor/prism/templates/src/json.c.erb +130 -0
  215. data/vendor/prism/templates/src/node.c.erb +79 -236
  216. data/vendor/prism/templates/src/prettyprint.c.erb +24 -13
  217. data/vendor/prism/templates/src/serialize.c.erb +369 -183
  218. data/vendor/prism/templates/src/{token_type.c.erb → tokens.c.erb} +22 -11
  219. data/vendor/prism/templates/template.rb +193 -91
  220. metadata +100 -42
  221. data/vendor/prism/include/prism/defines.h +0 -260
  222. data/vendor/prism/include/prism/pack.h +0 -163
  223. data/vendor/prism/include/prism/regexp.h +0 -43
  224. data/vendor/prism/include/prism/static_literals.h +0 -121
  225. data/vendor/prism/include/prism/util/pm_buffer.h +0 -236
  226. data/vendor/prism/include/prism/util/pm_char.h +0 -204
  227. data/vendor/prism/include/prism/util/pm_constant_pool.h +0 -218
  228. data/vendor/prism/include/prism/util/pm_integer.h +0 -130
  229. data/vendor/prism/include/prism/util/pm_memchr.h +0 -29
  230. data/vendor/prism/include/prism/util/pm_newline_list.h +0 -113
  231. data/vendor/prism/include/prism/util/pm_string.h +0 -200
  232. data/vendor/prism/src/pack.c +0 -509
  233. data/vendor/prism/src/util/pm_constant_pool.c +0 -342
  234. data/vendor/prism/src/util/pm_list.c +0 -49
  235. data/vendor/prism/src/util/pm_newline_list.c +0 -125
  236. data/vendor/prism/src/util/pm_string.c +0 -381
  237. data/vendor/prism/src/util/pm_strpbrk.c +0 -206
  238. data/vendor/prism/templates/include/prism/diagnostic.h.erb +0 -130
  239. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +0 -68
  240. data/vendor/prism/templates/rbi/prism/node.rbi.erb +0 -167
  241. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +0 -18
  242. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +0 -45
  243. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +0 -31
  244. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +0 -7
  245. data/vendor/prism/templates/sig/prism/node.rbs.erb +0 -136
  246. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +0 -17
  247. data/vendor/prism/templates/sig/prism.rbs.erb +0 -92
@@ -2,51 +2,51 @@
2
2
 
3
3
  #include <prism.h>
4
4
  #include <stdbool.h>
5
+ #include <stdio.h>
5
6
  #include <stdlib.h>
6
7
  #include <string.h>
7
8
 
8
- static bool herb_prism_visit(const pm_node_t* node, void* data) {
9
+ static pm_visit_result_t herb_prism_visit(const pm_node_t* node, void* data) {
9
10
  const size_t* indent = (size_t*) data;
10
11
 
11
12
  for (size_t i = 0; i < *indent * 2; i++) {
12
13
  putc(' ', stdout);
13
14
  }
14
15
 
15
- printf("%s\n", pm_node_type_to_str(node->type));
16
+ printf("%s\n", pm_node_type(node->type));
16
17
 
17
18
  size_t next_indent = *indent + 1;
18
19
  size_t* next_data = &next_indent;
19
20
  pm_visit_child_nodes(node, herb_prism_visit, next_data);
20
21
 
21
- return false;
22
+ return PM_VISIT_SKIP;
22
23
  }
23
24
 
24
25
  void herb_parse_ruby_to_stdout(char* source) {
25
26
  size_t length = strlen(source);
26
27
 
27
- pm_parser_t parser;
28
- pm_parser_init(&parser, (const uint8_t*) source, length, NULL);
28
+ pm_arena_t* arena = pm_arena_new();
29
+ pm_parser_t* parser = pm_parser_new(arena, (const uint8_t*) source, length, NULL);
29
30
 
30
- pm_buffer_t buffer;
31
- pm_buffer_init(&buffer);
31
+ pm_buffer_t* buffer = pm_buffer_new();
32
32
 
33
33
  size_t indent = 0;
34
- pm_node_t* root = pm_parse(&parser);
34
+ pm_node_t* root = pm_parse(parser);
35
35
  size_t* data = &indent;
36
36
 
37
- const char* root_type = pm_node_type_to_str(root->type);
37
+ const char* root_type = pm_node_type(root->type);
38
38
  printf("Root Type: %s\n", root_type);
39
39
 
40
40
  pm_visit_node(root, herb_prism_visit, data);
41
41
 
42
42
  #ifndef PRISM_EXCLUDE_PRETTYPRINT
43
- pm_prettyprint(&buffer, &parser, root);
44
- printf("%s\n", buffer.value);
43
+ pm_prettyprint(buffer, parser, root);
44
+ printf("%.*s\n", (int) pm_buffer_length(buffer), pm_buffer_value(buffer));
45
45
  #endif
46
46
 
47
- pm_buffer_free(&buffer);
48
- pm_node_destroy(&parser, root);
49
- pm_parser_free(&parser);
47
+ pm_buffer_free(buffer);
48
+ pm_parser_free(parser);
49
+ pm_arena_free(arena);
50
50
  }
51
51
 
52
52
  static const char* const RUBY_FRAGMENT_PREFIXES[] = {
@@ -56,14 +56,14 @@ static const char* const RUBY_FRAGMENT_PREFIXES[] = {
56
56
  static const char* const RUBY_FRAGMENT_SUFFIXES[] = { "", "\nend", "", "\nend", "\nend", "\nend" };
57
57
 
58
58
  static bool ruby_source_parses(const char* source, size_t length) {
59
- pm_parser_t parser;
60
- pm_parser_init(&parser, (const uint8_t*) source, length, NULL);
59
+ pm_arena_t* arena = pm_arena_new();
60
+ pm_parser_t* parser = pm_parser_new(arena, (const uint8_t*) source, length, NULL);
61
61
 
62
- pm_node_t* root = pm_parse(&parser);
63
- bool parses = (parser.error_list.size == 0);
62
+ pm_parse(parser);
63
+ bool parses = (pm_parser_errors_size(parser) == 0);
64
64
 
65
- if (root != NULL) { pm_node_destroy(&parser, root); }
66
- pm_parser_free(&parser);
65
+ pm_parser_free(parser);
66
+ pm_arena_free(arena);
67
67
 
68
68
  return parses;
69
69
  }
@@ -69,17 +69,17 @@ static VALUE rb_<%= node.human %>_from_c_struct(<%= node.struct_type %>* <%= nod
69
69
  <%- when Herb::Template::PrismNodeField -%>
70
70
  VALUE <%= node.human %>_<%= field.name %>;
71
71
  if (<%= node.human %>-><%= field.name %>.node != NULL && <%= node.human %>-><%= field.name %>.parser != NULL) {
72
- pm_buffer_t pm_buffer = { 0 };
73
- herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, &pm_buffer);
72
+ pm_buffer_t* pm_buffer = pm_buffer_new();
73
+ herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, pm_buffer);
74
74
 
75
- if (pm_buffer.length > 0) {
76
- <%= node.human %>_<%= field.name %> = rb_str_new(pm_buffer.value, pm_buffer.length);
75
+ if (pm_buffer_length(pm_buffer) > 0) {
76
+ <%= node.human %>_<%= field.name %> = rb_str_new(pm_buffer_value(pm_buffer), pm_buffer_length(pm_buffer));
77
77
  rb_enc_associate(<%= node.human %>_<%= field.name %>, rb_ascii8bit_encoding());
78
78
  OBJ_FREEZE(<%= node.human %>_<%= field.name %>);
79
79
  } else {
80
80
  <%= node.human %>_<%= field.name %> = Qnil;
81
81
  }
82
- pm_buffer_free(&pm_buffer);
82
+ pm_buffer_free(pm_buffer);
83
83
  } else {
84
84
  <%= node.human %>_<%= field.name %> = Qnil;
85
85
  }
@@ -1,5 +1,7 @@
1
1
  #include "parser_options_helpers.h"
2
2
 
3
+ #include <string.h>
4
+
3
5
  void herb_extract_parser_options(VALUE options, parser_options_T* parser_options) {
4
6
  if (NIL_P(options)) { return; }
5
7
  <%- parser_options.extractable_fields_for(:ruby).each do |field| -%>
@@ -10,6 +12,31 @@ void herb_extract_parser_options(VALUE options, parser_options_T* parser_options
10
12
  if (NIL_P(value)) { value = rb_hash_lookup(options, ID2SYM(rb_intern("<%= field.snake_case %>"))); }
11
13
  if (!NIL_P(value)) { parser_options-><%= field.c_name %> = RTEST(value); }
12
14
  }
15
+ <%- elsif field.string? -%>
16
+ {
17
+ VALUE value = rb_hash_lookup(options, rb_utf8_str_new_cstr("<%= field.snake_case %>"));
18
+ if (NIL_P(value)) { value = rb_hash_lookup(options, ID2SYM(rb_intern("<%= field.snake_case %>"))); }
19
+
20
+ if (!NIL_P(value)) {
21
+ Check_Type(value, T_STRING);
22
+
23
+ const char* data = RSTRING_PTR(value);
24
+ size_t length = (size_t) RSTRING_LEN(value);
25
+
26
+ <%- if field.validator -%>
27
+ if (!<%= field.validator %>(data, length)) {
28
+ rb_raise(rb_eArgError, "<%= field.snake_case %> %+" PRIsVALUE " is not supported", value);
29
+ }
30
+ <%- else -%>
31
+ if (length >= HERB_PARSER_OPTIONS_STRING_CAPACITY) {
32
+ rb_raise(rb_eArgError, "<%= field.snake_case %> must be shorter than %d bytes", HERB_PARSER_OPTIONS_STRING_CAPACITY);
33
+ }
34
+ <%- end -%>
35
+
36
+ memcpy(parser_options-><%= field.c_name %>, data, length);
37
+ parser_options-><%= field.c_name %>[length] = '\0';
38
+ }
39
+ }
13
40
  <%- elsif field.ruby_unit == "seconds" -%>
14
41
  {
15
42
  VALUE value = rb_hash_lookup(options, rb_utf8_str_new_cstr("<%= field.snake_case %>"));
@@ -52,6 +79,12 @@ VALUE herb_build_parser_options_hash(const parser_options_T* options) {
52
79
 
53
80
  rb_hash_aset(kwargs, ID2SYM(rb_intern("<%= field.snake_case %>")), <%= field.snake_case %>);
54
81
  }
82
+ <%- elsif field.string? -%>
83
+ rb_hash_aset(
84
+ kwargs,
85
+ ID2SYM(rb_intern("<%= field.snake_case %>")),
86
+ options-><%= field.c_name %>[0] == '\0' ? Qnil : rb_utf8_str_new_cstr(options-><%= field.c_name %>)
87
+ );
55
88
  <%- elsif field.ruby_unit == "seconds" -%>
56
89
  rb_hash_aset(kwargs, ID2SYM(rb_intern("<%= field.snake_case %>")), DBL2NUM((double) options-><%= field.c_name %> / 1000.0));
57
90
  <%- elsif field.nullable? -%>
@@ -49,15 +49,15 @@ jobject <%= node.name %>FromCStruct(JNIEnv* env, <%= node.struct_type %>* <%= no
49
49
  <%- elsif field.is_a?(Herb::Template::PrismNodeField) -%>
50
50
  jbyteArray <%= field.name %>;
51
51
  if (<%= node.human %>-><%= field.name %>.node != NULL && <%= node.human %>-><%= field.name %>.parser != NULL) {
52
- pm_buffer_t pm_buffer = { 0 };
53
- herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, &pm_buffer);
54
- if (pm_buffer.length > 0) {
55
- <%= field.name %> = (*env)->NewByteArray(env, (jsize)pm_buffer.length);
56
- (*env)->SetByteArrayRegion(env, <%= field.name %>, 0, (jsize)pm_buffer.length, (const jbyte*)pm_buffer.value);
52
+ pm_buffer_t* pm_buffer = pm_buffer_new();
53
+ herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, pm_buffer);
54
+ if (pm_buffer_length(pm_buffer) > 0) {
55
+ <%= field.name %> = (*env)->NewByteArray(env, (jsize)pm_buffer_length(pm_buffer));
56
+ (*env)->SetByteArrayRegion(env, <%= field.name %>, 0, (jsize)pm_buffer_length(pm_buffer), (const jbyte*)pm_buffer_value(pm_buffer));
57
57
  } else {
58
58
  <%= field.name %> = NULL;
59
59
  }
60
- pm_buffer_free(&pm_buffer);
60
+ pm_buffer_free(pm_buffer);
61
61
  } else {
62
62
  <%= field.name %> = NULL;
63
63
  }
@@ -1,7 +1,10 @@
1
1
  #include "parser_options_helpers.h"
2
2
 
3
- void herb_extract_parser_options(JNIEnv* env, jobject options, parser_options_T* parser_options) {
4
- if (options == NULL) { return; }
3
+ #include <stdio.h>
4
+ #include <string.h>
5
+
6
+ bool herb_extract_parser_options(JNIEnv* env, jobject options, parser_options_T* parser_options) {
7
+ if (options == NULL) { return true; }
5
8
 
6
9
  jclass optionsClass = (*env)->GetObjectClass(env, options);
7
10
  <%- parser_options.extractable_fields_for(:java).each do |field| -%>
@@ -15,6 +18,40 @@ void herb_extract_parser_options(JNIEnv* env, jobject options, parser_options_T*
15
18
  parser_options-><%= field.c_name %> = (value == JNI_TRUE);
16
19
  }
17
20
  }
21
+ <%- elsif field.string? -%>
22
+ {
23
+ jmethodID method = (*env)->GetMethodID(env, optionsClass, "<%= field.java_getter %>", "<%= field.java_jni_signature %>");
24
+
25
+ if (method != NULL) {
26
+ jstring value = (jstring) (*env)->CallObjectMethod(env, options, method);
27
+
28
+ if (value != NULL) {
29
+ const char* string = (*env)->GetStringUTFChars(env, value, NULL);
30
+ size_t length = strlen(string);
31
+
32
+ <%- if field.validator -%>
33
+ if (!<%= field.validator %>(string, length)) {
34
+ char message[96];
35
+ snprintf(message, sizeof(message), "<%= field.snake_case %> \"%.32s\" is not supported", string);
36
+ (*env)->ReleaseStringUTFChars(env, value, string);
37
+ (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/IllegalArgumentException"), message);
38
+
39
+ return false;
40
+ }
41
+ <%- else -%>
42
+ if (length >= HERB_PARSER_OPTIONS_STRING_CAPACITY) {
43
+ (*env)->ReleaseStringUTFChars(env, value, string);
44
+ (*env)->ThrowNew(env, (*env)->FindClass(env, "java/lang/IllegalArgumentException"), "<%= field.snake_case %> is too long");
45
+
46
+ return false;
47
+ }
48
+ <%- end -%>
49
+
50
+ memcpy(parser_options-><%= field.c_name %>, string, length + 1);
51
+ (*env)->ReleaseStringUTFChars(env, value, string);
52
+ }
53
+ }
54
+ }
18
55
  <%- elsif field.nullable? -%>
19
56
  {
20
57
  jmethodID method = (*env)->GetMethodID(env, optionsClass, "<%= field.java_getter %>", "<%= field.java_jni_signature %>");
@@ -42,4 +79,6 @@ void herb_extract_parser_options(JNIEnv* env, jobject options, parser_options_T*
42
79
  }
43
80
  <%- end -%>
44
81
  <%- end -%>
82
+
83
+ return true;
45
84
  }
@@ -4,7 +4,8 @@
4
4
  #include "../src/include/parser/parser_options.h"
5
5
 
6
6
  #include <jni.h>
7
+ #include <stdbool.h>
7
8
 
8
- void herb_extract_parser_options(JNIEnv* env, jobject options, parser_options_T* parser_options);
9
+ bool herb_extract_parser_options(JNIEnv* env, jobject options, parser_options_T* parser_options);
9
10
 
10
11
  #endif
@@ -89,17 +89,17 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
89
89
  <%- when Herb::Template::PrismNodeField -%>
90
90
  napi_value <%= field.name %>;
91
91
  if (<%= node.human %>-><%= field.name %>.node != NULL && <%= node.human %>-><%= field.name %>.parser != NULL) {
92
- pm_buffer_t pm_buffer = { 0 };
93
- herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, &pm_buffer);
92
+ pm_buffer_t* pm_buffer = pm_buffer_new();
93
+ herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, pm_buffer);
94
94
 
95
- if (pm_buffer.length > 0) {
95
+ if (pm_buffer_length(pm_buffer) > 0) {
96
96
  void* buffer_data;
97
- napi_create_buffer_copy(env, pm_buffer.length, pm_buffer.value, &buffer_data, &<%= field.name %>);
97
+ napi_create_buffer_copy(env, pm_buffer_length(pm_buffer), pm_buffer_value(pm_buffer), &buffer_data, &<%= field.name %>);
98
98
  } else {
99
99
  napi_get_null(env, &<%= field.name %>);
100
100
  }
101
101
 
102
- pm_buffer_free(&pm_buffer);
102
+ pm_buffer_free(pm_buffer);
103
103
  } else {
104
104
  napi_get_null(env, &<%= field.name %>);
105
105
  }
@@ -1,10 +1,13 @@
1
1
  #include "parser_options_helpers.h"
2
2
 
3
- void herb_extract_parser_options(napi_env env, napi_value options, parser_options_T* parser_options) {
3
+ #include <cstring>
4
+ #include <string>
5
+
6
+ bool herb_extract_parser_options(napi_env env, napi_value options, parser_options_T* parser_options) {
4
7
  napi_valuetype valuetype;
5
8
  napi_typeof(env, options, &valuetype);
6
9
 
7
- if (valuetype != napi_object) { return; }
10
+ if (valuetype != napi_object) { return true; }
8
11
  <%- parser_options.extractable_fields_for(:javascript).each do |field| -%>
9
12
 
10
13
  {
@@ -19,6 +22,33 @@ void herb_extract_parser_options(napi_env env, napi_value options, parser_option
19
22
  bool value = false;
20
23
  napi_get_value_bool(env, property, &value);
21
24
  parser_options-><%= field.c_name %> = value;
25
+ <%- elsif field.string? -%>
26
+ napi_valuetype property_type;
27
+ napi_typeof(env, property, &property_type);
28
+
29
+ if (property_type == napi_string) {
30
+ size_t length = 0;
31
+ napi_get_value_string_utf8(env, property, nullptr, 0, &length);
32
+
33
+ std::string value(length, '\0');
34
+ napi_get_value_string_utf8(env, property, &value[0], length + 1, &length);
35
+ value.resize(length);
36
+
37
+ <%- if field.validator -%>
38
+ if (!<%= field.validator %>(value.c_str(), value.length())) {
39
+ std::string message = "<%= field.snake_case %> \"" + value + "\" is not supported";
40
+ napi_throw_error(env, nullptr, message.c_str());
41
+ return false;
42
+ }
43
+ <%- else -%>
44
+ if (value.length() >= HERB_PARSER_OPTIONS_STRING_CAPACITY) {
45
+ napi_throw_error(env, nullptr, "<%= field.snake_case %> is too long");
46
+ return false;
47
+ }
48
+ <%- end -%>
49
+
50
+ memcpy(parser_options-><%= field.c_name %>, value.c_str(), value.length() + 1);
51
+ }
22
52
  <%- elsif field.nullable? -%>
23
53
  napi_valuetype property_type;
24
54
  napi_typeof(env, property, &property_type);
@@ -38,4 +68,6 @@ void herb_extract_parser_options(napi_env env, napi_value options, parser_option
38
68
  }
39
69
  }
40
70
  <%- end -%>
71
+
72
+ return true;
41
73
  }
@@ -7,6 +7,6 @@ extern "C" {
7
7
  #include "../extension/libherb/include/parser/parser_options.h"
8
8
  }
9
9
 
10
- void herb_extract_parser_options(napi_env env, napi_value options, parser_options_T* parser_options);
10
+ bool herb_extract_parser_options(napi_env env, napi_value options, parser_options_T* parser_options);
11
11
 
12
12
  #endif
@@ -15,7 +15,7 @@ module Herb
15
15
  <%- end -%>
16
16
  end
17
17
 
18
- #: () -> Hash[Symbol, (bool | Numeric | Array[String] | nil)]
18
+ #: () -> Hash[Symbol, (bool | Numeric | String | Array[String] | nil)]
19
19
  def to_h
20
20
  {
21
21
  <%- parser_options.fields_for(:ruby).each do |field| -%>
@@ -1,55 +1,21 @@
1
- fn read_node_body(buffer: &mut SerializationBuffer, type_id: u8, pool: usize, node: &mut PrismNode) {
1
+ fn read_node_body(
2
+ buffer: &mut SerializationBuffer,
3
+ type_id: u8,
4
+ pool: usize,
5
+ node: &mut PrismNode,
6
+ stack: &mut Vec<Option<PrismNode>>,
7
+ ) {
2
8
  match type_id {
3
9
  <%- prism_nodes.each do |prism_node| -%>
4
10
  <%= prism_node.type_id %> => {
5
- <%- if prism_node.name == "DefNode" -%>
6
- buffer.read_uint32();
7
- <%- end -%>
8
-
9
11
  let flags = buffer.read_var_int() as u32;
10
12
  node.flags = flags;
11
13
 
12
14
  <%- prism_node.fields.each do |field| -%>
13
15
  <%- case field.type -%>
14
- <%- when "node" -%>
15
- {
16
- let child = read_node(buffer, pool);
17
- node.children.push(child);
18
- }
19
-
20
- <%- if field.name == "receiver" -%>
21
- node.receiver_index = Some(node.children.len() - 1);
22
- <%- elsif prism_node.name == "AssocNode" && field.name == "key" -%>
23
- node.key = Some(Box::new(node.children[node.children.len() - 1].clone()));
24
- <%- end -%>
25
-
26
- <%- when "node?" -%>
27
- if buffer.peek_byte() != 0 {
28
- let child = read_node(buffer, pool);
29
- node.children.push(child);
30
- <%- if field.name == "block" -%>
31
- node.has_block = true;
32
- <%- end -%>
33
-
34
- <%- if field.name == "receiver" -%>
35
- node.receiver_index = Some(node.children.len() - 1);
36
- <%- elsif prism_node.name == "AssocNode" && field.name == "key" -%>
37
- node.key = Some(Box::new(node.children[node.children.len() - 1].clone()));
38
- <%- end -%>
39
-
40
- } else {
41
- buffer.read_byte();
42
- }
43
- <%- when "node[]" -%>
44
- {
45
- let count = buffer.read_var_int();
46
-
47
- for _ in 0..count {
48
- let child = read_node(buffer, pool);
49
- node.children.push(child);
50
- }
51
- }
52
-
16
+ <%- when "node", "node?" -%>
17
+ <%- when "node[]" -%>
18
+ let <%= field.name %>_count = buffer.read_var_int();
53
19
  <%- when "string" -%>
54
20
  <%- if field.name == "unescaped" -%>
55
21
  node.unescaped = Some(buffer.read_string_field(flags));
@@ -93,12 +59,92 @@ fn read_node_body(buffer: &mut SerializationBuffer, type_id: u8, pool: usize, no
93
59
  <%- raise "unhandled prism field type: #{field.type}" -%>
94
60
  <%- end -%>
95
61
  <%- end -%>
62
+
63
+ <%- prism_node.fields.reverse.each do |field| -%>
64
+ <%- case field.type -%>
65
+ <%- when "node", "node?" -%>
66
+ let <%= field.name %>_child = stack.pop().flatten();
67
+ <%- when "node[]" -%>
68
+ let <%= field.name %>_children = stack.split_off(stack.len().saturating_sub(<%= field.name %>_count));
69
+ <%- end -%>
70
+ <%- end -%>
71
+
72
+ <%- prism_node.fields.each do |field| -%>
73
+ <%- case field.type -%>
74
+ <%- when "node", "node?" -%>
75
+ if let Some(child) = <%= field.name %>_child {
76
+ node.children.push(child);
77
+ <%- if field.name == "block" && field.type == "node?" -%>
78
+ node.has_block = true;
79
+ <%- end -%>
80
+ <%- if field.name == "receiver" -%>
81
+ node.receiver_index = Some(node.children.len() - 1);
82
+ <%- elsif prism_node.name == "AssocNode" && field.name == "key" -%>
83
+ node.key = Some(Box::new(node.children[node.children.len() - 1].clone()));
84
+ <%- end -%>
85
+ }
86
+
87
+ <%- when "node[]" -%>
88
+ node.children.extend(<%= field.name %>_children.into_iter().flatten());
89
+
90
+ <%- end -%>
91
+ <%- end -%>
96
92
  }
97
93
  <%- end -%>
98
94
  _ => {}
99
95
  }
100
96
  }
101
97
 
98
+ fn record_child_count(buffer: &mut SerializationBuffer, type_id: u8, pool: usize) -> usize {
99
+ #[allow(unused_mut)]
100
+ let mut count = 0;
101
+
102
+ match type_id {
103
+ <%- prism_nodes.each do |prism_node| -%>
104
+ <%= prism_node.type_id %> => {
105
+ buffer.read_var_int();
106
+
107
+ <%- prism_node.fields.each do |field| -%>
108
+ <%- case field.type -%>
109
+ <%- when "node", "node?" -%>
110
+ count += 1;
111
+ <%- when "node[]" -%>
112
+ count += buffer.read_var_int();
113
+ <%- when "string" -%>
114
+ buffer.read_string_field(0);
115
+ <%- when "constant" -%>
116
+ buffer.read_required_constant(pool);
117
+ <%- when "constant?" -%>
118
+ buffer.read_optional_constant(pool);
119
+ <%- when "constant[]" -%>
120
+ for _ in 0..buffer.read_var_int() {
121
+ buffer.read_required_constant(pool);
122
+ }
123
+ <%- when "location" -%>
124
+ buffer.read_location();
125
+ <%- when "location?" -%>
126
+ buffer.read_optional_location();
127
+ <%- when "uint8" -%>
128
+ buffer.read_byte();
129
+ <%- when "uint32" -%>
130
+ buffer.read_var_int();
131
+ <%- when "integer" -%>
132
+ buffer.read_integer();
133
+ <%- when "double" -%>
134
+ buffer.read_double();
135
+ <%- when "flags" -%>
136
+ <%- else -%>
137
+ <%- raise "unhandled prism field type: #{field.type}" -%>
138
+ <%- end -%>
139
+ <%- end -%>
140
+ }
141
+ <%- end -%>
142
+ _ => {}
143
+ }
144
+
145
+ count
146
+ }
147
+
102
148
  fn node_type_name_for(type_id: u8) -> String {
103
149
  match type_id {
104
150
  <%- prism_nodes.each do |prism_node| -%>
@@ -8,14 +8,12 @@ fn prettyprint_body(
8
8
  start_offset: usize,
9
9
  end_offset: usize,
10
10
  newlines: &[usize],
11
+ children: &mut std::vec::IntoIter<Option<PrismRecord>>,
11
12
  ) {
12
13
  match type_id {
13
14
  <%- prism_nodes.each do |prism_node| -%>
14
15
  <%- entries = prism_node.entries -%>
15
16
  <%= prism_node.type_id %> => {
16
- <%- if prism_node.name == "DefNode" -%>
17
- buffer.read_uint32();
18
- <%- end -%>
19
17
  #[allow(unused_variables)]
20
18
  let flags = buffer.read_var_int() as u32;
21
19
  output.push_str(&format!("@ <%= prism_node.name %> (location: {})\n", location_string(start_offset, end_offset, newlines)));
@@ -45,29 +43,18 @@ fn prettyprint_body(
45
43
 
46
44
  output.push('\n');
47
45
  }
48
- <%- when "node" -%>
49
- output.push('\n');
50
-
51
- {
52
- let saved = prefix.len();
53
- prefix.push_str("<%= preadd %>");
54
- let copy = prefix.clone();
55
- output.push_str(&copy);
56
- prettyprint_node(buffer, pool, output, prefix, newlines);
57
- prefix.truncate(saved);
58
- }
59
- <%- when "node?" -%>
60
- if buffer.peek_byte() == 0 {
61
- buffer.read_byte();
62
- output.push_str(" nil\n");
63
- } else {
64
- output.push('\n');
65
- let saved = prefix.len();
66
- prefix.push_str("<%= preadd %>");
67
- let copy = prefix.clone();
68
- output.push_str(&copy);
69
- prettyprint_node(buffer, pool, output, prefix, newlines);
70
- prefix.truncate(saved);
46
+ <%- when "node", "node?" -%>
47
+ match children.next().flatten() {
48
+ None => output.push_str(" nil\n"),
49
+ Some(child) => {
50
+ output.push('\n');
51
+ let saved = prefix.len();
52
+ prefix.push_str("<%= preadd %>");
53
+ let copy = prefix.clone();
54
+ output.push_str(&copy);
55
+ prettyprint_record(child, buffer, pool, output, prefix, newlines);
56
+ prefix.truncate(saved);
57
+ }
71
58
  }
72
59
  <%- when "node[]" -%>
73
60
  {
@@ -81,7 +68,11 @@ fn prettyprint_body(
81
68
  output.push_str(&copy);
82
69
  output.push_str("+-- ");
83
70
  prefix.push_str(if index == count - 1 { " " } else { "| " });
84
- prettyprint_node(buffer, pool, output, prefix, newlines);
71
+
72
+ if let Some(child) = children.next().flatten() {
73
+ prettyprint_record(child, buffer, pool, output, prefix, newlines);
74
+ }
75
+
85
76
  prefix.truncate(saved);
86
77
  }
87
78
  }