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
@@ -1,57 +1,62 @@
1
- #include "prism.h"
1
+ #include "prism/excludes.h"
2
+
3
+ /* We optionally support serializing to a binary string. For systems that do not
4
+ * want or need this functionality, it can be turned off with the
5
+ * PRISM_EXCLUDE_SERIALIZATION define. */
6
+ #ifdef PRISM_EXCLUDE_SERIALIZATION
7
+
8
+ /* Ensure this translation unit is never empty, even when serialization is
9
+ * excluded. */
10
+ typedef int pm_serialize_unused_t;
11
+
12
+ #else
13
+
14
+ #include "prism/compiler/branch.h"
15
+ #include "prism/compiler/inline.h"
16
+
17
+ #include "prism/internal/allocator.h"
18
+ #include "prism/internal/buffer.h"
19
+ #include "prism/internal/comments.h"
20
+ #include "prism/internal/diagnostic.h"
21
+ #include "prism/internal/encoding.h"
22
+ #include "prism/internal/list.h"
23
+ #include "prism/internal/magic_comments.h"
24
+ #include "prism/internal/options.h"
25
+ #include "prism/internal/parser.h"
2
26
 
3
- // We optionally support serializing to a binary string. For systems that don't
4
- // want or need this functionality, it can be turned off with the
5
- // PRISM_EXCLUDE_SERIALIZATION define.
6
- #ifndef PRISM_EXCLUDE_SERIALIZATION
27
+ #include "prism.h"
28
+ #include "prism/ast.h"
29
+ #include "prism/line_offset_list.h"
7
30
 
31
+ #include <assert.h>
32
+ #include <stdbool.h>
8
33
  #include <stdio.h>
34
+ #include <stdlib.h>
35
+ #include <string.h>
9
36
 
10
- static inline uint32_t
37
+ static PRISM_INLINE uint32_t
11
38
  pm_ptrdifft_to_u32(ptrdiff_t value) {
12
39
  assert(value >= 0 && ((unsigned long) value) < UINT32_MAX);
13
40
  return (uint32_t) value;
14
41
  }
15
42
 
16
- static inline uint32_t
43
+ static PRISM_INLINE uint32_t
17
44
  pm_sizet_to_u32(size_t value) {
18
45
  assert(value < UINT32_MAX);
19
46
  return (uint32_t) value;
20
47
  }
21
48
 
22
49
  static void
23
- pm_serialize_location(const pm_parser_t *parser, const pm_location_t *location, pm_buffer_t *buffer) {
24
- assert(location->start);
25
- assert(location->end);
26
- assert(location->start <= location->end);
27
-
28
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(location->start - parser->start));
29
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(location->end - location->start));
50
+ pm_serialize_location(const pm_location_t *location, pm_buffer_t *buffer) {
51
+ pm_buffer_append_varuint(buffer, location->start);
52
+ pm_buffer_append_varuint(buffer, location->length);
30
53
  }
31
54
 
32
55
  static void
33
- pm_serialize_string(const pm_parser_t *parser, const pm_string_t *string, pm_buffer_t *buffer) {
34
- switch (string->type) {
35
- case PM_STRING_SHARED: {
36
- pm_buffer_append_byte(buffer, 1);
37
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(pm_string_source(string) - parser->start));
38
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_string_length(string)));
39
- break;
40
- }
41
- case PM_STRING_OWNED:
42
- case PM_STRING_CONSTANT: {
43
- uint32_t length = pm_sizet_to_u32(pm_string_length(string));
44
- pm_buffer_append_byte(buffer, 2);
45
- pm_buffer_append_varuint(buffer, length);
46
- pm_buffer_append_bytes(buffer, pm_string_source(string), length);
47
- break;
48
- }
49
- #ifdef PRISM_HAS_MMAP
50
- case PM_STRING_MAPPED:
51
- assert(false && "Cannot serialize mapped strings.");
52
- break;
53
- #endif
54
- }
56
+ pm_serialize_string(const pm_string_t *string, pm_buffer_t *buffer) {
57
+ uint32_t length = pm_sizet_to_u32(pm_string_length(string));
58
+ pm_buffer_append_varuint(buffer, length);
59
+ pm_buffer_append_bytes(buffer, pm_string_source(string), length);
55
60
  }
56
61
 
57
62
  static void
@@ -68,97 +73,247 @@ pm_serialize_integer(const pm_integer_t *integer, pm_buffer_t *buffer) {
68
73
  }
69
74
  }
70
75
 
76
+ /**
77
+ * The kinds of entries on the serialization stack.
78
+ */
79
+ typedef enum {
80
+ /** A node to serialize, or NULL for an absent optional node. */
81
+ PM_SERIALIZE_ENTRY_NODE,
82
+
83
+ /** Write the lazy marker and placeholders for its skip and length. */
84
+ PM_SERIALIZE_ENTRY_LAZY_HEADER,
85
+
86
+ /** Patch the skip, now that the lazy subtree is about to be written. */
87
+ PM_SERIALIZE_ENTRY_LAZY_START,
88
+
89
+ /** Patch the length, now that the lazy subtree has been written. */
90
+ PM_SERIALIZE_ENTRY_LAZY_END
91
+ } pm_serialize_entry_kind_t;
92
+
93
+ /**
94
+ * An entry on the serialization stack.
95
+ */
96
+ typedef struct {
97
+ /** The node to serialize, for NODE entries. */
98
+ const pm_node_t *node;
99
+
100
+ /**
101
+ * For NODE entries, the offset of the placeholders that follow the node's
102
+ * lazy marker. For LAZY_* entries, the index of the NODE entry that owns
103
+ * them, which stays valid because that entry is beneath them.
104
+ */
105
+ size_t offset;
106
+
107
+ /** The kind of this entry. */
108
+ pm_serialize_entry_kind_t kind;
109
+
110
+ /** Whether the children of this node have already been pushed. */
111
+ bool visited;
112
+ } pm_serialize_entry_t;
113
+
114
+ /**
115
+ * The explicit stack used to walk the tree, so that serializing deeply nested
116
+ * trees does not depend on the size of the C stack.
117
+ */
118
+ typedef struct {
119
+ /** The entries on the stack. */
120
+ pm_serialize_entry_t *entries;
121
+
122
+ /** The number of entries on the stack. */
123
+ size_t size;
124
+
125
+ /** The number of entries that fit in the allocated memory. */
126
+ size_t capacity;
127
+ } pm_serialize_stack_t;
128
+
129
+ /**
130
+ * Push an entry onto the serialization stack. This may reallocate the stack,
131
+ * which invalidates any pointers into it.
132
+ */
71
133
  static void
72
- pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
73
- pm_buffer_append_byte(buffer, (uint8_t) PM_NODE_TYPE(node));
134
+ pm_serialize_stack_push(pm_serialize_stack_t *stack, pm_serialize_entry_kind_t kind, const pm_node_t *node, size_t offset) {
135
+ if (PRISM_UNLIKELY(stack->size == stack->capacity)) {
136
+ size_t capacity = stack->capacity == 0 ? 64 : stack->capacity * 2;
137
+ pm_serialize_entry_t *entries = (pm_serialize_entry_t *) xrealloc_sized(stack->entries, capacity * sizeof(pm_serialize_entry_t), stack->capacity * sizeof(pm_serialize_entry_t));
138
+
139
+ if (PRISM_UNLIKELY(entries == NULL)) {
140
+ fprintf(stderr, "prism: out of memory; aborting\n");
141
+ abort();
142
+ }
74
143
 
75
- size_t offset = buffer->length;
144
+ stack->entries = entries;
145
+ stack->capacity = capacity;
146
+ }
76
147
 
77
- <%- if Prism::Template::INCLUDE_NODE_ID -%>
78
- pm_buffer_append_varuint(buffer, node->node_id);
79
- <%- end -%>
80
- pm_serialize_location(parser, &node->location, buffer);
81
-
82
- switch (PM_NODE_TYPE(node)) {
83
- // We do not need to serialize a ScopeNode ever as
84
- // it is not part of the AST
85
- case PM_SCOPE_NODE:
86
- return;
87
- <%- nodes.each do |node| -%>
88
- case <%= node.type %>: {
89
- <%- if node.needs_serialized_length? -%>
90
- // serialize length
91
- // encoding of location u32s make us need to save this offset.
92
- size_t length_offset = buffer->length;
93
- pm_buffer_append_string(buffer, "\0\0\0\0", 4); /* consume 4 bytes, updated below */
94
- <%- end -%>
95
- <%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS && !node.flags -%>
96
- pm_buffer_append_varuint(buffer, (uint32_t) node->flags);
97
- <%- end -%>
98
- <%- node.fields.each do |field| -%>
99
- <%- case field -%>
100
- <%- when Prism::Template::NodeField -%>
101
- pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
102
- <%- when Prism::Template::OptionalNodeField -%>
103
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %> == NULL) {
104
- pm_buffer_append_byte(buffer, 0);
105
- } else {
106
- pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
148
+ stack->entries[stack->size++] = (pm_serialize_entry_t) { .node = node, .offset = offset, .kind = kind, .visited = false };
149
+ }
150
+
151
+ /**
152
+ * Serialize the tree rooted at the given node in post-order: the subtrees of a
153
+ * node's child fields are written in field order, followed by the node's own
154
+ * record. A loader can therefore build every node from a stack of already
155
+ * built children without recursing.
156
+ *
157
+ * The child subtrees of a node with a lazy field are preceded by the lazy
158
+ * marker, the byte length of the subtrees before the lazy field's subtree, and
159
+ * the byte length of the lazy field's subtree, so that a loader can skip it.
160
+ */
161
+ static void
162
+ pm_serialize_node(pm_node_t *root, pm_buffer_t *buffer) {
163
+ pm_serialize_stack_t stack = { 0 };
164
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_NODE, root, 0);
165
+
166
+ while (stack.size > 0) {
167
+ pm_serialize_entry_t *entry = &stack.entries[--stack.size];
168
+
169
+ switch (entry->kind) {
170
+ case PM_SERIALIZE_ENTRY_LAZY_HEADER: {
171
+ pm_buffer_append_byte(buffer, <%= Prism::Template::LAZY_MARKER %>);
172
+ stack.entries[entry->offset].offset = buffer->length;
173
+ pm_buffer_append_zeroes(buffer, 8);
174
+ continue;
107
175
  }
108
- <%- when Prism::Template::StringField -%>
109
- pm_serialize_string(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
110
- <%- when Prism::Template::NodeListField -%>
111
- uint32_t <%= field.name %>_size = pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.size);
112
- pm_buffer_append_varuint(buffer, <%= field.name %>_size);
113
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
114
- pm_serialize_node(parser, (pm_node_t *) ((pm_<%= node.human %>_t *)node)-><%= field.name %>.nodes[index], buffer);
176
+ case PM_SERIALIZE_ENTRY_LAZY_START: {
177
+ size_t offset = stack.entries[entry->offset].offset;
178
+ uint32_t skip = pm_sizet_to_u32(buffer->length - offset - 8);
179
+ memcpy(buffer->value + offset, &skip, sizeof(uint32_t));
180
+ continue;
115
181
  }
116
- <%- when Prism::Template::ConstantField, Prism::Template::OptionalConstantField -%>
117
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>));
118
- <%- when Prism::Template::ConstantListField -%>
119
- uint32_t <%= field.name %>_size = pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.size);
120
- pm_buffer_append_varuint(buffer, <%= field.name %>_size);
121
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
122
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.ids[index]));
182
+ case PM_SERIALIZE_ENTRY_LAZY_END: {
183
+ size_t offset = stack.entries[entry->offset].offset;
184
+ uint32_t skip;
185
+ memcpy(&skip, buffer->value + offset, sizeof(uint32_t));
186
+
187
+ uint32_t length = pm_sizet_to_u32(buffer->length - offset - 8 - skip);
188
+ memcpy(buffer->value + offset + 4, &length, sizeof(uint32_t));
189
+ continue;
123
190
  }
124
- <%- when Prism::Template::LocationField -%>
125
- <%- if field.should_be_serialized? -%>
126
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
127
- <%- end -%>
128
- <%- when Prism::Template::OptionalLocationField -%>
129
- <%- if field.should_be_serialized? -%>
130
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %>.start == NULL) {
131
- pm_buffer_append_byte(buffer, 0);
132
- } else {
133
- pm_buffer_append_byte(buffer, 1);
134
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
191
+ case PM_SERIALIZE_ENTRY_NODE:
192
+ break;
193
+ }
194
+
195
+ const pm_node_t *node = entry->node;
196
+
197
+ if (node == NULL) {
198
+ pm_buffer_append_byte(buffer, 0);
199
+ continue;
200
+ }
201
+
202
+ if (!entry->visited) {
203
+ /* Leave the node on the stack beneath its children, which are
204
+ * pushed in reverse field order so that they are popped, and
205
+ * therefore written, in field order. A node without children is
206
+ * written straight away instead. */
207
+ entry->visited = true;
208
+ size_t index = stack.size++;
209
+
210
+ switch (PM_NODE_TYPE(node)) {
211
+ <%- nodes.each do |node| -%>
212
+ <%- next if node.child_fields.empty? -%>
213
+ case <%= node.type %>: {
214
+ const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node;
215
+ <%- node.child_fields.reverse_each do |field| -%>
216
+ <%- case field -%>
217
+ <%- when Prism::Template::NodeListField -%>
218
+ for (size_t list_index = cast-><%= field.name %>.size; list_index > 0; list_index--) {
219
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_NODE, cast-><%= field.name %>.nodes[list_index - 1], 0);
220
+ }
221
+ <%- else -%>
222
+ <%- if field == node.lazy_field -%>
223
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_LAZY_END, NULL, index);
224
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_NODE, (const pm_node_t *) cast-><%= field.name %>, 0);
225
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_LAZY_START, NULL, index);
226
+ <%- else -%>
227
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_NODE, (const pm_node_t *) cast-><%= field.name %>, 0);
228
+ <%- end -%>
229
+ <%- end -%>
230
+ <%- end -%>
231
+ <%- if node.lazy_field -%>
232
+ pm_serialize_stack_push(&stack, PM_SERIALIZE_ENTRY_LAZY_HEADER, NULL, index);
233
+ <%- end -%>
234
+ break;
235
+ }
236
+ <%- end -%>
237
+ default:
238
+ break;
135
239
  }
136
- <%- end -%>
137
- <%- when Prism::Template::UInt8Field -%>
138
- pm_buffer_append_byte(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
139
- <%- when Prism::Template::UInt32Field -%>
140
- pm_buffer_append_varuint(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
141
- <%- when Prism::Template::IntegerField -%>
142
- pm_serialize_integer(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
143
- <%- when Prism::Template::DoubleField -%>
144
- pm_buffer_append_double(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
145
- <%- else -%>
146
- <%- raise -%>
147
- <%- end -%>
148
- <%- end -%>
149
- <%- if node.needs_serialized_length? -%>
150
- // serialize length
151
- uint32_t length = pm_sizet_to_u32(buffer->length - offset - sizeof(uint32_t));
152
- memcpy(buffer->value + length_offset, &length, sizeof(uint32_t));
153
- <%- end -%>
154
- break;
240
+
241
+ if (stack.size != index + 1) continue;
242
+ stack.size--;
155
243
  }
244
+
245
+ pm_buffer_append_byte(buffer, (uint8_t) PM_NODE_TYPE(node));
246
+ <%- if Prism::Template::INCLUDE_NODE_ID -%>
247
+ pm_buffer_append_varuint(buffer, node->node_id);
156
248
  <%- end -%>
249
+ pm_serialize_location(&node->location, buffer);
250
+
251
+ switch (PM_NODE_TYPE(node)) {
252
+ /* A ScopeNode is never part of the tree, so it has no fields to
253
+ * serialize. */
254
+ case PM_SCOPE_NODE:
255
+ break;
256
+ <%- nodes.each do |node| -%>
257
+ case <%= node.type %>: {
258
+ <%- if node.fields.any? { |field| !field.is_a?(Prism::Template::NodeField) && !field.is_a?(Prism::Template::OptionalNodeField) && field.should_be_serialized? } -%>
259
+ const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node;
260
+ <%- end -%>
261
+ <%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS && !node.flags -%>
262
+ pm_buffer_append_varuint(buffer, (uint32_t) node->flags);
263
+ <%- end -%>
264
+ <%- node.fields.each do |field| -%>
265
+ <%- case field -%>
266
+ <%- when Prism::Template::NodeField, Prism::Template::OptionalNodeField -%>
267
+ <%- when Prism::Template::NodeListField -%>
268
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(cast-><%= field.name %>.size));
269
+ <%- when Prism::Template::StringField -%>
270
+ pm_serialize_string(&cast-><%= field.name %>, buffer);
271
+ <%- when Prism::Template::ConstantField, Prism::Template::OptionalConstantField -%>
272
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(cast-><%= field.name %>));
273
+ <%- when Prism::Template::ConstantListField -%>
274
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(cast-><%= field.name %>.size));
275
+ for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
276
+ pm_buffer_append_varuint(buffer, pm_sizet_to_u32(cast-><%= field.name %>.ids[index]));
277
+ }
278
+ <%- when Prism::Template::LocationField -%>
279
+ <%- if field.should_be_serialized? -%>
280
+ pm_serialize_location(&cast-><%= field.name %>, buffer);
281
+ <%- end -%>
282
+ <%- when Prism::Template::OptionalLocationField -%>
283
+ <%- if field.should_be_serialized? -%>
284
+ if (cast-><%= field.name %>.length == 0) {
285
+ pm_buffer_append_byte(buffer, 0);
286
+ } else {
287
+ pm_buffer_append_byte(buffer, 1);
288
+ pm_serialize_location(&cast-><%= field.name %>, buffer);
289
+ }
290
+ <%- end -%>
291
+ <%- when Prism::Template::UInt8Field -%>
292
+ pm_buffer_append_byte(buffer, cast-><%= field.name %>);
293
+ <%- when Prism::Template::UInt32Field -%>
294
+ pm_buffer_append_varuint(buffer, cast-><%= field.name %>);
295
+ <%- when Prism::Template::IntegerField -%>
296
+ pm_serialize_integer(&cast-><%= field.name %>, buffer);
297
+ <%- when Prism::Template::DoubleField -%>
298
+ pm_buffer_append_double(buffer, cast-><%= field.name %>);
299
+ <%- else -%>
300
+ <%- raise -%>
301
+ <%- end -%>
302
+ <%- end -%>
303
+ break;
304
+ }
305
+ <%- end -%>
306
+ }
157
307
  }
308
+
309
+ xfree_sized(stack.entries, stack.capacity * sizeof(pm_serialize_entry_t));
158
310
  }
159
311
 
160
- static void
161
- pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
312
+ /*
313
+ * Serialize the given list of offsets to the given buffer.
314
+ */
315
+ void
316
+ pm_serialize_line_offset_list(pm_line_offset_list_t *list, pm_buffer_t *buffer) {
162
317
  uint32_t size = pm_sizet_to_u32(list->size);
163
318
  pm_buffer_append_varuint(buffer, size);
164
319
 
@@ -169,60 +324,90 @@ pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
169
324
  }
170
325
 
171
326
  static void
172
- pm_serialize_comment(pm_parser_t *parser, pm_comment_t *comment, pm_buffer_t *buffer) {
327
+ pm_serialize_comment(pm_comment_t *comment, pm_buffer_t *buffer) {
173
328
  // serialize type
174
329
  pm_buffer_append_byte(buffer, (uint8_t) comment->type);
175
330
 
176
331
  // serialize location
177
- pm_serialize_location(parser, &comment->location, buffer);
332
+ pm_serialize_location(&comment->location, buffer);
178
333
  }
179
334
 
180
335
  /**
181
336
  * Serialize the given list of comments to the given buffer.
182
337
  */
183
338
  void
184
- pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
339
+ pm_serialize_comment_list(pm_list_t *list, pm_buffer_t *buffer) {
185
340
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_list_size(list)));
186
341
 
187
342
  pm_comment_t *comment;
188
343
  for (comment = (pm_comment_t *) list->head; comment != NULL; comment = (pm_comment_t *) comment->node.next) {
189
- pm_serialize_comment(parser, comment, buffer);
344
+ pm_serialize_comment(comment, buffer);
190
345
  }
191
346
  }
192
347
 
348
+ <%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
349
+ /**
350
+ * Serialize the comments attached to each node. This is the number of nodes
351
+ * that own comments, followed by each of those nodes' id, the number of
352
+ * comments it owns, and the index of each of those comments in the comment
353
+ * list.
354
+ */
193
355
  static void
194
- pm_serialize_magic_comment(pm_parser_t *parser, pm_magic_comment_t *magic_comment, pm_buffer_t *buffer) {
356
+ pm_serialize_comment_attachments(const pm_comment_attachments_t *attachments, pm_buffer_t *buffer) {
357
+ uint32_t count = 0;
358
+ for (uint32_t node_id = 0; node_id < attachments->ranges_size; node_id++) {
359
+ if (attachments->ranges[node_id].length > 0) count++;
360
+ }
361
+
362
+ pm_buffer_append_varuint(buffer, count);
363
+
364
+ for (uint32_t node_id = 0; node_id < attachments->ranges_size; node_id++) {
365
+ pm_comment_range_t range = attachments->ranges[node_id];
366
+ if (range.length == 0) continue;
367
+
368
+ pm_buffer_append_varuint(buffer, node_id);
369
+ pm_buffer_append_varuint(buffer, range.length);
370
+
371
+ for (uint32_t index = 0; index < range.length; index++) {
372
+ pm_buffer_append_varuint(buffer, attachments->attachments[range.index + index]);
373
+ }
374
+ }
375
+ }
376
+ <%- end -%>
377
+
378
+ static void
379
+ pm_serialize_magic_comment(pm_magic_comment_t *magic_comment, pm_buffer_t *buffer) {
195
380
  // serialize key location
196
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(magic_comment->key_start - parser->start));
197
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(magic_comment->key_length));
381
+ pm_buffer_append_varuint(buffer, magic_comment->key.start);
382
+ pm_buffer_append_varuint(buffer, magic_comment->key.length);
198
383
 
199
384
  // serialize value location
200
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(magic_comment->value_start - parser->start));
201
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(magic_comment->value_length));
385
+ pm_buffer_append_varuint(buffer, magic_comment->value.start);
386
+ pm_buffer_append_varuint(buffer, magic_comment->value.length);
202
387
  }
203
388
 
204
389
  static void
205
- pm_serialize_magic_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
390
+ pm_serialize_magic_comment_list(pm_list_t *list, pm_buffer_t *buffer) {
206
391
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_list_size(list)));
207
392
 
208
393
  pm_magic_comment_t *magic_comment;
209
394
  for (magic_comment = (pm_magic_comment_t *) list->head; magic_comment != NULL; magic_comment = (pm_magic_comment_t *) magic_comment->node.next) {
210
- pm_serialize_magic_comment(parser, magic_comment, buffer);
395
+ pm_serialize_magic_comment(magic_comment, buffer);
211
396
  }
212
397
  }
213
398
 
214
399
  static void
215
400
  pm_serialize_data_loc(const pm_parser_t *parser, pm_buffer_t *buffer) {
216
- if (parser->data_loc.end == NULL) {
401
+ if (parser->data_loc.length == 0) {
217
402
  pm_buffer_append_byte(buffer, 0);
218
403
  } else {
219
404
  pm_buffer_append_byte(buffer, 1);
220
- pm_serialize_location(parser, &parser->data_loc, buffer);
405
+ pm_serialize_location(&parser->data_loc, buffer);
221
406
  }
222
407
  }
223
408
 
224
409
  static void
225
- pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
410
+ pm_serialize_diagnostic(pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
226
411
  // serialize the type
227
412
  pm_buffer_append_varuint(buffer, (uint32_t) diagnostic->diag_id);
228
413
 
@@ -232,18 +417,18 @@ pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buf
232
417
  pm_buffer_append_string(buffer, diagnostic->message, message_length);
233
418
 
234
419
  // serialize location
235
- pm_serialize_location(parser, &diagnostic->location, buffer);
420
+ pm_serialize_location(&diagnostic->location, buffer);
236
421
 
237
422
  pm_buffer_append_byte(buffer, diagnostic->level);
238
423
  }
239
424
 
240
425
  static void
241
- pm_serialize_diagnostic_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
426
+ pm_serialize_diagnostic_list(pm_list_t *list, pm_buffer_t *buffer) {
242
427
  pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_list_size(list)));
243
428
 
244
429
  pm_diagnostic_t *diagnostic;
245
430
  for (diagnostic = (pm_diagnostic_t *) list->head; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
246
- pm_serialize_diagnostic(parser, diagnostic, buffer);
431
+ pm_serialize_diagnostic(diagnostic, buffer);
247
432
  }
248
433
  }
249
434
 
@@ -261,14 +446,17 @@ static void
261
446
  pm_serialize_metadata(pm_parser_t *parser, pm_buffer_t *buffer) {
262
447
  pm_serialize_encoding(parser->encoding, buffer);
263
448
  pm_buffer_append_varsint(buffer, parser->start_line);
264
- pm_serialize_newline_list(&parser->newline_list, buffer);
449
+ pm_buffer_append_uint64(buffer, pm_parser_checksum(parser));
450
+ pm_serialize_line_offset_list(&parser->line_offsets, buffer);
265
451
  <%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
266
- pm_serialize_comment_list(parser, &parser->comment_list, buffer);
452
+ pm_serialize_comment_list(&parser->comment_list, buffer);
453
+ pm_serialize_comment_attachments(&parser->comment_attachments, buffer);
267
454
  <%- end -%>
268
- pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer);
455
+ pm_serialize_magic_comment_list(&parser->magic_comment_list, buffer);
269
456
  pm_serialize_data_loc(parser, buffer);
270
- pm_serialize_diagnostic_list(parser, &parser->error_list, buffer);
271
- pm_serialize_diagnostic_list(parser, &parser->warning_list, buffer);
457
+ pm_serialize_diagnostic_list(&parser->error_list, buffer);
458
+ pm_serialize_diagnostic_list(&parser->warning_list, buffer);
459
+ pm_buffer_append_byte(buffer, (uint8_t) parser->continuable);
272
460
  }
273
461
 
274
462
  #line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
@@ -288,7 +476,7 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
288
476
  pm_buffer_append_varuint(buffer, parser->constant_pool.size);
289
477
 
290
478
  // Now we're going to serialize the content of the node.
291
- pm_serialize_node(parser, node, buffer);
479
+ pm_serialize_node(node, buffer);
292
480
 
293
481
  // Now we're going to serialize the offset of the constant pool back where
294
482
  // we left space for it.
@@ -308,28 +496,12 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
308
496
  pm_constant_t *constant = &parser->constant_pool.constants[bucket->id - 1];
309
497
  size_t buffer_offset = offset + ((((size_t)bucket->id) - 1) * 8);
310
498
 
311
- if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED || bucket->type == PM_CONSTANT_POOL_BUCKET_CONSTANT) {
312
- // Since this is an owned or constant constant, we are going to
313
- // write its contents into the buffer after the constant pool.
314
- // So effectively in place of the source offset, we have a
315
- // buffer offset. We will add a leading 1 to indicate that this
316
- // is a buffer offset.
317
- uint32_t content_offset = pm_sizet_to_u32(buffer->length);
318
- uint32_t owned_mask = 1U << 31;
319
-
320
- assert(content_offset < owned_mask);
321
- content_offset |= owned_mask;
322
-
323
- memcpy(buffer->value + buffer_offset, &content_offset, 4);
324
- pm_buffer_append_bytes(buffer, constant->start, constant->length);
325
- } else {
326
- // Since this is a shared constant, we are going to write its
327
- // source offset directly into the buffer.
328
- uint32_t source_offset = pm_ptrdifft_to_u32(constant->start - parser->start);
329
- memcpy(buffer->value + buffer_offset, &source_offset, 4);
330
- }
499
+ // Write the constant contents into the buffer after the constant
500
+ // pool. In place of the source offset, we store a buffer offset.
501
+ uint32_t content_offset = pm_sizet_to_u32(buffer->length);
502
+ memcpy(buffer->value + buffer_offset, &content_offset, 4);
503
+ pm_buffer_append_bytes(buffer, constant->start, constant->length);
331
504
 
332
- // Now we can write the length of the constant into the buffer.
333
505
  uint32_t constant_length = pm_sizet_to_u32(constant->length);
334
506
  memcpy(buffer->value + buffer_offset + 4, &constant_length, 4);
335
507
  }
@@ -337,7 +509,7 @@ pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
337
509
  }
338
510
 
339
511
  static void
340
- serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
512
+ serialize_token(pm_parser_t *parser, pm_token_t *token, void *data) {
341
513
  pm_buffer_t *buffer = (pm_buffer_t *) data;
342
514
 
343
515
  pm_buffer_append_varuint(buffer, token->type);
@@ -349,58 +521,72 @@ serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
349
521
  /**
350
522
  * Lex the given source and serialize to the given buffer.
351
523
  */
352
- PRISM_EXPORTED_FUNCTION void
524
+ void
353
525
  pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
354
526
  pm_options_t options = { 0 };
355
527
  pm_options_read(&options, data);
356
528
 
529
+ pm_arena_t arena = { 0 };
357
530
  pm_parser_t parser;
358
- pm_parser_init(&parser, source, size, &options);
359
-
360
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
361
- .data = (void *) buffer,
362
- .callback = serialize_token,
363
- };
531
+ pm_parser_init(&arena, &parser, source, size, &options);
364
532
 
365
- parser.lex_callback = &lex_callback;
366
- pm_node_t *node = pm_parse(&parser);
533
+ pm_parser_lex_callback_set(&parser, serialize_token, buffer);
534
+ pm_parse(&parser);
367
535
 
368
536
  // Append 0 to mark end of tokens.
369
537
  pm_buffer_append_byte(buffer, 0);
370
538
 
371
539
  pm_serialize_metadata(&parser, buffer);
372
540
 
373
- pm_node_destroy(&parser, node);
374
- pm_parser_free(&parser);
375
- pm_options_free(&options);
541
+ pm_parser_cleanup(&parser);
542
+ pm_arena_cleanup(&arena);
543
+ pm_options_cleanup(&options);
376
544
  }
377
545
 
378
546
  /**
379
547
  * Parse and serialize both the AST and the tokens represented by the given
380
548
  * source to the given buffer.
381
549
  */
382
- PRISM_EXPORTED_FUNCTION void
550
+ void
383
551
  pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
384
552
  pm_options_t options = { 0 };
385
553
  pm_options_read(&options, data);
386
554
 
555
+ pm_arena_t arena = { 0 };
387
556
  pm_parser_t parser;
388
- pm_parser_init(&parser, source, size, &options);
389
-
390
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
391
- .data = (void *) buffer,
392
- .callback = serialize_token,
393
- };
557
+ pm_parser_init(&arena, &parser, source, size, &options);
394
558
 
395
- parser.lex_callback = &lex_callback;
559
+ pm_parser_lex_callback_set(&parser, serialize_token, buffer);
396
560
  pm_node_t *node = pm_parse(&parser);
397
561
 
398
562
  pm_buffer_append_byte(buffer, 0);
399
563
  pm_serialize(&parser, node, buffer);
400
564
 
401
- pm_node_destroy(&parser, node);
402
- pm_parser_free(&parser);
403
- pm_options_free(&options);
565
+ pm_parser_cleanup(&parser);
566
+ pm_arena_cleanup(&arena);
567
+ pm_options_cleanup(&options);
568
+ }
569
+
570
+ /**
571
+ * Parse the source and return true if it parses without errors or warnings.
572
+ */
573
+ bool
574
+ pm_serialize_parse_success_p(const uint8_t *source, size_t size, const char *data) {
575
+ pm_options_t options = { 0 };
576
+ pm_options_read(&options, data);
577
+
578
+ pm_arena_t arena = { 0 };
579
+ pm_parser_t parser;
580
+ pm_parser_init(&arena, &parser, source, size, &options);
581
+
582
+ pm_parse(&parser);
583
+
584
+ bool result = parser.error_list.size == 0;
585
+ pm_parser_cleanup(&parser);
586
+ pm_arena_cleanup(&arena);
587
+ pm_options_cleanup(&options);
588
+
589
+ return result;
404
590
  }
405
591
 
406
592
  #endif