[ruby/yarp] Split up parse_target and parse_write
https://github.com/ruby/yarp/commit/75d8bb93ea
This commit is contained in:
parent
2ebaf077f6
commit
aeef709109
184
yarp/yarp.c
184
yarp/yarp.c
@ -7809,7 +7809,148 @@ parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power,
|
|||||||
|
|
||||||
// Convert the given node into a valid target node.
|
// Convert the given node into a valid target node.
|
||||||
static yp_node_t *
|
static yp_node_t *
|
||||||
parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
|
parse_target(yp_parser_t *parser, yp_node_t *target) {
|
||||||
|
yp_token_t operator = not_provided(parser);
|
||||||
|
|
||||||
|
switch (YP_NODE_TYPE(target)) {
|
||||||
|
case YP_NODE_MISSING_NODE:
|
||||||
|
return target;
|
||||||
|
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
||||||
|
yp_class_variable_write_node_t *write_node = yp_class_variable_read_node_to_class_variable_write_node(parser, (yp_class_variable_read_node_t *) target, &operator, NULL);
|
||||||
|
yp_node_destroy(parser, target);
|
||||||
|
return (yp_node_t *) write_node;
|
||||||
|
}
|
||||||
|
case YP_NODE_CONSTANT_PATH_NODE:
|
||||||
|
return (yp_node_t *) yp_constant_path_write_node_create(parser, (yp_constant_path_node_t *) target, &operator, NULL);
|
||||||
|
case YP_NODE_CONSTANT_READ_NODE: {
|
||||||
|
yp_constant_write_node_t *node = yp_constant_write_node_create(parser, &target->location, &operator, NULL);
|
||||||
|
yp_node_destroy(parser, target);
|
||||||
|
|
||||||
|
return (yp_node_t *) node;
|
||||||
|
}
|
||||||
|
case YP_NODE_BACK_REFERENCE_READ_NODE:
|
||||||
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
||||||
|
yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable");
|
||||||
|
/* fallthrough */
|
||||||
|
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
||||||
|
yp_global_variable_write_node_t *result = yp_global_variable_write_node_create(parser, &target->location, &operator, NULL);
|
||||||
|
yp_node_destroy(parser, target);
|
||||||
|
|
||||||
|
return (yp_node_t *) result;
|
||||||
|
}
|
||||||
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
||||||
|
yp_local_variable_read_node_t *local_read = (yp_local_variable_read_node_t *) target;
|
||||||
|
|
||||||
|
yp_constant_id_t constant_id = local_read->constant_id;
|
||||||
|
uint32_t depth = local_read->depth;
|
||||||
|
|
||||||
|
yp_location_t name_loc = target->location;
|
||||||
|
yp_node_destroy(parser, target);
|
||||||
|
|
||||||
|
return (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, depth, NULL, &name_loc, &operator);
|
||||||
|
}
|
||||||
|
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
||||||
|
yp_node_t *write_node = (yp_node_t *) yp_instance_variable_write_node_create(parser, (yp_instance_variable_read_node_t *) target, &operator, NULL);
|
||||||
|
yp_node_destroy(parser, target);
|
||||||
|
return write_node;
|
||||||
|
}
|
||||||
|
case YP_NODE_MULTI_WRITE_NODE: {
|
||||||
|
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
|
||||||
|
yp_multi_write_node_operator_loc_set(multi_write, &operator);
|
||||||
|
return (yp_node_t *) multi_write;
|
||||||
|
}
|
||||||
|
case YP_NODE_SPLAT_NODE: {
|
||||||
|
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
||||||
|
|
||||||
|
if (splat->expression != NULL) {
|
||||||
|
splat->expression = parse_target(parser, splat->expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
yp_location_t location = { .start = NULL, .end = NULL };
|
||||||
|
yp_multi_write_node_t *multi_write = yp_multi_write_node_create(parser, &operator, NULL, &location, &location);
|
||||||
|
yp_multi_write_node_targets_append(multi_write, (yp_node_t *) splat);
|
||||||
|
|
||||||
|
return (yp_node_t *) multi_write;
|
||||||
|
}
|
||||||
|
case YP_NODE_CALL_NODE: {
|
||||||
|
yp_call_node_t *call = (yp_call_node_t *) target;
|
||||||
|
// If we have no arguments to the call node and we need this to be a
|
||||||
|
// target then this is either a method call or a local variable write.
|
||||||
|
if (
|
||||||
|
(call->opening_loc.start == NULL) &&
|
||||||
|
(call->arguments == NULL) &&
|
||||||
|
(call->block == NULL)
|
||||||
|
) {
|
||||||
|
if (call->receiver == NULL) {
|
||||||
|
// When we get here, we have a local variable write, because it
|
||||||
|
// was previously marked as a method call but now we have an =.
|
||||||
|
// This looks like:
|
||||||
|
//
|
||||||
|
// foo = 1
|
||||||
|
//
|
||||||
|
// When it was parsed in the prefix position, foo was seen as a
|
||||||
|
// method call with no receiver and no arguments. Now we have an
|
||||||
|
// =, so we know it's a local variable write.
|
||||||
|
const yp_location_t message = call->message_loc;
|
||||||
|
|
||||||
|
yp_parser_local_add_location(parser, message.start, message.end);
|
||||||
|
yp_node_destroy(parser, target);
|
||||||
|
|
||||||
|
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message.start, message.end);
|
||||||
|
target = (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, 0, NULL, &message, &operator);
|
||||||
|
|
||||||
|
if (token_is_numbered_parameter(message.start, message.end)) {
|
||||||
|
yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The method name needs to change. If we previously had foo, we now
|
||||||
|
// need foo=. In this case we'll allocate a new owned string, copy
|
||||||
|
// the previous method name in, and append an =.
|
||||||
|
size_t length = yp_string_length(&call->name);
|
||||||
|
|
||||||
|
char *name = calloc(length + 2, sizeof(char));
|
||||||
|
if (name == NULL) return NULL;
|
||||||
|
|
||||||
|
snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
|
||||||
|
|
||||||
|
// Now switch the name to the new string.
|
||||||
|
yp_string_free(&call->name);
|
||||||
|
yp_string_owned_init(&call->name, name, length + 1);
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is no call operator and the message is "[]" then this is
|
||||||
|
// an aref expression, and we can transform it into an aset
|
||||||
|
// expression.
|
||||||
|
if (
|
||||||
|
(call->operator_loc.start == NULL) &&
|
||||||
|
(call->message_loc.start[0] == '[') &&
|
||||||
|
(call->message_loc.end[-1] == ']') &&
|
||||||
|
(call->block == NULL)
|
||||||
|
) {
|
||||||
|
// Free the previous name and replace it with "[]=".
|
||||||
|
yp_string_free(&call->name);
|
||||||
|
yp_string_constant_init(&call->name, "[]=", 3);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
// In this case we have a node that we don't know how to convert into a
|
||||||
|
// target. We need to treat it as an error. For now, we'll mark it as an
|
||||||
|
// error and just skip right past it.
|
||||||
|
yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Unexpected `='.");
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the given node into a valid write node.
|
||||||
|
static yp_node_t *
|
||||||
|
parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
|
||||||
switch (YP_NODE_TYPE(target)) {
|
switch (YP_NODE_TYPE(target)) {
|
||||||
case YP_NODE_MISSING_NODE:
|
case YP_NODE_MISSING_NODE:
|
||||||
return target;
|
return target;
|
||||||
@ -7856,18 +7997,15 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|||||||
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
|
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
|
||||||
yp_multi_write_node_operator_loc_set(multi_write, operator);
|
yp_multi_write_node_operator_loc_set(multi_write, operator);
|
||||||
|
|
||||||
if (value != NULL) {
|
|
||||||
multi_write->value = value;
|
multi_write->value = value;
|
||||||
multi_write->base.location.end = value->location.end;
|
multi_write->base.location.end = value->location.end;
|
||||||
}
|
|
||||||
|
|
||||||
return (yp_node_t *) multi_write;
|
return (yp_node_t *) multi_write;
|
||||||
}
|
}
|
||||||
case YP_NODE_SPLAT_NODE: {
|
case YP_NODE_SPLAT_NODE: {
|
||||||
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
||||||
|
|
||||||
if (splat->expression != NULL) {
|
if (splat->expression != NULL) {
|
||||||
splat->expression = parse_target(parser, splat->expression, operator, value);
|
splat->expression = parse_write(parser, splat->expression, operator, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
yp_location_t location = { .start = NULL, .end = NULL };
|
yp_location_t location = { .start = NULL, .end = NULL };
|
||||||
@ -7920,12 +8058,10 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|||||||
// method call with no arguments. Now we have an =, so we know it's
|
// method call with no arguments. Now we have an =, so we know it's
|
||||||
// a method call with an argument. In this case we will create the
|
// a method call with an argument. In this case we will create the
|
||||||
// arguments node, parse the argument, and add it to the list.
|
// arguments node, parse the argument, and add it to the list.
|
||||||
if (value) {
|
|
||||||
yp_arguments_node_t *arguments = yp_arguments_node_create(parser);
|
yp_arguments_node_t *arguments = yp_arguments_node_create(parser);
|
||||||
call->arguments = arguments;
|
call->arguments = arguments;
|
||||||
yp_arguments_node_arguments_append(arguments, value);
|
yp_arguments_node_arguments_append(arguments, value);
|
||||||
target->location.end = arguments->base.location.end;
|
target->location.end = arguments->base.location.end;
|
||||||
}
|
|
||||||
|
|
||||||
// The method name needs to change. If we previously had foo, we now
|
// The method name needs to change. If we previously had foo, we now
|
||||||
// need foo=. In this case we'll allocate a new owned string, copy
|
// need foo=. In this case we'll allocate a new owned string, copy
|
||||||
@ -7953,14 +8089,12 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|||||||
(call->message_loc.end[-1] == ']') &&
|
(call->message_loc.end[-1] == ']') &&
|
||||||
(call->block == NULL)
|
(call->block == NULL)
|
||||||
) {
|
) {
|
||||||
if (value != NULL) {
|
|
||||||
if (call->arguments == NULL) {
|
if (call->arguments == NULL) {
|
||||||
call->arguments = yp_arguments_node_create(parser);
|
call->arguments = yp_arguments_node_create(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
yp_arguments_node_arguments_append(call->arguments, value);
|
yp_arguments_node_arguments_append(call->arguments, value);
|
||||||
target->location.end = value->location.end;
|
target->location.end = value->location.end;
|
||||||
}
|
|
||||||
|
|
||||||
// Free the previous name and replace it with "[]=".
|
// Free the previous name and replace it with "[]=".
|
||||||
yp_string_free(&call->name);
|
yp_string_free(&call->name);
|
||||||
@ -7973,10 +8107,8 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|||||||
// syntax error. In this case we'll fall through to our default
|
// syntax error. In this case we'll fall through to our default
|
||||||
// handling. We need to free the value that we parsed because there
|
// handling. We need to free the value that we parsed because there
|
||||||
// is no way for us to attach it to the tree at this point.
|
// is no way for us to attach it to the tree at this point.
|
||||||
if (value != NULL) {
|
|
||||||
yp_node_destroy(parser, value);
|
yp_node_destroy(parser, value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
// In this case we have a node that we don't know how to convert into a
|
// In this case we have a node that we don't know how to convert into a
|
||||||
@ -8003,7 +8135,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|||||||
// location that we know requires a multi write, as in the case of a for loop.
|
// location that we know requires a multi write, as in the case of a for loop.
|
||||||
// In this case we will set up the parsing loop slightly differently.
|
// In this case we will set up the parsing loop slightly differently.
|
||||||
if (first_target != NULL) {
|
if (first_target != NULL) {
|
||||||
first_target = parse_target(parser, first_target, &operator, NULL);
|
first_target = parse_target(parser, first_target);
|
||||||
|
|
||||||
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
|
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
|
||||||
return first_target;
|
return first_target;
|
||||||
@ -8034,9 +8166,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|||||||
yp_node_t *name = NULL;
|
yp_node_t *name = NULL;
|
||||||
|
|
||||||
if (token_begins_expression_p(parser->current.type)) {
|
if (token_begins_expression_p(parser->current.type)) {
|
||||||
yp_token_t operator = not_provided(parser);
|
|
||||||
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
|
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
|
||||||
name = parse_target(parser, name, &operator, NULL);
|
name = parse_target(parser, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name);
|
yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name);
|
||||||
@ -8104,7 +8235,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|||||||
}
|
}
|
||||||
|
|
||||||
yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','.");
|
yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','.");
|
||||||
target = parse_target(parser, target, &operator, NULL);
|
target = parse_target(parser, target);
|
||||||
|
|
||||||
yp_multi_write_node_targets_append(result, target);
|
yp_multi_write_node_targets_append(result, target);
|
||||||
}
|
}
|
||||||
@ -8855,8 +8986,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|||||||
yp_rescue_node_operator_set(rescue, &parser->previous);
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
||||||
|
|
||||||
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
||||||
yp_token_t operator = not_provided(parser);
|
reference = parse_target(parser, reference);
|
||||||
reference = parse_target(parser, reference, &operator, NULL);
|
|
||||||
|
|
||||||
yp_rescue_node_reference_set(rescue, reference);
|
yp_rescue_node_reference_set(rescue, reference);
|
||||||
break;
|
break;
|
||||||
@ -8886,8 +9016,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|||||||
yp_rescue_node_operator_set(rescue, &parser->previous);
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
||||||
|
|
||||||
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
||||||
yp_token_t operator = not_provided(parser);
|
reference = parse_target(parser, reference);
|
||||||
reference = parse_target(parser, reference, &operator, NULL);
|
|
||||||
|
|
||||||
yp_rescue_node_reference_set(rescue, reference);
|
yp_rescue_node_reference_set(rescue, reference);
|
||||||
break;
|
break;
|
||||||
@ -12578,7 +12707,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|||||||
case YP_CASE_WRITABLE: {
|
case YP_CASE_WRITABLE: {
|
||||||
parser_lex(parser);
|
parser_lex(parser);
|
||||||
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
||||||
return parse_target(parser, node, &token, value);
|
return parse_write(parser, node, &token, value);
|
||||||
}
|
}
|
||||||
case YP_NODE_SPLAT_NODE: {
|
case YP_NODE_SPLAT_NODE: {
|
||||||
yp_splat_node_t *splat_node = (yp_splat_node_t *) node;
|
yp_splat_node_t *splat_node = (yp_splat_node_t *) node;
|
||||||
@ -12587,7 +12716,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|||||||
case YP_CASE_WRITABLE:
|
case YP_CASE_WRITABLE:
|
||||||
parser_lex(parser);
|
parser_lex(parser);
|
||||||
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
||||||
return parse_target(parser, (yp_node_t *) splat_node, &token, value);
|
return parse_write(parser, (yp_node_t *) splat_node, &token, value);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -12684,9 +12813,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
parser_lex(parser);
|
parser_lex(parser);
|
||||||
|
node = parse_target(parser, node);
|
||||||
yp_token_t operator = not_provided(parser);
|
|
||||||
node = parse_target(parser, node, &operator, NULL);
|
|
||||||
|
|
||||||
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
||||||
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
||||||
@ -12787,9 +12914,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
parser_lex(parser);
|
parser_lex(parser);
|
||||||
|
node = parse_target(parser, node);
|
||||||
yp_token_t operator = not_provided(parser);
|
|
||||||
node = parse_target(parser, node, &operator, NULL);
|
|
||||||
|
|
||||||
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
||||||
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
||||||
@ -12899,10 +13024,9 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
yp_token_t operator = not_provided(parser);
|
node = parse_target(parser, node);
|
||||||
node = parse_target(parser, node, &operator, NULL);
|
|
||||||
|
|
||||||
parser_lex(parser);
|
parser_lex(parser);
|
||||||
|
|
||||||
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
||||||
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user