@@ -549,48 +549,45 @@ typedef struct {
549
549
yp_location_t opening_loc;
550
550
yp_arguments_node_t *arguments;
551
551
yp_location_t closing_loc;
552
- yp_block_node_t *block;
553
-
554
- // This boolean is used to tell if there is an implicit block (i.e., an
555
- // argument passed with an & operator).
556
- bool implicit_block;
552
+ yp_node_t *block;
557
553
} yp_arguments_t;
558
554
559
555
#define YP_EMPTY_ARGUMENTS ((yp_arguments_t) { \
560
556
.opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \
561
557
.arguments = NULL, \
562
558
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \
563
559
.block = NULL, \
564
- .implicit_block = false \
565
560
})
566
561
567
- // Check that the set of arguments parsed for a given node is valid. This means
568
- // checking that we don't have both an implicit and explicit block .
562
+ // Check that we're not about to attempt to attach a brace block to a call that
563
+ // has arguments without parentheses .
569
564
static void
570
- yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) {
571
- if (arguments->block != NULL && arguments->implicit_block) {
572
- yp_diagnostic_list_append(
573
- &parser->error_list,
574
- arguments->block->base.location.start,
575
- arguments->block->base.location.end,
576
- YP_ERR_ARGUMENT_BLOCK_MULTI
577
- );
565
+ yp_arguments_validate_block(yp_parser_t *parser, yp_arguments_t *arguments, yp_block_node_t *block) {
566
+ // First, check that we have arguments and that we don't have a closing
567
+ // location for them.
568
+ if (arguments->arguments == NULL || arguments->closing_loc.start != NULL) {
569
+ return;
578
570
}
579
571
580
- // Brace blocks can't be attached to arguments, only to the call
581
- if (arguments->block != NULL &&
582
- *arguments->block->opening_loc.start == '{' &&
583
- arguments->arguments != NULL &&
584
- !(arguments->arguments->arguments.size == 1 &&
585
- YP_NODE_TYPE_P(arguments->arguments->arguments.nodes[0], YP_PARENTHESES_NODE)) &&
586
- !arguments->closing_loc.end) {
587
- yp_diagnostic_list_append(
588
- &parser->error_list,
589
- arguments->block->base.location.start,
590
- arguments->block->base.location.end,
591
- YP_ERR_ARGUMENT_BLOCK_MULTI
592
- );
572
+ // Next, check that we don't have a single parentheses argument. This would
573
+ // look like:
574
+ //
575
+ // foo (1) {}
576
+ //
577
+ // In this case, it's actually okay for the block to be attached to the
578
+ // call, even though it looks like it's attached to the argument.
579
+ if (arguments->arguments->arguments.size == 1 && YP_NODE_TYPE_P(arguments->arguments->arguments.nodes[0], YP_PARENTHESES_NODE)) {
580
+ return;
593
581
}
582
+
583
+ // If we didn't hit a case before this check, then at this point we need to
584
+ // add a syntax error.
585
+ yp_diagnostic_list_append(
586
+ &parser->error_list,
587
+ block->base.location.start,
588
+ block->base.location.end,
589
+ YP_ERR_ARGUMENT_UNEXPECTED_BLOCK
590
+ );
594
591
}
595
592
596
593
/******************************************************************************/
@@ -1340,7 +1337,7 @@ yp_call_node_aref_create(yp_parser_t *parser, yp_node_t *receiver, yp_arguments_
1340
1337
1341
1338
node->base.location.start = receiver->location.start;
1342
1339
if (arguments->block != NULL) {
1343
- node->base.location.end = arguments->block->base. location.end;
1340
+ node->base.location.end = arguments->block->location.end;
1344
1341
} else {
1345
1342
node->base.location.end = arguments->closing_loc.end;
1346
1343
}
@@ -1384,7 +1381,7 @@ yp_call_node_call_create(yp_parser_t *parser, yp_node_t *receiver, yp_token_t *o
1384
1381
1385
1382
node->base.location.start = receiver->location.start;
1386
1383
if (arguments->block != NULL) {
1387
- node->base.location.end = arguments->block->base. location.end;
1384
+ node->base.location.end = arguments->block->location.end;
1388
1385
} else if (arguments->closing_loc.start != NULL) {
1389
1386
node->base.location.end = arguments->closing_loc.end;
1390
1387
} else if (arguments->arguments != NULL) {
@@ -1417,7 +1414,7 @@ yp_call_node_fcall_create(yp_parser_t *parser, yp_token_t *message, yp_arguments
1417
1414
1418
1415
node->base.location.start = message->start;
1419
1416
if (arguments->block != NULL) {
1420
- node->base.location.end = arguments->block->base. location.end;
1417
+ node->base.location.end = arguments->block->location.end;
1421
1418
} else if (arguments->closing_loc.start != NULL) {
1422
1419
node->base.location.end = arguments->closing_loc.end;
1423
1420
} else if (arguments->arguments != NULL) {
@@ -1465,7 +1462,7 @@ yp_call_node_shorthand_create(yp_parser_t *parser, yp_node_t *receiver, yp_token
1465
1462
1466
1463
node->base.location.start = receiver->location.start;
1467
1464
if (arguments->block != NULL) {
1468
- node->base.location.end = arguments->block->base. location.end;
1465
+ node->base.location.end = arguments->block->location.end;
1469
1466
} else {
1470
1467
node->base.location.end = arguments->closing_loc.end;
1471
1468
}
@@ -2414,18 +2411,24 @@ yp_forwarding_parameter_node_create(yp_parser_t *parser, const yp_token_t *token
2414
2411
// Allocate and initialize a new ForwardingSuper node.
2415
2412
static yp_forwarding_super_node_t *
2416
2413
yp_forwarding_super_node_create(yp_parser_t *parser, const yp_token_t *token, yp_arguments_t *arguments) {
2414
+ assert(arguments->block == NULL || YP_NODE_TYPE_P(arguments->block, YP_BLOCK_NODE));
2417
2415
assert(token->type == YP_TOKEN_KEYWORD_SUPER);
2418
2416
yp_forwarding_super_node_t *node = YP_ALLOC_NODE(parser, yp_forwarding_super_node_t);
2419
2417
2418
+ yp_block_node_t *block = NULL;
2419
+ if (arguments->block != NULL) {
2420
+ block = (yp_block_node_t *) arguments->block;
2421
+ }
2422
+
2420
2423
*node = (yp_forwarding_super_node_t) {
2421
2424
{
2422
2425
.type = YP_FORWARDING_SUPER_NODE,
2423
2426
.location = {
2424
2427
.start = token->start,
2425
- .end = arguments-> block != NULL ? arguments-> block->base.location.end : token->end
2428
+ .end = block != NULL ? block->base.location.end : token->end
2426
2429
},
2427
2430
},
2428
- .block = arguments-> block
2431
+ .block = block
2429
2432
};
2430
2433
2431
2434
return node;
@@ -4282,7 +4285,7 @@ yp_super_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_argument
4282
4285
4283
4286
const uint8_t *end;
4284
4287
if (arguments->block != NULL) {
4285
- end = arguments->block->base. location.end;
4288
+ end = arguments->block->location.end;
4286
4289
} else if (arguments->closing_loc.start != NULL) {
4287
4290
end = arguments->closing_loc.end;
4288
4291
} else if (arguments->arguments != NULL) {
@@ -8893,6 +8896,16 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) {
8893
8896
}
8894
8897
}
8895
8898
8899
+ // Append an argument to a list of arguments.
8900
+ static inline void
8901
+ parse_arguments_append(yp_parser_t *parser, yp_arguments_t *arguments, yp_node_t *argument) {
8902
+ if (arguments->arguments == NULL) {
8903
+ arguments->arguments = yp_arguments_node_create(parser);
8904
+ }
8905
+
8906
+ yp_arguments_node_arguments_append(arguments->arguments, argument);
8907
+ }
8908
+
8896
8909
// Parse a list of arguments.
8897
8910
static void
8898
8911
parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_forwarding, yp_token_type_t terminator) {
@@ -8926,13 +8939,14 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for
8926
8939
}
8927
8940
8928
8941
yp_keyword_hash_node_t *hash = yp_keyword_hash_node_create(parser);
8929
- argument = (yp_node_t *)hash;
8942
+ argument = (yp_node_t *) hash;
8930
8943
8931
8944
if (!match7(parser, terminator, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON, YP_TOKEN_EOF, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_KEYWORD_DO, YP_TOKEN_PARENTHESIS_RIGHT)) {
8932
8945
parse_assocs(parser, (yp_node_t *) hash);
8933
8946
}
8934
8947
8935
8948
parsed_bare_hash = true;
8949
+ parse_arguments_append(parser, arguments, argument);
8936
8950
break;
8937
8951
}
8938
8952
case YP_TOKEN_UAMPERSAND: {
@@ -8946,9 +8960,14 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for
8946
8960
yp_diagnostic_list_append(&parser->error_list, operator.start, operator.end, YP_ERR_ARGUMENT_NO_FORWARDING_AMP);
8947
8961
}
8948
8962
8949
- argument = (yp_node_t *)yp_block_argument_node_create(parser, &operator, expression);
8963
+ argument = (yp_node_t *) yp_block_argument_node_create(parser, &operator, expression);
8964
+ if (parsed_block_argument) {
8965
+ parse_arguments_append(parser, arguments, argument);
8966
+ } else {
8967
+ arguments->block = argument;
8968
+ }
8969
+
8950
8970
parsed_block_argument = true;
8951
- arguments->implicit_block = true;
8952
8971
break;
8953
8972
}
8954
8973
case YP_TOKEN_USTAR: {
@@ -8971,6 +8990,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for
8971
8990
argument = (yp_node_t *) yp_splat_node_create(parser, &operator, expression);
8972
8991
}
8973
8992
8993
+ parse_arguments_append(parser, arguments, argument);
8974
8994
break;
8975
8995
}
8976
8996
case YP_TOKEN_UDOT_DOT_DOT: {
@@ -8988,7 +9008,8 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for
8988
9008
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, YP_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
8989
9009
}
8990
9010
8991
- argument = (yp_node_t *)yp_forwarding_arguments_node_create(parser, &parser->previous);
9011
+ argument = (yp_node_t *) yp_forwarding_arguments_node_create(parser, &parser->previous);
9012
+ parse_arguments_append(parser, arguments, argument);
8992
9013
break;
8993
9014
}
8994
9015
}
@@ -9031,12 +9052,11 @@ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_for
9031
9052
parsed_bare_hash = true;
9032
9053
}
9033
9054
9055
+ parse_arguments_append(parser, arguments, argument);
9034
9056
break;
9035
9057
}
9036
9058
}
9037
9059
9038
- yp_arguments_node_arguments_append(arguments->arguments, argument);
9039
-
9040
9060
// If parsing the argument failed, we need to stop parsing arguments.
9041
9061
if (YP_NODE_TYPE_P(argument, YP_MISSING_NODE) || parser->recovering) break;
9042
9062
@@ -9736,8 +9756,6 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
9736
9756
if (accept1(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
9737
9757
arguments->closing_loc = YP_LOCATION_TOKEN_VALUE(&parser->previous);
9738
9758
} else {
9739
- arguments->arguments = yp_arguments_node_create(parser);
9740
-
9741
9759
yp_accepts_block_stack_push(parser, true);
9742
9760
parse_arguments(parser, arguments, true, YP_TOKEN_PARENTHESIS_RIGHT);
9743
9761
expect1(parser, YP_TOKEN_PARENTHESIS_RIGHT, YP_ERR_ARGUMENT_TERM_PAREN);
@@ -9752,7 +9770,6 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
9752
9770
// If we get here, then the subsequent token cannot be used as an infix
9753
9771
// operator. In this case we assume the subsequent token is part of an
9754
9772
// argument to this method call.
9755
- arguments->arguments = yp_arguments_node_create(parser);
9756
9773
parse_arguments(parser, arguments, true, YP_TOKEN_EOF);
9757
9774
9758
9775
yp_accepts_block_stack_pop(parser);
@@ -9762,16 +9779,28 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
9762
9779
// node that starts with a {. If there is, then we can parse it and add it to
9763
9780
// the arguments.
9764
9781
if (accepts_block) {
9782
+ yp_block_node_t *block = NULL;
9783
+
9765
9784
if (accept1(parser, YP_TOKEN_BRACE_LEFT)) {
9766
9785
found |= true;
9767
- arguments->block = parse_block(parser);
9786
+ block = parse_block(parser);
9787
+ yp_arguments_validate_block(parser, arguments, block);
9768
9788
} else if (yp_accepts_block_stack_p(parser) && accept1(parser, YP_TOKEN_KEYWORD_DO)) {
9769
9789
found |= true;
9770
- arguments->block = parse_block(parser);
9790
+ block = parse_block(parser);
9791
+ }
9792
+
9793
+ if (block != NULL) {
9794
+ if (arguments->block == NULL) {
9795
+ arguments->block = (yp_node_t *) block;
9796
+ } else {
9797
+ yp_diagnostic_list_append(&parser->error_list, block->base.location.start, block->base.location.end, YP_ERR_ARGUMENT_BLOCK_MULTI);
9798
+ yp_arguments_node_arguments_append(arguments->arguments, arguments->block);
9799
+ arguments->block = (yp_node_t *) block;
9800
+ }
9771
9801
}
9772
9802
}
9773
9803
9774
- yp_arguments_validate(parser, arguments);
9775
9804
return found;
9776
9805
}
9777
9806
@@ -11705,7 +11734,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
11705
11734
call->block = arguments.block;
11706
11735
11707
11736
if (arguments.block != NULL) {
11708
- call->base.location.end = arguments.block->base. location.end;
11737
+ call->base.location.end = arguments.block->location.end;
11709
11738
} else if (arguments.closing_loc.start == NULL) {
11710
11739
if (arguments.arguments != NULL) {
11711
11740
call->base.location.end = arguments.arguments->base.location.end;
@@ -12121,7 +12150,6 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
12121
12150
yp_binding_power_t binding_power = yp_binding_powers[parser->current.type].left;
12122
12151
12123
12152
if (binding_power == YP_BINDING_POWER_UNSET || binding_power >= YP_BINDING_POWER_RANGE) {
12124
- arguments.arguments = yp_arguments_node_create(parser);
12125
12153
parse_arguments(parser, &arguments, false, YP_TOKEN_EOF);
12126
12154
}
12127
12155
}
@@ -14079,11 +14107,8 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
14079
14107
14080
14108
if (!accept1(parser, YP_TOKEN_BRACKET_RIGHT)) {
14081
14109
yp_accepts_block_stack_push(parser, true);
14082
- arguments.arguments = yp_arguments_node_create(parser);
14083
-
14084
14110
parse_arguments(parser, &arguments, false, YP_TOKEN_BRACKET_RIGHT);
14085
14111
yp_accepts_block_stack_pop(parser);
14086
-
14087
14112
expect1(parser, YP_TOKEN_BRACKET_RIGHT, YP_ERR_EXPECT_RBRACKET);
14088
14113
}
14089
14114
@@ -14099,13 +14124,23 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
14099
14124
// If we're at the end of the arguments, we can now check if there is a
14100
14125
// block node that starts with a {. If there is, then we can parse it and
14101
14126
// add it to the arguments.
14127
+ yp_block_node_t *block = NULL;
14102
14128
if (accept1(parser, YP_TOKEN_BRACE_LEFT)) {
14103
- arguments.block = parse_block(parser);
14129
+ block = parse_block(parser);
14130
+ yp_arguments_validate_block(parser, &arguments, block);
14104
14131
} else if (yp_accepts_block_stack_p(parser) && accept1(parser, YP_TOKEN_KEYWORD_DO)) {
14105
- arguments.block = parse_block(parser);
14132
+ block = parse_block(parser);
14133
+ }
14134
+
14135
+ if (block != NULL) {
14136
+ if (arguments.block != NULL) {
14137
+ yp_diagnostic_list_append(&parser->error_list, block->base.location.start, block->base.location.end, YP_ERR_ARGUMENT_AFTER_BLOCK);
14138
+ yp_arguments_node_arguments_append(arguments.arguments, arguments.block);
14139
+ }
14140
+
14141
+ arguments.block = (yp_node_t *) block;
14106
14142
}
14107
14143
14108
- yp_arguments_validate(parser, &arguments);
14109
14144
return (yp_node_t *) yp_call_node_aref_create(parser, node, &arguments);
14110
14145
}
14111
14146
case YP_TOKEN_KEYWORD_IN: {
0 commit comments