yarp 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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",
|