prism 2.0.0.rc2-x86_64-linux-gnu → 2.0.0-x86_64-linux-gnu

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -2
  3. data/docs/serialization.md +19 -6
  4. data/ext/prism/api_node.c +80 -80
  5. data/ext/prism/extension.c +34 -67
  6. data/ext/prism/extension.h +1 -1
  7. data/include/prism/arena.h +8 -0
  8. data/include/prism/arena.hpp +42 -0
  9. data/include/prism/ast.h +11 -1
  10. data/include/prism/ast.hpp +641 -0
  11. data/include/prism/buffer.h +8 -0
  12. data/include/prism/buffer.hpp +55 -0
  13. data/include/prism/comments.h +17 -0
  14. data/include/prism/compiler/branch.h +26 -0
  15. data/include/prism/compiler/cplusplus.hpp +16 -0
  16. data/include/prism/compiler/exceptions.hpp +17 -0
  17. data/include/prism/compiler/format.h +2 -0
  18. data/include/prism/compiler/lifetimebound.hpp +25 -0
  19. data/include/prism/constant_pool.h +25 -0
  20. data/include/prism/diagnostic.h +18 -0
  21. data/include/prism/errors_format.h +8 -0
  22. data/include/prism/internal/node.h +8 -4
  23. data/include/prism/internal/stringy.h +1 -6
  24. data/include/prism/json.h +8 -0
  25. data/include/prism/line_offset_list.h +8 -0
  26. data/include/prism/magic_comments.h +18 -0
  27. data/include/prism/node.h +55 -10
  28. data/include/prism/node.hpp +272 -0
  29. data/include/prism/node_type.hpp +38 -0
  30. data/include/prism/options.h +10 -1
  31. data/include/prism/options.hpp +43 -0
  32. data/include/prism/parser.h +72 -64
  33. data/include/prism/parser.hpp +274 -0
  34. data/include/prism/prettyprint.h +8 -0
  35. data/include/prism/serialize.h +8 -0
  36. data/include/prism/source.h +8 -0
  37. data/include/prism/stream.h +8 -0
  38. data/include/prism/string_query.h +8 -0
  39. data/include/prism/stringy.h +16 -27
  40. data/include/prism/stringy.hpp +31 -0
  41. data/include/prism/version.h +9 -1
  42. data/include/prism.h +0 -8
  43. data/include/prism.hpp +24 -0
  44. data/lib/prism/3.3/prism.so +0 -0
  45. data/lib/prism/3.4/prism.so +0 -0
  46. data/lib/prism/4.0/prism.so +0 -0
  47. data/lib/prism/serialize.rb +2549 -3281
  48. data/prism.gemspec +14 -1
  49. data/rbi/generated/prism/node.rbi +736 -0
  50. data/rbi/generated/prism/serialize.rbi +6 -5
  51. data/sig/generated/prism/node.rbs +736 -0
  52. data/sig/generated/prism/serialize.rbs +7 -5
  53. data/src/comments.c +2 -2
  54. data/src/diagnostic.c +8 -0
  55. data/src/node.c +216 -368
  56. data/src/options.c +7 -13
  57. data/src/parser.c +52 -48
  58. data/src/prism.c +175 -194
  59. data/src/regexp.c +0 -1
  60. data/src/serialize.c +2300 -1950
  61. data/src/source.c +8 -2
  62. data/src/stringy.c +3 -33
  63. metadata +14 -1
@@ -0,0 +1,272 @@
1
+ /**
2
+ * @file node.hpp
3
+ *
4
+ * Checked casts between node structs, iteration over lists of nodes, and
5
+ * walking the tree from C++.
6
+ */
7
+ #ifndef PRISM_NODE_HPP
8
+ #define PRISM_NODE_HPP
9
+
10
+ #include "prism/compiler/cplusplus.hpp"
11
+ #include "prism/compiler/exceptions.hpp"
12
+ #include "prism/compiler/lifetimebound.hpp"
13
+
14
+ #include "prism/ast.hpp"
15
+ #include "prism/node.h"
16
+ #include "prism/node_type.hpp"
17
+
18
+ #include <cassert>
19
+ #include <cstddef>
20
+ #include <exception>
21
+ #include <functional>
22
+ #include <memory>
23
+ #include <type_traits>
24
+
25
+ namespace prism {
26
+
27
+ /**
28
+ * Whether the given node, which must not be null, is of the given struct
29
+ *
30
+ * @tparam T The node struct type to check against.
31
+ * @param node The node to check.
32
+ * @return True if the node is of the given struct, false otherwise.
33
+ */
34
+ template <typename T> [[nodiscard]] bool
35
+ isa(const pm_node_t *node) noexcept {
36
+ static_assert(is_node_v<T>, "isa<T> requires a node struct declared in ast.h");
37
+ assert(node != nullptr);
38
+ return node->type == node_type_v<T>;
39
+ }
40
+
41
+ /**
42
+ * Cast the given node, which must not be null and must be of the given struct,
43
+ * to that struct. The type is checked in debug builds.
44
+ *
45
+ * @tparam T The node struct type to cast to.
46
+ * @param node The node to cast.
47
+ * @return The node cast to the given struct.
48
+ */
49
+ template <typename T> [[nodiscard]] T *
50
+ cast(pm_node_t *node) noexcept {
51
+ assert(isa<T>(node));
52
+ return reinterpret_cast<T *>(node);
53
+ }
54
+
55
+ /**
56
+ * Cast the given node, which must not be null and must be of the given struct,
57
+ * to that struct. The type is checked in debug builds.
58
+ *
59
+ * @tparam T The node struct type to cast to.
60
+ * @param node The node to cast.
61
+ * @return The node cast to the given struct.
62
+ */
63
+ template <typename T> [[nodiscard]] const T *
64
+ cast(const pm_node_t *node) noexcept {
65
+ assert(isa<T>(node));
66
+ return reinterpret_cast<const T *>(node);
67
+ }
68
+
69
+ /**
70
+ * Cast the given node to the given struct if it is of that struct, and return
71
+ * null otherwise. The node may be null, in which case this returns null.
72
+ *
73
+ * @tparam T The node struct type to cast to.
74
+ * @param node The node to cast.
75
+ * @return The node cast to the given struct if it is of that struct, or null
76
+ * otherwise.
77
+ */
78
+ template <typename T> [[nodiscard]] T *
79
+ dyn_cast(pm_node_t *node) noexcept {
80
+ return (node != nullptr && isa<T>(node)) ? reinterpret_cast<T *>(node) : nullptr;
81
+ }
82
+
83
+ /**
84
+ * Cast the given node to the given struct if it is of that struct, and return
85
+ * null otherwise. The node may be null, in which case this returns null.
86
+ *
87
+ * @tparam T The node struct type to cast to.
88
+ * @param node The node to cast.
89
+ * @return The node cast to the given struct if it is of that struct, or null
90
+ * otherwise.
91
+ */
92
+ template <typename T> [[nodiscard]] const T *
93
+ dyn_cast(const pm_node_t *node) noexcept {
94
+ return (node != nullptr && isa<T>(node)) ? reinterpret_cast<const T *>(node) : nullptr;
95
+ }
96
+
97
+ /**
98
+ * Return the pm_node_t embedded at the start of the given node struct.
99
+ *
100
+ * @tparam T The node struct type.
101
+ * @param node The node struct to upcast.
102
+ * @return The pm_node_t embedded at the start of the node struct.
103
+ */
104
+ template <typename T> [[nodiscard]] pm_node_t *
105
+ upcast(T *node) noexcept {
106
+ static_assert(is_node_v<T>, "upcast requires a node struct declared in ast.h");
107
+ return &node->base;
108
+ }
109
+
110
+ /**
111
+ * Return the pm_node_t embedded at the start of the given node struct.
112
+ *
113
+ * @tparam T The node struct type.
114
+ * @param node The node struct to upcast.
115
+ * @return The pm_node_t embedded at the start of the node struct.
116
+ */
117
+ template <typename T> [[nodiscard]] const pm_node_t *
118
+ upcast(const T *node) noexcept {
119
+ static_assert(is_node_v<T>, "upcast requires a node struct declared in ast.h");
120
+ return &node->base;
121
+ }
122
+
123
+ /**
124
+ * The nodes in a list, usable in a range-based for loop. It refers to the list
125
+ * rather than copying it, so the list must outlive it.
126
+ */
127
+ class node_range {
128
+ public:
129
+ /**
130
+ * Create a range over the nodes in the given list.
131
+ *
132
+ * @param list The list of nodes to create a range for.
133
+ */
134
+ explicit node_range(const pm_node_list_t &list PRISM_LIFETIMEBOUND) noexcept : list_(&list) {}
135
+
136
+ /**
137
+ * A pointer to the first node.
138
+ *
139
+ * @return A pointer to the first node, or null if the list is empty.
140
+ */
141
+ pm_node_t *const *begin() const noexcept { return list_->nodes; }
142
+
143
+ /**
144
+ * A pointer one past the last node.
145
+ *
146
+ * @return A pointer one past the last node, or null if the list is empty.
147
+ */
148
+ pm_node_t *const *end() const noexcept { return list_->nodes + list_->size; }
149
+
150
+ /**
151
+ * The number of nodes.
152
+ *
153
+ * @return The number of nodes.
154
+ */
155
+ std::size_t size() const noexcept { return list_->size; }
156
+
157
+ /**
158
+ * Whether there are no nodes.
159
+ *
160
+ * @return True if there are no nodes, false otherwise.
161
+ */
162
+ [[nodiscard]] bool empty() const noexcept { return list_->size == 0; }
163
+
164
+ private:
165
+ const pm_node_list_t *list_;
166
+ };
167
+
168
+ namespace detail {
169
+
170
+ /**
171
+ * The state shared between a walk and its C callback, passed through the C
172
+ * function's void * data parameter.
173
+ */
174
+ template <typename F> struct visit_context {
175
+ /**
176
+ * The context for a visit, holding the visitor and any exception thrown.
177
+ *
178
+ * @param visitor The visitor callable to be used for each node.
179
+ */
180
+ explicit visit_context(F *visitor) noexcept : callable(visitor) {}
181
+
182
+ /** The visitor that the walk calls for each node. */
183
+ F *callable;
184
+
185
+ #ifdef PRISM_HAS_EXCEPTIONS
186
+ /** The exception thrown by the visitor, if any. */
187
+ std::exception_ptr exception;
188
+ #endif
189
+ };
190
+
191
+ /**
192
+ * Forwards the C visitor callback to a C++ callable. An exception cannot unwind
193
+ * through the C frames that call this function, so one thrown by the callable
194
+ * is caught here and the walk is stopped. The function that started the walk
195
+ * rethrows it once the C walk has returned. Without exceptions, the callable
196
+ * cannot throw, so it is called directly.
197
+ *
198
+ * @tparam F The type of the visitor callable.
199
+ * @param node The current node being visited.
200
+ * @param data The visit context containing the visitor and exception state.
201
+ * @return The result of the visit, indicating whether to descend, skip, or stop.
202
+ */
203
+ template <typename F> pm_visit_result_t
204
+ visit_callback(const pm_node_t *node, void *data) noexcept {
205
+ visit_context<F> *context = static_cast<visit_context<F> *>(data);
206
+
207
+ #ifdef PRISM_HAS_EXCEPTIONS
208
+ try {
209
+ return std::invoke(*context->callable, node);
210
+ } catch (...) {
211
+ context->exception = std::current_exception();
212
+ return PM_VISIT_STOP;
213
+ }
214
+ #else
215
+ return std::invoke(*context->callable, node);
216
+ #endif
217
+ }
218
+
219
+ }
220
+
221
+ /**
222
+ * Walk the tree rooted at the given node in pre-order, calling the visitor with
223
+ * each node. The visitor returns PM_VISIT_DESCEND to continue into that node's
224
+ * children, PM_VISIT_SKIP to continue past them, or PM_VISIT_STOP to end the
225
+ * walk. Returns false if the walk was stopped. If the visitor throws, the walk
226
+ * stops and the exception propagates from this function.
227
+ *
228
+ * @tparam F The type of the visitor callable.
229
+ * @param node The root node to start the walk from.
230
+ * @param visitor The visitor callable to invoke for each node.
231
+ * @return True if the walk completed, false if it was stopped.
232
+ */
233
+ template <typename F> bool
234
+ visit_node(const pm_node_t *node, F &&visitor) {
235
+ static_assert(std::is_invocable_r_v<pm_visit_result_t, F &, const pm_node_t *>, "visit_node requires a callable taking const pm_node_t * and returning pm_visit_result_t");
236
+ detail::visit_context<std::remove_reference_t<F>> context(std::addressof(visitor));
237
+ bool completed = pm_visit_node(node, detail::visit_callback<std::remove_reference_t<F>>, &context);
238
+
239
+ #ifdef PRISM_HAS_EXCEPTIONS
240
+ if (context.exception) std::rethrow_exception(context.exception);
241
+ #endif
242
+
243
+ return completed;
244
+ }
245
+
246
+ /**
247
+ * Walk the children of the given node, as visit_node does for every node whose
248
+ * visitor returns PM_VISIT_DESCEND. Returns false if the walk was stopped. If
249
+ * the visitor throws, the walk stops and the exception propagates from this
250
+ * function.
251
+ *
252
+ * @tparam F The type of the visitor callable.
253
+ * @param node The node whose children to walk.
254
+ * @param visitor The visitor callable to invoke for each child node.
255
+ * @return True if the walk completed, false if it was stopped.
256
+ */
257
+ template <typename F> bool
258
+ visit_child_nodes(const pm_node_t *node, F &&visitor) {
259
+ static_assert(std::is_invocable_r_v<pm_visit_result_t, F &, const pm_node_t *>, "visit_child_nodes requires a callable taking const pm_node_t * and returning pm_visit_result_t");
260
+ detail::visit_context<std::remove_reference_t<F>> context(std::addressof(visitor));
261
+ bool completed = pm_visit_child_nodes(node, detail::visit_callback<std::remove_reference_t<F>>, &context);
262
+
263
+ #ifdef PRISM_HAS_EXCEPTIONS
264
+ if (context.exception) std::rethrow_exception(context.exception);
265
+ #endif
266
+
267
+ return completed;
268
+ }
269
+
270
+ }
271
+
272
+ #endif
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @file node_type.hpp
3
+ *
4
+ * The traits that map node structs to node types. The specialization for each
5
+ * node struct is generated into ast.hpp.
6
+ */
7
+ #ifndef PRISM_NODE_TYPE_HPP
8
+ #define PRISM_NODE_TYPE_HPP
9
+
10
+ #include "prism/compiler/cplusplus.hpp"
11
+
12
+ #include "prism/ast.h"
13
+
14
+ #include <type_traits>
15
+
16
+ namespace prism {
17
+
18
+ /**
19
+ * Maps a node struct to its node type, as in node_type<pm_call_node_t>::value
20
+ * being PM_CALL_NODE. Only the node structs declared in ast.h have a value.
21
+ */
22
+ template <typename T> struct node_type {};
23
+
24
+ /** The node type of the given node struct. */
25
+ template <typename T> inline constexpr pm_node_type_t node_type_v = node_type<T>::value;
26
+
27
+ /** Whether the given type is one of the node structs declared in ast.h. */
28
+ template <typename T, typename = void> struct is_node : std::false_type {};
29
+
30
+ /** Whether the given type is one of the node structs declared in ast.h. */
31
+ template <typename T> struct is_node<T, std::void_t<decltype(node_type<T>::value)>> : std::true_type {};
32
+
33
+ /** Whether the given type is one of the node structs declared in ast.h. */
34
+ template <typename T> inline constexpr bool is_node_v = is_node<T>::value;
35
+
36
+ }
37
+
38
+ #endif
@@ -15,6 +15,10 @@
15
15
  #include <stdbool.h>
16
16
  #include <stddef.h>
17
17
 
18
+ #ifdef __cplusplus
19
+ extern "C" {
20
+ #endif
21
+
18
22
  /**
19
23
  * A scope of locals surrounding the code that is being parsed.
20
24
  */
@@ -335,7 +339,8 @@ PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local(const pm_opti
335
339
 
336
340
  /**
337
341
  * Return a mutable pointer to the local at the given index within the given
338
- * scope.
342
+ * scope, for setting the local's name with pm_string_init. The parser copies
343
+ * the name when it is created, so its bytes must remain valid until then.
339
344
  *
340
345
  * @param scope The scope struct to get the local from.
341
346
  * @param index The index of the local to get.
@@ -351,4 +356,8 @@ PRISM_EXPORTED_FUNCTION pm_string_t * pm_options_scope_local_mut(pm_options_scop
351
356
  */
352
357
  PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) PRISM_NONNULL(1);
353
358
 
359
+ #ifdef __cplusplus
360
+ }
361
+ #endif
362
+
354
363
  #endif
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @file options.hpp
3
+ *
4
+ * Ownership of parse options from C++.
5
+ */
6
+ #ifndef PRISM_OPTIONS_HPP
7
+ #define PRISM_OPTIONS_HPP
8
+
9
+ #include "prism/compiler/cplusplus.hpp"
10
+
11
+ #include "prism/options.h"
12
+
13
+ #include <memory>
14
+
15
+ namespace prism {
16
+
17
+ /** Frees options with pm_options_free. */
18
+ struct options_deleter {
19
+ /**
20
+ * Free the given options.
21
+ *
22
+ * @param options The options to free.
23
+ */
24
+ void operator()(pm_options_t *options) const noexcept { pm_options_free(options); }
25
+ };
26
+
27
+ /** An owned set of options. */
28
+ using unique_options = std::unique_ptr<pm_options_t, options_deleter>;
29
+
30
+ /**
31
+ * Allocate a new set of options with every option at its default. Allocation
32
+ * failure aborts, so this never throws.
33
+ *
34
+ * @return A unique_options owning the newly allocated options.
35
+ */
36
+ [[nodiscard]] inline unique_options
37
+ make_options() noexcept {
38
+ return unique_options(pm_options_new());
39
+ }
40
+
41
+ }
42
+
43
+ #endif
@@ -16,6 +16,10 @@
16
16
  #include "prism/magic_comments.h"
17
17
  #include "prism/options.h"
18
18
 
19
+ #ifdef __cplusplus
20
+ extern "C" {
21
+ #endif
22
+
19
23
  /**
20
24
  * The parser used to parse Ruby source.
21
25
  */
@@ -150,6 +154,24 @@ PRISM_EXPORTED_FUNCTION const pm_string_t * pm_parser_filepath(const pm_parser_t
150
154
  */
151
155
  PRISM_EXPORTED_FUNCTION pm_constant_id_t pm_parser_constant_find(const pm_parser_t *parser, const uint8_t *start, size_t length) PRISM_NONNULL(1, 2);
152
156
 
157
+ /**
158
+ * Add a constant to the parser's constant pool, for naming a node that was not
159
+ * parsed from the source. If the constant is already in the pool, its existing
160
+ * id is returned. Otherwise the parser copies the bytes, so they only need to
161
+ * remain valid for the duration of the call.
162
+ *
163
+ * Adding a constant makes the pool larger, so a cache with one entry per
164
+ * constant built beforehand from pm_parser_constants_size and
165
+ * pm_parser_constant_at does not cover it. Build such caches after adding any
166
+ * constants.
167
+ *
168
+ * @param parser the parser whose constant pool we want to add to
169
+ * @param start a pointer to the start of the string to add
170
+ * @param length the length of the string to add
171
+ * @returns the id of the constant
172
+ */
173
+ PRISM_EXPORTED_FUNCTION pm_constant_id_t pm_parser_constant_insert(pm_parser_t *parser, const uint8_t *start, size_t length) PRISM_NONNULL(1, 2);
174
+
153
175
  /**
154
176
  * Returns the frozen string literal value of the parser, as determined by the
155
177
  * frozen_string_literal magic comment or the option set on the parser.
@@ -227,22 +249,19 @@ PRISM_EXPORTED_FUNCTION int pm_parser_lex_state(const pm_parser_t *parser) PRISM
227
249
  PRISM_EXPORTED_FUNCTION size_t pm_parser_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1);
228
250
 
229
251
  /**
230
- * A callback function that can be used to process comments found while parsing.
231
- */
232
- typedef void (*pm_comment_callback_t)(const pm_comment_t *comment, void *data);
233
-
234
- /**
235
- * Iterates over the comments associated with the given parser and calls the
236
- * given callback for each comment.
252
+ * Returns the first comment associated with the given parser. Iterate over the
253
+ * rest with pm_comment_next, as in:
254
+ *
255
+ * ```c
256
+ * for (const pm_comment_t *comment = pm_parser_comments_first(parser); comment != NULL; comment = pm_comment_next(comment)) {
257
+ * pm_location_t location = pm_comment_location(comment);
258
+ * }
259
+ * ```
237
260
  *
238
261
  * @param parser the parser whose comments we want to iterate over
239
- * @param callback the callback function to call for each comment. This function
240
- * will be passed a pointer to the comment and the data parameter passed to
241
- * this function.
242
- * @param data the data to pass to the callback function for each comment. This
243
- * can be NULL if no data needs to be passed to the callback function.
262
+ * @returns the first comment, or NULL if there are no comments
244
263
  */
245
- PRISM_EXPORTED_FUNCTION void pm_parser_comments_each(const pm_parser_t *parser, pm_comment_callback_t callback, void *data) PRISM_NONNULL(1);
264
+ PRISM_EXPORTED_FUNCTION const pm_comment_t * pm_parser_comments_first(const pm_parser_t *parser) PRISM_NONNULL(1);
246
265
 
247
266
  /**
248
267
  * Returns the number of comments owned by the given node. This is 0 if the
@@ -309,22 +328,13 @@ PRISM_EXPORTED_FUNCTION pm_comment_range_t pm_parser_comment_range(const pm_pars
309
328
  PRISM_EXPORTED_FUNCTION size_t pm_parser_magic_comments_size(const pm_parser_t *parser) PRISM_NONNULL(1);
310
329
 
311
330
  /**
312
- * A callback function that can be used to process magic comments found while parsing.
313
- */
314
- typedef void (*pm_magic_comment_callback_t)(const pm_magic_comment_t *magic_comment, void *data);
315
-
316
- /**
317
- * Iterates over the magic comments associated with the given parser and calls the
318
- * given callback for each magic comment.
331
+ * Returns the first magic comment associated with the given parser. Iterate
332
+ * over the rest with pm_magic_comment_next.
319
333
  *
320
334
  * @param parser the parser whose magic comments we want to iterate over
321
- * @param callback the callback function to call for each magic comment. This
322
- * function will be passed a pointer to the magic comment and the data
323
- * parameter passed to this function.
324
- * @param data the data to pass to the callback function for each magic comment.
325
- * This can be NULL if no data needs to be passed to the callback function.
335
+ * @returns the first magic comment, or NULL if there are no magic comments
326
336
  */
327
- PRISM_EXPORTED_FUNCTION void pm_parser_magic_comments_each(const pm_parser_t *parser, pm_magic_comment_callback_t callback, void *data) PRISM_NONNULL(1);
337
+ PRISM_EXPORTED_FUNCTION const pm_magic_comment_t * pm_parser_magic_comments_first(const pm_parser_t *parser) PRISM_NONNULL(1);
328
338
 
329
339
  /**
330
340
  * Returns the number of errors associated with the given parser.
@@ -343,36 +353,22 @@ PRISM_EXPORTED_FUNCTION size_t pm_parser_errors_size(const pm_parser_t *parser)
343
353
  PRISM_EXPORTED_FUNCTION size_t pm_parser_warnings_size(const pm_parser_t *parser) PRISM_NONNULL(1);
344
354
 
345
355
  /**
346
- * A callback function that can be used to process diagnostics found while
347
- * parsing.
348
- */
349
- typedef void (*pm_diagnostic_callback_t)(const pm_diagnostic_t *diagnostic, void *data);
350
-
351
- /**
352
- * Iterates over the errors associated with the given parser and calls the
353
- * given callback for each error.
356
+ * Returns the first error associated with the given parser. Iterate over the
357
+ * rest with pm_diagnostic_next.
354
358
  *
355
359
  * @param parser the parser whose errors we want to iterate over
356
- * @param callback the callback function to call for each error. This function
357
- * will be passed a pointer to the error and the data parameter passed to
358
- * this function.
359
- * @param data the data to pass to the callback function for each error. This
360
- * can be NULL if no data needs to be passed to the callback function.
360
+ * @returns the first error, or NULL if there are no errors
361
361
  */
362
- PRISM_EXPORTED_FUNCTION void pm_parser_errors_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1);
362
+ PRISM_EXPORTED_FUNCTION const pm_diagnostic_t * pm_parser_errors_first(const pm_parser_t *parser) PRISM_NONNULL(1);
363
363
 
364
364
  /**
365
- * Iterates over the warnings associated with the given parser and calls the
366
- * given callback for each warning.
365
+ * Returns the first warning associated with the given parser. Iterate over the
366
+ * rest with pm_diagnostic_next.
367
367
  *
368
368
  * @param parser the parser whose warnings we want to iterate over
369
- * @param callback the callback function to call for each warning. This function
370
- * will be passed a pointer to the warning and the data parameter passed to
371
- * this function.
372
- * @param data the data to pass to the callback function for each warning. This
373
- * can be NULL if no data needs to be passed to the callback function.
369
+ * @returns the first warning, or NULL if there are no warnings
374
370
  */
375
- PRISM_EXPORTED_FUNCTION void pm_parser_warnings_each(const pm_parser_t *parser, pm_diagnostic_callback_t callback, void *data) PRISM_NONNULL(1);
371
+ PRISM_EXPORTED_FUNCTION const pm_diagnostic_t * pm_parser_warnings_first(const pm_parser_t *parser) PRISM_NONNULL(1);
376
372
 
377
373
  /**
378
374
  * Returns the number of constants in the constant pool associated with the
@@ -386,30 +382,38 @@ PRISM_EXPORTED_FUNCTION void pm_parser_warnings_each(const pm_parser_t *parser,
386
382
  PRISM_EXPORTED_FUNCTION size_t pm_parser_constants_size(const pm_parser_t *parser) PRISM_NONNULL(1);
387
383
 
388
384
  /**
389
- * A callback function that can be used to process constants found while
390
- * parsing.
391
- */
392
- typedef void (*pm_constant_callback_t)(const pm_constant_t *constant, void *data);
393
-
394
- /**
395
- * Iterates over the constants in the constant pool associated with the given
396
- * parser and calls the given callback for each constant.
385
+ * Returns the constant at the given index in the constant pool associated with
386
+ * the given parser. Together with pm_constant_id_index, this lets a caller
387
+ * build a cache with one entry per constant and then find the entry for any
388
+ * constant id, as in:
397
389
  *
398
- * @param parser the parser whose constants we want to iterate over
399
- * @param callback the callback function to call for each constant. This function
400
- * will be passed a pointer to the constant and the data parameter passed to
401
- * this function.
402
- * @param data the data to pass to the callback function for each constant. This
403
- * can be NULL if no data needs to be passed to the callback function.
390
+ * ```c
391
+ * size_t size = pm_parser_constants_size(parser);
392
+ * for (size_t index = 0; index < size; index++) {
393
+ * cache[index] = convert(pm_parser_constant_at(parser, index));
394
+ * }
395
+ *
396
+ * value = cache[pm_constant_id_index(constant_id)];
397
+ * ```
398
+ *
399
+ * For any constant id, pm_parser_constant_at(parser,
400
+ * pm_constant_id_index(constant_id)) is pm_parser_constant(parser,
401
+ * constant_id).
402
+ *
403
+ * @param parser the parser whose constant pool we want to look up from
404
+ * @param index the index of the constant, which must be less than
405
+ * pm_parser_constants_size(parser)
406
+ * @returns a pointer to the constant at the given index
404
407
  */
405
- PRISM_EXPORTED_FUNCTION void pm_parser_constants_each(const pm_parser_t *parser, pm_constant_callback_t callback, void *data) PRISM_NONNULL(1);
408
+ PRISM_EXPORTED_FUNCTION const pm_constant_t * pm_parser_constant_at(const pm_parser_t *parser, size_t index) PRISM_NONNULL(1);
406
409
 
407
410
  /**
408
411
  * Returns a pointer to the constant at the given id in the constant pool
409
412
  * associated with the given parser.
410
413
  *
411
414
  * @param parser the parser whose constant pool we want to look up from
412
- * @param constant_id the id of the constant to look up (1-based)
415
+ * @param constant_id the id of the constant to look up. Optional constant
416
+ * fields on nodes hold 0 when they are absent, which is not a valid id.
413
417
  * @returns a pointer to the constant at the given id
414
418
  */
415
419
  PRISM_EXPORTED_FUNCTION const pm_constant_t * pm_parser_constant(const pm_parser_t *parser, pm_constant_id_t constant_id) PRISM_NONNULL(1);
@@ -422,4 +426,8 @@ PRISM_EXPORTED_FUNCTION const pm_constant_t * pm_parser_constant(const pm_parser
422
426
  */
423
427
  PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1);
424
428
 
429
+ #ifdef __cplusplus
430
+ }
431
+ #endif
432
+
425
433
  #endif