Ruby 4.1.0dev (2026-10-21 revision 536dc6f98b72e6999a84bb6373562c43cb1ddf8a)
node.hpp
Go to the documentation of this file.
1
7#ifndef PRISM_NODE_HPP
8#define PRISM_NODE_HPP
9
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
25namespace prism {
26
34template <typename T> [[nodiscard]] bool
35isa(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
49template <typename T> [[nodiscard]] T *
50cast(pm_node_t *node) noexcept {
51 assert(isa<T>(node));
52 return reinterpret_cast<T *>(node);
53}
54
63template <typename T> [[nodiscard]] const T *
64cast(const pm_node_t *node) noexcept {
65 assert(isa<T>(node));
66 return reinterpret_cast<const T *>(node);
67}
68
78template <typename T> [[nodiscard]] T *
79dyn_cast(pm_node_t *node) noexcept {
80 return (node != nullptr && isa<T>(node)) ? reinterpret_cast<T *>(node) : nullptr;
81}
82
92template <typename T> [[nodiscard]] const T *
93dyn_cast(const pm_node_t *node) noexcept {
94 return (node != nullptr && isa<T>(node)) ? reinterpret_cast<const T *>(node) : nullptr;
95}
96
104template <typename T> [[nodiscard]] pm_node_t *
105upcast(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
117template <typename T> [[nodiscard]] const pm_node_t *
118upcast(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
128public:
134 explicit node_range(const pm_node_list_t &list PRISM_LIFETIMEBOUND) noexcept : list_(&list) {}
135
141 pm_node_t *const *begin() const noexcept { return list_->nodes; }
142
148 pm_node_t *const *end() const noexcept { return list_->nodes + list_->size; }
149
155 std::size_t size() const noexcept { return list_->size; }
156
162 [[nodiscard]] bool empty() const noexcept { return list_->size == 0; }
163
164private:
165 const pm_node_list_t *list_;
166};
167
168namespace detail {
169
174template <typename F> struct visit_context {
180 explicit visit_context(F *visitor) noexcept : callable(visitor) {}
181
183 F *callable;
184
185#ifdef PRISM_HAS_EXCEPTIONS
187 std::exception_ptr exception;
188#endif
189};
190
203template <typename F> pm_visit_result_t
204visit_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
233template <typename F> bool
234visit_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
257template <typename F> bool
258visit_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
The nodes in a list, usable in a range-based for loop.
Definition node.hpp:127
bool empty() const noexcept
Whether there are no nodes.
Definition node.hpp:162
pm_node_t *const * end() const noexcept
A pointer one past the last node.
Definition node.hpp:148
node_range(const pm_node_list_t &list PRISM_LIFETIMEBOUND) noexcept
Create a range over the nodes in the given list.
Definition node.hpp:134
std::size_t size() const noexcept
The number of nodes.
Definition node.hpp:155
pm_node_t *const * begin() const noexcept
A pointer to the first node.
Definition node.hpp:141
#define PRISM_LIFETIMEBOUND
Mark a parameter that the return value points into, so that the compiler warns if a temporary is pass...
bool isa(const pm_node_t *node) noexcept
Whether the given node, which must not be null, is of the given struct.
Definition node.hpp:35
T * dyn_cast(pm_node_t *node) noexcept
Cast the given node to the given struct if it is of that struct, and return null otherwise.
Definition node.hpp:79
bool visit_node(const pm_node_t *node, F &&visitor)
Walk the tree rooted at the given node in pre-order, calling the visitor with each node.
Definition node.hpp:234
bool visit_child_nodes(const pm_node_t *node, F &&visitor)
Walk the children of the given node, as visit_node does for every node whose visitor returns PM_VISIT...
Definition node.hpp:258
T * cast(pm_node_t *node) noexcept
Cast the given node, which must not be null and must be of the given struct, to that struct.
Definition node.hpp:50
pm_node_t * upcast(T *node) noexcept
Return the pm_node_t embedded at the start of the given node struct.
Definition node.hpp:105
The traits that map node structs to node types.
Functions related to nodes in the AST.
pm_visit_result_t
The value returned by a visitor callback, which determines where the walk goes next.
Definition node.h:49
@ PM_VISIT_STOP
End the walk without visiting any more nodes.
Definition node.h:57
A list of nodes in the source, most often used for lists of children.
Definition ast.h:592
size_t size
The number of nodes in the list.
Definition ast.h:594
struct pm_node ** nodes
The nodes in the list.
Definition ast.h:600
This is the base structure that represents a node in the syntax tree.
Definition ast.h:1090