ruby/prism/static_literals.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);
}