yarp 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/CONTRIBUTING.md +4 -0
- data/{Makefile.in → Makefile} +3 -4
- data/README.md +1 -1
- data/config.yml +29 -7
- data/docs/build_system.md +4 -15
- data/docs/building.md +1 -5
- data/docs/encoding.md +1 -0
- data/docs/{extension.md → ruby_api.md} +6 -3
- data/docs/serialization.md +71 -24
- data/ext/yarp/api_node.c +38 -6
- data/ext/yarp/extconf.rb +15 -10
- data/ext/yarp/extension.c +2 -0
- data/ext/yarp/extension.h +1 -1
- data/include/yarp/ast.h +108 -104
- data/include/yarp/defines.h +0 -15
- data/include/yarp/enc/yp_encoding.h +1 -0
- data/include/yarp/util/yp_buffer.h +1 -0
- data/include/yarp/util/yp_string.h +5 -1
- data/include/yarp/version.h +2 -3
- data/include/yarp.h +4 -2
- data/lib/yarp/ffi.rb +211 -0
- data/lib/yarp/lex_compat.rb +16 -2
- data/lib/yarp/node.rb +169 -117
- data/lib/yarp/ripper_compat.rb +3 -3
- data/lib/yarp/serialize.rb +285 -92
- data/lib/yarp.rb +167 -2
- data/src/enc/yp_unicode.c +9 -0
- data/src/node.c +22 -0
- data/src/prettyprint.c +49 -30
- data/src/serialize.c +90 -17
- data/src/util/yp_string.c +8 -17
- data/src/yarp.c +181 -49
- data/yarp.gemspec +5 -5
- metadata +6 -6
- data/config.h.in +0 -25
- data/configure +0 -4487
data/src/yarp.c
CHANGED
@@ -431,6 +431,49 @@ yp_parser_constant_id_token(yp_parser_t *parser, const yp_token_t *token) {
|
|
431
431
|
return yp_parser_constant_id_location(parser, token->start, token->end);
|
432
432
|
}
|
433
433
|
|
434
|
+
// Mark any range nodes in this subtree as flipflops.
|
435
|
+
static void
|
436
|
+
yp_flip_flop(yp_node_t *node) {
|
437
|
+
switch (YP_NODE_TYPE(node)) {
|
438
|
+
case YP_NODE_AND_NODE: {
|
439
|
+
yp_and_node_t *cast = (yp_and_node_t *) node;
|
440
|
+
yp_flip_flop(cast->left);
|
441
|
+
yp_flip_flop(cast->right);
|
442
|
+
break;
|
443
|
+
}
|
444
|
+
case YP_NODE_OR_NODE: {
|
445
|
+
yp_or_node_t *cast = (yp_or_node_t *) node;
|
446
|
+
yp_flip_flop(cast->left);
|
447
|
+
yp_flip_flop(cast->right);
|
448
|
+
break;
|
449
|
+
}
|
450
|
+
case YP_NODE_PARENTHESES_NODE: {
|
451
|
+
yp_parentheses_node_t *cast = (yp_parentheses_node_t *) node;
|
452
|
+
|
453
|
+
if ((cast->statements != NULL) && YP_NODE_TYPE_P(cast->statements, YP_NODE_STATEMENTS_NODE)) {
|
454
|
+
yp_statements_node_t *statements = (yp_statements_node_t *) cast->statements;
|
455
|
+
if (statements->body.size == 1) yp_flip_flop(statements->body.nodes[0]);
|
456
|
+
}
|
457
|
+
|
458
|
+
break;
|
459
|
+
}
|
460
|
+
case YP_NODE_RANGE_NODE: {
|
461
|
+
yp_range_node_t *cast = (yp_range_node_t *) node;
|
462
|
+
yp_flip_flop(cast->left);
|
463
|
+
yp_flip_flop(cast->right);
|
464
|
+
|
465
|
+
// Here we change the range node into a flip flop node. We can do
|
466
|
+
// this since the nodes are exactly the same except for the type.
|
467
|
+
assert(sizeof(yp_range_node_t) == sizeof(yp_flip_flop_node_t));
|
468
|
+
node->type = YP_NODE_FLIP_FLOP_NODE;
|
469
|
+
|
470
|
+
break;
|
471
|
+
}
|
472
|
+
default:
|
473
|
+
break;
|
474
|
+
}
|
475
|
+
}
|
476
|
+
|
434
477
|
// In a lot of places in the tree you can have tokens that are not provided but
|
435
478
|
// that do not cause an error. For example, in a method call without
|
436
479
|
// parentheses. In these cases we set the token to the "not provided" type. For
|
@@ -461,18 +504,42 @@ typedef struct {
|
|
461
504
|
yp_arguments_node_t *arguments;
|
462
505
|
yp_location_t closing_loc;
|
463
506
|
yp_block_node_t *block;
|
507
|
+
|
508
|
+
// This boolean is used to tell if there is an implicit block (i.e., an
|
509
|
+
// argument passed with an & operator).
|
510
|
+
bool implicit_block;
|
464
511
|
} yp_arguments_t;
|
465
512
|
|
466
|
-
#define YP_EMPTY_ARGUMENTS ((yp_arguments_t) {
|
513
|
+
#define YP_EMPTY_ARGUMENTS ((yp_arguments_t) { \
|
514
|
+
.opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \
|
515
|
+
.arguments = NULL, \
|
516
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \
|
517
|
+
.block = NULL, \
|
518
|
+
.implicit_block = false \
|
519
|
+
})
|
520
|
+
|
521
|
+
// Check that the set of arguments parsed for a given node is valid. This means
|
522
|
+
// checking that we don't have both an implicit and explicit block.
|
523
|
+
static void
|
524
|
+
yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) {
|
525
|
+
if (arguments->block != NULL && arguments->implicit_block) {
|
526
|
+
yp_diagnostic_list_append(
|
527
|
+
&parser->error_list,
|
528
|
+
arguments->block->base.location.start,
|
529
|
+
arguments->block->base.location.end,
|
530
|
+
"both block arg and actual block given"
|
531
|
+
);
|
532
|
+
}
|
533
|
+
}
|
467
534
|
|
468
535
|
/******************************************************************************/
|
469
536
|
/* Node creation functions */
|
470
537
|
/******************************************************************************/
|
471
538
|
|
472
539
|
// Parse out the options for a regular expression.
|
473
|
-
static inline
|
540
|
+
static inline yp_node_flags_t
|
474
541
|
yp_regular_expression_flags_create(const yp_token_t *closing) {
|
475
|
-
|
542
|
+
yp_node_flags_t flags = 0;
|
476
543
|
|
477
544
|
if (closing->type == YP_TOKEN_REGEXP_END) {
|
478
545
|
for (const char *flag = closing->start + 1; flag < closing->end; flag++) {
|
@@ -1063,8 +1130,7 @@ yp_call_node_create(yp_parser_t *parser) {
|
|
1063
1130
|
.opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1064
1131
|
.arguments = NULL,
|
1065
1132
|
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1066
|
-
.block = NULL
|
1067
|
-
.flags = 0
|
1133
|
+
.block = NULL
|
1068
1134
|
};
|
1069
1135
|
|
1070
1136
|
return node;
|
@@ -1140,7 +1206,7 @@ yp_call_node_call_create(yp_parser_t *parser, yp_node_t *receiver, yp_token_t *o
|
|
1140
1206
|
node->block = arguments->block;
|
1141
1207
|
|
1142
1208
|
if (operator->type == YP_TOKEN_AMPERSAND_DOT) {
|
1143
|
-
node->flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
|
1209
|
+
node->base.flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
|
1144
1210
|
}
|
1145
1211
|
|
1146
1212
|
yp_string_shared_init(&node->name, message->start, message->end);
|
@@ -1216,7 +1282,7 @@ yp_call_node_shorthand_create(yp_parser_t *parser, yp_node_t *receiver, yp_token
|
|
1216
1282
|
node->block = arguments->block;
|
1217
1283
|
|
1218
1284
|
if (operator->type == YP_TOKEN_AMPERSAND_DOT) {
|
1219
|
-
node->flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
|
1285
|
+
node->base.flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
|
1220
1286
|
}
|
1221
1287
|
|
1222
1288
|
yp_string_constant_init(&node->name, "call", 4);
|
@@ -1257,7 +1323,7 @@ yp_call_node_variable_call_create(yp_parser_t *parser, yp_token_t *message) {
|
|
1257
1323
|
// without a receiver that could also have been a local variable read).
|
1258
1324
|
static inline bool
|
1259
1325
|
yp_call_node_variable_call_p(yp_call_node_t *node) {
|
1260
|
-
return node->flags & YP_CALL_NODE_FLAGS_VARIABLE_CALL;
|
1326
|
+
return node->base.flags & YP_CALL_NODE_FLAGS_VARIABLE_CALL;
|
1261
1327
|
}
|
1262
1328
|
|
1263
1329
|
// Allocate and initialize a new CallOperatorAndWriteNode node.
|
@@ -2269,6 +2335,7 @@ yp_if_node_create(yp_parser_t *parser,
|
|
2269
2335
|
yp_node_t *consequent,
|
2270
2336
|
const yp_token_t *end_keyword
|
2271
2337
|
) {
|
2338
|
+
yp_flip_flop(predicate);
|
2272
2339
|
yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t);
|
2273
2340
|
|
2274
2341
|
const char *end;
|
@@ -2304,6 +2371,7 @@ yp_if_node_create(yp_parser_t *parser,
|
|
2304
2371
|
// Allocate and initialize new IfNode node in the modifier form.
|
2305
2372
|
static yp_if_node_t *
|
2306
2373
|
yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_token_t *if_keyword, yp_node_t *predicate) {
|
2374
|
+
yp_flip_flop(predicate);
|
2307
2375
|
yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t);
|
2308
2376
|
|
2309
2377
|
yp_statements_node_t *statements = yp_statements_node_create(parser);
|
@@ -2331,6 +2399,8 @@ yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_t
|
|
2331
2399
|
// Allocate and initialize an if node from a ternary expression.
|
2332
2400
|
static yp_if_node_t *
|
2333
2401
|
yp_if_node_ternary_create(yp_parser_t *parser, yp_node_t *predicate, yp_node_t *true_expression, const yp_token_t *colon, yp_node_t *false_expression) {
|
2402
|
+
yp_flip_flop(predicate);
|
2403
|
+
|
2334
2404
|
yp_statements_node_t *if_statements = yp_statements_node_create(parser);
|
2335
2405
|
yp_statements_node_body_append(if_statements, true_expression);
|
2336
2406
|
|
@@ -2593,7 +2663,6 @@ yp_interpolated_regular_expression_node_create(yp_parser_t *parser, const yp_tok
|
|
2593
2663
|
},
|
2594
2664
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
2595
2665
|
.closing_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
2596
|
-
.flags = 0,
|
2597
2666
|
.parts = YP_EMPTY_NODE_LIST
|
2598
2667
|
};
|
2599
2668
|
|
@@ -2610,7 +2679,7 @@ static inline void
|
|
2610
2679
|
yp_interpolated_regular_expression_node_closing_set(yp_interpolated_regular_expression_node_t *node, const yp_token_t *closing) {
|
2611
2680
|
node->closing_loc = YP_LOCATION_TOKEN_VALUE(closing);
|
2612
2681
|
node->base.location.end = closing->end;
|
2613
|
-
node->flags
|
2682
|
+
node->base.flags |= yp_regular_expression_flags_create(closing);
|
2614
2683
|
}
|
2615
2684
|
|
2616
2685
|
// Allocate and initialize a new InterpolatedStringNode node.
|
@@ -3394,14 +3463,13 @@ yp_range_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *ope
|
|
3394
3463
|
},
|
3395
3464
|
.left = left,
|
3396
3465
|
.right = right,
|
3397
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator)
|
3398
|
-
.flags = 0,
|
3466
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator)
|
3399
3467
|
};
|
3400
3468
|
|
3401
3469
|
switch (operator->type) {
|
3402
3470
|
case YP_TOKEN_DOT_DOT_DOT:
|
3403
3471
|
case YP_TOKEN_UDOT_DOT_DOT:
|
3404
|
-
node->flags |=
|
3472
|
+
node->base.flags |= YP_RANGE_FLAGS_EXCLUDE_END;
|
3405
3473
|
break;
|
3406
3474
|
default:
|
3407
3475
|
break;
|
@@ -3428,6 +3496,7 @@ yp_regular_expression_node_create(yp_parser_t *parser, const yp_token_t *opening
|
|
3428
3496
|
*node = (yp_regular_expression_node_t) {
|
3429
3497
|
{
|
3430
3498
|
.type = YP_NODE_REGULAR_EXPRESSION_NODE,
|
3499
|
+
.flags = yp_regular_expression_flags_create(closing),
|
3431
3500
|
.location = {
|
3432
3501
|
.start = opening->start,
|
3433
3502
|
.end = closing->end
|
@@ -3436,7 +3505,7 @@ yp_regular_expression_node_create(yp_parser_t *parser, const yp_token_t *opening
|
|
3436
3505
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
3437
3506
|
.content_loc = YP_LOCATION_TOKEN_VALUE(content),
|
3438
3507
|
.closing_loc = YP_LOCATION_TOKEN_VALUE(closing),
|
3439
|
-
.
|
3508
|
+
.unescaped = YP_EMPTY_STRING
|
3440
3509
|
};
|
3441
3510
|
|
3442
3511
|
return node;
|
@@ -3749,7 +3818,7 @@ yp_statements_node_body_append(yp_statements_node_t *node, yp_node_t *statement)
|
|
3749
3818
|
node->base.location.end = statement->location.end;
|
3750
3819
|
|
3751
3820
|
// Every statement gets marked as a place where a newline can occur.
|
3752
|
-
statement->flags
|
3821
|
+
statement->flags |= YP_NODE_FLAG_NEWLINE;
|
3753
3822
|
}
|
3754
3823
|
|
3755
3824
|
// Allocate a new StringConcatNode node.
|
@@ -3996,6 +4065,7 @@ yp_undef_node_append(yp_undef_node_t *node, yp_node_t *name) {
|
|
3996
4065
|
// Allocate a new UnlessNode node.
|
3997
4066
|
static yp_unless_node_t *
|
3998
4067
|
yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements) {
|
4068
|
+
yp_flip_flop(predicate);
|
3999
4069
|
yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t);
|
4000
4070
|
|
4001
4071
|
const char *end;
|
@@ -4027,6 +4097,7 @@ yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t
|
|
4027
4097
|
// Allocate and initialize new UnlessNode node in the modifier form.
|
4028
4098
|
static yp_unless_node_t *
|
4029
4099
|
yp_unless_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_token_t *unless_keyword, yp_node_t *predicate) {
|
4100
|
+
yp_flip_flop(predicate);
|
4030
4101
|
yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t);
|
4031
4102
|
|
4032
4103
|
yp_statements_node_t *statements = yp_statements_node_create(parser);
|
@@ -4059,7 +4130,7 @@ yp_unless_node_end_keyword_loc_set(yp_unless_node_t *node, const yp_token_t *end
|
|
4059
4130
|
|
4060
4131
|
// Allocate a new UntilNode node.
|
4061
4132
|
static yp_until_node_t *
|
4062
|
-
yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements,
|
4133
|
+
yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4063
4134
|
yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
|
4064
4135
|
bool has_statements = (statements != NULL) && (statements->body.size != 0);
|
4065
4136
|
|
@@ -4080,6 +4151,7 @@ yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
|
|
4080
4151
|
*node = (yp_until_node_t) {
|
4081
4152
|
{
|
4082
4153
|
.type = YP_NODE_UNTIL_NODE,
|
4154
|
+
.flags = flags,
|
4083
4155
|
.location = {
|
4084
4156
|
.start = start,
|
4085
4157
|
.end = end,
|
@@ -4087,8 +4159,7 @@ yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
|
|
4087
4159
|
},
|
4088
4160
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4089
4161
|
.predicate = predicate,
|
4090
|
-
.statements = statements
|
4091
|
-
.flags = flags
|
4162
|
+
.statements = statements
|
4092
4163
|
};
|
4093
4164
|
|
4094
4165
|
return node;
|
@@ -4134,7 +4205,7 @@ yp_when_node_statements_set(yp_when_node_t *node, yp_statements_node_t *statemen
|
|
4134
4205
|
|
4135
4206
|
// Allocate a new WhileNode node.
|
4136
4207
|
static yp_while_node_t *
|
4137
|
-
yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements,
|
4208
|
+
yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4138
4209
|
yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
|
4139
4210
|
|
4140
4211
|
const char *start = NULL;
|
@@ -4155,6 +4226,7 @@ yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
|
|
4155
4226
|
*node = (yp_while_node_t) {
|
4156
4227
|
{
|
4157
4228
|
.type = YP_NODE_WHILE_NODE,
|
4229
|
+
.flags = flags,
|
4158
4230
|
.location = {
|
4159
4231
|
.start = start,
|
4160
4232
|
.end = end,
|
@@ -4162,8 +4234,7 @@ yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
|
|
4162
4234
|
},
|
4163
4235
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4164
4236
|
.predicate = predicate,
|
4165
|
-
.statements = statements
|
4166
|
-
.flags = flags
|
4237
|
+
.statements = statements
|
4167
4238
|
};
|
4168
4239
|
|
4169
4240
|
return node;
|
@@ -4599,6 +4670,7 @@ parser_lex_encoding_comment(yp_parser_t *parser) {
|
|
4599
4670
|
ENCODING("cp1252", yp_encoding_windows_1252);
|
4600
4671
|
ENCODING("cp932", yp_encoding_windows_31j);
|
4601
4672
|
ENCODING("sjis", yp_encoding_windows_31j);
|
4673
|
+
ENCODING("utf8-mac", yp_encoding_utf8_mac);
|
4602
4674
|
|
4603
4675
|
#undef ENCODING
|
4604
4676
|
|
@@ -5344,13 +5416,14 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5344
5416
|
} else {
|
5345
5417
|
size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end);
|
5346
5418
|
|
5347
|
-
//
|
5348
|
-
//
|
5419
|
+
// Ternary operators can have a ? immediately followed by an identifier which starts with
|
5420
|
+
// an underscore. We check for this case
|
5349
5421
|
if (
|
5350
|
-
!parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
|
5422
|
+
!(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
|
5423
|
+
*parser->current.end == '_') ||
|
5351
5424
|
(
|
5352
5425
|
(parser->current.end + encoding_width >= parser->end) ||
|
5353
|
-
!
|
5426
|
+
!char_is_identifier(parser, parser->current.end + encoding_width)
|
5354
5427
|
)
|
5355
5428
|
) {
|
5356
5429
|
lex_state_set(parser, YP_LEX_STATE_END);
|
@@ -7084,14 +7157,14 @@ parser_lex(yp_parser_t *parser) {
|
|
7084
7157
|
breakpoint = yp_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1));
|
7085
7158
|
break;
|
7086
7159
|
case '\n': {
|
7087
|
-
yp_newline_list_append(&parser->newline_list, breakpoint);
|
7088
|
-
|
7089
7160
|
if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
|
7090
7161
|
parser_flush_heredoc_end(parser);
|
7091
7162
|
parser->current.end = breakpoint + 1;
|
7092
7163
|
LEX(YP_TOKEN_STRING_CONTENT);
|
7093
7164
|
}
|
7094
7165
|
|
7166
|
+
yp_newline_list_append(&parser->newline_list, breakpoint);
|
7167
|
+
|
7095
7168
|
const char *start = breakpoint + 1;
|
7096
7169
|
if (parser->lex_modes.current->as.heredoc.indent != YP_HEREDOC_INDENT_NONE) {
|
7097
7170
|
start += yp_strspn_inline_whitespace(start, parser->end - start);
|
@@ -7705,7 +7778,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7705
7778
|
char *name = calloc(length + 2, sizeof(char));
|
7706
7779
|
if (name == NULL) return NULL;
|
7707
7780
|
|
7708
|
-
|
7781
|
+
snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
|
7709
7782
|
|
7710
7783
|
// Now switch the name to the new string.
|
7711
7784
|
yp_string_free(&call->name);
|
@@ -8032,7 +8105,7 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) {
|
|
8032
8105
|
|
8033
8106
|
// Parse a list of arguments.
|
8034
8107
|
static void
|
8035
|
-
parse_arguments(yp_parser_t *parser,
|
8108
|
+
parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_forwarding, yp_token_type_t terminator) {
|
8036
8109
|
yp_binding_power_t binding_power = yp_binding_powers[parser->current.type].left;
|
8037
8110
|
|
8038
8111
|
// First we need to check if the next token is one that could be the start of
|
@@ -8085,6 +8158,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_node_t *arguments, bool accept
|
|
8085
8158
|
|
8086
8159
|
argument = (yp_node_t *)yp_block_argument_node_create(parser, &operator, expression);
|
8087
8160
|
parsed_block_argument = true;
|
8161
|
+
arguments->implicit_block = true;
|
8088
8162
|
break;
|
8089
8163
|
}
|
8090
8164
|
case YP_TOKEN_USTAR: {
|
@@ -8171,7 +8245,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_node_t *arguments, bool accept
|
|
8171
8245
|
}
|
8172
8246
|
}
|
8173
8247
|
|
8174
|
-
yp_arguments_node_arguments_append(arguments, argument);
|
8248
|
+
yp_arguments_node_arguments_append(arguments->arguments, argument);
|
8175
8249
|
|
8176
8250
|
// If parsing the argument failed, we need to stop parsing arguments.
|
8177
8251
|
if (YP_NODE_TYPE_P(argument, YP_NODE_MISSING_NODE) || parser->recovering) break;
|
@@ -8308,6 +8382,10 @@ update_parameter_state(yp_parser_t *parser, yp_token_t *token, yp_parameters_ord
|
|
8308
8382
|
return;
|
8309
8383
|
}
|
8310
8384
|
|
8385
|
+
if (token->type == YP_TOKEN_USTAR && *current == YP_PARAMETERS_ORDER_AFTER_OPTIONAL) {
|
8386
|
+
yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter *");
|
8387
|
+
}
|
8388
|
+
|
8311
8389
|
if (*current == YP_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
|
8312
8390
|
// We know what transition we failed on, so we can provide a better error here.
|
8313
8391
|
yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter order");
|
@@ -8863,7 +8941,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
|
|
8863
8941
|
arguments->arguments = yp_arguments_node_create(parser);
|
8864
8942
|
|
8865
8943
|
yp_accepts_block_stack_push(parser, true);
|
8866
|
-
parse_arguments(parser, arguments
|
8944
|
+
parse_arguments(parser, arguments, true, YP_TOKEN_PARENTHESIS_RIGHT);
|
8867
8945
|
expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a ')' to close the argument list.");
|
8868
8946
|
yp_accepts_block_stack_pop(parser);
|
8869
8947
|
|
@@ -8877,7 +8955,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
|
|
8877
8955
|
// operator. In this case we assume the subsequent token is part of an
|
8878
8956
|
// argument to this method call.
|
8879
8957
|
arguments->arguments = yp_arguments_node_create(parser);
|
8880
|
-
parse_arguments(parser, arguments
|
8958
|
+
parse_arguments(parser, arguments, true, YP_TOKEN_EOF);
|
8881
8959
|
|
8882
8960
|
yp_accepts_block_stack_pop(parser);
|
8883
8961
|
}
|
@@ -8895,6 +8973,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
|
|
8895
8973
|
}
|
8896
8974
|
}
|
8897
8975
|
|
8976
|
+
yp_arguments_validate(parser, arguments);
|
8898
8977
|
return found;
|
8899
8978
|
}
|
8900
8979
|
|
@@ -9359,7 +9438,7 @@ parse_alias_argument(yp_parser_t *parser, bool first) {
|
|
9359
9438
|
// Parse an identifier into either a local variable read or a call.
|
9360
9439
|
static yp_node_t *
|
9361
9440
|
parse_variable_call(yp_parser_t *parser) {
|
9362
|
-
|
9441
|
+
yp_node_flags_t flags = 0;
|
9363
9442
|
|
9364
9443
|
if (!match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) {
|
9365
9444
|
int depth;
|
@@ -9371,7 +9450,7 @@ parse_variable_call(yp_parser_t *parser) {
|
|
9371
9450
|
}
|
9372
9451
|
|
9373
9452
|
yp_call_node_t *node = yp_call_node_variable_call_create(parser, &parser->previous);
|
9374
|
-
node->flags
|
9453
|
+
node->base.flags |= flags;
|
9375
9454
|
|
9376
9455
|
return (yp_node_t *) node;
|
9377
9456
|
}
|
@@ -10172,6 +10251,30 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) {
|
|
10172
10251
|
return node;
|
10173
10252
|
}
|
10174
10253
|
|
10254
|
+
// Incorporate a negative sign into a numeric node by subtracting 1 character
|
10255
|
+
// from its start bounds. If it's a compound node, then we will recursively
|
10256
|
+
// apply this function to its value.
|
10257
|
+
static inline void
|
10258
|
+
parse_negative_numeric(yp_node_t *node) {
|
10259
|
+
switch (YP_NODE_TYPE(node)) {
|
10260
|
+
case YP_NODE_INTEGER_NODE:
|
10261
|
+
case YP_NODE_FLOAT_NODE:
|
10262
|
+
node->location.start--;
|
10263
|
+
break;
|
10264
|
+
case YP_NODE_RATIONAL_NODE:
|
10265
|
+
node->location.start--;
|
10266
|
+
parse_negative_numeric(((yp_rational_node_t *) node)->numeric);
|
10267
|
+
break;
|
10268
|
+
case YP_NODE_IMAGINARY_NODE:
|
10269
|
+
node->location.start--;
|
10270
|
+
parse_negative_numeric(((yp_imaginary_node_t *) node)->numeric);
|
10271
|
+
break;
|
10272
|
+
default:
|
10273
|
+
assert(false && "unreachable");
|
10274
|
+
break;
|
10275
|
+
}
|
10276
|
+
}
|
10277
|
+
|
10175
10278
|
// Parse an expression that begins with the previous node that we just lexed.
|
10176
10279
|
static inline yp_node_t *
|
10177
10280
|
parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
@@ -10260,6 +10363,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10260
10363
|
}
|
10261
10364
|
case YP_TOKEN_PARENTHESIS_LEFT:
|
10262
10365
|
case YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
|
10366
|
+
yp_token_type_t current_token_type = parser->current.type;
|
10263
10367
|
parser_lex(parser);
|
10264
10368
|
|
10265
10369
|
yp_token_t opening = parser->previous;
|
@@ -10280,7 +10384,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10280
10384
|
|
10281
10385
|
// If we hit a right parenthesis, then we're done parsing the parentheses
|
10282
10386
|
// node, and we can check which kind of node we should return.
|
10283
|
-
if (
|
10387
|
+
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
10388
|
+
if (current_token_type == YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
|
10389
|
+
lex_state_set(parser, YP_LEX_STATE_ENDARG);
|
10390
|
+
}
|
10391
|
+
parser_lex(parser);
|
10284
10392
|
yp_accepts_block_stack_pop(parser);
|
10285
10393
|
|
10286
10394
|
// If we have a single statement and are ending on a right parenthesis,
|
@@ -10496,7 +10604,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10496
10604
|
if (parse_arguments_list(parser, &arguments, true)) {
|
10497
10605
|
// Since we found arguments, we need to turn off the
|
10498
10606
|
// variable call bit in the flags.
|
10499
|
-
call->flags &= (
|
10607
|
+
call->base.flags &= (yp_node_flags_t) ~YP_CALL_NODE_FLAGS_VARIABLE_CALL;
|
10500
10608
|
|
10501
10609
|
call->opening_loc = arguments.opening_loc;
|
10502
10610
|
call->arguments = arguments.arguments;
|
@@ -10850,7 +10958,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10850
10958
|
parser_lex(parser);
|
10851
10959
|
|
10852
10960
|
yp_token_t keyword = parser->previous;
|
10853
|
-
|
10961
|
+
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
10854
10962
|
|
10855
10963
|
if (
|
10856
10964
|
token_begins_expression_p(parser->current.type) ||
|
@@ -10859,16 +10967,16 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10859
10967
|
yp_binding_power_t binding_power = yp_binding_powers[parser->current.type].left;
|
10860
10968
|
|
10861
10969
|
if (binding_power == YP_BINDING_POWER_UNSET || binding_power >= YP_BINDING_POWER_RANGE) {
|
10862
|
-
arguments = yp_arguments_node_create(parser);
|
10863
|
-
parse_arguments(parser, arguments, false, YP_TOKEN_EOF);
|
10970
|
+
arguments.arguments = yp_arguments_node_create(parser);
|
10971
|
+
parse_arguments(parser, &arguments, false, YP_TOKEN_EOF);
|
10864
10972
|
}
|
10865
10973
|
}
|
10866
10974
|
|
10867
10975
|
switch (keyword.type) {
|
10868
10976
|
case YP_TOKEN_KEYWORD_BREAK:
|
10869
|
-
return (yp_node_t *) yp_break_node_create(parser, &keyword, arguments);
|
10977
|
+
return (yp_node_t *) yp_break_node_create(parser, &keyword, arguments.arguments);
|
10870
10978
|
case YP_TOKEN_KEYWORD_NEXT:
|
10871
|
-
return (yp_node_t *) yp_next_node_create(parser, &keyword, arguments);
|
10979
|
+
return (yp_node_t *) yp_next_node_create(parser, &keyword, arguments.arguments);
|
10872
10980
|
case YP_TOKEN_KEYWORD_RETURN: {
|
10873
10981
|
if (
|
10874
10982
|
(parser->current_context->context == YP_CONTEXT_CLASS) ||
|
@@ -10876,7 +10984,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10876
10984
|
) {
|
10877
10985
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid return in class/module body");
|
10878
10986
|
}
|
10879
|
-
return (yp_node_t *) yp_return_node_create(parser, &keyword, arguments);
|
10987
|
+
return (yp_node_t *) yp_return_node_create(parser, &keyword, arguments.arguments);
|
10880
10988
|
}
|
10881
10989
|
default:
|
10882
10990
|
assert(false && "unreachable");
|
@@ -11342,6 +11450,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11342
11450
|
arguments.closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end });
|
11343
11451
|
} else {
|
11344
11452
|
receiver = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected expression after `not`.");
|
11453
|
+
yp_flip_flop(receiver);
|
11345
11454
|
|
11346
11455
|
if (!parser->recovering) {
|
11347
11456
|
accept(parser, YP_TOKEN_NEWLINE);
|
@@ -11351,6 +11460,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11351
11460
|
}
|
11352
11461
|
} else {
|
11353
11462
|
receiver = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected expression after `not`.");
|
11463
|
+
yp_flip_flop(receiver);
|
11354
11464
|
}
|
11355
11465
|
|
11356
11466
|
return (yp_node_t *) yp_call_node_not_create(parser, receiver, &message, &arguments);
|
@@ -11928,6 +12038,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11928
12038
|
yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary !.");
|
11929
12039
|
yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "!");
|
11930
12040
|
|
12041
|
+
yp_flip_flop(receiver);
|
11931
12042
|
return (yp_node_t *) node;
|
11932
12043
|
}
|
11933
12044
|
case YP_TOKEN_TILDE: {
|
@@ -11939,8 +12050,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11939
12050
|
|
11940
12051
|
return (yp_node_t *) node;
|
11941
12052
|
}
|
11942
|
-
case YP_TOKEN_UMINUS:
|
11943
|
-
case YP_TOKEN_UMINUS_NUM: {
|
12053
|
+
case YP_TOKEN_UMINUS: {
|
11944
12054
|
parser_lex(parser);
|
11945
12055
|
|
11946
12056
|
yp_token_t operator = parser->previous;
|
@@ -11949,6 +12059,26 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11949
12059
|
|
11950
12060
|
return (yp_node_t *) node;
|
11951
12061
|
}
|
12062
|
+
case YP_TOKEN_UMINUS_NUM: {
|
12063
|
+
parser_lex(parser);
|
12064
|
+
|
12065
|
+
yp_token_t operator = parser->previous;
|
12066
|
+
yp_node_t *node = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary -.");
|
12067
|
+
|
12068
|
+
switch (YP_NODE_TYPE(node)) {
|
12069
|
+
case YP_NODE_INTEGER_NODE:
|
12070
|
+
case YP_NODE_FLOAT_NODE:
|
12071
|
+
case YP_NODE_RATIONAL_NODE:
|
12072
|
+
case YP_NODE_IMAGINARY_NODE:
|
12073
|
+
parse_negative_numeric(node);
|
12074
|
+
break;
|
12075
|
+
default:
|
12076
|
+
node = (yp_node_t *) yp_call_node_unary_create(parser, &operator, node, "-@");
|
12077
|
+
break;
|
12078
|
+
}
|
12079
|
+
|
12080
|
+
return node;
|
12081
|
+
}
|
11952
12082
|
case YP_TOKEN_MINUS_GREATER: {
|
11953
12083
|
int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
|
11954
12084
|
parser->lambda_enclosure_nesting = parser->enclosure_nesting;
|
@@ -12195,18 +12325,18 @@ static inline yp_node_t *
|
|
12195
12325
|
parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power, const char *message) {
|
12196
12326
|
yp_node_t *value = parse_starred_expression(parser, binding_power, message);
|
12197
12327
|
|
12198
|
-
if (previous_binding_power == YP_BINDING_POWER_STATEMENT &&
|
12328
|
+
if (previous_binding_power == YP_BINDING_POWER_STATEMENT && (YP_NODE_TYPE_P(value, YP_NODE_SPLAT_NODE) || match_type_p(parser, YP_TOKEN_COMMA))) {
|
12199
12329
|
yp_token_t opening = not_provided(parser);
|
12200
12330
|
yp_array_node_t *array = yp_array_node_create(parser, &opening);
|
12201
12331
|
|
12202
12332
|
yp_array_node_elements_append(array, value);
|
12203
12333
|
value = (yp_node_t *) array;
|
12204
12334
|
|
12205
|
-
|
12335
|
+
while (accept(parser, YP_TOKEN_COMMA)) {
|
12206
12336
|
yp_node_t *element = parse_starred_expression(parser, binding_power, "Expected an element for the array.");
|
12207
12337
|
yp_array_node_elements_append(array, element);
|
12208
12338
|
if (YP_NODE_TYPE_P(element, YP_NODE_MISSING_NODE)) break;
|
12209
|
-
}
|
12339
|
+
}
|
12210
12340
|
}
|
12211
12341
|
|
12212
12342
|
return value;
|
@@ -12808,12 +12938,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12808
12938
|
case YP_CASE_KEYWORD:
|
12809
12939
|
case YP_TOKEN_IDENTIFIER: {
|
12810
12940
|
parser_lex(parser);
|
12941
|
+
yp_token_t message = parser->previous;
|
12811
12942
|
|
12812
12943
|
// If we have an identifier following a '::' operator, then it is for
|
12813
12944
|
// sure a method call.
|
12814
12945
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
12815
12946
|
parse_arguments_list(parser, &arguments, true);
|
12816
|
-
yp_call_node_t *call = yp_call_node_call_create(parser, node, &delimiter, &
|
12947
|
+
yp_call_node_t *call = yp_call_node_call_create(parser, node, &delimiter, &message, &arguments);
|
12817
12948
|
|
12818
12949
|
// If this is followed by a comma then it is a multiple assignment.
|
12819
12950
|
if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) {
|
@@ -12854,7 +12985,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12854
12985
|
yp_accepts_block_stack_push(parser, true);
|
12855
12986
|
arguments.arguments = yp_arguments_node_create(parser);
|
12856
12987
|
|
12857
|
-
parse_arguments(parser, arguments
|
12988
|
+
parse_arguments(parser, &arguments, false, YP_TOKEN_BRACKET_RIGHT);
|
12858
12989
|
yp_accepts_block_stack_pop(parser);
|
12859
12990
|
|
12860
12991
|
expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected ']' to close the bracket expression.");
|
@@ -12878,6 +13009,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12878
13009
|
arguments.block = parse_block(parser);
|
12879
13010
|
}
|
12880
13011
|
|
13012
|
+
yp_arguments_validate(parser, &arguments);
|
12881
13013
|
return (yp_node_t *) yp_call_node_aref_create(parser, node, &arguments);
|
12882
13014
|
}
|
12883
13015
|
case YP_TOKEN_KEYWORD_IN: {
|
data/yarp.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "yarp"
|
5
|
-
spec.version = "0.
|
5
|
+
spec.version = "0.7.0"
|
6
6
|
spec.authors = ["Shopify"]
|
7
7
|
spec.email = ["ruby@shopify.com"]
|
8
8
|
|
@@ -14,24 +14,23 @@ Gem::Specification.new do |spec|
|
|
14
14
|
|
15
15
|
spec.require_paths = ["lib"]
|
16
16
|
spec.files = [
|
17
|
+
"CHANGELOG.md",
|
17
18
|
"CODE_OF_CONDUCT.md",
|
18
19
|
"CONTRIBUTING.md",
|
19
20
|
"LICENSE.md",
|
20
|
-
"Makefile
|
21
|
+
"Makefile",
|
21
22
|
"README.md",
|
22
|
-
"config.h.in",
|
23
23
|
"config.yml",
|
24
|
-
"configure",
|
25
24
|
"docs/build_system.md",
|
26
25
|
"docs/building.md",
|
27
26
|
"docs/configuration.md",
|
28
27
|
"docs/design.md",
|
29
28
|
"docs/encoding.md",
|
30
|
-
"docs/extension.md",
|
31
29
|
"docs/fuzzing.md",
|
32
30
|
"docs/heredocs.md",
|
33
31
|
"docs/mapping.md",
|
34
32
|
"docs/ripper.md",
|
33
|
+
"docs/ruby_api.md",
|
35
34
|
"docs/serialization.md",
|
36
35
|
"docs/testing.md",
|
37
36
|
"ext/yarp/api_node.c",
|
@@ -60,6 +59,7 @@ Gem::Specification.new do |spec|
|
|
60
59
|
"include/yarp/util/yp_strpbrk.h",
|
61
60
|
"include/yarp/version.h",
|
62
61
|
"lib/yarp.rb",
|
62
|
+
"lib/yarp/ffi.rb",
|
63
63
|
"lib/yarp/lex_compat.rb",
|
64
64
|
"lib/yarp/node.rb",
|
65
65
|
"lib/yarp/pack.rb",
|