23murmur_scramble(uint32_t value) {
25 value = (value << 15) | (value >> 17);
36murmur_hash(
const uint8_t *key,
size_t length) {
37 uint32_t hash = 0x9747b28c;
40 for (
size_t index = length >> 2; index; index--) {
41 memcpy(&segment, key,
sizeof(uint32_t));
42 key +=
sizeof(uint32_t);
43 hash ^= murmur_scramble(segment);
44 hash = (hash << 13) | (hash >> 19);
45 hash = hash * 5 + 0xe6546b64;
49 for (
size_t index = length & 3; index; index--) {
51 segment |= key[index - 1];
54 hash ^= murmur_scramble(segment);
55 hash ^= (uint32_t) length;
71 hash = murmur_hash((
const uint8_t *) integer->
values,
sizeof(uint32_t) * integer->
length);
73 hash = murmur_hash((
const uint8_t *) &integer->
value,
sizeof(uint32_t));
77 hash ^= murmur_scramble((uint32_t) 1);
90 switch (PM_NODE_TYPE(node)) {
91 case PM_INTEGER_NODE: {
94 return integer_hash(&cast->
value);
96 case PM_SOURCE_LINE_NODE: {
99 const int32_t *value = &line_column.
line;
100 return murmur_hash((
const uint8_t *) value,
sizeof(int32_t));
102 case PM_FLOAT_NODE: {
105 return murmur_hash((
const uint8_t *) value,
sizeof(
double));
107 case PM_RATIONAL_NODE: {
112 case PM_IMAGINARY_NODE: {
117 return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->
type);
119 case PM_STRING_NODE: {
124 pm_node_flags_t flags = node->
flags;
125 flags &= (PM_STRING_FLAGS_FORCED_BINARY_ENCODING | PM_STRING_FLAGS_FORCED_UTF8_ENCODING);
129 case PM_SOURCE_FILE_NODE: {
135 case PM_REGULAR_EXPRESSION_NODE: {
141 case PM_SYMBOL_NODE: {
148 assert(
false &&
"unreachable");
167 if (new_nodes == NULL)
return NULL;
173 uint32_t mask = new_capacity - 1;
176 for (uint32_t index = 0; index < hash->
capacity; index++) {
180 uint32_t index = node_hash(metadata, node) & mask;
181 new_nodes[index] = node;
187 hash->
nodes = new_nodes;
193 uint32_t index = node_hash(metadata, node) & mask;
199 while (hash->
nodes[index] != NULL) {
200 if (compare(metadata, hash->
nodes[index], node) == 0)
break;
201 index = (index + 1) & mask;
209 if (result == NULL) {
211 hash->
nodes[index] = node;
212 }
else if (replace) {
213 hash->
nodes[index] = node;
230#define PM_NUMERIC_COMPARISON(left, right) ((left < right) ? -1 : (left > right) ? 1 : 0)
237 switch (PM_NODE_TYPE(node)) {
238 case PM_INTEGER_NODE: {
240 if (integer->
values)
return integer->
negative ? INT64_MIN : INT64_MAX;
242 int64_t value = (int64_t) integer->
value;
243 return integer->
negative ? -value : value;
245 case PM_SOURCE_LINE_NODE:
248 assert(
false &&
"unreachable");
259 if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
260 int64_t left_value = pm_int64_value(metadata, left);
261 int64_t right_value = pm_int64_value(metadata, right);
262 return PM_NUMERIC_COMPARISON(left_value, right_value);
267 return pm_integer_compare(left_integer, right_integer);
277 return PM_NUMERIC_COMPARISON(left_value, right_value);
285 if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
286 return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
289 switch (PM_NODE_TYPE(left)) {
290 case PM_IMAGINARY_NODE:
292 case PM_RATIONAL_NODE: {
297 if (result != 0)
return result;
301 case PM_INTEGER_NODE:
302 return pm_compare_integer_nodes(metadata, left, right);
304 return pm_compare_float_nodes(metadata, left, right);
306 assert(
false &&
"unreachable");
316 switch (PM_NODE_TYPE(node)) {
319 case PM_SOURCE_FILE_NODE:
324 assert(
false &&
"unreachable");
334 const pm_string_t *left_string = pm_string_value(left);
335 const pm_string_t *right_string = pm_string_value(right);
336 return pm_string_compare(left_string, right_string);
348 if (result != 0)
return result;
353#undef PM_NUMERIC_COMPARISON
360 switch (PM_NODE_TYPE(node)) {
361 case PM_INTEGER_NODE:
362 case PM_SOURCE_LINE_NODE:
363 return pm_node_hash_insert(
366 .line_offsets = line_offsets,
368 .start_line = start_line,
369 .encoding_name = NULL
373 pm_compare_integer_nodes
376 return pm_node_hash_insert(
379 .line_offsets = line_offsets,
381 .start_line = start_line,
382 .encoding_name = NULL
386 pm_compare_float_nodes
388 case PM_RATIONAL_NODE:
389 case PM_IMAGINARY_NODE:
390 return pm_node_hash_insert(
393 .line_offsets = line_offsets,
395 .start_line = start_line,
396 .encoding_name = NULL
400 pm_compare_number_nodes
403 case PM_SOURCE_FILE_NODE:
404 return pm_node_hash_insert(
407 .line_offsets = line_offsets,
409 .start_line = start_line,
410 .encoding_name = NULL
414 pm_compare_string_nodes
416 case PM_REGULAR_EXPRESSION_NODE:
417 return pm_node_hash_insert(
420 .line_offsets = line_offsets,
422 .start_line = start_line,
423 .encoding_name = NULL
427 pm_compare_regular_expression_nodes
430 return pm_node_hash_insert(
433 .line_offsets = line_offsets,
435 .start_line = start_line,
436 .encoding_name = NULL
440 pm_compare_string_nodes
444 if ((duplicated == NULL) || replace) literals->
true_node = node;
447 case PM_FALSE_NODE: {
449 if ((duplicated == NULL) || replace) literals->
false_node = node;
454 if ((duplicated == NULL) || replace) literals->
nil_node = node;
457 case PM_SOURCE_ENCODING_NODE: {
485pm_static_literal_positive_p(
const pm_node_t *node) {
486 switch (PM_NODE_TYPE(node)) {
489 case PM_INTEGER_NODE:
491 case PM_RATIONAL_NODE:
493 case PM_IMAGINARY_NODE:
496 assert(
false &&
"unreachable");
506 switch (PM_NODE_TYPE(node)) {
508 pm_buffer_append_string(buffer,
"false", 5);
510 case PM_FLOAT_NODE: {
515 pm_buffer_append_byte(buffer,
'-');
517 pm_buffer_append_string(buffer,
"Infinity", 8);
518 }
else if (value == 0.0) {
520 pm_buffer_append_byte(buffer,
'-');
522 pm_buffer_append_string(buffer,
"0.0", 3);
524 pm_buffer_append_format(buffer,
"%g", value);
529 if (pm_buffer_index(buffer,
'.') == SIZE_MAX) {
530 size_t exponent_index = pm_buffer_index(buffer,
'e');
531 size_t index = exponent_index == SIZE_MAX ?
pm_buffer_length(buffer) : exponent_index;
532 pm_buffer_insert(buffer, index,
".0", 2);
538 case PM_IMAGINARY_NODE: {
540 pm_buffer_append_string(buffer,
"(0", 2);
541 if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer,
'+');
542 pm_static_literal_inspect_node(buffer, metadata, numeric);
543 if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) {
544 pm_buffer_append_byte(buffer,
'*');
546 pm_buffer_append_string(buffer,
"i)", 2);
549 case PM_INTEGER_NODE:
553 pm_buffer_append_string(buffer,
"nil", 3);
555 case PM_RATIONAL_NODE: {
557 pm_buffer_append_byte(buffer,
'(');
559 pm_buffer_append_byte(buffer,
'/');
561 pm_buffer_append_byte(buffer,
')');
564 case PM_REGULAR_EXPRESSION_NODE: {
566 pm_buffer_append_byte(buffer,
'/');
568 pm_buffer_append_byte(buffer,
'/');
570 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) pm_buffer_append_string(buffer,
"m", 1);
571 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) pm_buffer_append_string(buffer,
"i", 1);
572 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) pm_buffer_append_string(buffer,
"x", 1);
573 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) pm_buffer_append_string(buffer,
"n", 1);
577 case PM_SOURCE_ENCODING_NODE:
578 pm_buffer_append_format(buffer,
"#<Encoding:%s>", metadata->
encoding_name);
580 case PM_SOURCE_FILE_NODE: {
582 pm_buffer_append_byte(buffer,
'"');
584 pm_buffer_append_byte(buffer,
'"');
587 case PM_SOURCE_LINE_NODE:
590 case PM_STRING_NODE: {
592 pm_buffer_append_byte(buffer,
'"');
594 pm_buffer_append_byte(buffer,
'"');
597 case PM_SYMBOL_NODE: {
599 pm_buffer_append_byte(buffer,
':');
604 pm_buffer_append_string(buffer,
"true", 4);
607 assert(
false &&
"unreachable");
617 pm_static_literal_inspect_node(
620 .line_offsets = line_offsets,
622 .start_line = start_line,
623 .encoding_name = encoding_name
#define xcalloc
Old name of ruby_xcalloc.
size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
PRISM_EXPORTED_FUNCTION void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer)
Convert an integer to a decimal string.
PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string)
Returns the length associated with the string.
PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string)
Returns the start pointer associated with the string.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_ISINF(x)
isinf on POSIX systems it accepts a float, a double, or a long double.
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.
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.
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.
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.
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.
A generic string type that can have various ownership semantics.