@@ -7777,7 +7777,148 @@ parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power,
7777
7777
7778
7778
// Convert the given node into a valid target node.
7779
7779
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) {
7781
7922
switch (YP_NODE_TYPE(target)) {
7782
7923
case YP_NODE_MISSING_NODE:
7783
7924
return target;
@@ -7824,18 +7965,15 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
7824
7965
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
7825
7966
yp_multi_write_node_operator_loc_set(multi_write, operator);
7826
7967
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;
7832
7970
return (yp_node_t *) multi_write;
7833
7971
}
7834
7972
case YP_NODE_SPLAT_NODE: {
7835
7973
yp_splat_node_t *splat = (yp_splat_node_t *) target;
7836
7974
7837
7975
if (splat->expression != NULL) {
7838
- splat->expression = parse_target (parser, splat->expression, operator, value);
7976
+ splat->expression = parse_write (parser, splat->expression, operator, value);
7839
7977
}
7840
7978
7841
7979
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
7888
8026
// method call with no arguments. Now we have an =, so we know it's
7889
8027
// a method call with an argument. In this case we will create the
7890
8028
// 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;
7897
8033
7898
8034
// The method name needs to change. If we previously had foo, we now
7899
8035
// 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
7921
8057
(call->message_loc.end[-1] == ']') &&
7922
8058
(call->block == NULL)
7923
8059
) {
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);
7931
8062
}
7932
8063
8064
+ yp_arguments_node_arguments_append(call->arguments, value);
8065
+ target->location.end = value->location.end;
8066
+
7933
8067
// Free the previous name and replace it with "[]=".
7934
8068
yp_string_free(&call->name);
7935
8069
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
7941
8075
// syntax error. In this case we'll fall through to our default
7942
8076
// handling. We need to free the value that we parsed because there
7943
8077
// 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);
7947
8079
}
7948
8080
/* fallthrough */
7949
8081
default:
@@ -7971,7 +8103,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
7971
8103
// location that we know requires a multi write, as in the case of a for loop.
7972
8104
// In this case we will set up the parsing loop slightly differently.
7973
8105
if (first_target != NULL) {
7974
- first_target = parse_target(parser, first_target, &operator, NULL );
8106
+ first_target = parse_target(parser, first_target);
7975
8107
7976
8108
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
7977
8109
return first_target;
@@ -8002,9 +8134,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
8002
8134
yp_node_t *name = NULL;
8003
8135
8004
8136
if (token_begins_expression_p(parser->current.type)) {
8005
- yp_token_t operator = not_provided(parser);
8006
8137
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
8007
- name = parse_target(parser, name, &operator, NULL );
8138
+ name = parse_target(parser, name);
8008
8139
}
8009
8140
8010
8141
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
8072
8203
}
8073
8204
8074
8205
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);
8076
8207
8077
8208
yp_multi_write_node_targets_append(result, target);
8078
8209
}
@@ -8823,8 +8954,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
8823
8954
yp_rescue_node_operator_set(rescue, &parser->previous);
8824
8955
8825
8956
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);
8828
8958
8829
8959
yp_rescue_node_reference_set(rescue, reference);
8830
8960
break;
@@ -8854,8 +8984,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
8854
8984
yp_rescue_node_operator_set(rescue, &parser->previous);
8855
8985
8856
8986
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);
8859
8988
8860
8989
yp_rescue_node_reference_set(rescue, reference);
8861
8990
break;
@@ -12530,7 +12659,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12530
12659
case YP_CASE_WRITABLE: {
12531
12660
parser_lex(parser);
12532
12661
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);
12534
12663
}
12535
12664
case YP_NODE_SPLAT_NODE: {
12536
12665
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
12539
12668
case YP_CASE_WRITABLE:
12540
12669
parser_lex(parser);
12541
12670
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);
12543
12672
default:
12544
12673
break;
12545
12674
}
@@ -12636,9 +12765,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12636
12765
}
12637
12766
12638
12767
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);
12642
12769
12643
12770
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12644
12771
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
12739
12866
}
12740
12867
12741
12868
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);
12745
12870
12746
12871
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12747
12872
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
12851
12976
return result;
12852
12977
}
12853
12978
12854
- yp_token_t operator = not_provided(parser);
12855
- node = parse_target(parser, node, &operator, NULL);
12856
-
12979
+ node = parse_target(parser, node);
12857
12980
parser_lex(parser);
12981
+
12858
12982
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12859
12983
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
12860
12984
}
0 commit comments