herb 0.11.0 → 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 (269) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -2
  3. data/config.yml +9 -0
  4. data/ext/herb/extconf.rb +8 -31
  5. data/ext/herb/nodes.c +90 -73
  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/ast/nodes.rb +32 -6
  11. data/lib/herb/bootstrap.rb +6 -2
  12. data/lib/herb/configuration.rb +11 -1
  13. data/lib/herb/dev/classifier.rb +1 -1
  14. data/lib/herb/dev/runner.rb +6 -1
  15. data/lib/herb/engine/compiler.rb +52 -19
  16. data/lib/herb/engine/slots/dynamics_compiler.rb +63 -14
  17. data/lib/herb/engine/slots/markers.rb +24 -0
  18. data/lib/herb/engine/slots/state_compiler.rb +1 -2
  19. data/lib/herb/engine/slots/subtree_compiler.rb +1 -1
  20. data/lib/herb/engine/slots/visitor.rb +71 -32
  21. data/lib/herb/engine/visitors/instrumentation_visitor.rb +18 -6
  22. data/lib/herb/engine.rb +0 -2
  23. data/lib/herb/parser_options.rb +6 -3
  24. data/lib/herb/project.rb +19 -8
  25. data/lib/herb/version.rb +1 -1
  26. data/lib/herb.rb +1 -1
  27. data/sig/herb/analysis/partial_resolution.rbs +8 -0
  28. data/sig/herb/ast/nodes.rbs +10 -4
  29. data/sig/herb/bootstrap.rbs +2 -0
  30. data/sig/herb/configuration.rbs +3 -0
  31. data/sig/herb/dev/runner.rbs +3 -0
  32. data/sig/herb/engine/compiler.rbs +14 -3
  33. data/sig/herb/engine/slots/dynamics_compiler.rbs +27 -7
  34. data/sig/herb/engine/slots/markers.rbs +14 -0
  35. data/sig/herb/engine/slots/visitor.rbs +31 -13
  36. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +5 -1
  37. data/sig/herb/parser_options.rbs +6 -4
  38. data/sig/herb.rbs +2 -2
  39. data/sig/serialized_ast_nodes.rbs +1 -0
  40. data/src/analyze/action_view/attribute_extraction_helpers.c +40 -21
  41. data/src/analyze/action_view/generated_handlers.c +36 -36
  42. data/src/analyze/action_view/image_tag.c +7 -3
  43. data/src/analyze/action_view/javascript_include_tag.c +6 -3
  44. data/src/analyze/action_view/link_to.c +23 -23
  45. data/src/analyze/action_view/registry.c +7 -3
  46. data/src/analyze/action_view/tag_helper_node_builders.c +12 -16
  47. data/src/analyze/action_view/tag_helpers.c +215 -110
  48. data/src/analyze/action_view/turbo_frame_tag.c +5 -4
  49. data/src/analyze/analyze.c +41 -45
  50. data/src/analyze/analyze_helpers.c +240 -405
  51. data/src/analyze/analyzed_ruby.c +10 -7
  52. data/src/analyze/builders.c +1 -0
  53. data/src/analyze/control_type.c +46 -29
  54. data/src/analyze/herb_directives.c +16 -20
  55. data/src/analyze/iteration_nodes.c +69 -24
  56. data/src/analyze/parse_errors.c +32 -22
  57. data/src/analyze/postfix_conditionals.c +23 -13
  58. data/src/analyze/prism_annotate.c +56 -32
  59. data/src/analyze/render_nodes.c +51 -41
  60. data/src/analyze/strict_locals.c +14 -15
  61. data/src/analyze/ternary_conditionals.c +14 -10
  62. data/src/ast/ast_nodes.c +3 -1
  63. data/src/ast/ast_pretty_print.c +5 -1
  64. data/src/extract.c +204 -143
  65. data/src/herb.c +10 -8
  66. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  67. data/src/include/analyze/action_view/tag_helper_node_builders.h +1 -0
  68. data/src/include/analyze/action_view/tag_helpers.h +1 -1
  69. data/src/include/analyze/analyze.h +3 -24
  70. data/src/include/analyze/analyzed_ruby.h +29 -2
  71. data/src/include/analyze/helpers.h +7 -27
  72. data/src/include/ast/ast_nodes.h +2 -1
  73. data/src/include/herb.h +3 -2
  74. data/src/include/lexer/lexer.h +1 -0
  75. data/src/include/parser/parser_options.h +5 -0
  76. data/src/include/prism/herb_prism_node.h +6 -1
  77. data/src/include/prism/prism_context.h +12 -12
  78. data/src/include/prism/prism_helpers.h +30 -0
  79. data/src/include/prism_version.h +11 -0
  80. data/src/include/version.h +1 -1
  81. data/src/lexer.c +32 -0
  82. data/src/parser/parser_helpers.c +1 -2
  83. data/src/parser.c +6 -7
  84. data/src/parser_options_defaults.c +1 -0
  85. data/src/prism/prism_helpers.c +167 -42
  86. data/src/prism/ruby_parser.c +20 -20
  87. data/templates/ext/herb/nodes.c.erb +5 -5
  88. data/templates/ext/herb/parser_options_helpers.c.erb +33 -0
  89. data/templates/java/nodes.c.erb +6 -6
  90. data/templates/java/parser_options_helpers.c.erb +41 -2
  91. data/templates/java/parser_options_helpers.h.erb +2 -1
  92. data/templates/javascript/packages/core/src/nodes.ts.erb +21 -1
  93. data/templates/javascript/packages/node/extension/nodes.cpp.erb +5 -5
  94. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +34 -2
  95. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +1 -1
  96. data/templates/lib/herb/parser_options.rb.erb +1 -1
  97. data/templates/rust/src/ast/nodes.rs.erb +1 -4
  98. data/templates/rust/src/prism/generated_deserialize.rs.erb +90 -44
  99. data/templates/rust/src/prism/generated_prettyprint.rs.erb +18 -27
  100. data/templates/src/analyze/action_view/generated_handlers.c.erb +23 -22
  101. data/templates/src/include/parser/parser_options.h.erb +10 -0
  102. data/templates/src/include/prism_version.h.erb +17 -0
  103. data/templates/src/parser_options_defaults.c.erb +1 -1
  104. data/templates/template.rb +17 -2
  105. data/templates/wasm/nodes.cpp.erb +8 -18
  106. data/templates/wasm/parser_options_helpers.cpp.erb +24 -0
  107. data/vendor/prism/Rakefile +76 -7
  108. data/vendor/prism/config.yml +174 -161
  109. data/vendor/prism/include/prism/arena.h +45 -0
  110. data/vendor/prism/include/prism/arena.hpp +42 -0
  111. data/vendor/prism/include/prism/ast.h +2738 -611
  112. data/vendor/prism/include/prism/ast.hpp +641 -0
  113. data/vendor/prism/include/prism/buffer.h +60 -0
  114. data/vendor/prism/include/prism/buffer.hpp +55 -0
  115. data/vendor/prism/include/prism/comments.h +72 -0
  116. data/vendor/prism/include/prism/compiler/accel.h +26 -0
  117. data/vendor/prism/include/prism/compiler/align.h +36 -0
  118. data/vendor/prism/include/prism/compiler/assume.h +25 -0
  119. data/vendor/prism/include/prism/compiler/branch.h +26 -0
  120. data/vendor/prism/include/prism/compiler/bswap.h +46 -0
  121. data/vendor/prism/include/prism/compiler/cplusplus.hpp +16 -0
  122. data/vendor/prism/include/prism/compiler/endianness.h +34 -0
  123. data/vendor/prism/include/prism/compiler/exceptions.hpp +17 -0
  124. data/vendor/prism/include/prism/compiler/exported.h +24 -0
  125. data/vendor/prism/include/prism/compiler/fallthrough.h +22 -0
  126. data/vendor/prism/include/prism/compiler/filesystem.h +32 -0
  127. data/vendor/prism/include/prism/compiler/flex_array.h +19 -0
  128. data/vendor/prism/include/prism/compiler/force_inline.h +21 -0
  129. data/vendor/prism/include/prism/compiler/format.h +27 -0
  130. data/vendor/prism/include/prism/compiler/inline.h +17 -0
  131. data/vendor/prism/include/prism/compiler/lifetimebound.hpp +25 -0
  132. data/vendor/prism/include/prism/compiler/nodiscard.h +22 -0
  133. data/vendor/prism/include/prism/compiler/nonnull.h +18 -0
  134. data/vendor/prism/include/prism/compiler/unused.h +18 -0
  135. data/vendor/prism/include/prism/constant_pool.h +106 -0
  136. data/vendor/prism/include/prism/diagnostic.h +55 -402
  137. data/vendor/prism/include/prism/errors_format.h +61 -0
  138. data/vendor/prism/include/prism/excludes.h +29 -0
  139. data/vendor/prism/include/prism/integer.h +41 -0
  140. data/vendor/prism/include/prism/internal/allocator.h +68 -0
  141. data/vendor/prism/include/prism/internal/allocator_debug.h +88 -0
  142. data/vendor/prism/include/prism/internal/arena.h +108 -0
  143. data/vendor/prism/include/prism/internal/bit.h +42 -0
  144. data/vendor/prism/include/prism/internal/buffer.h +94 -0
  145. data/vendor/prism/include/prism/internal/char.h +145 -0
  146. data/vendor/prism/include/prism/internal/comments.h +54 -0
  147. data/vendor/prism/include/prism/internal/constant_pool.h +152 -0
  148. data/vendor/prism/include/prism/internal/diagnostic.h +389 -0
  149. data/vendor/prism/include/prism/{encoding.h → internal/encoding.h} +27 -68
  150. data/vendor/prism/include/prism/internal/integer.h +68 -0
  151. data/vendor/prism/include/prism/internal/isinf.h +16 -0
  152. data/vendor/prism/include/prism/internal/line_offset_list.h +34 -0
  153. data/vendor/prism/include/prism/{util/pm_list.h → internal/list.h} +11 -52
  154. data/vendor/prism/include/prism/internal/magic_comments.h +23 -0
  155. data/vendor/prism/include/prism/internal/memchr.h +15 -0
  156. data/vendor/prism/include/prism/internal/node.h +42 -0
  157. data/vendor/prism/include/prism/internal/options.h +232 -0
  158. data/vendor/prism/include/prism/internal/parser.h +1015 -0
  159. data/vendor/prism/include/prism/internal/regexp.h +26 -0
  160. data/vendor/prism/include/prism/internal/serialize.h +39 -0
  161. data/vendor/prism/include/prism/internal/source.h +72 -0
  162. data/vendor/prism/include/prism/internal/static_literals.h +60 -0
  163. data/vendor/prism/include/prism/internal/stringy.h +30 -0
  164. data/vendor/prism/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
  165. data/vendor/prism/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
  166. data/vendor/prism/include/prism/internal/tokens.h +11 -0
  167. data/vendor/prism/include/prism/internal/xxh3.h +16 -0
  168. data/vendor/prism/include/prism/json.h +40 -0
  169. data/vendor/prism/include/prism/line_offset_list.h +69 -0
  170. data/vendor/prism/include/prism/magic_comments.h +53 -0
  171. data/vendor/prism/include/prism/node.h +59 -49
  172. data/vendor/prism/include/prism/node.hpp +272 -0
  173. data/vendor/prism/include/prism/node_type.hpp +38 -0
  174. data/vendor/prism/include/prism/options.h +154 -279
  175. data/vendor/prism/include/prism/options.hpp +43 -0
  176. data/vendor/prism/include/prism/parser.h +367 -870
  177. data/vendor/prism/include/prism/parser.hpp +274 -0
  178. data/vendor/prism/include/prism/prettyprint.h +14 -9
  179. data/vendor/prism/include/prism/serialize.h +123 -0
  180. data/vendor/prism/include/prism/source.h +163 -0
  181. data/vendor/prism/include/prism/stream.h +36 -0
  182. data/vendor/prism/include/prism/string_query.h +82 -0
  183. data/vendor/prism/include/prism/stringy.h +61 -0
  184. data/vendor/prism/include/prism/stringy.hpp +31 -0
  185. data/vendor/prism/include/prism/version.h +20 -3
  186. data/vendor/prism/include/prism.h +35 -320
  187. data/vendor/prism/include/prism.hpp +24 -0
  188. data/vendor/prism/src/arena.c +122 -0
  189. data/vendor/prism/src/{util/pm_buffer.c → buffer.c} +53 -21
  190. data/vendor/prism/src/{util/pm_char.c → char.c} +28 -57
  191. data/vendor/prism/src/comments.c +455 -0
  192. data/vendor/prism/src/constant_pool.c +406 -0
  193. data/vendor/prism/src/diagnostic.c +120 -68
  194. data/vendor/prism/src/encoding.c +8 -3
  195. data/vendor/prism/src/errors_format.c +519 -0
  196. data/vendor/prism/src/{util/pm_integer.c → integer.c} +38 -22
  197. data/vendor/prism/src/json.c +5733 -0
  198. data/vendor/prism/src/line_offset_list.c +100 -0
  199. data/vendor/prism/src/list.c +24 -0
  200. data/vendor/prism/src/{util/pm_memchr.c → memchr.c} +8 -6
  201. data/vendor/prism/src/node.c +3465 -7787
  202. data/vendor/prism/src/options.c +161 -54
  203. data/vendor/prism/src/parser.c +371 -0
  204. data/vendor/prism/src/prettyprint.c +421 -354
  205. data/vendor/prism/src/prism.c +8522 -7280
  206. data/vendor/prism/src/regexp.c +960 -45
  207. data/vendor/prism/src/serialize.c +2434 -2048
  208. data/vendor/prism/src/source.c +524 -0
  209. data/vendor/prism/src/static_literals.c +303 -360
  210. data/vendor/prism/src/string_query.c +180 -0
  211. data/vendor/prism/src/stringy.c +61 -0
  212. data/vendor/prism/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
  213. data/vendor/prism/src/strpbrk.c +447 -0
  214. data/vendor/prism/src/{token_type.c → tokens.c} +39 -18
  215. data/vendor/prism/src/xxh3.c +292 -0
  216. data/vendor/prism/templates/ext/prism/api_node.c.erb +58 -44
  217. data/vendor/prism/templates/include/prism/ast.h.erb +67 -17
  218. data/vendor/prism/templates/include/prism/ast.hpp.erb +31 -0
  219. data/vendor/prism/templates/include/prism/internal/diagnostic.h.erb +60 -0
  220. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/AbstractNodeVisitor.java.erb +1 -1
  221. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Loader.java.erb +232 -133
  222. data/vendor/prism/templates/java/{org → api/src/main/java-templates/org/ruby_lang}/prism/Nodes.java.erb +62 -23
  223. data/vendor/prism/templates/javascript/src/deserialize.js.erb +153 -146
  224. data/vendor/prism/templates/javascript/src/nodes.js.erb +4 -9
  225. data/vendor/prism/templates/lib/prism/compiler.rb.erb +14 -5
  226. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +20 -12
  227. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +37 -11
  228. data/vendor/prism/templates/lib/prism/dsl.rb.erb +43 -4
  229. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +26 -10
  230. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +5 -2
  231. data/vendor/prism/templates/lib/prism/node.rb.erb +283 -105
  232. data/vendor/prism/templates/lib/prism/reflection.rb.erb +11 -2
  233. data/vendor/prism/templates/lib/prism/serialize.rb.erb +291 -134
  234. data/vendor/prism/templates/lib/prism/visitor.rb.erb +18 -0
  235. data/vendor/prism/templates/src/diagnostic.c.erb +114 -63
  236. data/vendor/prism/templates/src/json.c.erb +130 -0
  237. data/vendor/prism/templates/src/node.c.erb +79 -236
  238. data/vendor/prism/templates/src/prettyprint.c.erb +24 -13
  239. data/vendor/prism/templates/src/serialize.c.erb +369 -183
  240. data/vendor/prism/templates/src/{token_type.c.erb → tokens.c.erb} +22 -11
  241. data/vendor/prism/templates/template.rb +193 -91
  242. metadata +100 -42
  243. data/vendor/prism/include/prism/defines.h +0 -260
  244. data/vendor/prism/include/prism/pack.h +0 -163
  245. data/vendor/prism/include/prism/regexp.h +0 -43
  246. data/vendor/prism/include/prism/static_literals.h +0 -121
  247. data/vendor/prism/include/prism/util/pm_buffer.h +0 -236
  248. data/vendor/prism/include/prism/util/pm_char.h +0 -204
  249. data/vendor/prism/include/prism/util/pm_constant_pool.h +0 -218
  250. data/vendor/prism/include/prism/util/pm_integer.h +0 -130
  251. data/vendor/prism/include/prism/util/pm_memchr.h +0 -29
  252. data/vendor/prism/include/prism/util/pm_newline_list.h +0 -113
  253. data/vendor/prism/include/prism/util/pm_string.h +0 -200
  254. data/vendor/prism/src/pack.c +0 -509
  255. data/vendor/prism/src/util/pm_constant_pool.c +0 -342
  256. data/vendor/prism/src/util/pm_list.c +0 -49
  257. data/vendor/prism/src/util/pm_newline_list.c +0 -125
  258. data/vendor/prism/src/util/pm_string.c +0 -381
  259. data/vendor/prism/src/util/pm_strpbrk.c +0 -206
  260. data/vendor/prism/templates/include/prism/diagnostic.h.erb +0 -130
  261. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +0 -68
  262. data/vendor/prism/templates/rbi/prism/node.rbi.erb +0 -167
  263. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +0 -18
  264. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +0 -45
  265. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +0 -31
  266. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +0 -7
  267. data/vendor/prism/templates/sig/prism/node.rbs.erb +0 -136
  268. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +0 -17
  269. data/vendor/prism/templates/sig/prism.rbs.erb +0 -92
@@ -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