1#include "prism/internal/comments.h"
3#include "prism/internal/arena.h"
4#include "prism/internal/char.h"
5#include "prism/internal/node.h"
6#include "prism/internal/parser.h"
18 const uint8_t *source;
62pm_comments_compare(
const void *left,
const void *right) {
63 uint32_t left_start = (*(
const pm_comment_t *
const *) left)->location.start;
64 uint32_t right_start = (*(
const pm_comment_t *
const *) right)->location.start;
65 return (left_start > right_start) - (left_start < right_start);
74pm_comments_sort(
pm_parser_t *parser, uint32_t size) {
78 for (
pm_list_node_t *node = parser->comment_list.head; node != NULL; node = node->next) {
82 qsort((
void *) comments, size,
sizeof(
pm_comment_t *), pm_comments_compare);
84 for (index = 0; index + 1 < size; index++) {
85 comments[index]->node.next = &comments[index + 1]->node;
88 comments[size - 1]->node.next = NULL;
89 parser->comment_list.head = &comments[0]->node;
90 parser->comment_list.tail = &comments[size - 1]->node;
100pm_comments_lower_bound(
const pm_comments_walk_t *walk, uint32_t left, uint32_t right, uint32_t offset) {
101 while (left < right) {
102 uint32_t middle = left + (right - left) / 2;
104 if (walk->starts[middle] < offset) {
122 const uint32_t *starts = walk->starts;
124 uint32_t size = walk->size;
125 uint32_t cursor = walk->cursor;
130 if (cursor == size || starts[cursor] >= offset) {
138 while (left > 0 && starts[left - 1] >= offset) {
140 left = (left - 1 > step) ? left - 1 - step : 0;
151 while (right < size && starts[right] < offset) {
153 right = (size - left > step) ? left + step : size;
158 walk->cursor = pm_comments_lower_bound(walk, left, right, offset);
168 uint32_t *unclaimed = walk->unclaimed;
170 while (unclaimed[index] != index) {
171 unclaimed[index] = unclaimed[unclaimed[index]];
172 index = unclaimed[index];
186 uint32_t index = pm_comments_lower_bound(walk, 0, walk->size, offset);
189 offset -= (uint32_t) pm_strrspn_whitespace(walk->source, (ptrdiff_t) offset);
190 if (index == 0)
return offset;
194 const pm_location_t *location = &walk->comments[index - 1]->location;
195 if (location->
start >= offset || PM_LOCATION_END(location) < offset)
return offset;
197 offset = location->
start;
209pm_comments_blank_after(
const pm_comments_walk_t *walk, uint32_t offset, uint32_t end) {
210 uint32_t index = pm_comments_lower_bound(walk, 0, walk->size, offset);
213 offset += (uint32_t) pm_strspn_whitespace(walk->source + offset, (ptrdiff_t) end - (ptrdiff_t) offset);
214 if (index == walk->size || walk->starts[index] != offset)
return offset;
216 offset = PM_LOCATION_END(&walk->comments[index]->location);
227pm_comments_push(
const pm_node_t *node,
void *data) {
230 if (walk->stack.size == walk->stack.capacity) {
231 size_t capacity = walk->stack.capacity == 0 ? 64 : walk->stack.capacity * 2;
233 if (walk->stack.size > 0) memcpy((
void *) nodes, (
const void *) walk->stack.nodes,
sizeof(
pm_node_t *) * walk->stack.size);
235 walk->stack.nodes = nodes;
236 walk->stack.capacity = capacity;
239 walk->stack.nodes[walk->stack.size++] = node;
250 size_t base = walk->stack.size;
251 pm_visit_child_nodes(node, pm_comments_push, walk);
252 size_t top = walk->stack.size;
255 for (
size_t index = base + 1; index < top; index++) {
256 const pm_node_t *child = walk->stack.nodes[index];
257 size_t insert = index;
260 walk->stack.nodes[insert] = walk->stack.nodes[insert - 1];
264 walk->stack.nodes[insert] = child;
268 for (
size_t index = base; index < top; index++) {
269 pm_comments_visit(walk, walk->stack.nodes[index]);
273 uint32_t end = PM_LOCATION_END(&node->
location);
274 uint32_t after = pm_comments_seek(walk, end);
281 after < walk->size &&
282 !PM_NODE_TYPE_P(node, PM_PROGRAM_NODE) &&
283 !PM_NODE_TYPE_P(node, PM_STATEMENTS_NODE) &&
286 uint32_t comment_start = walk->starts[after];
288 if (memchr(walk->source + end,
'\n', comment_start - end) == NULL) {
289 const pm_node_t *attached = walk->attached[after];
290 uint32_t attached_end = attached == NULL ? 0 : PM_LOCATION_END(&attached->
location);
292 if (end >= attached_end || attached_end > comment_start) {
293 walk->attached[after] = node;
306 if (after > 0 && walk->starts[after - 1] >= start) {
307 uint32_t index = pm_comments_unclaimed(walk, pm_comments_lower_bound(walk, 0, after, start));
308 size_t child_index = base;
314 uint32_t leading_boundary = 0;
316 uint32_t trailing_boundary = 0;
318 while (index < after && PM_LOCATION_END(&walk->comments[index]->location) <= end) {
319 if (walk->attached[index] == NULL) {
320 uint32_t comment_end = PM_LOCATION_END(&walk->comments[index]->location);
323 while (child_index < top && walk->stack.nodes[child_index]->location.start < comment_end) child_index++;
325 if (child_index < top) {
326 const pm_node_t *child = walk->stack.nodes[child_index];
328 if (PM_NODE_TYPE_P(child, PM_STATEMENTS_NODE)) {
329 if (child != leading) {
331 leading_boundary = pm_comments_blank_before(walk, child->
location.
start);
334 if (walk->starts[index] >= leading_boundary) attached = child;
338 if (attached == node && child_index > base) {
339 const pm_node_t *child = walk->stack.nodes[child_index - 1];
346 if (PM_NODE_TYPE_P(child, PM_RESCUE_NODE)) {
352 if (child != NULL && PM_NODE_TYPE_P(child, PM_STATEMENTS_NODE) && PM_LOCATION_END(&child->
location) <= walk->starts[index]) {
353 if (child != trailing) {
355 trailing_boundary = pm_comments_blank_after(walk, PM_LOCATION_END(&child->
location), end);
358 if (comment_end <= trailing_boundary) attached = child;
362 walk->attached[index] = attached;
365 walk->unclaimed[index] = index + 1;
366 index = pm_comments_unclaimed(walk, index + 1);
371 walk->stack.size = base;
387 assert(PM_NODE_TYPE_P(root, PM_PROGRAM_NODE));
389 uint32_t size = (uint32_t) parser->comment_list.size;
390 if (size == 0)
return;
395 .source = parser->start,
396 .comments = pm_comments_sort(parser, size),
398 .starts = (uint32_t *) pm_arena_alloc(&arena,
sizeof(uint32_t) * size,
PRISM_ALIGNOF(uint32_t)),
400 .unclaimed = (uint32_t *) pm_arena_alloc(&arena,
sizeof(uint32_t) * (size + 1),
PRISM_ALIGNOF(uint32_t))
403 for (uint32_t index = 0; index < size; index++) walk.starts[index] = walk.comments[index]->location.
start;
404 for (uint32_t index = 0; index <= size; index++) walk.unclaimed[index] = index;
406 pm_comments_visit(&walk, root);
415 uint32_t ranges_size = 0;
417 for (uint32_t index = 0; index < size; index++) {
418 if (walk.attached[index] == NULL) walk.attached[index] = statements;
420 uint32_t node_id = walk.attached[index]->
node_id;
421 assert(node_id <= parser->node_id);
422 if (node_id >= ranges_size) ranges_size = node_id + 1;
428 uint32_t *attachments = (uint32_t *) pm_arena_alloc(&parser->metadata_arena,
sizeof(uint32_t) * size,
PRISM_ALIGNOF(uint32_t));
430 for (uint32_t index = 0; index < size; index++) {
435 for (uint32_t index = 0; index < ranges_size; index++) {
436 ranges[index].
index = offset;
437 offset += ranges[index].
length;
441 for (uint32_t index = 0; index < size; index++) {
443 attachments[range->index + range->length++] = index;
446 pm_arena_cleanup(&arena);
449 .comments = walk.comments,
450 .attachments = attachments,
452 .ranges_size = ranges_size
#define PRISM_ALIGNOF
Get the alignment requirement of a type.
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.