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"
37murmur_scramble(uint32_t value) {
39 value = (value << 15) | (value >> 17);
50murmur_hash(
const uint8_t *key,
size_t length) {
51 uint32_t hash = 0x9747b28c;
54 for (
size_t index = length >> 2; index; index--) {
55 memcpy(&segment, key,
sizeof(uint32_t));
56 key +=
sizeof(uint32_t);
57 hash ^= murmur_scramble(segment);
58 hash = (hash << 13) | (hash >> 19);
59 hash = hash * 5 + 0xe6546b64;
63 for (
size_t index = length & 3; index; index--) {
65 segment |= key[index - 1];
68 hash ^= murmur_scramble(segment);
69 hash ^= (uint32_t) length;
85 hash = murmur_hash((
const uint8_t *) integer->
values,
sizeof(uint32_t) * integer->
length);
87 hash = murmur_hash((
const uint8_t *) &integer->
value,
sizeof(uint32_t));
91 hash ^= murmur_scramble((uint32_t) 1);
104 switch (PM_NODE_TYPE(node)) {
105 case PM_INTEGER_NODE: {
108 return integer_hash(&cast->
value);
110 case PM_SOURCE_LINE_NODE: {
113 const int32_t *value = &line_column.
line;
114 return murmur_hash((
const uint8_t *) value,
sizeof(int32_t));
116 case PM_FLOAT_NODE: {
119 return murmur_hash((
const uint8_t *) value,
sizeof(
double));
121 case PM_RATIONAL_NODE: {
126 case PM_IMAGINARY_NODE: {
131 return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->
type);
133 case PM_STRING_NODE: {
138 pm_node_flags_t flags = node->
flags;
139 flags &= (PM_STRING_FLAGS_FORCED_BINARY_ENCODING | PM_STRING_FLAGS_FORCED_UTF8_ENCODING);
141 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t)) ^ murmur_scramble((uint32_t) flags);
143 case PM_SOURCE_FILE_NODE: {
147 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t));
149 case PM_REGULAR_EXPRESSION_NODE: {
153 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->
flags);
155 case PM_SYMBOL_NODE: {
159 return murmur_hash(pm_string_source(value), pm_string_length(value) *
sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->
flags);
162 assert(
false &&
"unreachable");
177 if (hash->size * 2 >= hash->capacity) {
179 uint32_t new_capacity = hash->capacity == 0 ? 4 : hash->capacity * 2;
181 if (new_nodes == NULL)
return NULL;
187 uint32_t mask = new_capacity - 1;
190 for (uint32_t index = 0; index < hash->capacity; index++) {
194 uint32_t index = node_hash(metadata, node) & mask;
195 new_nodes[index] = node;
200 xfree_sized(hash->nodes, hash->capacity *
sizeof(
pm_node_t *));
201 hash->nodes = new_nodes;
202 hash->capacity = new_capacity;
206 uint32_t mask = hash->capacity - 1;
207 uint32_t index = node_hash(metadata, node) & mask;
213 while (hash->nodes[index] != NULL) {
214 if (compare(metadata, hash->nodes[index], node) == 0)
break;
215 index = (index + 1) & mask;
223 if (result == NULL) {
225 hash->nodes[index] = node;
226 }
else if (replace) {
227 hash->nodes[index] = node;
238 if (hash->capacity > 0) xfree_sized(hash->nodes, hash->capacity *
sizeof(
pm_node_t *));
244#define PM_NUMERIC_COMPARISON(left, right) ((left < right) ? -1 : (left > right) ? 1 : 0)
251 switch (PM_NODE_TYPE(node)) {
252 case PM_INTEGER_NODE: {
254 if (integer->
values)
return integer->
negative ? INT64_MIN : INT64_MAX;
256 int64_t value = (int64_t) integer->
value;
257 return integer->
negative ? -value : value;
259 case PM_SOURCE_LINE_NODE:
262 assert(
false &&
"unreachable");
273 if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
274 int64_t left_value = pm_int64_value(metadata, left);
275 int64_t right_value = pm_int64_value(metadata, right);
276 return PM_NUMERIC_COMPARISON(left_value, right_value);
281 return pm_integer_compare(left_integer, right_integer);
291 return PM_NUMERIC_COMPARISON(left_value, right_value);
299 if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
300 return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
303 switch (PM_NODE_TYPE(left)) {
304 case PM_IMAGINARY_NODE:
306 case PM_RATIONAL_NODE: {
311 if (result != 0)
return result;
315 case PM_INTEGER_NODE:
316 return pm_compare_integer_nodes(metadata, left, right);
318 return pm_compare_float_nodes(metadata, left, right);
320 assert(
false &&
"unreachable");
330 switch (PM_NODE_TYPE(node)) {
333 case PM_SOURCE_FILE_NODE:
338 assert(
false &&
"unreachable");
348 const pm_string_t *left_string = pm_string_value(left);
349 const pm_string_t *right_string = pm_string_value(right);
350 return pm_string_compare(left_string, right_string);
362 if (result != 0)
return result;
367#undef PM_NUMERIC_COMPARISON
374 switch (PM_NODE_TYPE(node)) {
375 case PM_INTEGER_NODE:
376 case PM_SOURCE_LINE_NODE:
377 return pm_node_hash_insert(
378 &literals->integer_nodes,
380 .line_offsets = line_offsets,
382 .start_line = start_line,
383 .encoding_name = NULL
387 pm_compare_integer_nodes
390 return pm_node_hash_insert(
391 &literals->float_nodes,
393 .line_offsets = line_offsets,
395 .start_line = start_line,
396 .encoding_name = NULL
400 pm_compare_float_nodes
402 case PM_RATIONAL_NODE:
403 case PM_IMAGINARY_NODE:
404 return pm_node_hash_insert(
405 &literals->number_nodes,
407 .line_offsets = line_offsets,
409 .start_line = start_line,
410 .encoding_name = NULL
414 pm_compare_number_nodes
417 case PM_SOURCE_FILE_NODE:
418 return pm_node_hash_insert(
419 &literals->string_nodes,
421 .line_offsets = line_offsets,
423 .start_line = start_line,
424 .encoding_name = NULL
428 pm_compare_string_nodes
430 case PM_REGULAR_EXPRESSION_NODE:
431 return pm_node_hash_insert(
432 &literals->regexp_nodes,
434 .line_offsets = line_offsets,
436 .start_line = start_line,
437 .encoding_name = NULL
441 pm_compare_regular_expression_nodes
444 return pm_node_hash_insert(
445 &literals->symbol_nodes,
447 .line_offsets = line_offsets,
449 .start_line = start_line,
450 .encoding_name = NULL
454 pm_compare_string_nodes
457 pm_node_t *duplicated = literals->true_node;
458 if ((duplicated == NULL) || replace) literals->true_node = node;
461 case PM_FALSE_NODE: {
462 pm_node_t *duplicated = literals->false_node;
463 if ((duplicated == NULL) || replace) literals->false_node = node;
467 pm_node_t *duplicated = literals->nil_node;
468 if ((duplicated == NULL) || replace) literals->nil_node = node;
471 case PM_SOURCE_ENCODING_NODE: {
472 pm_node_t *duplicated = literals->source_encoding_node;
473 if ((duplicated == NULL) || replace) literals->source_encoding_node = node;
486 pm_node_hash_free(&literals->integer_nodes);
487 pm_node_hash_free(&literals->float_nodes);
488 pm_node_hash_free(&literals->number_nodes);
489 pm_node_hash_free(&literals->string_nodes);
490 pm_node_hash_free(&literals->regexp_nodes);
491 pm_node_hash_free(&literals->symbol_nodes);
499pm_static_literal_positive_p(
const pm_node_t *node) {
500 switch (PM_NODE_TYPE(node)) {
503 case PM_INTEGER_NODE:
505 case PM_RATIONAL_NODE:
507 case PM_IMAGINARY_NODE:
510 assert(
false &&
"unreachable");
520 switch (PM_NODE_TYPE(node)) {
522 pm_buffer_append_string(buffer,
"false", 5);
524 case PM_FLOAT_NODE: {
527 if (PRISM_ISINF(value)) {
529 pm_buffer_append_byte(buffer,
'-');
531 pm_buffer_append_string(buffer,
"Infinity", 8);
532 }
else if (value == 0.0) {
534 pm_buffer_append_byte(buffer,
'-');
536 pm_buffer_append_string(buffer,
"0.0", 3);
538 pm_buffer_append_format(buffer,
"%g", value);
543 if (pm_buffer_index(buffer,
'.') == SIZE_MAX) {
544 size_t exponent_index = pm_buffer_index(buffer,
'e');
545 size_t index = exponent_index == SIZE_MAX ? pm_buffer_length(buffer) : exponent_index;
546 pm_buffer_insert(buffer, index,
".0", 2);
552 case PM_IMAGINARY_NODE: {
554 pm_buffer_append_string(buffer,
"(0", 2);
555 if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer,
'+');
556 pm_static_literal_inspect_node(buffer, metadata, numeric);
557 if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) {
558 pm_buffer_append_byte(buffer,
'*');
560 pm_buffer_append_string(buffer,
"i)", 2);
563 case PM_INTEGER_NODE:
567 pm_buffer_append_string(buffer,
"nil", 3);
569 case PM_RATIONAL_NODE: {
571 pm_buffer_append_byte(buffer,
'(');
572 pm_integer_string(buffer, &rational->
numerator);
573 pm_buffer_append_byte(buffer,
'/');
575 pm_buffer_append_byte(buffer,
')');
578 case PM_REGULAR_EXPRESSION_NODE: {
580 pm_buffer_append_byte(buffer,
'/');
581 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
582 pm_buffer_append_byte(buffer,
'/');
584 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) pm_buffer_append_string(buffer,
"m", 1);
585 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) pm_buffer_append_string(buffer,
"i", 1);
586 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) pm_buffer_append_string(buffer,
"x", 1);
587 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) pm_buffer_append_string(buffer,
"n", 1);
591 case PM_SOURCE_ENCODING_NODE:
592 pm_buffer_append_format(buffer,
"#<Encoding:%s>", metadata->
encoding_name);
594 case PM_SOURCE_FILE_NODE: {
596 pm_buffer_append_byte(buffer,
'"');
597 pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_RUBY);
598 pm_buffer_append_byte(buffer,
'"');
601 case PM_SOURCE_LINE_NODE:
604 case PM_STRING_NODE: {
606 pm_buffer_append_byte(buffer,
'"');
607 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
608 pm_buffer_append_byte(buffer,
'"');
611 case PM_SYMBOL_NODE: {
613 pm_buffer_append_byte(buffer,
':');
614 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
618 pm_buffer_append_string(buffer,
"true", 4);
621 assert(
false &&
"unreachable");
631 pm_static_literal_inspect_node(
634 .line_offsets = line_offsets,
636 .start_line = start_line,
637 .encoding_name = encoding_name
#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.