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
@@ -16,9 +16,9 @@
16
16
  bool detect_<%= helper.safe_name %>(pm_call_node_t* call_node, pm_parser_t* parser) {
17
17
  if (!call_node || !call_node->name) { return false; }
18
18
 
19
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
19
+ const pm_constant_t* constant = pm_parser_constant(parser, call_node->name);
20
20
 
21
- return constant && constant->length == <%= helper.name.length %> && strncmp((const char*) constant->start, "<%= helper.name %>", <%= helper.name.length %>) == 0;
21
+ return constant && pm_constant_length(constant) == <%= helper.name.length %> && strncmp((const char*) pm_constant_start(constant), "<%= helper.name %>", <%= helper.name.length %>) == 0;
22
22
  }
23
23
  <%- elsif helper.receiver_call_detect? -%>
24
24
 
@@ -29,9 +29,9 @@ bool detect_<%= helper.safe_name %>(pm_call_node_t* call_node, pm_parser_t* pars
29
29
  pm_call_node_t* receiver_node = (pm_call_node_t*) call_node->receiver;
30
30
  if (!receiver_node->name) { return false; }
31
31
 
32
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, receiver_node->name);
32
+ const pm_constant_t* constant = pm_parser_constant(parser, receiver_node->name);
33
33
 
34
- return constant && constant->length == 3 && strncmp((const char*) constant->start, "tag", 3) == 0;
34
+ return constant && pm_constant_length(constant) == 3 && strncmp((const char*) pm_constant_start(constant), "tag", 3) == 0;
35
35
  }
36
36
  <%- end -%>
37
37
  <%- end -%>
@@ -79,14 +79,17 @@ extern bool is_ruby_introspection_method(hb_string_T method_name);
79
79
  static char* extract_<%= helper.safe_name %>_tag_name(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
80
80
  if (!call_node || !call_node->name) { return NULL; }
81
81
 
82
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
82
+ const pm_constant_t* constant = pm_parser_constant(parser, call_node->name);
83
83
  if (!constant) { return NULL; }
84
84
 
85
- if (is_ruby_introspection_method(hb_string_from_data((const char*) constant->start, constant->length))) { return NULL; }
85
+ const char* constant_start = (const char*) pm_constant_start(constant);
86
+ size_t constant_length = pm_constant_length(constant);
86
87
 
87
- char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
88
+ if (is_ruby_introspection_method(hb_string_from_data(constant_start, constant_length))) { return NULL; }
88
89
 
89
- for (size_t i = 0; i < constant->length && name[i] != '\0'; i++) {
90
+ char* name = hb_allocator_strndup(allocator, constant_start, constant_length);
91
+
92
+ for (size_t i = 0; i < constant_length && name[i] != '\0'; i++) {
90
93
  if (name[i] == '_') { name[i] = '-'; }
91
94
  }
92
95
 
@@ -111,9 +114,7 @@ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* _call_node,
111
114
  }
112
115
  <%- elsif content.first_arg? -%>
113
116
 
114
- static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node, pm_parser_t* _parser, hb_allocator_T* allocator) {
115
- (void) _parser;
116
-
117
+ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
117
118
  if (!call_node || !call_node->arguments) { return NULL; }
118
119
 
119
120
  pm_arguments_node_t* arguments = call_node->arguments;
@@ -131,27 +132,26 @@ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node,
131
132
  return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
132
133
  }
133
134
 
134
- size_t source_length = first_argument->location.end - first_argument->location.start;
135
- return hb_allocator_strndup(allocator, (const char*) first_argument->location.start, source_length);
135
+ const uint8_t* source = pm_parser_start(parser);
136
+ size_t source_length = first_argument->location.length;
137
+ return hb_allocator_strndup(allocator, (const char*) (source + first_argument->location.start), source_length);
136
138
  }
137
139
  <%- elsif content.block_or_arg? -%>
138
140
 
139
- static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node, pm_parser_t* <%= helper.receiver_call_detect? ? "parser" : "_parser" %>, hb_allocator_T* allocator) {
140
- (void) <%= helper.receiver_call_detect? ? "parser" : "_parser" %>;
141
-
141
+ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node, pm_parser_t* parser, hb_allocator_T* allocator) {
142
142
  if (!call_node) { return NULL; }
143
143
 
144
144
  <%- if helper.receiver_call_detect? -%>
145
145
  if (call_node->name) {
146
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, call_node->name);
146
+ const pm_constant_t* constant = pm_parser_constant(parser, call_node->name);
147
147
 
148
- if (constant && is_ruby_introspection_method(hb_string_from_data((const char*) constant->start, constant->length))) {
148
+ if (constant && is_ruby_introspection_method(hb_string_from_data((const char*) pm_constant_start(constant), pm_constant_length(constant)))) {
149
149
  return NULL;
150
150
  }
151
151
  }
152
152
  <%- end -%>
153
153
 
154
- char* block_content = extract_inline_block_content(call_node, allocator);
154
+ char* block_content = extract_inline_block_content(call_node, parser, allocator);
155
155
  if (block_content) { return block_content; }
156
156
 
157
157
  <%- arg_index = (content.arg_position || 1) - 1 -%>
@@ -173,7 +173,8 @@ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node,
173
173
  return hb_allocator_strndup(allocator, (const char*) pm_string_source(&string_node->unescaped), length);
174
174
  }
175
175
 
176
- size_t source_length = argument->location.end - argument->location.start;
176
+ const uint8_t* source = pm_parser_start(parser);
177
+ size_t source_length = argument->location.length;
177
178
 
178
179
  <%- if content.to_s_suffix_when_single -%>
179
180
  if (arguments->arguments.size == 1 && argument->type != PM_NIL_NODE) {
@@ -182,7 +183,7 @@ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node,
182
183
  size_t total_length = source_length + suffix_length;
183
184
  char* ruby_expression = hb_allocator_alloc(allocator, total_length + 1);
184
185
 
185
- memcpy(ruby_expression, (const char*) argument->location.start, source_length);
186
+ memcpy(ruby_expression, (const char*) (source + argument->location.start), source_length);
186
187
  memcpy(ruby_expression + source_length, suffix, suffix_length);
187
188
  ruby_expression[total_length] = '\0';
188
189
 
@@ -190,7 +191,7 @@ static char* extract_<%= helper.safe_name %>_content(pm_call_node_t* call_node,
190
191
  }
191
192
  <%- end -%>
192
193
 
193
- return hb_allocator_strndup(allocator, (const char*) argument->location.start, source_length);
194
+ return hb_allocator_strndup(allocator, (const char*) (source + argument->location.start), source_length);
194
195
 
195
196
  <%- if content.skip_if_hash -%>
196
197
  }
@@ -7,9 +7,15 @@
7
7
  #include <stddef.h>
8
8
  #include <stdint.h>
9
9
 
10
+ #define HERB_PARSER_OPTIONS_STRING_CAPACITY 16
11
+
10
12
  typedef struct PARSER_OPTIONS_STRUCT {
11
13
  <%- parser_options.all_c_fields.each do |field| -%>
14
+ <%- if field.string? -%>
15
+ char <%= field.c_name %>[HERB_PARSER_OPTIONS_STRING_CAPACITY];
16
+ <%- else -%>
12
17
  <%= field.c_type %> <%= field.c_name %>;
18
+ <%- end -%>
13
19
  <%- if field.string_array? -%>
14
20
  size_t <%= field.count_name %>;
15
21
  <%- end -%>
@@ -17,5 +23,9 @@ typedef struct PARSER_OPTIONS_STRUCT {
17
23
  } parser_options_T;
18
24
 
19
25
  extern const parser_options_T HERB_DEFAULT_PARSER_OPTIONS;
26
+ <%- parser_options.all_c_fields.select(&:validator).each do |field| -%>
27
+
28
+ bool <%= field.validator %>(const char* value, size_t length);
29
+ <%- end -%>
20
30
 
21
31
  #endif
@@ -0,0 +1,17 @@
1
+ <%-
2
+ lockfile = File.expand_path("../../../Gemfile.lock", __dir__)
3
+ prism_git = File.exist?(lockfile) ? File.read(lockfile).split(/\n\n+/).find { |block| block.start_with?("GIT") && block.match?(/^\s+prism \(/) } : nil
4
+ prism_revision = prism_git && !prism_git.match?(/^\s+tag:/) ? prism_git[/^\s+revision: (\h{7})/, 1] : nil
5
+ -%>
6
+ #ifndef HERB_PRISM_VERSION_H
7
+ #define HERB_PRISM_VERSION_H
8
+
9
+ #include <prism/version.h>
10
+
11
+ <%- if prism_revision -%>
12
+ #define HERB_PRISM_VERSION PRISM_VERSION "+<%= prism_revision %>"
13
+ <%- else -%>
14
+ #define HERB_PRISM_VERSION PRISM_VERSION
15
+ <%- end -%>
16
+
17
+ #endif
@@ -2,7 +2,7 @@
2
2
 
3
3
  #include <stddef.h>
4
4
 
5
- <%- entries = parser_options.all_c_fields.flat_map { |field| field.string_array? ? [[field.c_name, "NULL"], [field.count_name, "0"]] : [[field.c_name, field.pointer? ? "NULL" : field.c_default.to_s]] } -%>
5
+ <%- entries = parser_options.all_c_fields.flat_map { |field| field.string_array? ? [[field.c_name, "NULL"], [field.count_name, "0"]] : field.string? ? [[field.c_name, field.default ? field.default.inspect : "{ 0 }"]] : [[field.c_name, field.pointer? ? "NULL" : field.c_default.to_s]] } -%>
6
6
  <%- prefix = "const parser_options_T HERB_DEFAULT_PARSER_OPTIONS = { " -%>
7
7
  <%- entries.each_with_index do |(name, value), index| -%>
8
8
  <%= index.zero? ? prefix : " " * prefix.length %>.<%= name %> = <%= value %><%= index < entries.length - 1 ? "," : " };" %>
@@ -1176,7 +1176,8 @@ module Herb
1176
1176
  end
1177
1177
 
1178
1178
  class ParserOptionField
1179
- attr_reader :name, :type, :default, :description, :c_name, :nullable, :null_sentinel, :ruby_unit, :default_ms, :count_name
1179
+ attr_reader :name, :type, :default, :description, :c_name, :nullable, :null_sentinel, :ruby_unit, :default_ms, :count_name,
1180
+ :validator
1180
1181
 
1181
1182
  def initialize(config)
1182
1183
  @name = config.fetch("name")
@@ -1193,6 +1194,7 @@ module Herb
1193
1194
  @only = config["only"]
1194
1195
  @skip = config.fetch("skip", [])
1195
1196
  @lex = config.fetch("lex", false)
1197
+ @validator = config["validator"]
1196
1198
  end
1197
1199
 
1198
1200
  def for?(language)
@@ -1217,6 +1219,10 @@ module Herb
1217
1219
  @type == "string_array"
1218
1220
  end
1219
1221
 
1222
+ def string?
1223
+ @type == "string"
1224
+ end
1225
+
1220
1226
  def uint64?
1221
1227
  @type == "uint64"
1222
1228
  end
@@ -1253,17 +1259,19 @@ module Herb
1253
1259
 
1254
1260
  def java_jni_signature
1255
1261
  return "()Z" if boolean?
1262
+ return "()Ljava/lang/String;" if string?
1256
1263
  return "()Ljava/lang/Integer;" if nullable?
1257
1264
 
1258
1265
  "()I"
1259
1266
  end
1260
1267
 
1261
1268
  def ruby_constant?
1262
- !string_array?
1269
+ !string_array? && !string?
1263
1270
  end
1264
1271
 
1265
1272
  def ruby_default
1266
1273
  return "[]" if string_array?
1274
+ return @default.nil? ? "nil" : @default.inspect if string?
1267
1275
  return "nil" if nullable? && @default.nil?
1268
1276
 
1269
1277
  if @ruby_unit == "seconds" && @default_ms
@@ -1290,12 +1298,14 @@ module Herb
1290
1298
 
1291
1299
  def js_default
1292
1300
  return "[]" if string_array?
1301
+ return @default.nil? ? "null" : @default.inspect if string?
1293
1302
  return "null" if nullable? && @default.nil?
1294
1303
 
1295
1304
  @default_ms || @default
1296
1305
  end
1297
1306
 
1298
1307
  def java_default
1308
+ return @default.nil? ? "null" : @default.inspect if string?
1299
1309
  return "null" if nullable? && @default.nil?
1300
1310
 
1301
1311
  @default_ms || @default
@@ -1303,6 +1313,7 @@ module Herb
1303
1313
 
1304
1314
  def rust_default
1305
1315
  return "None" if string_array?
1316
+ return @default.nil? ? "None" : "Some(#{@default.inspect}.to_string())" if string?
1306
1317
  return "None" if nullable? && @default.nil?
1307
1318
 
1308
1319
  value = @default_ms || @default
@@ -1322,6 +1333,7 @@ module Herb
1322
1333
  def ruby_type
1323
1334
  return "bool" if boolean?
1324
1335
  return "Array[String]" if string_array?
1336
+ return "String?" if string?
1325
1337
  return "Numeric" if @ruby_unit == "seconds"
1326
1338
 
1327
1339
  nullable? ? "Integer?" : "Integer"
@@ -1330,12 +1342,14 @@ module Herb
1330
1342
  def typescript_type
1331
1343
  return "boolean" if boolean?
1332
1344
  return "string[]" if string_array?
1345
+ return "string | null" if string?
1333
1346
 
1334
1347
  nullable? ? "number | null" : "number"
1335
1348
  end
1336
1349
 
1337
1350
  def java_type
1338
1351
  return "boolean" if boolean?
1352
+ return "String" if string?
1339
1353
 
1340
1354
  nullable? ? "Integer" : "int"
1341
1355
  end
@@ -1343,6 +1357,7 @@ module Herb
1343
1357
  def rust_type
1344
1358
  return "bool" if boolean?
1345
1359
  return "Option<Vec<String>>" if string_array?
1360
+ return "Option<String>" if string?
1346
1361
 
1347
1362
  nullable? ? "Option<u32>" : "u32"
1348
1363
  end
@@ -54,17 +54,17 @@ val <%= node.name %>FromCStruct(<%= node.struct_type %>* <%= node.human %>, cons
54
54
  }
55
55
  <%- when Herb::Template::PrismNodeField -%>
56
56
  if (<%= node.human %>-><%= field.name %>.node != NULL && <%= node.human %>-><%= field.name %>.parser != NULL) {
57
- pm_buffer_t pm_buffer = { 0 };
58
- herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, &pm_buffer);
57
+ pm_buffer_t* pm_buffer = pm_buffer_new();
58
+ herb_prism_node_serialize(<%= node.human %>-><%= field.name %>, pm_buffer);
59
59
 
60
- if (pm_buffer.length > 0) {
61
- val view = val(typed_memory_view(pm_buffer.length, (const uint8_t*) pm_buffer.value));
60
+ if (pm_buffer_length(pm_buffer) > 0) {
61
+ val view = val(typed_memory_view(pm_buffer_length(pm_buffer), (const uint8_t*) pm_buffer_value(pm_buffer)));
62
62
  result.set("<%= field.name %>", val::global("Uint8Array").new_(view));
63
63
  } else {
64
64
  result.set("<%= field.name %>", val::null());
65
65
  }
66
66
 
67
- pm_buffer_free(&pm_buffer);
67
+ pm_buffer_free(pm_buffer);
68
68
  } else {
69
69
  result.set("<%= field.name %>", val::null());
70
70
  }
@@ -1,5 +1,8 @@
1
1
  #include "parser_options_helpers.h"
2
2
 
3
+ #include <cstring>
4
+ #include <string>
5
+
3
6
  void herb_extract_parser_options(emscripten::val options, parser_options_T* parser_options) {
4
7
  if (options.isUndefined() || options.isNull() || options.typeOf().as<std::string>() != "object") { return; }
5
8
 
@@ -9,6 +12,27 @@ void herb_extract_parser_options(emscripten::val options, parser_options_T* pars
9
12
  parser_options-><%= field.c_name %> = options["<%= field.snake_case %>"].as<bool>();
10
13
  }
11
14
 
15
+ <%- elsif field.string? -%>
16
+ if (options.hasOwnProperty("<%= field.snake_case %>")) {
17
+ emscripten::val value = options["<%= field.snake_case %>"];
18
+
19
+ if (value.isString()) {
20
+ std::string string = value.as<std::string>();
21
+
22
+ <%- if field.validator -%>
23
+ if (!<%= field.validator %>(string.c_str(), string.length())) {
24
+ emscripten::val::global("Error").new_("<%= field.snake_case %> \"" + string + "\" is not supported").throw_();
25
+ }
26
+ <%- else -%>
27
+ if (string.length() >= HERB_PARSER_OPTIONS_STRING_CAPACITY) {
28
+ emscripten::val::global("Error").new_(std::string("<%= field.snake_case %> is too long")).throw_();
29
+ }
30
+ <%- end -%>
31
+
32
+ memcpy(parser_options-><%= field.c_name %>, string.c_str(), string.length() + 1);
33
+ }
34
+ }
35
+
12
36
  <%- elsif field.nullable? -%>
13
37
  if (options.hasOwnProperty("<%= field.snake_case %>")) {
14
38
  emscripten::val value = options["<%= field.snake_case %>"];
@@ -3,6 +3,15 @@
3
3
  require "bundler/gem_tasks"
4
4
  require "rake/clean"
5
5
 
6
+ begin
7
+ require "rake_compiler_dock"
8
+ rescue LoadError
9
+ # rake_compiler_dock is not available in versioned Gemfiles (gemfiles/2.7/, etc.)
10
+ # that don't include the gem. The native gem tasks will not be defined.
11
+ end
12
+
13
+ PRISM_SPEC = Bundler.load_gemspec("prism.gemspec")
14
+
6
15
  task default: %i[compile test]
7
16
 
8
17
  require_relative "templates/template"
@@ -28,14 +37,55 @@ task build: [:check_manifest, :templates]
28
37
  # the C extension
29
38
  task "compile:prism" => ["templates"] # must be before the ExtensionTask is created
30
39
 
40
+ RCD_CROSS_PLATFORMS = %w[
41
+ aarch64-linux-gnu
42
+ aarch64-linux-musl
43
+ aarch64-mingw-ucrt
44
+ arm-linux-gnu
45
+ arm-linux-musl
46
+ arm64-darwin
47
+ x64-mingw-ucrt
48
+ x86_64-darwin
49
+ x86_64-linux-gnu
50
+ x86_64-linux-musl
51
+ ]
52
+
53
+ if defined?(RakeCompilerDock)
54
+ RakeCompilerDock.set_ruby_cc_version(">= 3.3")
55
+
56
+ namespace "gem" do
57
+ RCD_CROSS_PLATFORMS.each do |platform|
58
+ desc "build native gem for #{platform}"
59
+ task platform do
60
+ RakeCompilerDock.sh(<<~EOF, platform: platform, verbose: true)
61
+ gem install bundler --no-document &&
62
+ bundle &&
63
+ bundle exec rake gem:#{platform}:build
64
+ EOF
65
+ end
66
+
67
+ namespace platform do
68
+ # this runs in the rake-compiler-dock docker container
69
+ task "build" => ["templates"] do
70
+ Rake::Task["native:#{platform}"].invoke
71
+ Rake::Task["pkg/#{PRISM_SPEC.full_name}-#{Gem::Platform.new(platform)}.gem"].invoke
72
+ end
73
+ end
74
+ end
75
+
76
+ desc "build native gem for all platforms"
77
+ task "all" => [RCD_CROSS_PLATFORMS, "build"].flatten
78
+ end
79
+ end
80
+
31
81
  if RUBY_ENGINE == "ruby" and !ENV["PRISM_FFI_BACKEND"]
32
82
  require "rake/extensiontask"
33
83
 
34
- Rake::ExtensionTask.new(:compile) do |ext|
35
- ext.name = "prism"
84
+ Rake::ExtensionTask.new("prism", PRISM_SPEC) do |ext|
36
85
  ext.ext_dir = "ext/prism"
37
86
  ext.lib_dir = "lib/prism"
38
- ext.gem_spec = Gem::Specification.load("prism.gemspec")
87
+ ext.cross_compile = true
88
+ ext.cross_platform = RCD_CROSS_PLATFORMS
39
89
  end
40
90
  elsif RUBY_ENGINE == "jruby"
41
91
  require "rake/javaextensiontask"
@@ -43,11 +93,10 @@ elsif RUBY_ENGINE == "jruby"
43
93
  # This compiles java to make sure any templating changes produces valid code.
44
94
  Rake::JavaExtensionTask.new(:compile) do |ext|
45
95
  ext.name = "prism"
46
- ext.ext_dir = "java"
96
+ ext.ext_dir = "java/api"
47
97
  ext.lib_dir = "tmp"
48
- ext.source_version = "1.8"
49
- ext.target_version = "1.8"
50
- ext.gem_spec = Gem::Specification.load("prism.gemspec")
98
+ ext.release = "21"
99
+ ext.gem_spec = PRISM_SPEC
51
100
  end
52
101
  end
53
102
 
@@ -55,6 +104,7 @@ end
55
104
  CLOBBER.concat(Prism::Template::TEMPLATES)
56
105
  CLOBBER.concat(["build"])
57
106
  CLOBBER << "lib/prism/prism.#{RbConfig::CONFIG["DLEXT"]}"
107
+ CLOBBER << "java/wasm/src/main/resources/prism.wasm"
58
108
 
59
109
  Prism::Template::TEMPLATES.each do |filepath|
60
110
  desc "Generate #{filepath}"
@@ -76,3 +126,22 @@ namespace :build do
76
126
  desc "Build a development version of the gem"
77
127
  task dev: ["build:dev_version_set", "build", "build:dev_version_clear"]
78
128
  end
129
+
130
+ task :build_in_docker => :templates do
131
+ # Versions from https://github.com/ruby/ruby/blob/master/.github/workflows/compilers.yml
132
+ versions = (7..15).to_a
133
+ versions.each do |version|
134
+ dockerfile = <<~DOCKERFILE
135
+ FROM docker.io/library/gcc:#{version}
136
+ COPY Makefile /prism/
137
+ COPY src /prism/src
138
+ COPY include /prism/include
139
+ WORKDIR /prism
140
+ RUN gcc --version
141
+ RUN make SOEXT=so
142
+ DOCKERFILE
143
+ File.write 'Dockerfile', dockerfile
144
+ sh "docker build ."
145
+ rm 'Dockerfile'
146
+ end
147
+ end