1#include "prism/internal/comments.h"
3#include "prism/internal/arena.h"
4#include "prism/internal/assert.h"
5#include "prism/internal/char.h"
6#include "prism/internal/node.h"
7#include "prism/internal/parser.h"
21 const uint8_t *source;
65pm_comments_compare(
const void *left,
const void *right) {
66 uint32_t left_start = (*(
const pm_comment_t *
const *) left)->location.start;
67 uint32_t right_start = (*(
const pm_comment_t *
const *) right)->location.start;
68 return (left_start > right_start) - (left_start < right_start);
77pm_comments_sort(
pm_parser_t *parser, uint32_t size) {
81 for (
pm_list_node_t *node = parser->comment_list.head; node != NULL; node = node->next) {
85 qsort((
void *) comments, size,
sizeof(
pm_comment_t *), pm_comments_compare);
87 for (index = 0; index + 1 < size; index++) {
91 comments[size - 1]->node.next = NULL;
92 parser->comment_list.head = &
comments[0]->node;
93 parser->comment_list.tail = &
comments[size - 1]->node;
103pm_comments_lower_bound(
const pm_comments_walk_t *walk, uint32_t left, uint32_t right, uint32_t offset) {
104 while (left < right) {
105 uint32_t middle = left + (right - left) / 2;
107 if (walk->starts[middle] < offset) {
125 const uint32_t *starts = walk->starts;
127 uint32_t size = walk->size;
128 uint32_t cursor = walk->cursor;
133 if (cursor == size || starts[cursor] >= offset) {
141 while (left > 0 && starts[left - 1] >= offset) {
143 left = (left - 1 > step) ? left - 1 - step : 0;
154 while (right < size && starts[right] < offset) {
156 right = (size - left > step) ? left + step : size;
161 walk->cursor = pm_comments_lower_bound(walk, left, right, offset);
171 uint32_t *unclaimed = walk->unclaimed;
173 while (unclaimed[index] != index) {
174 unclaimed[index] = unclaimed[unclaimed[index]];
175 index = unclaimed[index];
189 uint32_t index = pm_comments_lower_bound(walk, 0, walk->size, offset);
192 offset -= (uint32_t) pm_strrspn_whitespace(walk->source, (ptrdiff_t) offset);
193 if (index == 0)
return offset;
197 const pm_location_t *location = &walk->comments[index - 1]->location;
198 if (location->
start >= offset || PM_LOCATION_END(location) < offset)
return offset;
200 offset = location->
start;
212pm_comments_blank_after(
const pm_comments_walk_t *walk, uint32_t offset, uint32_t end) {
213 uint32_t index = pm_comments_lower_bound(walk, 0, walk->size, offset);
216 offset += (uint32_t) pm_strspn_whitespace(walk->source + offset, (ptrdiff_t) end - (ptrdiff_t) offset);
217 if (index == walk->size || walk->starts[index] != offset)
return offset;
219 offset = PM_LOCATION_END(&walk->comments[index]->location);
230pm_comments_push(
const pm_node_t *node,
void *data) {
233 if (walk->stack.size == walk->stack.capacity) {
234 size_t capacity = walk->stack.capacity == 0 ? 64 : walk->stack.capacity * 2;
236 if (walk->stack.size > 0) memcpy((
void *) nodes, (
const void *) walk->stack.nodes,
sizeof(
pm_node_t *) * walk->stack.size);
238 walk->stack.nodes = nodes;
239 walk->stack.capacity = capacity;
242 walk->stack.nodes[walk->stack.size++] = node;
253 size_t base = walk->stack.size;
254 pm_visit_child_nodes(node, pm_comments_push, walk);
255 size_t top = walk->stack.size;
258 for (
size_t index = base + 1; index < top; index++) {
259 const pm_node_t *child = walk->stack.nodes[index];
260 size_t insert = index;
263 walk->stack.nodes[insert] = walk->stack.nodes[insert - 1];
267 walk->stack.nodes[insert] = child;
271 for (
size_t index = base; index < top; index++) {
272 pm_comments_visit(walk, walk->stack.nodes[index]);
276 uint32_t end = PM_LOCATION_END(&node->
location);
277 uint32_t after = pm_comments_seek(walk, end);
284 after < walk->size &&
285 !PM_NODE_TYPE_P(node, PM_PROGRAM_NODE) &&
286 !PM_NODE_TYPE_P(node, PM_STATEMENTS_NODE) &&
289 uint32_t comment_start = walk->starts[after];
291 if (memchr(walk->source + end,
'\n', comment_start - end) == NULL) {
292 const pm_node_t *attached = walk->attached[after];
293 uint32_t attached_end = attached == NULL ? 0 : PM_LOCATION_END(&attached->
location);
295 if (end >= attached_end || attached_end > comment_start) {
296 walk->attached[after] = node;
309 if (after > 0 && walk->starts[after - 1] >= start) {
310 uint32_t index = pm_comments_unclaimed(walk, pm_comments_lower_bound(walk, 0, after, start));
311 size_t child_index = base;
317 uint32_t leading_boundary = 0;
319 uint32_t trailing_boundary = 0;
321 while (index < after && PM_LOCATION_END(&walk->comments[index]->location) <= end) {
322 if (walk->attached[index] == NULL) {
323 uint32_t comment_end = PM_LOCATION_END(&walk->comments[index]->location);
326 while (child_index < top && walk->stack.nodes[child_index]->location.start < comment_end) child_index++;
328 if (child_index < top) {
329 const pm_node_t *child = walk->stack.nodes[child_index];
331 if (PM_NODE_TYPE_P(child, PM_STATEMENTS_NODE)) {
332 if (child != leading) {
334 leading_boundary = pm_comments_blank_before(walk, child->
location.
start);
337 if (walk->starts[index] >= leading_boundary) attached = child;
341 if (attached == node && child_index > base) {
342 const pm_node_t *child = walk->stack.nodes[child_index - 1];
349 if (PM_NODE_TYPE_P(child, PM_RESCUE_NODE)) {
355 if (child != NULL && PM_NODE_TYPE_P(child, PM_STATEMENTS_NODE) && PM_LOCATION_END(&child->
location) <= walk->starts[index]) {
356 if (child != trailing) {
358 trailing_boundary = pm_comments_blank_after(walk, PM_LOCATION_END(&child->
location), end);
361 if (comment_end <= trailing_boundary) attached = child;
365 walk->attached[index] = attached;
368 walk->unclaimed[index] = index + 1;
369 index = pm_comments_unclaimed(walk, index + 1);
374 walk->stack.size = base;
390 PRISM_ASSERT(PM_NODE_TYPE_P(root, PM_PROGRAM_NODE));
392 uint32_t size = (uint32_t) parser->comment_list.size;
393 if (size == 0)
return;
398 .source = parser->start,
399 .comments = pm_comments_sort(parser, size),
401 .starts = (uint32_t *) pm_arena_alloc(arena,
sizeof(uint32_t) * size,
PRISM_ALIGNOF(uint32_t)),
403 .unclaimed = (uint32_t *) pm_arena_alloc(arena,
sizeof(uint32_t) * (size + 1),
PRISM_ALIGNOF(uint32_t))
406 for (uint32_t index = 0; index < size; index++) walk.starts[index] = walk.comments[index]->location.
start;
407 for (uint32_t index = 0; index <= size; index++) walk.unclaimed[index] = index;
409 pm_comments_visit(&walk, root);
418 uint32_t ranges_size = 0;
420 for (uint32_t index = 0; index < size; index++) {
421 if (walk.attached[index] == NULL) walk.attached[index] = statements;
423 uint32_t node_id = walk.attached[index]->
node_id;
424 PRISM_ASSERT(node_id <= parser->node_id);
425 if (node_id >= ranges_size) ranges_size = node_id + 1;
431 uint32_t *attachments = (uint32_t *) pm_arena_alloc(&parser->metadata_arena,
sizeof(uint32_t) * size,
PRISM_ALIGNOF(uint32_t));
433 for (uint32_t index = 0; index < size; index++) {
438 for (uint32_t index = 0; index < ranges_size; index++) {
439 ranges[index].
index = offset;
440 offset += ranges[index].
length;
444 for (uint32_t index = 0; index < size; index++) {
446 attachments[range->index + range->length++] = index;
450 .comments = walk.comments,
451 .attachments = attachments,
453 .ranges_size = ranges_size
#define PRISM_ALIGNOF
Get the alignment requirement of a type.
comment_range comments(const pm_parser_t *parser PRISM_LIFETIMEBOUND) noexcept
The comments found while parsing, in source order.
pm_visit_result_t
The value returned by a visitor callback, which determines where the walk goes next.
@ PM_VISIT_SKIP
Continue the walk without visiting this node's children.
This struct represents a slice in the source code, defined by an offset and a length.
uint32_t start
The offset of the location from the start of the source.
uint32_t length
The length of the location.
This is the base structure that represents a node in the syntax tree.
uint32_t node_id
The unique identifier for this node, which is deterministic based on the source.
pm_location_t location
This is the location of the node in the source.
PM_NODE_ALIGNAS struct pm_statements_node * statements
RescueNode::statements.
PM_NODE_ALIGNAS struct pm_rescue_node * subsequent
RescueNode::subsequent.