Skip to content

Commit 75d8bb9

Browse files
committed
Split up parse_target and parse_write
1 parent 9fad513 commit 75d8bb9

File tree

1 file changed

+166
-42
lines changed

1 file changed

+166
-42
lines changed

src/yarp.c

Lines changed: 166 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7777,7 +7777,148 @@ parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power,
77777777

77787778
// Convert the given node into a valid target node.
77797779
static yp_node_t *
7780-
parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
7780+
parse_target(yp_parser_t *parser, yp_node_t *target) {
7781+
yp_token_t operator = not_provided(parser);
7782+
7783+
switch (YP_NODE_TYPE(target)) {
7784+
case YP_NODE_MISSING_NODE:
7785+
return target;
7786+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
7787+
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);
7788+
yp_node_destroy(parser, target);
7789+
return (yp_node_t *) write_node;
7790+
}
7791+
case YP_NODE_CONSTANT_PATH_NODE:
7792+
return (yp_node_t *) yp_constant_path_write_node_create(parser, (yp_constant_path_node_t *) target, &operator, NULL);
7793+
case YP_NODE_CONSTANT_READ_NODE: {
7794+
yp_constant_write_node_t *node = yp_constant_write_node_create(parser, &target->location, &operator, NULL);
7795+
yp_node_destroy(parser, target);
7796+
7797+
return (yp_node_t *) node;
7798+
}
7799+
case YP_NODE_BACK_REFERENCE_READ_NODE:
7800+
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
7801+
yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable");
7802+
/* fallthrough */
7803+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
7804+
yp_global_variable_write_node_t *result = yp_global_variable_write_node_create(parser, &target->location, &operator, NULL);
7805+
yp_node_destroy(parser, target);
7806+
7807+
return (yp_node_t *) result;
7808+
}
7809+
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
7810+
yp_local_variable_read_node_t *local_read = (yp_local_variable_read_node_t *) target;
7811+
7812+
yp_constant_id_t constant_id = local_read->constant_id;
7813+
uint32_t depth = local_read->depth;
7814+
7815+
yp_location_t name_loc = target->location;
7816+
yp_node_destroy(parser, target);
7817+
7818+
return (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, depth, NULL, &name_loc, &operator);
7819+
}
7820+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
7821+
yp_node_t *write_node = (yp_node_t *) yp_instance_variable_write_node_create(parser, (yp_instance_variable_read_node_t *) target, &operator, NULL);
7822+
yp_node_destroy(parser, target);
7823+
return write_node;
7824+
}
7825+
case YP_NODE_MULTI_WRITE_NODE: {
7826+
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
7827+
yp_multi_write_node_operator_loc_set(multi_write, &operator);
7828+
return (yp_node_t *) multi_write;
7829+
}
7830+
case YP_NODE_SPLAT_NODE: {
7831+
yp_splat_node_t *splat = (yp_splat_node_t *) target;
7832+
7833+
if (splat->expression != NULL) {
7834+
splat->expression = parse_target(parser, splat->expression);
7835+
}
7836+
7837+
yp_location_t location = { .start = NULL, .end = NULL };
7838+
yp_multi_write_node_t *multi_write = yp_multi_write_node_create(parser, &operator, NULL, &location, &location);
7839+
yp_multi_write_node_targets_append(multi_write, (yp_node_t *) splat);
7840+
7841+
return (yp_node_t *) multi_write;
7842+
}
7843+
case YP_NODE_CALL_NODE: {
7844+
yp_call_node_t *call = (yp_call_node_t *) target;
7845+
// If we have no arguments to the call node and we need this to be a
7846+
// target then this is either a method call or a local variable write.
7847+
if (
7848+
(call->opening_loc.start == NULL) &&
7849+
(call->arguments == NULL) &&
7850+
(call->block == NULL)
7851+
) {
7852+
if (call->receiver == NULL) {
7853+
// When we get here, we have a local variable write, because it
7854+
// was previously marked as a method call but now we have an =.
7855+
// This looks like:
7856+
//
7857+
// foo = 1
7858+
//
7859+
// When it was parsed in the prefix position, foo was seen as a
7860+
// method call with no receiver and no arguments. Now we have an
7861+
// =, so we know it's a local variable write.
7862+
const yp_location_t message = call->message_loc;
7863+
7864+
yp_parser_local_add_location(parser, message.start, message.end);
7865+
yp_node_destroy(parser, target);
7866+
7867+
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message.start, message.end);
7868+
target = (yp_node_t *) yp_local_variable_write_node_create(parser, constant_id, 0, NULL, &message, &operator);
7869+
7870+
if (token_is_numbered_parameter(message.start, message.end)) {
7871+
yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter");
7872+
}
7873+
7874+
return target;
7875+
}
7876+
7877+
// The method name needs to change. If we previously had foo, we now
7878+
// need foo=. In this case we'll allocate a new owned string, copy
7879+
// the previous method name in, and append an =.
7880+
size_t length = yp_string_length(&call->name);
7881+
7882+
char *name = calloc(length + 2, sizeof(char));
7883+
if (name == NULL) return NULL;
7884+
7885+
snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
7886+
7887+
// Now switch the name to the new string.
7888+
yp_string_free(&call->name);
7889+
yp_string_owned_init(&call->name, name, length + 1);
7890+
7891+
return target;
7892+
}
7893+
7894+
// If there is no call operator and the message is "[]" then this is
7895+
// an aref expression, and we can transform it into an aset
7896+
// expression.
7897+
if (
7898+
(call->operator_loc.start == NULL) &&
7899+
(call->message_loc.start[0] == '[') &&
7900+
(call->message_loc.end[-1] == ']') &&
7901+
(call->block == NULL)
7902+
) {
7903+
// Free the previous name and replace it with "[]=".
7904+
yp_string_free(&call->name);
7905+
yp_string_constant_init(&call->name, "[]=", 3);
7906+
return target;
7907+
}
7908+
}
7909+
/* fallthrough */
7910+
default:
7911+
// In this case we have a node that we don't know how to convert into a
7912+
// target. We need to treat it as an error. For now, we'll mark it as an
7913+
// error and just skip right past it.
7914+
yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, "Unexpected `='.");
7915+
return target;
7916+
}
7917+
}
7918+
7919+
// Convert the given node into a valid write node.
7920+
static yp_node_t *
7921+
parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
77817922
switch (YP_NODE_TYPE(target)) {
77827923
case YP_NODE_MISSING_NODE:
77837924
return target;
@@ -7824,18 +7965,15 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
78247965
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
78257966
yp_multi_write_node_operator_loc_set(multi_write, operator);
78267967

7827-
if (value != NULL) {
7828-
multi_write->value = value;
7829-
multi_write->base.location.end = value->location.end;
7830-
}
7831-
7968+
multi_write->value = value;
7969+
multi_write->base.location.end = value->location.end;
78327970
return (yp_node_t *) multi_write;
78337971
}
78347972
case YP_NODE_SPLAT_NODE: {
78357973
yp_splat_node_t *splat = (yp_splat_node_t *) target;
78367974

78377975
if (splat->expression != NULL) {
7838-
splat->expression = parse_target(parser, splat->expression, operator, value);
7976+
splat->expression = parse_write(parser, splat->expression, operator, value);
78397977
}
78407978

78417979
yp_location_t location = { .start = NULL, .end = NULL };
@@ -7888,12 +8026,10 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
78888026
// method call with no arguments. Now we have an =, so we know it's
78898027
// a method call with an argument. In this case we will create the
78908028
// arguments node, parse the argument, and add it to the list.
7891-
if (value) {
7892-
yp_arguments_node_t *arguments = yp_arguments_node_create(parser);
7893-
call->arguments = arguments;
7894-
yp_arguments_node_arguments_append(arguments, value);
7895-
target->location.end = arguments->base.location.end;
7896-
}
8029+
yp_arguments_node_t *arguments = yp_arguments_node_create(parser);
8030+
call->arguments = arguments;
8031+
yp_arguments_node_arguments_append(arguments, value);
8032+
target->location.end = arguments->base.location.end;
78978033

78988034
// The method name needs to change. If we previously had foo, we now
78998035
// need foo=. In this case we'll allocate a new owned string, copy
@@ -7921,15 +8057,13 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
79218057
(call->message_loc.end[-1] == ']') &&
79228058
(call->block == NULL)
79238059
) {
7924-
if (value != NULL) {
7925-
if (call->arguments == NULL) {
7926-
call->arguments = yp_arguments_node_create(parser);
7927-
}
7928-
7929-
yp_arguments_node_arguments_append(call->arguments, value);
7930-
target->location.end = value->location.end;
8060+
if (call->arguments == NULL) {
8061+
call->arguments = yp_arguments_node_create(parser);
79318062
}
79328063

8064+
yp_arguments_node_arguments_append(call->arguments, value);
8065+
target->location.end = value->location.end;
8066+
79338067
// Free the previous name and replace it with "[]=".
79348068
yp_string_free(&call->name);
79358069
yp_string_constant_init(&call->name, "[]=", 3);
@@ -7941,9 +8075,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
79418075
// syntax error. In this case we'll fall through to our default
79428076
// handling. We need to free the value that we parsed because there
79438077
// is no way for us to attach it to the tree at this point.
7944-
if (value != NULL) {
7945-
yp_node_destroy(parser, value);
7946-
}
8078+
yp_node_destroy(parser, value);
79478079
}
79488080
/* fallthrough */
79498081
default:
@@ -7971,7 +8103,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
79718103
// location that we know requires a multi write, as in the case of a for loop.
79728104
// In this case we will set up the parsing loop slightly differently.
79738105
if (first_target != NULL) {
7974-
first_target = parse_target(parser, first_target, &operator, NULL);
8106+
first_target = parse_target(parser, first_target);
79758107

79768108
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
79778109
return first_target;
@@ -8002,9 +8134,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
80028134
yp_node_t *name = NULL;
80038135

80048136
if (token_begins_expression_p(parser->current.type)) {
8005-
yp_token_t operator = not_provided(parser);
80068137
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
8007-
name = parse_target(parser, name, &operator, NULL);
8138+
name = parse_target(parser, name);
80088139
}
80098140

80108141
yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name);
@@ -8072,7 +8203,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
80728203
}
80738204

80748205
yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','.");
8075-
target = parse_target(parser, target, &operator, NULL);
8206+
target = parse_target(parser, target);
80768207

80778208
yp_multi_write_node_targets_append(result, target);
80788209
}
@@ -8823,8 +8954,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
88238954
yp_rescue_node_operator_set(rescue, &parser->previous);
88248955

88258956
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
8826-
yp_token_t operator = not_provided(parser);
8827-
reference = parse_target(parser, reference, &operator, NULL);
8957+
reference = parse_target(parser, reference);
88288958

88298959
yp_rescue_node_reference_set(rescue, reference);
88308960
break;
@@ -8854,8 +8984,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
88548984
yp_rescue_node_operator_set(rescue, &parser->previous);
88558985

88568986
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
8857-
yp_token_t operator = not_provided(parser);
8858-
reference = parse_target(parser, reference, &operator, NULL);
8987+
reference = parse_target(parser, reference);
88598988

88608989
yp_rescue_node_reference_set(rescue, reference);
88618990
break;
@@ -12530,7 +12659,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
1253012659
case YP_CASE_WRITABLE: {
1253112660
parser_lex(parser);
1253212661
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
12533-
return parse_target(parser, node, &token, value);
12662+
return parse_write(parser, node, &token, value);
1253412663
}
1253512664
case YP_NODE_SPLAT_NODE: {
1253612665
yp_splat_node_t *splat_node = (yp_splat_node_t *) node;
@@ -12539,7 +12668,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
1253912668
case YP_CASE_WRITABLE:
1254012669
parser_lex(parser);
1254112670
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
12542-
return parse_target(parser, (yp_node_t *) splat_node, &token, value);
12671+
return parse_write(parser, (yp_node_t *) splat_node, &token, value);
1254312672
default:
1254412673
break;
1254512674
}
@@ -12636,9 +12765,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
1263612765
}
1263712766

1263812767
parser_lex(parser);
12639-
12640-
yp_token_t operator = not_provided(parser);
12641-
node = parse_target(parser, node, &operator, NULL);
12768+
node = parse_target(parser, node);
1264212769

1264312770
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
1264412771
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
@@ -12739,9 +12866,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
1273912866
}
1274012867

1274112868
parser_lex(parser);
12742-
12743-
yp_token_t operator = not_provided(parser);
12744-
node = parse_target(parser, node, &operator, NULL);
12869+
node = parse_target(parser, node);
1274512870

1274612871
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
1274712872
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
@@ -12851,10 +12976,9 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
1285112976
return result;
1285212977
}
1285312978

12854-
yp_token_t operator = not_provided(parser);
12855-
node = parse_target(parser, node, &operator, NULL);
12856-
12979+
node = parse_target(parser, node);
1285712980
parser_lex(parser);
12981+
1285812982
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
1285912983
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
1286012984
}

0 commit comments

Comments
 (0)