mirror of
https://github.com/ruby/ruby.git
synced 2025-08-25 05:55:46 +02:00
221 lines
8.1 KiB
C
221 lines
8.1 KiB
C
#include "prism/static_literals.h"
|
|
|
|
/**
|
|
* Insert a node into the given sorted list. This will return false if the node
|
|
* was not already in the list, and true if it was.
|
|
*/
|
|
static pm_node_t *
|
|
pm_node_list_insert(const pm_parser_t *parser, pm_node_list_t *list, pm_node_t *node, int (*compare)(const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right)) {
|
|
size_t low = 0;
|
|
size_t high = list->size;
|
|
|
|
while (low < high) {
|
|
size_t mid = (low + high) / 2;
|
|
int result = compare(parser, list->nodes[mid], node);
|
|
|
|
// If we find a match, then replace the old node with the new one and
|
|
// return the old one.
|
|
if (result == 0) {
|
|
pm_node_t *result = list->nodes[mid];
|
|
list->nodes[mid] = node;
|
|
return result;
|
|
}
|
|
|
|
if (result < 0) {
|
|
low = mid + 1;
|
|
} else {
|
|
high = mid;
|
|
}
|
|
}
|
|
|
|
pm_node_list_grow(list);
|
|
memmove(&list->nodes[low + 1], &list->nodes[low], (list->size - low) * sizeof(pm_node_t *));
|
|
|
|
list->nodes[low] = node;
|
|
list->size++;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Compare two values that can be compared with a simple numeric comparison.
|
|
*/
|
|
#define PM_NUMERIC_COMPARISON(left, right) ((left < right) ? -1 : (left > right) ? 1 : 0)
|
|
|
|
/**
|
|
* Return the integer value of the given node as an int64_t.
|
|
*/
|
|
static int64_t
|
|
pm_int64_value(const pm_parser_t *parser, const pm_node_t *node) {
|
|
switch (PM_NODE_TYPE(node)) {
|
|
case PM_INTEGER_NODE: {
|
|
const pm_integer_t *integer = &((const pm_integer_node_t *) node)->value;
|
|
if (integer->length > 0) return integer->negative ? INT64_MIN : INT64_MAX;
|
|
|
|
int64_t value = (int64_t) integer->head.value;
|
|
return integer->negative ? -value : value;
|
|
}
|
|
case PM_SOURCE_LINE_NODE:
|
|
return (int64_t) pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line;
|
|
default:
|
|
assert(false && "unreachable");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A comparison function for comparing two IntegerNode or SourceLineNode
|
|
* instances.
|
|
*/
|
|
static int
|
|
pm_compare_integer_nodes(const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
|
|
if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
|
|
int64_t left_value = pm_int64_value(parser, left);
|
|
int64_t right_value = pm_int64_value(parser, right);
|
|
return PM_NUMERIC_COMPARISON(left_value, right_value);
|
|
}
|
|
|
|
const pm_integer_t *left_integer = &((const pm_integer_node_t *) left)->value;
|
|
const pm_integer_t *right_integer = &((const pm_integer_node_t *) right)->value;
|
|
return pm_integer_compare(left_integer, right_integer);
|
|
}
|
|
|
|
/**
|
|
* A comparison function for comparing two FloatNode instances.
|
|
*/
|
|
static int
|
|
pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
|
|
const double left_value = ((const pm_float_node_t *) left)->value;
|
|
const double right_value = ((const pm_float_node_t *) right)->value;
|
|
return PM_NUMERIC_COMPARISON(left_value, right_value);
|
|
}
|
|
|
|
/**
|
|
* A comparison function for comparing two nodes that have attached numbers.
|
|
*/
|
|
static int
|
|
pm_compare_number_nodes(const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
|
|
if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
|
|
return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
|
|
}
|
|
|
|
switch (PM_NODE_TYPE(left)) {
|
|
case PM_IMAGINARY_NODE:
|
|
return pm_compare_number_nodes(parser, ((const pm_imaginary_node_t *) left)->numeric, ((const pm_imaginary_node_t *) right)->numeric);
|
|
case PM_RATIONAL_NODE:
|
|
return pm_compare_number_nodes(parser, ((const pm_rational_node_t *) left)->numeric, ((const pm_rational_node_t *) right)->numeric);
|
|
case PM_INTEGER_NODE:
|
|
return pm_compare_integer_nodes(parser, left, right);
|
|
case PM_FLOAT_NODE:
|
|
return pm_compare_float_nodes(parser, left, right);
|
|
default:
|
|
assert(false && "unreachable");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return a pointer to the string value of the given node.
|
|
*/
|
|
static const pm_string_t *
|
|
pm_string_value(const pm_node_t *node) {
|
|
switch (PM_NODE_TYPE(node)) {
|
|
case PM_STRING_NODE:
|
|
return &((const pm_string_node_t *) node)->unescaped;
|
|
case PM_SOURCE_FILE_NODE:
|
|
return &((const pm_source_file_node_t *) node)->filepath;
|
|
case PM_SYMBOL_NODE:
|
|
return &((const pm_symbol_node_t *) node)->unescaped;
|
|
default:
|
|
assert(false && "unreachable");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A comparison function for comparing two nodes that have attached strings.
|
|
*/
|
|
static int
|
|
pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
|
|
const pm_string_t *left_string = pm_string_value(left);
|
|
const pm_string_t *right_string = pm_string_value(right);
|
|
return pm_string_compare(left_string, right_string);
|
|
}
|
|
|
|
/**
|
|
* A comparison function for comparing two RegularExpressionNode instances.
|
|
*/
|
|
static int
|
|
pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_parser_t *parser, const pm_node_t *left, const pm_node_t *right) {
|
|
const pm_regular_expression_node_t *left_regexp = (const pm_regular_expression_node_t *) left;
|
|
const pm_regular_expression_node_t *right_regexp = (const pm_regular_expression_node_t *) right;
|
|
|
|
int result = pm_string_compare(&left_regexp->unescaped, &right_regexp->unescaped);
|
|
if (result != 0) return result;
|
|
|
|
return PM_NUMERIC_COMPARISON(left_regexp->base.flags, right_regexp->base.flags);
|
|
}
|
|
|
|
#undef PM_NUMERIC_COMPARISON
|
|
|
|
/**
|
|
* Add a node to the set of static literals.
|
|
*/
|
|
pm_node_t *
|
|
pm_static_literals_add(const pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
|
|
if (!PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) return NULL;
|
|
|
|
switch (PM_NODE_TYPE(node)) {
|
|
case PM_INTEGER_NODE:
|
|
case PM_SOURCE_LINE_NODE:
|
|
return pm_node_list_insert(parser, &literals->integer_nodes, node, pm_compare_integer_nodes);
|
|
case PM_FLOAT_NODE:
|
|
return pm_node_list_insert(parser, &literals->float_nodes, node, pm_compare_float_nodes);
|
|
case PM_RATIONAL_NODE:
|
|
case PM_IMAGINARY_NODE:
|
|
return pm_node_list_insert(parser, &literals->rational_nodes, node, pm_compare_number_nodes);
|
|
case PM_STRING_NODE:
|
|
case PM_SOURCE_FILE_NODE:
|
|
return pm_node_list_insert(parser, &literals->string_nodes, node, pm_compare_string_nodes);
|
|
case PM_REGULAR_EXPRESSION_NODE:
|
|
return pm_node_list_insert(parser, &literals->regexp_nodes, node, pm_compare_regular_expression_nodes);
|
|
case PM_SYMBOL_NODE:
|
|
return pm_node_list_insert(parser, &literals->symbol_nodes, node, pm_compare_string_nodes);
|
|
case PM_TRUE_NODE: {
|
|
pm_node_t *duplicated = literals->true_node;
|
|
literals->true_node = node;
|
|
return duplicated;
|
|
}
|
|
case PM_FALSE_NODE: {
|
|
pm_node_t *duplicated = literals->false_node;
|
|
literals->false_node = node;
|
|
return duplicated;
|
|
}
|
|
case PM_NIL_NODE: {
|
|
pm_node_t *duplicated = literals->nil_node;
|
|
literals->nil_node = node;
|
|
return duplicated;
|
|
}
|
|
case PM_SOURCE_ENCODING_NODE: {
|
|
pm_node_t *duplicated = literals->source_encoding_node;
|
|
literals->source_encoding_node = node;
|
|
return duplicated;
|
|
}
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Free the internal memory associated with the given static literals set.
|
|
*/
|
|
void
|
|
pm_static_literals_free(pm_static_literals_t *literals) {
|
|
pm_node_list_free(&literals->integer_nodes);
|
|
pm_node_list_free(&literals->float_nodes);
|
|
pm_node_list_free(&literals->rational_nodes);
|
|
pm_node_list_free(&literals->imaginary_nodes);
|
|
pm_node_list_free(&literals->string_nodes);
|
|
pm_node_list_free(&literals->regexp_nodes);
|
|
pm_node_list_free(&literals->symbol_nodes);
|
|
}
|