Ruby: prism/static_literals.c Source File

Ruby 4.0.5p0 (2026-05-20 revision 64336ffd0ee9e1f4c05891695a3d7b49cb709721)

static_literals.c
1#include "prism/static_literals.h"
2
8 typedef struct {
10 const pm_newline_list_t *newline_list;
11
13 int32_t start_line;
14
16 const char *encoding_name;
17} pm_static_literals_metadata_t;
18
19static inline uint32_t
20murmur_scramble(uint32_t value) {
21 value *= 0xcc9e2d51;
22 value = (value << 15) | (value >> 17);
23 value *= 0x1b873593;
24 return value;
25}
26
32static uint32_t
33murmur_hash(const uint8_t *key, size_t length) {
34 uint32_t hash = 0x9747b28c;
35 uint32_t segment;
36
37 for (size_t index = length >> 2; index; index--) {
38 memcpy(&segment, key, sizeof(uint32_t));
39 key += sizeof(uint32_t);
40 hash ^= murmur_scramble(segment);
41 hash = (hash << 13) | (hash >> 19);
42 hash = hash * 5 + 0xe6546b64;
43 }
44
45 segment = 0;
46 for (size_t index = length & 3; index; index--) {
47 segment <<= 8;
48 segment |= key[index - 1];
49 }
50
51 hash ^= murmur_scramble(segment);
52 hash ^= (uint32_t) length;
53 hash ^= hash >> 16;
54 hash *= 0x85ebca6b;
55 hash ^= hash >> 13;
56 hash *= 0xc2b2ae35;
57 hash ^= hash >> 16;
58 return hash;
59}
60
64static uint32_t
65integer_hash(const pm_integer_t *integer) {
66 uint32_t hash;
67 if (integer->values) {
68 hash = murmur_hash((const uint8_t *) integer->values, sizeof(uint32_t) * integer->length);
69 } else {
70 hash = murmur_hash((const uint8_t *) &integer->value, sizeof(uint32_t));
71 }
72
73 if (integer->negative) {
74 hash ^= murmur_scramble((uint32_t) 1);
75 }
76
77 return hash;
78}
79
85static uint32_t
86node_hash(const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
87 switch (PM_NODE_TYPE(node)) {
88 case PM_INTEGER_NODE: {
89 // Integers hash their value.
90 const pm_integer_node_t *cast = (const pm_integer_node_t *) node;
91 return integer_hash(&cast->value);
92 }
93 case PM_SOURCE_LINE_NODE: {
94 // Source lines hash their line number.
95 const pm_line_column_t line_column = pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line);
96 const int32_t *value = &line_column.line;
97 return murmur_hash((const uint8_t *) value, sizeof(int32_t));
98 }
99 case PM_FLOAT_NODE: {
100 // Floats hash their value.
101 const double *value = &((const pm_float_node_t *) node)->value;
102 return murmur_hash((const uint8_t *) value, sizeof(double));
103 }
104 case PM_RATIONAL_NODE: {
105 // Rationals hash their numerator and denominator.
106 const pm_rational_node_t *cast = (const pm_rational_node_t *) node;
107 return integer_hash(&cast->numerator) ^ integer_hash(&cast->denominator) ^ murmur_scramble((uint32_t) cast->base.type);
108 }
109 case PM_IMAGINARY_NODE: {
110 // Imaginaries hash their numeric value. Because their numeric value
111 // is stored as a subnode, we hash that node and then mix in the
112 // fact that this is an imaginary node.
113 const pm_node_t *numeric = ((const pm_imaginary_node_t *) node)->numeric;
114 return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->type);
115 }
116 case PM_STRING_NODE: {
117 // Strings hash their value and mix in their flags so that different
118 // encodings are not considered equal.
119 const pm_string_t *value = &((const pm_string_node_t *) node)->unescaped;
120
121 pm_node_flags_t flags = node->flags;
122 flags &= (PM_STRING_FLAGS_FORCED_BINARY_ENCODING | PM_STRING_FLAGS_FORCED_UTF8_ENCODING);
123
124 return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t)) ^ murmur_scramble((uint32_t) flags);
125 }
126 case PM_SOURCE_FILE_NODE: {
127 // Source files hash their value and mix in their flags so that
128 // different encodings are not considered equal.
129 const pm_string_t *value = &((const pm_source_file_node_t *) node)->filepath;
130 return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t));
131 }
132 case PM_REGULAR_EXPRESSION_NODE: {
133 // Regular expressions hash their value and mix in their flags so
134 // that different encodings are not considered equal.
135 const pm_string_t *value = &((const pm_regular_expression_node_t *) node)->unescaped;
136 return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->flags);
137 }
138 case PM_SYMBOL_NODE: {
139 // Symbols hash their value and mix in their flags so that different
140 // encodings are not considered equal.
141 const pm_string_t *value = &((const pm_symbol_node_t *) node)->unescaped;
142 return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->flags);
143 }
144 default:
145 assert(false && "unreachable");
146 return 0;
147 }
148}
149
156static pm_node_t *
157pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *metadata, pm_node_t *node, bool replace, int (*compare)(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right)) {
158 // If we are out of space, we need to resize the hash. This will cause all
159 // of the nodes to be rehashed and reinserted into the new hash.
160 if (hash->size * 2 >= hash->capacity) {
161 // First, allocate space for the new node list.
162 uint32_t new_capacity = hash->capacity == 0 ? 4 : hash->capacity * 2;
163 pm_node_t **new_nodes = xcalloc(new_capacity, sizeof(pm_node_t *));
164 if (new_nodes == NULL) return NULL;
165
166 // It turns out to be more efficient to mask the hash value than to use
167 // the modulo operator. Because our capacities are always powers of two,
168 // we can use a bitwise AND to get the same result as the modulo
169 // operator.
170 uint32_t mask = new_capacity - 1;
171
172 // Now, rehash all of the nodes into the new list.
173 for (uint32_t index = 0; index < hash->capacity; index++) {
174 pm_node_t *node = hash->nodes[index];
175
176 if (node != NULL) {
177 uint32_t index = node_hash(metadata, node) & mask;
178 new_nodes[index] = node;
179 }
180 }
181
182 // Finally, free the old node list and update the hash.
183 xfree(hash->nodes);
184 hash->nodes = new_nodes;
185 hash->capacity = new_capacity;
186 }
187
188 // Now, insert the node into the hash.
189 uint32_t mask = hash->capacity - 1;
190 uint32_t index = node_hash(metadata, node) & mask;
191
192 // We use linear probing to resolve collisions. This means that if the
193 // current index is occupied, we will move to the next index and try again.
194 // We are guaranteed that this will eventually find an empty slot because we
195 // resize the hash when it gets too full.
196 while (hash->nodes[index] != NULL) {
197 if (compare(metadata, hash->nodes[index], node) == 0) break;
198 index = (index + 1) & mask;
199 }
200
201 // If the current index is occupied, we need to return the node that was
202 // already in the hash. Otherwise, we can just increment the size and insert
203 // the new node.
204 pm_node_t *result = hash->nodes[index];
205
206 if (result == NULL) {
207 hash->size++;
208 hash->nodes[index] = node;
209 } else if (replace) {
210 hash->nodes[index] = node;
211 }
212
213 return result;
214}
215
219static void
220pm_node_hash_free(pm_node_hash_t *hash) {
221 if (hash->capacity > 0) xfree(hash->nodes);
222}
223
227#define PM_NUMERIC_COMPARISON(left, right) ((left < right) ? -1 : (left > right) ? 1 : 0)
228
232static int64_t
233pm_int64_value(const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
234 switch (PM_NODE_TYPE(node)) {
235 case PM_INTEGER_NODE: {
236 const pm_integer_t *integer = &((const pm_integer_node_t *) node)->value;
237 if (integer->values) return integer->negative ? INT64_MIN : INT64_MAX;
238
239 int64_t value = (int64_t) integer->value;
240 return integer->negative ? -value : value;
241 }
242 case PM_SOURCE_LINE_NODE:
243 return (int64_t) pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line;
244 default:
245 assert(false && "unreachable");
246 return 0;
247 }
248}
249
254static int
255pm_compare_integer_nodes(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
256 if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
257 int64_t left_value = pm_int64_value(metadata, left);
258 int64_t right_value = pm_int64_value(metadata, right);
259 return PM_NUMERIC_COMPARISON(left_value, right_value);
260 }
261
262 const pm_integer_t *left_integer = &((const pm_integer_node_t *) left)->value;
263 const pm_integer_t *right_integer = &((const pm_integer_node_t *) right)->value;
264 return pm_integer_compare(left_integer, right_integer);
265}
266
270static int
271pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
272 const double left_value = ((const pm_float_node_t *) left)->value;
273 const double right_value = ((const pm_float_node_t *) right)->value;
274 return PM_NUMERIC_COMPARISON(left_value, right_value);
275}
276
280static int
281pm_compare_number_nodes(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
282 if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
283 return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
284 }
285
286 switch (PM_NODE_TYPE(left)) {
287 case PM_IMAGINARY_NODE:
288 return pm_compare_number_nodes(metadata, ((const pm_imaginary_node_t *) left)->numeric, ((const pm_imaginary_node_t *) right)->numeric);
289 case PM_RATIONAL_NODE: {
290 const pm_rational_node_t *left_rational = (const pm_rational_node_t *) left;
291 const pm_rational_node_t *right_rational = (const pm_rational_node_t *) right;
292
293 int result = pm_integer_compare(&left_rational->denominator, &right_rational->denominator);
294 if (result != 0) return result;
295
296 return pm_integer_compare(&left_rational->numerator, &right_rational->numerator);
297 }
298 case PM_INTEGER_NODE:
299 return pm_compare_integer_nodes(metadata, left, right);
300 case PM_FLOAT_NODE:
301 return pm_compare_float_nodes(metadata, left, right);
302 default:
303 assert(false && "unreachable");
304 return 0;
305 }
306}
307
311static const pm_string_t *
312pm_string_value(const pm_node_t *node) {
313 switch (PM_NODE_TYPE(node)) {
314 case PM_STRING_NODE:
315 return &((const pm_string_node_t *) node)->unescaped;
316 case PM_SOURCE_FILE_NODE:
317 return &((const pm_source_file_node_t *) node)->filepath;
318 case PM_SYMBOL_NODE:
319 return &((const pm_symbol_node_t *) node)->unescaped;
320 default:
321 assert(false && "unreachable");
322 return NULL;
323 }
324}
325
329static int
330pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
331 const pm_string_t *left_string = pm_string_value(left);
332 const pm_string_t *right_string = pm_string_value(right);
333 return pm_string_compare(left_string, right_string);
334}
335
339static int
340pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
341 const pm_regular_expression_node_t *left_regexp = (const pm_regular_expression_node_t *) left;
342 const pm_regular_expression_node_t *right_regexp = (const pm_regular_expression_node_t *) right;
343
344 int result = pm_string_compare(&left_regexp->unescaped, &right_regexp->unescaped);
345 if (result != 0) return result;
346
347 return PM_NUMERIC_COMPARISON(left_regexp->base.flags, right_regexp->base.flags);
348}
349
350#undef PM_NUMERIC_COMPARISON
351
355pm_node_t *
356pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace) {
357 switch (PM_NODE_TYPE(node)) {
358 case PM_INTEGER_NODE:
359 case PM_SOURCE_LINE_NODE:
360 return pm_node_hash_insert(
361 &literals->integer_nodes,
362 &(pm_static_literals_metadata_t) {
363 .newline_list = newline_list,
364 .start_line = start_line,
365 .encoding_name = NULL
366 },
367 node,
368 replace,
369 pm_compare_integer_nodes
370 );
371 case PM_FLOAT_NODE:
372 return pm_node_hash_insert(
373 &literals->float_nodes,
374 &(pm_static_literals_metadata_t) {
375 .newline_list = newline_list,
376 .start_line = start_line,
377 .encoding_name = NULL
378 },
379 node,
380 replace,
381 pm_compare_float_nodes
382 );
383 case PM_RATIONAL_NODE:
384 case PM_IMAGINARY_NODE:
385 return pm_node_hash_insert(
386 &literals->number_nodes,
387 &(pm_static_literals_metadata_t) {
388 .newline_list = newline_list,
389 .start_line = start_line,
390 .encoding_name = NULL
391 },
392 node,
393 replace,
394 pm_compare_number_nodes
395 );
396 case PM_STRING_NODE:
397 case PM_SOURCE_FILE_NODE:
398 return pm_node_hash_insert(
399 &literals->string_nodes,
400 &(pm_static_literals_metadata_t) {
401 .newline_list = newline_list,
402 .start_line = start_line,
403 .encoding_name = NULL
404 },
405 node,
406 replace,
407 pm_compare_string_nodes
408 );
409 case PM_REGULAR_EXPRESSION_NODE:
410 return pm_node_hash_insert(
411 &literals->regexp_nodes,
412 &(pm_static_literals_metadata_t) {
413 .newline_list = newline_list,
414 .start_line = start_line,
415 .encoding_name = NULL
416 },
417 node,
418 replace,
419 pm_compare_regular_expression_nodes
420 );
421 case PM_SYMBOL_NODE:
422 return pm_node_hash_insert(
423 &literals->symbol_nodes,
424 &(pm_static_literals_metadata_t) {
425 .newline_list = newline_list,
426 .start_line = start_line,
427 .encoding_name = NULL
428 },
429 node,
430 replace,
431 pm_compare_string_nodes
432 );
433 case PM_TRUE_NODE: {
434 pm_node_t *duplicated = literals->true_node;
435 if ((duplicated == NULL) || replace) literals->true_node = node;
436 return duplicated;
437 }
438 case PM_FALSE_NODE: {
439 pm_node_t *duplicated = literals->false_node;
440 if ((duplicated == NULL) || replace) literals->false_node = node;
441 return duplicated;
442 }
443 case PM_NIL_NODE: {
444 pm_node_t *duplicated = literals->nil_node;
445 if ((duplicated == NULL) || replace) literals->nil_node = node;
446 return duplicated;
447 }
448 case PM_SOURCE_ENCODING_NODE: {
449 pm_node_t *duplicated = literals->source_encoding_node;
450 if ((duplicated == NULL) || replace) literals->source_encoding_node = node;
451 return duplicated;
452 }
453 default:
454 return NULL;
455 }
456}
457
461void
462pm_static_literals_free(pm_static_literals_t *literals) {
463 pm_node_hash_free(&literals->integer_nodes);
464 pm_node_hash_free(&literals->float_nodes);
465 pm_node_hash_free(&literals->number_nodes);
466 pm_node_hash_free(&literals->string_nodes);
467 pm_node_hash_free(&literals->regexp_nodes);
468 pm_node_hash_free(&literals->symbol_nodes);
469}
470
475static bool
476pm_static_literal_positive_p(const pm_node_t *node) {
477 switch (PM_NODE_TYPE(node)) {
478 case PM_FLOAT_NODE:
479 return ((const pm_float_node_t *) node)->value > 0;
480 case PM_INTEGER_NODE:
481 return !((const pm_integer_node_t *) node)->value.negative;
482 case PM_RATIONAL_NODE:
483 return !((const pm_rational_node_t *) node)->numerator.negative;
484 case PM_IMAGINARY_NODE:
485 return pm_static_literal_positive_p(((const pm_imaginary_node_t *) node)->numeric);
486 default:
487 assert(false && "unreachable");
488 return false;
489 }
490}
491
495static inline void
496pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
497 switch (PM_NODE_TYPE(node)) {
498 case PM_FALSE_NODE:
499 pm_buffer_append_string(buffer, "false", 5);
500 break;
501 case PM_FLOAT_NODE: {
502 const double value = ((const pm_float_node_t *) node)->value;
503
504 if (PRISM_ISINF(value)) {
505 if (*node->location.start == '-') {
506 pm_buffer_append_byte(buffer, '-');
507 }
508 pm_buffer_append_string(buffer, "Infinity", 8);
509 } else if (value == 0.0) {
510 if (*node->location.start == '-') {
511 pm_buffer_append_byte(buffer, '-');
512 }
513 pm_buffer_append_string(buffer, "0.0", 3);
514 } else {
515 pm_buffer_append_format(buffer, "%g", value);
516
517 // %g will not insert a .0 for 1e100 (we'll get back 1e+100). So
518 // we check for the decimal point and add it in here if it's not
519 // present.
520 if (pm_buffer_index(buffer, '.') == SIZE_MAX) {
521 size_t exponent_index = pm_buffer_index(buffer, 'e');
522 size_t index = exponent_index == SIZE_MAX ? pm_buffer_length(buffer) : exponent_index;
523 pm_buffer_insert(buffer, index, ".0", 2);
524 }
525 }
526
527 break;
528 }
529 case PM_IMAGINARY_NODE: {
530 const pm_node_t *numeric = ((const pm_imaginary_node_t *) node)->numeric;
531 pm_buffer_append_string(buffer, "(0", 2);
532 if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer, '+');
533 pm_static_literal_inspect_node(buffer, metadata, numeric);
534 if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) {
535 pm_buffer_append_byte(buffer, '*');
536 }
537 pm_buffer_append_string(buffer, "i)", 2);
538 break;
539 }
540 case PM_INTEGER_NODE:
541 pm_integer_string(buffer, &((const pm_integer_node_t *) node)->value);
542 break;
543 case PM_NIL_NODE:
544 pm_buffer_append_string(buffer, "nil", 3);
545 break;
546 case PM_RATIONAL_NODE: {
547 const pm_rational_node_t *rational = (const pm_rational_node_t *) node;
548 pm_buffer_append_byte(buffer, '(');
549 pm_integer_string(buffer, &rational->numerator);
550 pm_buffer_append_byte(buffer, '/');
551 pm_integer_string(buffer, &rational->denominator);
552 pm_buffer_append_byte(buffer, ')');
553 break;
554 }
555 case PM_REGULAR_EXPRESSION_NODE: {
556 const pm_string_t *unescaped = &((const pm_regular_expression_node_t *) node)->unescaped;
557 pm_buffer_append_byte(buffer, '/');
558 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
559 pm_buffer_append_byte(buffer, '/');
560
561 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) pm_buffer_append_string(buffer, "m", 1);
562 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) pm_buffer_append_string(buffer, "i", 1);
563 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) pm_buffer_append_string(buffer, "x", 1);
564 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) pm_buffer_append_string(buffer, "n", 1);
565
566 break;
567 }
568 case PM_SOURCE_ENCODING_NODE:
569 pm_buffer_append_format(buffer, "#<Encoding:%s>", metadata->encoding_name);
570 break;
571 case PM_SOURCE_FILE_NODE: {
572 const pm_string_t *filepath = &((const pm_source_file_node_t *) node)->filepath;
573 pm_buffer_append_byte(buffer, '"');
574 pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_RUBY);
575 pm_buffer_append_byte(buffer, '"');
576 break;
577 }
578 case PM_SOURCE_LINE_NODE:
579 pm_buffer_append_format(buffer, "%d", pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line);
580 break;
581 case PM_STRING_NODE: {
582 const pm_string_t *unescaped = &((const pm_string_node_t *) node)->unescaped;
583 pm_buffer_append_byte(buffer, '"');
584 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
585 pm_buffer_append_byte(buffer, '"');
586 break;
587 }
588 case PM_SYMBOL_NODE: {
589 const pm_string_t *unescaped = &((const pm_symbol_node_t *) node)->unescaped;
590 pm_buffer_append_byte(buffer, ':');
591 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
592 break;
593 }
594 case PM_TRUE_NODE:
595 pm_buffer_append_string(buffer, "true", 4);
596 break;
597 default:
598 assert(false && "unreachable");
599 break;
600 }
601}
602
606void
607pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node) {
608 pm_static_literal_inspect_node(
609 buffer,
610 &(pm_static_literals_metadata_t) {
611 .newline_list = newline_list,
612 .start_line = start_line,
613 .encoding_name = encoding_name
614 },
615 node
616 );
617}
xfree
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
xcalloc
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
PRISM_ATTRIBUTE_UNUSED
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
Definition defines.h:81
PRISM_ISINF
#define PRISM_ISINF(x)
isinf on POSIX systems it accepts a float, a double, or a long double.
Definition defines.h:151
static_literals.h
A set of static literal nodes that can be checked for duplicates.
pm_buffer_t
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
Definition pm_buffer.h:22
pm_integer_node::value
pm_integer_t value
IntegerNode::value.
Definition ast.h:5252
pm_integer_t
A structure represents an arbitrary-sized integer.
Definition pm_integer.h:20
pm_integer_t::length
size_t length
The number of allocated values.
Definition pm_integer.h:25
pm_integer_t::value
uint32_t value
Embedded value for small integer.
Definition pm_integer.h:36
pm_integer_t::values
uint32_t * values
List of 32-bit integers.
Definition pm_integer.h:30
pm_integer_t::negative
bool negative
Whether or not the integer is negative.
Definition pm_integer.h:42
pm_line_column_t
A line and column in a string.
Definition pm_newline_list.h:45
pm_line_column_t::line
int32_t line
The line number.
Definition pm_newline_list.h:47
pm_location_t::start
const uint8_t * start
A pointer to the start location of the range in the source.
Definition ast.h:546
pm_newline_list_t
A list of offsets of newlines in a string.
Definition pm_newline_list.h:28
pm_node_hash_t
An internal hash table for a set of nodes.
Definition static_literals.h:19
pm_node::type
pm_node_type_t type
This represents the type of the node.
Definition ast.h:1057
pm_node::flags
pm_node_flags_t flags
This represents any flags on the node.
Definition ast.h:1063
pm_node::location
pm_location_t location
This is the location of the node in the source.
Definition ast.h:1075
pm_rational_node::base
pm_node_t base
The embedded base node.
Definition ast.h:6967
pm_rational_node::denominator
pm_integer_t denominator
RationalNode::denominator.
Definition ast.h:6986
pm_rational_node::numerator
pm_integer_t numerator
RationalNode::numerator.
Definition ast.h:6977
pm_regular_expression_node::base
pm_node_t base
The embedded base node.
Definition ast.h:7034
pm_regular_expression_node::unescaped
pm_string_t unescaped
RegularExpressionNode::unescaped.
Definition ast.h:7055
pm_static_literals_metadata_t
A small struct used for passing around a subset of the information that is stored on the parser.
Definition static_literals.c:8
pm_static_literals_metadata_t::encoding_name
const char * encoding_name
The name of the encoding that the parser is using.
Definition static_literals.c:16
pm_static_literals_metadata_t::newline_list
const pm_newline_list_t * newline_list
The list of newline offsets to use to calculate line numbers.
Definition static_literals.c:10
pm_static_literals_metadata_t::start_line
int32_t start_line
The line number that the parser starts on.
Definition static_literals.c:13
pm_static_literals_t
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
Definition static_literals.h:38
pm_static_literals_t::string_nodes
pm_node_hash_t string_nodes
This is the set of StringNode and SourceFileNode instances.
Definition static_literals.h:57
pm_static_literals_t::false_node
pm_node_t * false_node
A pointer to the last FalseNode instance that was inserted, or NULL.
Definition static_literals.h:77
pm_static_literals_t::regexp_nodes
pm_node_hash_t regexp_nodes
This is the set of RegularExpressionNode instances.
Definition static_literals.h:62
pm_static_literals_t::source_encoding_node
pm_node_t * source_encoding_node
A pointer to the last SourceEncodingNode instance that was inserted, or NULL.
Definition static_literals.h:88
pm_static_literals_t::nil_node
pm_node_t * nil_node
A pointer to the last NilNode instance that was inserted, or NULL.
Definition static_literals.h:82
pm_static_literals_t::number_nodes
pm_node_hash_t number_nodes
This is the set of RationalNode and ImaginaryNode instances.
Definition static_literals.h:52
pm_static_literals_t::true_node
pm_node_t * true_node
A pointer to the last TrueNode instance that was inserted, or NULL.
Definition static_literals.h:72
pm_static_literals_t::symbol_nodes
pm_node_hash_t symbol_nodes
This is the set of SymbolNode instances.
Definition static_literals.h:67
pm_static_literals_t::float_nodes
pm_node_hash_t float_nodes
This is the set of FloatNode instances.
Definition static_literals.h:47
pm_static_literals_t::integer_nodes
pm_node_hash_t integer_nodes
This is the set of IntegerNode and SourceLineNode instances.
Definition static_literals.h:42
pm_string_t
A generic string type that can have various ownership semantics.
Definition pm_string.h:33