Ruby 3.5.0dev (2025-01-11 revision 76b620b341b54eb80028f03cc828333defacc87e)
static_literals.c
2
8typedef struct {
11
13 int32_t start_line;
14
16 const char *encoding_name;
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 }
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;
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 }
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 }
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) {
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)) {
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;
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:
360 return pm_node_hash_insert(
361 &literals->integer_nodes,
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,
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:
385 return pm_node_hash_insert(
386 &literals->number_nodes,
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:
398 return pm_node_hash_insert(
399 &literals->string_nodes,
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 );
410 return pm_node_hash_insert(
411 &literals->regexp_nodes,
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,
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 }
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;
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 }
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 }
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 }
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,
611 .newline_list = newline_list,
612 .start_line = start_line,
613 .encoding_name = encoding_name
614 },
615 node
616 );
617}
@ PM_SOURCE_LINE_NODE
SourceLineNode.
Definition ast.h:985
@ PM_NIL_NODE
NilNode.
Definition ast.h:895
@ PM_RATIONAL_NODE
RationalNode.
Definition ast.h:940
@ PM_FALSE_NODE
FalseNode.
Definition ast.h:724
@ PM_SOURCE_FILE_NODE
SourceFileNode.
Definition ast.h:982
@ PM_SYMBOL_NODE
SymbolNode.
Definition ast.h:1000
@ PM_TRUE_NODE
TrueNode.
Definition ast.h:1003
@ PM_REGULAR_EXPRESSION_NODE
RegularExpressionNode.
Definition ast.h:946
@ PM_IMAGINARY_NODE
ImaginaryNode.
Definition ast.h:775
@ PM_SOURCE_ENCODING_NODE
SourceEncodingNode.
Definition ast.h:979
@ PM_FLOAT_NODE
FloatNode.
Definition ast.h:733
@ PM_INTEGER_NODE
IntegerNode.
Definition ast.h:817
@ PM_STRING_NODE
StringNode.
Definition ast.h:994
@ PM_STRING_FLAGS_FORCED_BINARY_ENCODING
internal bytes forced the encoding to binary
Definition ast.h:7917
@ PM_STRING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
Definition ast.h:7914
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
Definition ast.h:1063
#define PM_NODE_TYPE_P(node, type)
Return true if the type of the given node matches the given type.
Definition ast.h:1058
#define PM_NODE_TYPE(node)
Cast the type to an enum to allow the compiler to provide exhaustiveness checking.
Definition ast.h:1053
@ PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE
i - ignores the case of characters when matching
Definition ast.h:7862
@ PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT
n - forces the ASCII-8BIT encoding
Definition ast.h:7877
@ PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE
m - allows $ to match the end of lines within strings
Definition ast.h:7868
@ PM_REGULAR_EXPRESSION_FLAGS_EXTENDED
x - ignores whitespace and allows comments in regular expressions
Definition ast.h:7865
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
Definition ast.h:1040
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
Definition defines.h:81
#define PRISM_ISINF(x)
isinf on POSIX systems it accepts a float, a double, or a long double.
Definition defines.h:151
A set of static literal nodes that can be checked for duplicates.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
Definition pm_buffer.h:22
FloatNode.
Definition ast.h:3849
ImaginaryNode.
Definition ast.h:4468
IntegerNode.
Definition ast.h:5078
pm_integer_t value
IntegerNode::value.
Definition ast.h:5088
A structure represents an arbitrary-sized integer.
Definition pm_integer.h:20
size_t length
The number of allocated values.
Definition pm_integer.h:25
uint32_t value
Embedded value for small integer.
Definition pm_integer.h:36
uint32_t * values
List of 32-bit integers.
Definition pm_integer.h:30
bool negative
Whether or not the integer is negative.
Definition pm_integer.h:42
A line and column in a string.
int32_t line
The line number.
const uint8_t * start
A pointer to the start location of the range in the source.
Definition ast.h:547
A list of offsets of newlines in a string.
An internal hash table for a set of nodes.
pm_node_t ** nodes
The array of nodes in the hash table.
uint32_t size
The size of the hash table.
uint32_t capacity
The space that has been allocated in the hash table.
This is the base structure that represents a node in the syntax tree.
Definition ast.h:1069
pm_node_type_t type
This represents the type of the node.
Definition ast.h:1074
pm_node_flags_t flags
This represents any flags on the node.
Definition ast.h:1080
pm_location_t location
This is the location of the node in the source.
Definition ast.h:1092
RationalNode.
Definition ast.h:6711
pm_node_t base
The embedded base node.
Definition ast.h:6713
pm_integer_t denominator
RationalNode::denominator.
Definition ast.h:6732
pm_integer_t numerator
RationalNode::numerator.
Definition ast.h:6723
RegularExpressionNode.
Definition ast.h:6778
pm_node_t base
The embedded base node.
Definition ast.h:6780
pm_string_t unescaped
RegularExpressionNode::unescaped.
Definition ast.h:6801
SourceFileNode.
Definition ast.h:7165
A small struct used for passing around a subset of the information that is stored on the parser.
const char * encoding_name
The name of the encoding that the parser is using.
const pm_newline_list_t * newline_list
The list of newline offsets to use to calculate line numbers.
int32_t start_line
The line number that the parser starts on.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_hash_t string_nodes
This is the set of StringNode and SourceFileNode instances.
pm_node_t * false_node
A pointer to the last FalseNode instance that was inserted, or NULL.
pm_node_hash_t regexp_nodes
This is the set of RegularExpressionNode instances.
pm_node_t * source_encoding_node
A pointer to the last SourceEncodingNode instance that was inserted, or NULL.
pm_node_t * nil_node
A pointer to the last NilNode instance that was inserted, or NULL.
pm_node_hash_t number_nodes
This is the set of RationalNode and ImaginaryNode instances.
pm_node_t * true_node
A pointer to the last TrueNode instance that was inserted, or NULL.
pm_node_hash_t symbol_nodes
This is the set of SymbolNode instances.
pm_node_hash_t float_nodes
This is the set of FloatNode instances.
pm_node_hash_t integer_nodes
This is the set of IntegerNode and SourceLineNode instances.
StringNode.
Definition ast.h:7271
A generic string type that can have various ownership semantics.
Definition pm_string.h:33
SymbolNode.
Definition ast.h:7363