1#include "prism/internal/static_literals.h"
6#include "prism/internal/allocator.h"
7#include "prism/internal/buffer.h"
8#include "prism/internal/integer.h"
9#include "prism/internal/isinf.h"
10#include "prism/internal/stringy.h"
38murmur_scramble(uint32_t value) {
40 value = (value << 15) | (value >> 17);
51murmur_hash(
const uint8_t *key,
size_t length) {
52 uint32_t hash = 0x9747b28c;
55 for (
size_t index = length >> 2; index; index--) {
56 memcpy(&segment, key,
sizeof(uint32_t));
57 key +=
sizeof(uint32_t);
58 hash ^= murmur_scramble(segment);
59 hash = (hash << 13) | (hash >> 19);
60 hash = hash * 5 + 0xe6546b64;
64 for (
size_t index = length & 3; index; index--) {
66 segment |= key[index - 1];
69 hash ^= murmur_scramble(segment);
70 hash ^= (uint32_t) length;
86 hash = murmur_hash((
const uint8_t *) integer->
values,
sizeof(uint32_t) * integer->
length);
88 hash = murmur_hash((
const uint8_t *) &integer->
value,
sizeof(uint32_t));
92 hash ^= murmur_scramble((uint32_t) 1);
108static pm_node_flags_t
110 switch (PM_NODE_TYPE(node)) {
111 case PM_STRING_NODE: {
112 pm_node_flags_t mask = PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
113 if (metadata->
encoding != PM_ENCODING_UTF_8_ENTRY) mask |= PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
114 return node->
flags & mask;
116 case PM_SYMBOL_NODE: {
117 pm_node_flags_t mask = PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
118 if (metadata->
encoding != PM_ENCODING_UTF_8_ENTRY) mask |= PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
119 return node->
flags & mask;
121 case PM_SOURCE_FILE_NODE:
126 assert(
false &&
"unreachable");
138 switch (PM_NODE_TYPE(node)) {
139 case PM_INTEGER_NODE: {
142 return integer_hash(&cast->
value);
144 case PM_SOURCE_LINE_NODE: {
147 const int32_t *value = &line_column.
line;
148 return murmur_hash((
const uint8_t *) value,
sizeof(int32_t));
150 case PM_FLOAT_NODE: {
153 return murmur_hash((
const uint8_t *) value,
sizeof(
double));
155 case PM_RATIONAL_NODE: {
160 case PM_IMAGINARY_NODE: {
165 return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->
type);
167 case PM_STRING_NODE: {
171 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node_encoding_flags(metadata, node));
173 case PM_SOURCE_FILE_NODE: {
177 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t));
179 case PM_REGULAR_EXPRESSION_NODE: {
183 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->
flags);
185 case PM_SYMBOL_NODE: {
189 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node_encoding_flags(metadata, node));
192 assert(
false &&
"unreachable");
207 if (hash->size * 2 >= hash->capacity) {
209 uint32_t new_capacity = hash->capacity == 0 ? 4 : hash->capacity * 2;
211 if (new_nodes == NULL) abort();
217 uint32_t mask = new_capacity - 1;
220 for (uint32_t index = 0; index < hash->capacity; index++) {
224 uint32_t new_index = node_hash(metadata, node) & mask;
225 while (new_nodes[new_index] != NULL) {
226 new_index = (new_index + 1) & mask;
228 new_nodes[new_index] = node;
233 xfree_sized(hash->nodes, hash->capacity *
sizeof(
pm_node_t *));
234 hash->nodes = new_nodes;
235 hash->capacity = new_capacity;
239 uint32_t mask = hash->capacity - 1;
240 uint32_t index = node_hash(metadata, node) & mask;
246 while (hash->nodes[index] != NULL) {
247 if (compare(metadata, hash->nodes[index], node) == 0)
break;
248 index = (index + 1) & mask;
256 if (result == NULL) {
258 hash->nodes[index] = node;
259 }
else if (replace) {
260 hash->nodes[index] = node;
271 if (hash->capacity > 0) xfree_sized(hash->nodes, hash->capacity *
sizeof(
pm_node_t *));
277#define PM_NUMERIC_COMPARISON(left, right) ((left < right) ? -1 : (left > right) ? 1 : 0)
284 switch (PM_NODE_TYPE(node)) {
285 case PM_INTEGER_NODE: {
287 if (integer->
values)
return integer->
negative ? INT64_MIN : INT64_MAX;
289 int64_t value = (int64_t) integer->
value;
290 return integer->
negative ? -value : value;
292 case PM_SOURCE_LINE_NODE:
295 assert(
false &&
"unreachable");
306 if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
307 int64_t left_value = pm_int64_value(metadata, left);
308 int64_t right_value = pm_int64_value(metadata, right);
309 return PM_NUMERIC_COMPARISON(left_value, right_value);
314 return pm_integer_compare(left_integer, right_integer);
324 return PM_NUMERIC_COMPARISON(left_value, right_value);
332 if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
333 return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
336 switch (PM_NODE_TYPE(left)) {
337 case PM_IMAGINARY_NODE:
339 case PM_RATIONAL_NODE: {
344 if (result != 0)
return result;
348 case PM_INTEGER_NODE:
349 return pm_compare_integer_nodes(metadata, left, right);
351 return pm_compare_float_nodes(metadata, left, right);
353 assert(
false &&
"unreachable");
363 switch (PM_NODE_TYPE(node)) {
366 case PM_SOURCE_FILE_NODE:
371 assert(
false &&
"unreachable");
381 const pm_string_t *left_string = pm_string_value(left);
382 const pm_string_t *right_string = pm_string_value(right);
384 int result = pm_string_compare(left_string, right_string);
385 if (result != 0)
return result;
392 pm_node_flags_t left_flags = node_encoding_flags(metadata, left);
393 pm_node_flags_t right_flags = node_encoding_flags(metadata, right);
394 return PM_NUMERIC_COMPARISON(left_flags, right_flags);
406 if (result != 0)
return result;
411#undef PM_NUMERIC_COMPARISON
418 switch (PM_NODE_TYPE(node)) {
419 case PM_INTEGER_NODE:
420 case PM_SOURCE_LINE_NODE:
421 return pm_node_hash_insert(
422 &literals->integer_nodes,
424 .line_offsets = line_offsets,
426 .start_line = start_line,
431 pm_compare_integer_nodes
434 return pm_node_hash_insert(
435 &literals->float_nodes,
437 .line_offsets = line_offsets,
439 .start_line = start_line,
444 pm_compare_float_nodes
446 case PM_RATIONAL_NODE:
447 case PM_IMAGINARY_NODE:
448 return pm_node_hash_insert(
449 &literals->number_nodes,
451 .line_offsets = line_offsets,
453 .start_line = start_line,
458 pm_compare_number_nodes
461 case PM_SOURCE_FILE_NODE:
462 return pm_node_hash_insert(
463 &literals->string_nodes,
465 .line_offsets = line_offsets,
467 .start_line = start_line,
472 pm_compare_string_nodes
474 case PM_REGULAR_EXPRESSION_NODE:
475 return pm_node_hash_insert(
476 &literals->regexp_nodes,
478 .line_offsets = line_offsets,
480 .start_line = start_line,
485 pm_compare_regular_expression_nodes
488 return pm_node_hash_insert(
489 &literals->symbol_nodes,
491 .line_offsets = line_offsets,
493 .start_line = start_line,
498 pm_compare_string_nodes
501 pm_node_t *duplicated = literals->true_node;
502 if ((duplicated == NULL) || replace) literals->true_node = node;
505 case PM_FALSE_NODE: {
506 pm_node_t *duplicated = literals->false_node;
507 if ((duplicated == NULL) || replace) literals->false_node = node;
511 pm_node_t *duplicated = literals->nil_node;
512 if ((duplicated == NULL) || replace) literals->nil_node = node;
515 case PM_SOURCE_ENCODING_NODE: {
516 pm_node_t *duplicated = literals->source_encoding_node;
517 if ((duplicated == NULL) || replace) literals->source_encoding_node = node;
530 pm_node_hash_free(&literals->integer_nodes);
531 pm_node_hash_free(&literals->float_nodes);
532 pm_node_hash_free(&literals->number_nodes);
533 pm_node_hash_free(&literals->string_nodes);
534 pm_node_hash_free(&literals->regexp_nodes);
535 pm_node_hash_free(&literals->symbol_nodes);
543pm_static_literal_positive_p(
const pm_node_t *node) {
544 switch (PM_NODE_TYPE(node)) {
547 case PM_INTEGER_NODE:
549 case PM_RATIONAL_NODE:
551 case PM_IMAGINARY_NODE:
554 assert(
false &&
"unreachable");
564 switch (PM_NODE_TYPE(node)) {
566 pm_buffer_append_string(buffer,
"false", 5);
568 case PM_FLOAT_NODE: {
571 if (PRISM_ISINF(value)) {
573 pm_buffer_append_byte(buffer,
'-');
575 pm_buffer_append_string(buffer,
"Infinity", 8);
576 }
else if (value == 0.0) {
578 pm_buffer_append_byte(buffer,
'-');
580 pm_buffer_append_string(buffer,
"0.0", 3);
582 pm_buffer_append_format(buffer,
"%g", value);
587 if (pm_buffer_index(buffer,
'.') == SIZE_MAX) {
588 size_t exponent_index = pm_buffer_index(buffer,
'e');
589 size_t index = exponent_index == SIZE_MAX ? pm_buffer_length(buffer) : exponent_index;
590 pm_buffer_insert(buffer, index,
".0", 2);
596 case PM_IMAGINARY_NODE: {
598 pm_buffer_append_string(buffer,
"(0", 2);
599 if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer,
'+');
600 pm_static_literal_inspect_node(buffer, metadata, numeric);
601 if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) {
602 pm_buffer_append_byte(buffer,
'*');
604 pm_buffer_append_string(buffer,
"i)", 2);
607 case PM_INTEGER_NODE:
611 pm_buffer_append_string(buffer,
"nil", 3);
613 case PM_RATIONAL_NODE: {
615 pm_buffer_append_byte(buffer,
'(');
616 pm_integer_string(buffer, &rational->
numerator);
617 pm_buffer_append_byte(buffer,
'/');
619 pm_buffer_append_byte(buffer,
')');
622 case PM_REGULAR_EXPRESSION_NODE: {
624 pm_buffer_append_byte(buffer,
'/');
625 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
626 pm_buffer_append_byte(buffer,
'/');
628 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) pm_buffer_append_string(buffer,
"m", 1);
629 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) pm_buffer_append_string(buffer,
"i", 1);
630 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) pm_buffer_append_string(buffer,
"x", 1);
631 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) pm_buffer_append_string(buffer,
"n", 1);
635 case PM_SOURCE_ENCODING_NODE:
636 pm_buffer_append_format(buffer,
"#<Encoding:%s>", metadata->
encoding->name);
638 case PM_SOURCE_FILE_NODE: {
640 pm_buffer_append_byte(buffer,
'"');
641 pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_RUBY);
642 pm_buffer_append_byte(buffer,
'"');
645 case PM_SOURCE_LINE_NODE:
648 case PM_STRING_NODE: {
650 pm_buffer_append_byte(buffer,
'"');
651 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
652 pm_buffer_append_byte(buffer,
'"');
655 case PM_SYMBOL_NODE: {
657 pm_buffer_append_byte(buffer,
':');
658 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
662 pm_buffer_append_string(buffer,
"true", 4);
665 assert(
false &&
"unreachable");
675 pm_static_literal_inspect_node(
678 .line_offsets = line_offsets,
680 .start_line = start_line,
#define xcalloc
Old name of ruby_xcalloc.
#define PRISM_INLINE
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
pm_integer_t value
IntegerNode::value.
A structure represents an arbitrary-sized integer.
size_t length
The number of allocated values.
uint32_t value
Embedded value for small integer.
uint32_t * values
List of 32-bit integers.
bool negative
Whether or not the integer is negative.
A line and column in a string.
int32_t line
The line number.
A list of offsets of the start of lines in a string.
uint32_t start
The offset of the location from the start of the source.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_node_flags_t flags
This represents any flags on the node.
pm_location_t location
This is the location of the node in the source.
pm_node_t base
The embedded base node.
pm_integer_t denominator
RationalNode::denominator.
pm_integer_t numerator
RationalNode::numerator.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
A generic string type that can have various ownership semantics.
#define PRISM_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.