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/oom.h"
11#include "prism/internal/parser.h"
12#include "prism/internal/stringy.h"
13#include "prism/internal/xxh3.h"
29key_hash(uint64_t
type, uint64_t a, uint64_t b) {
30 const uint64_t key[3] = {
type, a, b };
31 return pm_xxh3((
const uint8_t *) key,
sizeof(key));
41 uint64_t magnitude = integer->
values ? pm_xxh3((
const uint8_t *) integer->
values,
sizeof(uint32_t) * integer->
length) : integer->value;
42 return key_hash(PM_INTEGER_NODE, integer->
negative, magnitude);
52 switch (PM_NODE_TYPE(node)) {
55 case PM_SOURCE_LINE_NODE: {
56 int64_t line = (int64_t) pm_line_offset_list_line_column(&parser->line_offsets, node->
location.
start, parser->start_line).
line;
57 return key_hash(PM_INTEGER_NODE, line < 0, (uint64_t) (line < 0 ? -line : line));
61 double value =
cast->value;
62 if (value == 0.0) value = 0.0;
65 memcpy(&bits, &value,
sizeof(bits));
66 return key_hash(PM_FLOAT_NODE, bits, 0);
68 case PM_RATIONAL_NODE: {
70 return key_hash(PM_RATIONAL_NODE, integer_hash(&
cast->numerator), integer_hash(&
cast->denominator));
72 case PM_IMAGINARY_NODE: {
74 return key_hash(PM_IMAGINARY_NODE, node_hash(parser,
cast->numeric), 0);
76 case PM_STRING_NODE: {
79 pm_node_flags_t mask = PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
80 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) mask |= PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
82 return key_hash(PM_STRING_NODE, pm_xxh3(pm_string_source(&
cast->unescaped), pm_string_length(&
cast->unescaped)), node->
flags & mask);
84 case PM_SOURCE_FILE_NODE: {
86 return key_hash(PM_STRING_NODE, pm_xxh3(pm_string_source(&
cast->filepath), pm_string_length(&
cast->filepath)), 0);
88 case PM_REGULAR_EXPRESSION_NODE: {
90 return key_hash(PM_REGULAR_EXPRESSION_NODE, pm_xxh3(pm_string_source(&
cast->unescaped), pm_string_length(&
cast->unescaped)), node->
flags & (pm_node_flags_t) ~PM_REGULAR_EXPRESSION_FLAGS_ONCE);
92 case PM_SYMBOL_NODE: {
95 pm_node_flags_t mask = PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
96 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) mask |= PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
98 return key_hash(PM_SYMBOL_NODE, pm_xxh3(pm_string_source(&
cast->unescaped), pm_string_length(&
cast->unescaped)), node->
flags & mask);
102 case PM_SOURCE_ENCODING_NODE:
104 return key_hash(PM_NODE_TYPE(node), 0, 0);
106 assert(
false &&
"unreachable");
114#define COMPARE(left_, right_) (((left_) < (right_)) ? -1 : ((left_) > (right_)) ? 1 : 0)
121 switch (PM_NODE_TYPE(node)) {
122 case PM_INTEGER_NODE: {
124 if (integer->
values)
return integer->
negative ? INT64_MIN : INT64_MAX;
126 int64_t value = (int64_t) integer->
value;
127 return integer->
negative ? -value : value;
129 case PM_SOURCE_LINE_NODE:
130 return (int64_t) pm_line_offset_list_line_column(&parser->line_offsets, node->
location.
start, parser->start_line).
line;
132 assert(
false &&
"unreachable");
143 if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
144 return COMPARE(int64_value(parser, left), int64_value(parser, right));
149 return pm_integer_compare(left_integer, right_integer);
165 switch (PM_NODE_TYPE(node)) {
168 case PM_SOURCE_FILE_NODE:
173 assert(
false &&
"unreachable");
191compare_string_nodes(
const pm_node_t *left,
const pm_node_t *right, pm_node_flags_t mask) {
192 const pm_string_t *left_string = string_value(left);
193 const pm_string_t *right_string = string_value(right);
195 int result = pm_string_compare(left_string, right_string);
196 if (result != 0)
return result;
203 return COMPARE(left->
flags & mask, right->
flags & mask);
217 if (result != 0)
return result;
219 pm_node_flags_t mask = (pm_node_flags_t) ~PM_REGULAR_EXPRESSION_FLAGS_ONCE;
220 return COMPARE(left->
flags & mask, right->
flags & mask);
228static enum pm_node_type
229static_literal_type(
const pm_node_t *node) {
230 switch (PM_NODE_TYPE(node)) {
231 case PM_SOURCE_LINE_NODE:
232 return PM_INTEGER_NODE;
233 case PM_SOURCE_FILE_NODE:
234 return PM_STRING_NODE;
236 return PM_NODE_TYPE(node);
246 enum pm_node_type left_type = static_literal_type(left);
247 enum pm_node_type right_type = static_literal_type(right);
248 if (left_type != right_type)
return COMPARE(left_type, right_type);
251 case PM_INTEGER_NODE:
252 return compare_integer_nodes(parser, left, right);
254 return compare_float_nodes(parser, left, right);
255 case PM_IMAGINARY_NODE:
257 case PM_RATIONAL_NODE: {
262 if (result != 0)
return result;
266 case PM_STRING_NODE: {
267 pm_node_flags_t mask = PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
268 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) mask |= PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
269 return compare_string_nodes(left, right, mask);
271 case PM_SYMBOL_NODE: {
272 pm_node_flags_t mask = PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
273 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) mask |= PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
274 return compare_string_nodes(left, right, mask);
276 case PM_REGULAR_EXPRESSION_NODE:
277 return compare_regular_expression_nodes(parser, left, right);
280 case PM_SOURCE_ENCODING_NODE:
284 assert(
false &&
"unreachable");
297 uint32_t index = (uint32_t) (entry.hash & mask);
298 while (entries[index].node != NULL) {
299 index = (index + 1) & mask;
301 entries[index] = entry;
312 if (entries == NULL) PRISM_OOM();
317 uint32_t mask = capacity - 1;
319 if (literals->capacity == 0) {
320 for (uint32_t index = 0; index < literals->size; index++) {
321 pm_node_t *node = literals->nodes[index];
325 for (uint32_t index = 0; index < literals->capacity; index++) {
326 if (literals->entries[index].node != NULL) {
327 pm_static_literals_place(entries, mask, literals->entries[index]);
334 literals->entries = entries;
335 literals->capacity = capacity;
346 switch (PM_NODE_TYPE(node)) {
349 case PM_IMAGINARY_NODE:
350 case PM_INTEGER_NODE:
352 case PM_RATIONAL_NODE:
353 case PM_REGULAR_EXPRESSION_NODE:
354 case PM_SOURCE_ENCODING_NODE:
355 case PM_SOURCE_FILE_NODE:
356 case PM_SOURCE_LINE_NODE:
365 if (literals->capacity == 0) {
369 for (uint32_t index = 0; index < literals->size; index++) {
370 pm_node_t *existing = literals->nodes[index];
372 if (compare_nodes(parser, existing, node) == 0) {
373 if (replace) literals->nodes[index] = node;
378 if (literals->size < PM_STATIC_LITERALS_INLINE_CAPACITY) {
379 literals->nodes[literals->size++] = node;
386 pm_static_literals_resize(parser, literals, PM_STATIC_LITERALS_INLINE_CAPACITY * 4);
387 }
else if (literals->size * 2 >= literals->capacity) {
389 pm_static_literals_resize(parser, literals, literals->capacity * 2);
392 uint64_t hash = node_hash(parser, node);
393 uint32_t mask = literals->capacity - 1;
394 uint32_t index = (uint32_t) (hash & mask);
401 while (literals->entries[index].node != NULL) {
403 if (entry->hash == hash && compare_nodes(parser, entry->node, node) == 0)
break;
404 index = (index + 1) & mask;
410 pm_node_t *result = literals->entries[index].node;
412 if (result == NULL) {
415 }
else if (replace) {
416 literals->entries[index].node = node;
435pm_static_literal_positive_p(
const pm_node_t *node) {
436 switch (PM_NODE_TYPE(node)) {
439 case PM_INTEGER_NODE:
441 case PM_RATIONAL_NODE:
443 case PM_IMAGINARY_NODE:
446 assert(
false &&
"unreachable");
456 switch (PM_NODE_TYPE(node)) {
458 pm_buffer_append_string(buffer,
"false", 5);
460 case PM_FLOAT_NODE: {
463 if (PRISM_ISINF(value)) {
465 pm_buffer_append_byte(buffer,
'-');
467 pm_buffer_append_string(buffer,
"Infinity", 8);
468 }
else if (value == 0.0) {
470 pm_buffer_append_byte(buffer,
'-');
472 pm_buffer_append_string(buffer,
"0.0", 3);
474 pm_buffer_append_format(buffer,
"%g", value);
479 if (pm_buffer_index(buffer,
'.') == SIZE_MAX) {
480 size_t exponent_index = pm_buffer_index(buffer,
'e');
481 size_t index = exponent_index == SIZE_MAX ? pm_buffer_length(buffer) : exponent_index;
482 pm_buffer_insert(buffer, index,
".0", 2);
488 case PM_IMAGINARY_NODE: {
490 pm_buffer_append_string(buffer,
"(0", 2);
491 if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer,
'+');
492 pm_static_literal_inspect(buffer, parser, numeric);
493 if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) {
494 pm_buffer_append_byte(buffer,
'*');
496 pm_buffer_append_string(buffer,
"i)", 2);
499 case PM_INTEGER_NODE:
503 pm_buffer_append_string(buffer,
"nil", 3);
505 case PM_RATIONAL_NODE: {
507 pm_buffer_append_byte(buffer,
'(');
508 pm_integer_string(buffer, &rational->
numerator);
509 pm_buffer_append_byte(buffer,
'/');
511 pm_buffer_append_byte(buffer,
')');
514 case PM_REGULAR_EXPRESSION_NODE: {
516 pm_buffer_append_byte(buffer,
'/');
517 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
518 pm_buffer_append_byte(buffer,
'/');
520 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) pm_buffer_append_string(buffer,
"m", 1);
521 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) pm_buffer_append_string(buffer,
"i", 1);
522 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) pm_buffer_append_string(buffer,
"x", 1);
523 if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) pm_buffer_append_string(buffer,
"n", 1);
527 case PM_SOURCE_ENCODING_NODE:
528 pm_buffer_append_format(buffer,
"#<Encoding:%s>", parser->encoding->name);
530 case PM_SOURCE_FILE_NODE: {
532 pm_buffer_append_byte(buffer,
'"');
533 pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_RUBY);
534 pm_buffer_append_byte(buffer,
'"');
537 case PM_SOURCE_LINE_NODE:
538 pm_buffer_append_format(buffer,
"%" PRIi32, pm_line_offset_list_line_column(&parser->line_offsets, node->
location.
start, parser->start_line).
line);
540 case PM_STRING_NODE: {
542 pm_buffer_append_byte(buffer,
'"');
543 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
544 pm_buffer_append_byte(buffer,
'"');
547 case PM_SYMBOL_NODE: {
549 pm_buffer_append_byte(buffer,
':');
550 pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
554 pm_buffer_append_string(buffer,
"true", 4);
557 assert(
false &&
"unreachable");
#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.
VALUE type(ANYARGS)
ANYARGS-ed function type.
T * cast(pm_node_t *node) noexcept
Cast the given node, which must not be null and must be of the given struct, to that struct.
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.
int32_t line
The line number.
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_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_integer_t denominator
RationalNode::denominator.
pm_integer_t numerator
RationalNode::numerator.
pm_string_t unescaped
RegularExpressionNode::unescaped.
A view of a sequence of bytes.
#define PRISM_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.