yarp 0.6.0 → 0.7.0

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