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.
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) { .opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .arguments = NULL, .closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, .block = NULL })
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 uint32_t
540
+ static inline yp_node_flags_t
474
541
  yp_regular_expression_flags_create(const yp_token_t *closing) {
475
- uint32_t flags = 0;
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 = yp_regular_expression_flags_create(closing);
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 |= YP_RANGE_NODE_FLAGS_EXCLUDE_END;
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
- .flags = yp_regular_expression_flags_create(closing)
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 = YP_NODE_FLAG_NEWLINE;
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, uint32_t flags) {
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, uint32_t flags) {
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
- // We only want to return a character literal if there's exactly one
5348
- // alphanumeric character right after the `?`
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
- !parser->encoding.alnum_char(parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
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
- yp_snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
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, yp_arguments_node_t *arguments, bool accepts_forwarding, yp_token_type_t terminator) {
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->arguments, true, YP_TOKEN_PARENTHESIS_RIGHT);
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->arguments, true, YP_TOKEN_EOF);
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
- uint32_t flags = 0;
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 = 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 (accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
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 &= (uint32_t) ~YP_CALL_NODE_FLAGS_VARIABLE_CALL;
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
- yp_arguments_node_t *arguments = NULL;
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 && accept(parser, YP_TOKEN_COMMA)) {
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
- do {
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
- } while (accept(parser, YP_TOKEN_COMMA));
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, &parser->previous, &arguments);
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.arguments, false, YP_TOKEN_BRACKET_RIGHT);
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.6.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.in",
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",