yarp 0.6.0 → 0.8.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/CONTRIBUTING.md +4 -0
  4. data/{Makefile.in → Makefile} +5 -4
  5. data/README.md +6 -3
  6. data/config.yml +83 -274
  7. data/docs/build_system.md +4 -15
  8. data/docs/building.md +1 -5
  9. data/docs/encoding.md +1 -0
  10. data/docs/{extension.md → ruby_api.md} +6 -3
  11. data/docs/serialization.md +71 -24
  12. data/ext/yarp/api_node.c +173 -585
  13. data/ext/yarp/extconf.rb +15 -10
  14. data/ext/yarp/extension.c +4 -2
  15. data/ext/yarp/extension.h +1 -1
  16. data/include/yarp/ast.h +167 -306
  17. data/include/yarp/defines.h +5 -15
  18. data/include/yarp/enc/yp_encoding.h +1 -0
  19. data/include/yarp/unescape.h +1 -1
  20. data/include/yarp/util/yp_buffer.h +9 -0
  21. data/include/yarp/util/yp_constant_pool.h +3 -0
  22. data/include/yarp/util/yp_list.h +7 -7
  23. data/include/yarp/util/yp_newline_list.h +4 -0
  24. data/include/yarp/util/yp_state_stack.h +1 -1
  25. data/include/yarp/util/yp_string.h +5 -1
  26. data/include/yarp/version.h +2 -3
  27. data/include/yarp.h +4 -2
  28. data/lib/yarp/ffi.rb +226 -0
  29. data/lib/yarp/lex_compat.rb +16 -2
  30. data/lib/yarp/node.rb +594 -1437
  31. data/lib/yarp/ripper_compat.rb +3 -3
  32. data/lib/yarp/serialize.rb +312 -149
  33. data/lib/yarp.rb +167 -2
  34. data/src/enc/yp_unicode.c +9 -0
  35. data/src/node.c +92 -250
  36. data/src/prettyprint.c +81 -206
  37. data/src/serialize.c +124 -149
  38. data/src/unescape.c +29 -35
  39. data/src/util/yp_buffer.c +18 -0
  40. data/src/util/yp_list.c +7 -16
  41. data/src/util/yp_state_stack.c +0 -6
  42. data/src/util/yp_string.c +8 -17
  43. data/src/yarp.c +444 -717
  44. data/yarp.gemspec +5 -5
  45. metadata +6 -6
  46. data/config.h.in +0 -25
  47. data/configure +0 -4487
data/src/yarp.c CHANGED
@@ -431,6 +431,53 @@ 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->body != NULL) && YP_NODE_TYPE_P(cast->body, YP_NODE_STATEMENTS_NODE)) {
454
+ yp_statements_node_t *statements = (yp_statements_node_t *) cast->body;
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
+ if (cast->left) {
463
+ yp_flip_flop(cast->left);
464
+ }
465
+ if (cast->right) {
466
+ yp_flip_flop(cast->right);
467
+ }
468
+
469
+ // Here we change the range node into a flip flop node. We can do
470
+ // this since the nodes are exactly the same except for the type.
471
+ assert(sizeof(yp_range_node_t) == sizeof(yp_flip_flop_node_t));
472
+ node->type = YP_NODE_FLIP_FLOP_NODE;
473
+
474
+ break;
475
+ }
476
+ default:
477
+ break;
478
+ }
479
+ }
480
+
434
481
  // In a lot of places in the tree you can have tokens that are not provided but
435
482
  // that do not cause an error. For example, in a method call without
436
483
  // parentheses. In these cases we set the token to the "not provided" type. For
@@ -461,18 +508,42 @@ typedef struct {
461
508
  yp_arguments_node_t *arguments;
462
509
  yp_location_t closing_loc;
463
510
  yp_block_node_t *block;
511
+
512
+ // This boolean is used to tell if there is an implicit block (i.e., an
513
+ // argument passed with an & operator).
514
+ bool implicit_block;
464
515
  } yp_arguments_t;
465
516
 
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 })
517
+ #define YP_EMPTY_ARGUMENTS ((yp_arguments_t) { \
518
+ .opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \
519
+ .arguments = NULL, \
520
+ .closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE, \
521
+ .block = NULL, \
522
+ .implicit_block = false \
523
+ })
524
+
525
+ // Check that the set of arguments parsed for a given node is valid. This means
526
+ // checking that we don't have both an implicit and explicit block.
527
+ static void
528
+ yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) {
529
+ if (arguments->block != NULL && arguments->implicit_block) {
530
+ yp_diagnostic_list_append(
531
+ &parser->error_list,
532
+ arguments->block->base.location.start,
533
+ arguments->block->base.location.end,
534
+ "both block arg and actual block given"
535
+ );
536
+ }
537
+ }
467
538
 
468
539
  /******************************************************************************/
469
540
  /* Node creation functions */
470
541
  /******************************************************************************/
471
542
 
472
543
  // Parse out the options for a regular expression.
473
- static inline uint32_t
544
+ static inline yp_node_flags_t
474
545
  yp_regular_expression_flags_create(const yp_token_t *closing) {
475
- uint32_t flags = 0;
546
+ yp_node_flags_t flags = 0;
476
547
 
477
548
  if (closing->type == YP_TOKEN_REGEXP_END) {
478
549
  for (const char *flag = closing->start + 1; flag < closing->end; flag++) {
@@ -587,6 +658,27 @@ yp_and_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *opera
587
658
  return node;
588
659
  }
589
660
 
661
+ // Allocate and initialize a new AndWriteNode.
662
+ static yp_and_write_node_t *
663
+ yp_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
664
+ yp_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_and_write_node_t);
665
+
666
+ *node = (yp_and_write_node_t) {
667
+ {
668
+ .type = YP_NODE_AND_WRITE_NODE,
669
+ .location = {
670
+ .start = target->location.start,
671
+ .end = value->location.end
672
+ },
673
+ },
674
+ .target = target,
675
+ .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
676
+ .value = value
677
+ };
678
+
679
+ return node;
680
+ }
681
+
590
682
  // Allocate an initialize a new arguments node.
591
683
  static yp_arguments_node_t *
592
684
  yp_arguments_node_create(yp_parser_t *parser) {
@@ -926,7 +1018,7 @@ yp_block_argument_node_create(yp_parser_t *parser, const yp_token_t *operator, y
926
1018
 
927
1019
  // Allocate and initialize a new BlockNode node.
928
1020
  static yp_block_node_t *
929
- yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *opening, yp_block_parameters_node_t *parameters, yp_node_t *statements, const yp_token_t *closing) {
1021
+ yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *opening, yp_block_parameters_node_t *parameters, yp_node_t *body, const yp_token_t *closing) {
930
1022
  yp_block_node_t *node = YP_ALLOC_NODE(parser, yp_block_node_t);
931
1023
 
932
1024
  *node = (yp_block_node_t) {
@@ -936,7 +1028,7 @@ yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y
936
1028
  },
937
1029
  .locals = *locals,
938
1030
  .parameters = parameters,
939
- .statements = statements,
1031
+ .body = body,
940
1032
  .opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
941
1033
  .closing_loc = YP_LOCATION_TOKEN_VALUE(closing)
942
1034
  };
@@ -1063,8 +1155,7 @@ yp_call_node_create(yp_parser_t *parser) {
1063
1155
  .opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
1064
1156
  .arguments = NULL,
1065
1157
  .closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
1066
- .block = NULL,
1067
- .flags = 0
1158
+ .block = NULL
1068
1159
  };
1069
1160
 
1070
1161
  return node;
@@ -1140,7 +1231,7 @@ yp_call_node_call_create(yp_parser_t *parser, yp_node_t *receiver, yp_token_t *o
1140
1231
  node->block = arguments->block;
1141
1232
 
1142
1233
  if (operator->type == YP_TOKEN_AMPERSAND_DOT) {
1143
- node->flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
1234
+ node->base.flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
1144
1235
  }
1145
1236
 
1146
1237
  yp_string_shared_init(&node->name, message->start, message->end);
@@ -1216,7 +1307,7 @@ yp_call_node_shorthand_create(yp_parser_t *parser, yp_node_t *receiver, yp_token
1216
1307
  node->block = arguments->block;
1217
1308
 
1218
1309
  if (operator->type == YP_TOKEN_AMPERSAND_DOT) {
1219
- node->flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
1310
+ node->base.flags |= YP_CALL_NODE_FLAGS_SAFE_NAVIGATION;
1220
1311
  }
1221
1312
 
1222
1313
  yp_string_constant_init(&node->name, "call", 4);
@@ -1257,7 +1348,7 @@ yp_call_node_variable_call_create(yp_parser_t *parser, yp_token_t *message) {
1257
1348
  // without a receiver that could also have been a local variable read).
1258
1349
  static inline bool
1259
1350
  yp_call_node_variable_call_p(yp_call_node_t *node) {
1260
- return node->flags & YP_CALL_NODE_FLAGS_VARIABLE_CALL;
1351
+ return node->base.flags & YP_CALL_NODE_FLAGS_VARIABLE_CALL;
1261
1352
  }
1262
1353
 
1263
1354
  // Allocate and initialize a new CallOperatorAndWriteNode node.
@@ -1395,7 +1486,7 @@ yp_case_node_end_keyword_loc_set(yp_case_node_t *node, const yp_token_t *end_key
1395
1486
 
1396
1487
  // Allocate a new ClassNode node.
1397
1488
  static yp_class_node_t *
1398
- yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, yp_node_t *constant_path, const yp_token_t *inheritance_operator, yp_node_t *superclass, yp_node_t *statements, const yp_token_t *end_keyword) {
1489
+ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, yp_node_t *constant_path, const yp_token_t *inheritance_operator, yp_node_t *superclass, yp_node_t *body, const yp_token_t *end_keyword) {
1399
1490
  yp_class_node_t *node = YP_ALLOC_NODE(parser, yp_class_node_t);
1400
1491
 
1401
1492
  *node = (yp_class_node_t) {
@@ -1408,81 +1499,13 @@ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y
1408
1499
  .constant_path = constant_path,
1409
1500
  .inheritance_operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
1410
1501
  .superclass = superclass,
1411
- .statements = statements,
1502
+ .body = body,
1412
1503
  .end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
1413
1504
  };
1414
1505
 
1415
1506
  return node;
1416
1507
  }
1417
1508
 
1418
- // Allocate and initialize a new ClassVariableOperatorAndWriteNode node.
1419
- static yp_class_variable_operator_and_write_node_t *
1420
- yp_class_variable_operator_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1421
- assert(YP_NODE_TYPE_P(target, YP_NODE_CLASS_VARIABLE_READ_NODE));
1422
- assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
1423
- yp_class_variable_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_operator_and_write_node_t);
1424
-
1425
- *node = (yp_class_variable_operator_and_write_node_t) {
1426
- {
1427
- .type = YP_NODE_CLASS_VARIABLE_OPERATOR_AND_WRITE_NODE,
1428
- .location = {
1429
- .start = target->location.start,
1430
- .end = value->location.end
1431
- }
1432
- },
1433
- .name_loc = target->location,
1434
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1435
- .value = value
1436
- };
1437
-
1438
- return node;
1439
- }
1440
-
1441
- // Allocate and initialize a new ClassVariableOperatorWriteNode node.
1442
- static yp_class_variable_operator_write_node_t *
1443
- yp_class_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1444
- yp_class_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_operator_write_node_t);
1445
-
1446
- *node = (yp_class_variable_operator_write_node_t) {
1447
- {
1448
- .type = YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
1449
- .location = {
1450
- .start = target->location.start,
1451
- .end = value->location.end
1452
- }
1453
- },
1454
- .name_loc = target->location,
1455
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1456
- .value = value,
1457
- .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
1458
- };
1459
-
1460
- return node;
1461
- }
1462
-
1463
- // Allocate and initialize a new ClassVariableOperatorOrWriteNode node.
1464
- static yp_class_variable_operator_or_write_node_t *
1465
- yp_class_variable_operator_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1466
- assert(YP_NODE_TYPE_P(target, YP_NODE_CLASS_VARIABLE_READ_NODE));
1467
- assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
1468
- yp_class_variable_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_operator_or_write_node_t);
1469
-
1470
- *node = (yp_class_variable_operator_or_write_node_t) {
1471
- {
1472
- .type = YP_NODE_CLASS_VARIABLE_OPERATOR_OR_WRITE_NODE,
1473
- .location = {
1474
- .start = target->location.start,
1475
- .end = value->location.end
1476
- }
1477
- },
1478
- .name_loc = target->location,
1479
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1480
- .value = value
1481
- };
1482
-
1483
- return node;
1484
- }
1485
-
1486
1509
  // Allocate and initialize a new ClassVariableReadNode node.
1487
1510
  static yp_class_variable_read_node_t *
1488
1511
  yp_class_variable_read_node_create(yp_parser_t *parser, const yp_token_t *token) {
@@ -1513,72 +1536,6 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
1513
1536
  return node;
1514
1537
  }
1515
1538
 
1516
- // Allocate and initialize a new ConstantPathOperatorAndWriteNode node.
1517
- static yp_constant_path_operator_and_write_node_t *
1518
- yp_constant_path_operator_and_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1519
- assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
1520
- yp_constant_path_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_operator_and_write_node_t);
1521
-
1522
- *node = (yp_constant_path_operator_and_write_node_t) {
1523
- {
1524
- .type = YP_NODE_CONSTANT_PATH_OPERATOR_AND_WRITE_NODE,
1525
- .location = {
1526
- .start = target->base.location.start,
1527
- .end = value->location.end
1528
- }
1529
- },
1530
- .target = target,
1531
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1532
- .value = value
1533
- };
1534
-
1535
- return node;
1536
- }
1537
-
1538
- // Allocate and initialize a new ConstantPathOperatorWriteNode node.
1539
- static yp_constant_path_operator_write_node_t *
1540
- yp_constant_path_operator_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1541
- yp_constant_path_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_operator_write_node_t);
1542
-
1543
- *node = (yp_constant_path_operator_write_node_t) {
1544
- {
1545
- .type = YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE,
1546
- .location = {
1547
- .start = target->base.location.start,
1548
- .end = value->location.end
1549
- }
1550
- },
1551
- .target = target,
1552
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1553
- .value = value,
1554
- .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
1555
- };
1556
-
1557
- return node;
1558
- }
1559
-
1560
- // Allocate and initialize a new ConstantPathOperatorOrWriteNode node.
1561
- static yp_constant_path_operator_or_write_node_t *
1562
- yp_constant_path_operator_or_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1563
- assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
1564
- yp_constant_path_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_operator_or_write_node_t);
1565
-
1566
- *node = (yp_constant_path_operator_or_write_node_t) {
1567
- {
1568
- .type = YP_NODE_CONSTANT_PATH_OPERATOR_OR_WRITE_NODE,
1569
- .location = {
1570
- .start = target->base.location.start,
1571
- .end = value->location.end
1572
- }
1573
- },
1574
- .target = target,
1575
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1576
- .value = value
1577
- };
1578
-
1579
- return node;
1580
- }
1581
-
1582
1539
  // Allocate and initialize a new ConstantPathNode node.
1583
1540
  static yp_constant_path_node_t *
1584
1541
  yp_constant_path_node_create(yp_parser_t *parser, yp_node_t *parent, const yp_token_t *delimiter, yp_node_t *child) {
@@ -1621,74 +1578,6 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
1621
1578
  return node;
1622
1579
  }
1623
1580
 
1624
- // Allocate and initialize a new ConstantOperatorAndWriteNode node.
1625
- static yp_constant_operator_and_write_node_t *
1626
- yp_constant_operator_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1627
- assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
1628
- assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
1629
- yp_constant_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_operator_and_write_node_t);
1630
-
1631
- *node = (yp_constant_operator_and_write_node_t) {
1632
- {
1633
- .type = YP_NODE_CONSTANT_OPERATOR_AND_WRITE_NODE,
1634
- .location = {
1635
- .start = target->location.start,
1636
- .end = value->location.end
1637
- }
1638
- },
1639
- .name_loc = target->location,
1640
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1641
- .value = value
1642
- };
1643
-
1644
- return node;
1645
- }
1646
-
1647
- // Allocate and initialize a new ConstantOperatorWriteNode node.
1648
- static yp_constant_operator_write_node_t *
1649
- yp_constant_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1650
- yp_constant_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_operator_write_node_t);
1651
-
1652
- *node = (yp_constant_operator_write_node_t) {
1653
- {
1654
- .type = YP_NODE_CONSTANT_OPERATOR_WRITE_NODE,
1655
- .location = {
1656
- .start = target->location.start,
1657
- .end = value->location.end
1658
- }
1659
- },
1660
- .name_loc = target->location,
1661
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1662
- .value = value,
1663
- .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
1664
- };
1665
-
1666
- return node;
1667
- }
1668
-
1669
- // Allocate and initialize a new ConstantOperatorOrWriteNode node.
1670
- static yp_constant_operator_or_write_node_t *
1671
- yp_constant_operator_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
1672
- assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
1673
- assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
1674
- yp_constant_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_operator_or_write_node_t);
1675
-
1676
- *node = (yp_constant_operator_or_write_node_t) {
1677
- {
1678
- .type = YP_NODE_CONSTANT_OPERATOR_OR_WRITE_NODE,
1679
- .location = {
1680
- .start = target->location.start,
1681
- .end = value->location.end
1682
- }
1683
- },
1684
- .name_loc = target->location,
1685
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
1686
- .value = value
1687
- };
1688
-
1689
- return node;
1690
- }
1691
-
1692
1581
  // Allocate and initialize a new ConstantReadNode node.
1693
1582
  static yp_constant_read_node_t *
1694
1583
  yp_constant_read_node_create(yp_parser_t *parser, const yp_token_t *name) {
@@ -1727,7 +1616,7 @@ yp_def_node_create(
1727
1616
  const yp_token_t *name,
1728
1617
  yp_node_t *receiver,
1729
1618
  yp_parameters_node_t *parameters,
1730
- yp_node_t *statements,
1619
+ yp_node_t *body,
1731
1620
  yp_constant_id_list_t *locals,
1732
1621
  const yp_token_t *def_keyword,
1733
1622
  const yp_token_t *operator,
@@ -1740,7 +1629,7 @@ yp_def_node_create(
1740
1629
  const char *end;
1741
1630
 
1742
1631
  if (end_keyword->type == YP_TOKEN_NOT_PROVIDED) {
1743
- end = statements->location.end;
1632
+ end = body->location.end;
1744
1633
  } else {
1745
1634
  end = end_keyword->end;
1746
1635
  }
@@ -1753,7 +1642,7 @@ yp_def_node_create(
1753
1642
  .name_loc = YP_LOCATION_TOKEN_VALUE(name),
1754
1643
  .receiver = receiver,
1755
1644
  .parameters = parameters,
1756
- .statements = statements,
1645
+ .body = body,
1757
1646
  .locals = *locals,
1758
1647
  .def_keyword_loc = YP_LOCATION_TOKEN_VALUE(def_keyword),
1759
1648
  .operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
@@ -2123,74 +2012,6 @@ yp_hash_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *assoc
2123
2012
  return node;
2124
2013
  }
2125
2014
 
2126
- // Allocate and initialize a new GlobalVariableOperatorAndWriteNode node.
2127
- static yp_global_variable_operator_and_write_node_t *
2128
- yp_global_variable_operator_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2129
- assert(YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE));
2130
- assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2131
- yp_global_variable_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_operator_and_write_node_t);
2132
-
2133
- *node = (yp_global_variable_operator_and_write_node_t) {
2134
- {
2135
- .type = YP_NODE_GLOBAL_VARIABLE_OPERATOR_AND_WRITE_NODE,
2136
- .location = {
2137
- .start = target->location.start,
2138
- .end = value->location.end
2139
- }
2140
- },
2141
- .name_loc = target->location,
2142
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2143
- .value = value
2144
- };
2145
-
2146
- return node;
2147
- }
2148
-
2149
- // Allocate and initialize a new GlobalVariableOperatorWriteNode node.
2150
- static yp_global_variable_operator_write_node_t *
2151
- yp_global_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2152
- yp_global_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_operator_write_node_t);
2153
-
2154
- *node = (yp_global_variable_operator_write_node_t) {
2155
- {
2156
- .type = YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
2157
- .location = {
2158
- .start = target->location.start,
2159
- .end = value->location.end
2160
- }
2161
- },
2162
- .name_loc = target->location,
2163
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2164
- .value = value,
2165
- .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
2166
- };
2167
-
2168
- return node;
2169
- }
2170
-
2171
- // Allocate and initialize a new GlobalVariableOperatorOrWriteNode node.
2172
- static yp_global_variable_operator_or_write_node_t *
2173
- yp_global_variable_operator_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2174
- assert(YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE));
2175
- assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
2176
- yp_global_variable_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_operator_or_write_node_t);
2177
-
2178
- *node = (yp_global_variable_operator_or_write_node_t) {
2179
- {
2180
- .type = YP_NODE_GLOBAL_VARIABLE_OPERATOR_OR_WRITE_NODE,
2181
- .location = {
2182
- .start = target->location.start,
2183
- .end = value->location.end
2184
- }
2185
- },
2186
- .name_loc = target->location,
2187
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2188
- .value = value
2189
- };
2190
-
2191
- return node;
2192
- }
2193
-
2194
2015
  // Allocate a new GlobalVariableReadNode node.
2195
2016
  static yp_global_variable_read_node_t *
2196
2017
  yp_global_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name) {
@@ -2269,6 +2090,7 @@ yp_if_node_create(yp_parser_t *parser,
2269
2090
  yp_node_t *consequent,
2270
2091
  const yp_token_t *end_keyword
2271
2092
  ) {
2093
+ yp_flip_flop(predicate);
2272
2094
  yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t);
2273
2095
 
2274
2096
  const char *end;
@@ -2304,6 +2126,7 @@ yp_if_node_create(yp_parser_t *parser,
2304
2126
  // Allocate and initialize new IfNode node in the modifier form.
2305
2127
  static yp_if_node_t *
2306
2128
  yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_token_t *if_keyword, yp_node_t *predicate) {
2129
+ yp_flip_flop(predicate);
2307
2130
  yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t);
2308
2131
 
2309
2132
  yp_statements_node_t *statements = yp_statements_node_create(parser);
@@ -2331,6 +2154,8 @@ yp_if_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_t
2331
2154
  // Allocate and initialize an if node from a ternary expression.
2332
2155
  static yp_if_node_t *
2333
2156
  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) {
2157
+ yp_flip_flop(predicate);
2158
+
2334
2159
  yp_statements_node_t *if_statements = yp_statements_node_create(parser);
2335
2160
  yp_statements_node_body_append(if_statements, true_expression);
2336
2161
 
@@ -2477,74 +2302,6 @@ yp_in_node_create(yp_parser_t *parser, yp_node_t *pattern, yp_statements_node_t
2477
2302
  return node;
2478
2303
  }
2479
2304
 
2480
- // Allocate and initialize a new InstanceVariableOperatorAndWriteNode node.
2481
- static yp_instance_variable_operator_and_write_node_t *
2482
- yp_instance_variable_operator_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2483
- assert(YP_NODE_TYPE_P(target, YP_NODE_INSTANCE_VARIABLE_READ_NODE));
2484
- assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2485
- yp_instance_variable_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_operator_and_write_node_t);
2486
-
2487
- *node = (yp_instance_variable_operator_and_write_node_t) {
2488
- {
2489
- .type = YP_NODE_INSTANCE_VARIABLE_OPERATOR_AND_WRITE_NODE,
2490
- .location = {
2491
- .start = target->location.start,
2492
- .end = value->location.end
2493
- }
2494
- },
2495
- .name_loc = target->location,
2496
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2497
- .value = value
2498
- };
2499
-
2500
- return node;
2501
- }
2502
-
2503
- // Allocate and initialize a new InstanceVariableOperatorWriteNode node.
2504
- static yp_instance_variable_operator_write_node_t *
2505
- yp_instance_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2506
- yp_instance_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_operator_write_node_t);
2507
-
2508
- *node = (yp_instance_variable_operator_write_node_t) {
2509
- {
2510
- .type = YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
2511
- .location = {
2512
- .start = target->location.start,
2513
- .end = value->location.end
2514
- }
2515
- },
2516
- .name_loc = target->location,
2517
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2518
- .value = value,
2519
- .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
2520
- };
2521
-
2522
- return node;
2523
- }
2524
-
2525
- // Allocate and initialize a new InstanceVariableOperatorOrWriteNode node.
2526
- static yp_instance_variable_operator_or_write_node_t *
2527
- yp_instance_variable_operator_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2528
- assert(YP_NODE_TYPE_P(target, YP_NODE_INSTANCE_VARIABLE_READ_NODE));
2529
- assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
2530
- yp_instance_variable_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_operator_or_write_node_t);
2531
-
2532
- *node = (yp_instance_variable_operator_or_write_node_t) {
2533
- {
2534
- .type = YP_NODE_INSTANCE_VARIABLE_OPERATOR_OR_WRITE_NODE,
2535
- .location = {
2536
- .start = target->location.start,
2537
- .end = value->location.end
2538
- }
2539
- },
2540
- .name_loc = target->location,
2541
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2542
- .value = value
2543
- };
2544
-
2545
- return node;
2546
- }
2547
-
2548
2305
  // Allocate and initialize a new InstanceVariableReadNode node.
2549
2306
  static yp_instance_variable_read_node_t *
2550
2307
  yp_instance_variable_read_node_create(yp_parser_t *parser, const yp_token_t *token) {
@@ -2593,7 +2350,6 @@ yp_interpolated_regular_expression_node_create(yp_parser_t *parser, const yp_tok
2593
2350
  },
2594
2351
  .opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
2595
2352
  .closing_loc = YP_LOCATION_TOKEN_VALUE(opening),
2596
- .flags = 0,
2597
2353
  .parts = YP_EMPTY_NODE_LIST
2598
2354
  };
2599
2355
 
@@ -2610,7 +2366,7 @@ static inline void
2610
2366
  yp_interpolated_regular_expression_node_closing_set(yp_interpolated_regular_expression_node_t *node, const yp_token_t *closing) {
2611
2367
  node->closing_loc = YP_LOCATION_TOKEN_VALUE(closing);
2612
2368
  node->base.location.end = closing->end;
2613
- node->flags = yp_regular_expression_flags_create(closing);
2369
+ node->base.flags |= yp_regular_expression_flags_create(closing);
2614
2370
  }
2615
2371
 
2616
2372
  // Allocate and initialize a new InterpolatedStringNode node.
@@ -2637,6 +2393,10 @@ yp_interpolated_string_node_create(yp_parser_t *parser, const yp_token_t *openin
2637
2393
  // Append a part to an InterpolatedStringNode node.
2638
2394
  static inline void
2639
2395
  yp_interpolated_string_node_append(yp_interpolated_string_node_t *node, yp_node_t *part) {
2396
+ if (node->parts.size == 0 && node->opening_loc.start == NULL) {
2397
+ node->base.location.start = part->location.start;
2398
+ }
2399
+
2640
2400
  yp_node_list_append(&node->parts, part);
2641
2401
  node->base.location.end = part->location.end;
2642
2402
  }
@@ -2793,7 +2553,7 @@ yp_lambda_node_create(
2793
2553
  yp_constant_id_list_t *locals,
2794
2554
  const yp_token_t *opening,
2795
2555
  yp_block_parameters_node_t *parameters,
2796
- yp_node_t *statements,
2556
+ yp_node_t *body,
2797
2557
  const yp_token_t *closing
2798
2558
  ) {
2799
2559
  yp_lambda_node_t *node = YP_ALLOC_NODE(parser, yp_lambda_node_t);
@@ -2807,80 +2567,9 @@ yp_lambda_node_create(
2807
2567
  },
2808
2568
  },
2809
2569
  .locals = *locals,
2810
- .opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
2811
- .parameters = parameters,
2812
- .statements = statements
2813
- };
2814
-
2815
- return node;
2816
- }
2817
-
2818
- // Allocate and initialize a new LocalVariableOperatorAndWriteNode node.
2819
- static yp_local_variable_operator_and_write_node_t *
2820
- yp_local_variable_operator_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t constant_id) {
2821
- assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
2822
- assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2823
- yp_local_variable_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_operator_and_write_node_t);
2824
-
2825
- *node = (yp_local_variable_operator_and_write_node_t) {
2826
- {
2827
- .type = YP_NODE_LOCAL_VARIABLE_OPERATOR_AND_WRITE_NODE,
2828
- .location = {
2829
- .start = target->location.start,
2830
- .end = value->location.end
2831
- }
2832
- },
2833
- .name_loc = target->location,
2834
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2835
- .value = value,
2836
- .constant_id = constant_id
2837
- };
2838
-
2839
- return node;
2840
- }
2841
-
2842
- // Allocate and initialize a new LocalVariableOperatorWriteNode node.
2843
- static yp_local_variable_operator_write_node_t *
2844
- yp_local_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t constant_id) {
2845
- yp_local_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_operator_write_node_t);
2846
-
2847
- *node = (yp_local_variable_operator_write_node_t) {
2848
- {
2849
- .type = YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
2850
- .location = {
2851
- .start = target->location.start,
2852
- .end = value->location.end
2853
- }
2854
- },
2855
- .name_loc = target->location,
2856
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2857
- .value = value,
2858
- .constant_id = constant_id,
2859
- .operator_id = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
2860
- };
2861
-
2862
- return node;
2863
- }
2864
-
2865
- // Allocate and initialize a new LocalVariableOperatorOrWriteNode node.
2866
- static yp_local_variable_operator_or_write_node_t *
2867
- yp_local_variable_operator_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t constant_id) {
2868
- assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
2869
- assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
2870
- yp_local_variable_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_operator_or_write_node_t);
2871
-
2872
- *node = (yp_local_variable_operator_or_write_node_t) {
2873
- {
2874
- .type = YP_NODE_LOCAL_VARIABLE_OPERATOR_OR_WRITE_NODE,
2875
- .location = {
2876
- .start = target->location.start,
2877
- .end = value->location.end
2878
- }
2879
- },
2880
- .name_loc = target->location,
2881
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2882
- .value = value,
2883
- .constant_id = constant_id
2570
+ .opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
2571
+ .parameters = parameters,
2572
+ .body = body
2884
2573
  };
2885
2574
 
2886
2575
  return node;
@@ -2990,7 +2679,7 @@ yp_match_required_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t *
2990
2679
 
2991
2680
  // Allocate a new ModuleNode node.
2992
2681
  static yp_module_node_t *
2993
- yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, yp_node_t *statements, const yp_token_t *end_keyword) {
2682
+ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, yp_node_t *body, const yp_token_t *end_keyword) {
2994
2683
  yp_module_node_t *node = YP_ALLOC_NODE(parser, yp_module_node_t);
2995
2684
 
2996
2685
  *node = (yp_module_node_t) {
@@ -3004,7 +2693,7 @@ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const
3004
2693
  .locals = (locals == NULL ? ((yp_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
3005
2694
  .module_keyword_loc = YP_LOCATION_TOKEN_VALUE(module_keyword),
3006
2695
  .constant_path = constant_path,
3007
- .statements = statements,
2696
+ .body = body,
3008
2697
  .end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
3009
2698
  };
3010
2699
 
@@ -3119,6 +2808,28 @@ yp_numbered_reference_read_node_create(yp_parser_t *parser, const yp_token_t *na
3119
2808
  return node;
3120
2809
  }
3121
2810
 
2811
+ // Allocate and initialize a new OperatorWriteNode.
2812
+ static yp_operator_write_node_t *
2813
+ yp_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2814
+ yp_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_operator_write_node_t);
2815
+
2816
+ *node = (yp_operator_write_node_t) {
2817
+ {
2818
+ .type = YP_NODE_OPERATOR_WRITE_NODE,
2819
+ .location = {
2820
+ .start = target->location.start,
2821
+ .end = value->location.end
2822
+ },
2823
+ },
2824
+ .target = target,
2825
+ .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2826
+ .operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
2827
+ .value = value
2828
+ };
2829
+
2830
+ return node;
2831
+ }
2832
+
3122
2833
  // Allocate a new OptionalParameterNode node.
3123
2834
  static yp_optional_parameter_node_t *
3124
2835
  yp_optional_parameter_node_create(yp_parser_t *parser, const yp_token_t *name, const yp_token_t *operator, yp_node_t *value) {
@@ -3162,6 +2873,27 @@ yp_or_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *operat
3162
2873
  return node;
3163
2874
  }
3164
2875
 
2876
+ // Allocate and initialize a new OrWriteNode.
2877
+ static yp_or_write_node_t *
2878
+ yp_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
2879
+ yp_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_or_write_node_t);
2880
+
2881
+ *node = (yp_or_write_node_t) {
2882
+ {
2883
+ .type = YP_NODE_OR_WRITE_NODE,
2884
+ .location = {
2885
+ .start = target->location.start,
2886
+ .end = value->location.end
2887
+ },
2888
+ },
2889
+ .target = target,
2890
+ .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
2891
+ .value = value
2892
+ };
2893
+
2894
+ return node;
2895
+ }
2896
+
3165
2897
  // Allocate and initialize a new ParametersNode node.
3166
2898
  static yp_parameters_node_t *
3167
2899
  yp_parameters_node_create(yp_parser_t *parser) {
@@ -3274,7 +3006,7 @@ yp_program_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, yp_st
3274
3006
 
3275
3007
  // Allocate and initialize new ParenthesesNode node.
3276
3008
  static yp_parentheses_node_t *
3277
- yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_node_t *statements, const yp_token_t *closing) {
3009
+ yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_node_t *body, const yp_token_t *closing) {
3278
3010
  yp_parentheses_node_t *node = YP_ALLOC_NODE(parser, yp_parentheses_node_t);
3279
3011
 
3280
3012
  *node = (yp_parentheses_node_t) {
@@ -3285,7 +3017,7 @@ yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_no
3285
3017
  .end = closing->end
3286
3018
  }
3287
3019
  },
3288
- .statements = statements,
3020
+ .body = body,
3289
3021
  .opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
3290
3022
  .closing_loc = YP_LOCATION_TOKEN_VALUE(closing)
3291
3023
  };
@@ -3394,14 +3126,13 @@ yp_range_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *ope
3394
3126
  },
3395
3127
  .left = left,
3396
3128
  .right = right,
3397
- .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
3398
- .flags = 0,
3129
+ .operator_loc = YP_LOCATION_TOKEN_VALUE(operator)
3399
3130
  };
3400
3131
 
3401
3132
  switch (operator->type) {
3402
3133
  case YP_TOKEN_DOT_DOT_DOT:
3403
3134
  case YP_TOKEN_UDOT_DOT_DOT:
3404
- node->flags |= YP_RANGE_NODE_FLAGS_EXCLUDE_END;
3135
+ node->base.flags |= YP_RANGE_FLAGS_EXCLUDE_END;
3405
3136
  break;
3406
3137
  default:
3407
3138
  break;
@@ -3428,6 +3159,7 @@ yp_regular_expression_node_create(yp_parser_t *parser, const yp_token_t *opening
3428
3159
  *node = (yp_regular_expression_node_t) {
3429
3160
  {
3430
3161
  .type = YP_NODE_REGULAR_EXPRESSION_NODE,
3162
+ .flags = yp_regular_expression_flags_create(closing),
3431
3163
  .location = {
3432
3164
  .start = opening->start,
3433
3165
  .end = closing->end
@@ -3436,7 +3168,7 @@ yp_regular_expression_node_create(yp_parser_t *parser, const yp_token_t *opening
3436
3168
  .opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
3437
3169
  .content_loc = YP_LOCATION_TOKEN_VALUE(content),
3438
3170
  .closing_loc = YP_LOCATION_TOKEN_VALUE(closing),
3439
- .flags = yp_regular_expression_flags_create(closing)
3171
+ .unescaped = YP_EMPTY_STRING
3440
3172
  };
3441
3173
 
3442
3174
  return node;
@@ -3631,7 +3363,7 @@ yp_self_node_create(yp_parser_t *parser, const yp_token_t *token) {
3631
3363
 
3632
3364
  // Allocate a new SingletonClassNode node.
3633
3365
  static yp_singleton_class_node_t *
3634
- yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, const yp_token_t *operator, yp_node_t *expression, yp_node_t *statements, const yp_token_t *end_keyword) {
3366
+ yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, const yp_token_t *operator, yp_node_t *expression, yp_node_t *body, const yp_token_t *end_keyword) {
3635
3367
  yp_singleton_class_node_t *node = YP_ALLOC_NODE(parser, yp_singleton_class_node_t);
3636
3368
 
3637
3369
  *node = (yp_singleton_class_node_t) {
@@ -3646,7 +3378,7 @@ yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *local
3646
3378
  .class_keyword_loc = YP_LOCATION_TOKEN_VALUE(class_keyword),
3647
3379
  .operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
3648
3380
  .expression = expression,
3649
- .statements = statements,
3381
+ .body = body,
3650
3382
  .end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
3651
3383
  };
3652
3384
 
@@ -3749,7 +3481,7 @@ yp_statements_node_body_append(yp_statements_node_t *node, yp_node_t *statement)
3749
3481
  node->base.location.end = statement->location.end;
3750
3482
 
3751
3483
  // Every statement gets marked as a place where a newline can occur.
3752
- statement->flags = YP_NODE_FLAG_NEWLINE;
3484
+ statement->flags |= YP_NODE_FLAG_NEWLINE;
3753
3485
  }
3754
3486
 
3755
3487
  // Allocate a new StringConcatNode node.
@@ -3865,10 +3597,10 @@ yp_symbol_node_label_create(yp_parser_t *parser, const yp_token_t *token) {
3865
3597
  yp_token_t label = { .type = YP_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
3866
3598
  node = yp_symbol_node_create(parser, &opening, &label, &closing);
3867
3599
 
3868
- ptrdiff_t length = label.end - label.start;
3869
- assert(length >= 0);
3600
+ assert((label.end - label.start) >= 0);
3601
+ yp_string_shared_init(&node->unescaped, label.start, label.end);
3870
3602
 
3871
- yp_unescape_manipulate_string(parser, label.start, (size_t) length, &node->unescaped, YP_UNESCAPE_ALL, &parser->error_list);
3603
+ yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL, &parser->error_list);
3872
3604
  break;
3873
3605
  }
3874
3606
  case YP_TOKEN_MISSING: {
@@ -3996,6 +3728,7 @@ yp_undef_node_append(yp_undef_node_t *node, yp_node_t *name) {
3996
3728
  // Allocate a new UnlessNode node.
3997
3729
  static yp_unless_node_t *
3998
3730
  yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements) {
3731
+ yp_flip_flop(predicate);
3999
3732
  yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t);
4000
3733
 
4001
3734
  const char *end;
@@ -4027,6 +3760,7 @@ yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t
4027
3760
  // Allocate and initialize new UnlessNode node in the modifier form.
4028
3761
  static yp_unless_node_t *
4029
3762
  yp_unless_node_modifier_create(yp_parser_t *parser, yp_node_t *statement, const yp_token_t *unless_keyword, yp_node_t *predicate) {
3763
+ yp_flip_flop(predicate);
4030
3764
  yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t);
4031
3765
 
4032
3766
  yp_statements_node_t *statements = yp_statements_node_create(parser);
@@ -4059,7 +3793,7 @@ yp_unless_node_end_keyword_loc_set(yp_unless_node_t *node, const yp_token_t *end
4059
3793
 
4060
3794
  // Allocate a new UntilNode node.
4061
3795
  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) {
3796
+ 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
3797
  yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
4064
3798
  bool has_statements = (statements != NULL) && (statements->body.size != 0);
4065
3799
 
@@ -4080,6 +3814,7 @@ yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
4080
3814
  *node = (yp_until_node_t) {
4081
3815
  {
4082
3816
  .type = YP_NODE_UNTIL_NODE,
3817
+ .flags = flags,
4083
3818
  .location = {
4084
3819
  .start = start,
4085
3820
  .end = end,
@@ -4087,8 +3822,7 @@ yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
4087
3822
  },
4088
3823
  .keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
4089
3824
  .predicate = predicate,
4090
- .statements = statements,
4091
- .flags = flags
3825
+ .statements = statements
4092
3826
  };
4093
3827
 
4094
3828
  return node;
@@ -4134,7 +3868,7 @@ yp_when_node_statements_set(yp_when_node_t *node, yp_statements_node_t *statemen
4134
3868
 
4135
3869
  // Allocate a new WhileNode node.
4136
3870
  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) {
3871
+ 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
3872
  yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
4139
3873
 
4140
3874
  const char *start = NULL;
@@ -4155,6 +3889,7 @@ yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
4155
3889
  *node = (yp_while_node_t) {
4156
3890
  {
4157
3891
  .type = YP_NODE_WHILE_NODE,
3892
+ .flags = flags,
4158
3893
  .location = {
4159
3894
  .start = start,
4160
3895
  .end = end,
@@ -4162,8 +3897,7 @@ yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *
4162
3897
  },
4163
3898
  .keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
4164
3899
  .predicate = predicate,
4165
- .statements = statements,
4166
- .flags = flags
3900
+ .statements = statements
4167
3901
  };
4168
3902
 
4169
3903
  return node;
@@ -4599,6 +4333,7 @@ parser_lex_encoding_comment(yp_parser_t *parser) {
4599
4333
  ENCODING("cp1252", yp_encoding_windows_1252);
4600
4334
  ENCODING("cp932", yp_encoding_windows_31j);
4601
4335
  ENCODING("sjis", yp_encoding_windows_31j);
4336
+ ENCODING("utf8-mac", yp_encoding_utf8_mac);
4602
4337
 
4603
4338
  #undef ENCODING
4604
4339
 
@@ -5344,13 +5079,14 @@ lex_question_mark(yp_parser_t *parser) {
5344
5079
  } else {
5345
5080
  size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end);
5346
5081
 
5347
- // We only want to return a character literal if there's exactly one
5348
- // alphanumeric character right after the `?`
5082
+ // Ternary operators can have a ? immediately followed by an identifier which starts with
5083
+ // an underscore. We check for this case
5349
5084
  if (
5350
- !parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
5085
+ !(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
5086
+ *parser->current.end == '_') ||
5351
5087
  (
5352
5088
  (parser->current.end + encoding_width >= parser->end) ||
5353
- !parser->encoding.alnum_char(parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
5089
+ !char_is_identifier(parser, parser->current.end + encoding_width)
5354
5090
  )
5355
5091
  ) {
5356
5092
  lex_state_set(parser, YP_LEX_STATE_END);
@@ -5572,13 +5308,23 @@ parser_lex(yp_parser_t *parser) {
5572
5308
  break;
5573
5309
  case '\\':
5574
5310
  if (peek_at(parser, 1) == '\n') {
5575
- yp_newline_list_append(&parser->newline_list, parser->current.end + 1);
5576
- parser->current.end += 2;
5577
- space_seen = true;
5578
- } else if (parser->current.end + 2 < parser->end && peek_at(parser, 1) == '\r' && peek_at(parser, 2) == '\n') {
5579
- yp_newline_list_append(&parser->newline_list, parser->current.end + 2);
5580
- parser->current.end += 3;
5581
- space_seen = true;
5311
+ if (parser->heredoc_end) {
5312
+ parser->current.end = parser->heredoc_end;
5313
+ parser->heredoc_end = NULL;
5314
+ } else {
5315
+ yp_newline_list_append(&parser->newline_list, parser->current.end + 1);
5316
+ parser->current.end += 2;
5317
+ space_seen = true;
5318
+ }
5319
+ } else if (peek_at(parser, 1) == '\r' && peek_at(parser, 2) == '\n') {
5320
+ if (parser->heredoc_end) {
5321
+ parser->current.end = parser->heredoc_end;
5322
+ parser->heredoc_end = NULL;
5323
+ } else {
5324
+ yp_newline_list_append(&parser->newline_list, parser->current.end + 2);
5325
+ parser->current.end += 3;
5326
+ space_seen = true;
5327
+ }
5582
5328
  } else if (yp_char_is_inline_whitespace(*parser->current.end)) {
5583
5329
  parser->current.end += 2;
5584
5330
  } else {
@@ -6413,13 +6159,11 @@ parser_lex(yp_parser_t *parser) {
6413
6159
 
6414
6160
  // % %= %i %I %q %Q %w %W
6415
6161
  case '%': {
6416
- // In a BEG state, if you encounter a % then you must be
6417
- // starting something. In this case if there is no
6418
- // subsequent character then we have an invalid token. We're
6419
- // going to say it's the percent operator because we don't
6420
- // want to move into the string lex mode unnecessarily.
6421
- if (lex_state_beg_p(parser) && (parser->current.end >= parser->end)) {
6422
- yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "unexpected end of input");
6162
+ // If there is no subsequent character then we have an invalid token. We're
6163
+ // going to say it's the percent operator because we don't want to move into the
6164
+ // string lex mode unnecessarily.
6165
+ if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
6166
+ yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected end of input");
6423
6167
  LEX(YP_TOKEN_PERCENT);
6424
6168
  }
6425
6169
 
@@ -6592,7 +6336,7 @@ parser_lex(yp_parser_t *parser) {
6592
6336
  ((parser->current.end - parser->current.start) == 7) &&
6593
6337
  current_token_starts_line(parser) &&
6594
6338
  (strncmp(parser->current.start, "__END__", 7) == 0) &&
6595
- (*parser->current.end == '\n' || (*parser->current.end == '\r' && parser->current.end[1] == '\n'))
6339
+ (parser->current.end == parser->end || *parser->current.end == '\n' || (*parser->current.end == '\r' && parser->current.end[1] == '\n'))
6596
6340
  ) {
6597
6341
  parser->current.end = parser->end;
6598
6342
  parser->current.type = YP_TOKEN___END__;
@@ -7009,6 +6753,7 @@ parser_lex(yp_parser_t *parser) {
7009
6753
  } else {
7010
6754
  parser->current.start = parser->next_start;
7011
6755
  parser->current.end = parser->next_start;
6756
+ parser->heredoc_end = NULL;
7012
6757
  parser->next_start = NULL;
7013
6758
  }
7014
6759
 
@@ -7084,14 +6829,14 @@ parser_lex(yp_parser_t *parser) {
7084
6829
  breakpoint = yp_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1));
7085
6830
  break;
7086
6831
  case '\n': {
7087
- yp_newline_list_append(&parser->newline_list, breakpoint);
7088
-
7089
6832
  if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
7090
6833
  parser_flush_heredoc_end(parser);
7091
6834
  parser->current.end = breakpoint + 1;
7092
6835
  LEX(YP_TOKEN_STRING_CONTENT);
7093
6836
  }
7094
6837
 
6838
+ yp_newline_list_append(&parser->newline_list, breakpoint);
6839
+
7095
6840
  const char *start = breakpoint + 1;
7096
6841
  if (parser->lex_modes.current->as.heredoc.indent != YP_HEREDOC_INDENT_NONE) {
7097
6842
  start += yp_strspn_inline_whitespace(start, parser->end - start);
@@ -7130,11 +6875,16 @@ parser_lex(yp_parser_t *parser) {
7130
6875
  break;
7131
6876
  }
7132
6877
  case '\\': {
7133
- // If we hit escapes, then we need to treat the next token
7134
- // literally. In this case we'll skip past the next character and
7135
- // find the next breakpoint.
7136
- if (breakpoint[1] == '\n') {
6878
+ // If we hit an escape, then we need to skip past
6879
+ // however many characters the escape takes up. However
6880
+ // it's important that if \n or \r\n are escaped that we
6881
+ // stop looping before the newline and not after the
6882
+ // newline so that we can still potentially find the
6883
+ // terminator of the heredoc.
6884
+ if (breakpoint + 1 < parser->end && breakpoint[1] == '\n') {
7137
6885
  breakpoint++;
6886
+ } else if (breakpoint + 2 < parser->end && breakpoint[1] == '\r' && breakpoint[2] == '\n') {
6887
+ breakpoint += 2;
7138
6888
  } else {
7139
6889
  yp_unescape_type_t unescape_type = (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL;
7140
6890
  size_t difference = yp_unescape_calculate_difference(breakpoint, parser->end, unescape_type, false, &parser->error_list);
@@ -7145,6 +6895,7 @@ parser_lex(yp_parser_t *parser) {
7145
6895
 
7146
6896
  breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
7147
6897
  }
6898
+
7148
6899
  break;
7149
6900
  }
7150
6901
  case '#': {
@@ -7191,10 +6942,10 @@ static yp_regular_expression_node_t *
7191
6942
  yp_regular_expression_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
7192
6943
  yp_regular_expression_node_t *node = yp_regular_expression_node_create(parser, opening, content, closing);
7193
6944
 
7194
- ptrdiff_t length = content->end - content->start;
7195
- assert(length >= 0);
6945
+ assert((content->end - content->start) >= 0);
6946
+ yp_string_shared_init(&node->unescaped, content->start, content->end);
7196
6947
 
7197
- yp_unescape_manipulate_string(parser, content->start, (size_t) length, &node->unescaped, unescape_type, &parser->error_list);
6948
+ yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type, &parser->error_list);
7198
6949
  return node;
7199
6950
  }
7200
6951
 
@@ -7202,10 +6953,10 @@ static yp_symbol_node_t *
7202
6953
  yp_symbol_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
7203
6954
  yp_symbol_node_t *node = yp_symbol_node_create(parser, opening, content, closing);
7204
6955
 
7205
- ptrdiff_t length = content->end - content->start;
7206
- assert(length >= 0);
6956
+ assert((content->end - content->start) >= 0);
6957
+ yp_string_shared_init(&node->unescaped, content->start, content->end);
7207
6958
 
7208
- yp_unescape_manipulate_string(parser, content->start, (size_t) length, &node->unescaped, unescape_type, &parser->error_list);
6959
+ yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type, &parser->error_list);
7209
6960
  return node;
7210
6961
  }
7211
6962
 
@@ -7213,10 +6964,10 @@ static yp_string_node_t *
7213
6964
  yp_string_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
7214
6965
  yp_string_node_t *node = yp_string_node_create(parser, opening, content, closing);
7215
6966
 
7216
- ptrdiff_t length = content->end - content->start;
7217
- assert(length >= 0);
6967
+ assert((content->end - content->start) >= 0);
6968
+ yp_string_shared_init(&node->unescaped, content->start, content->end);
7218
6969
 
7219
- yp_unescape_manipulate_string(parser, content->start, (size_t) length, &node->unescaped, unescape_type, &parser->error_list);
6970
+ yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type, &parser->error_list);
7220
6971
  return node;
7221
6972
  }
7222
6973
 
@@ -7224,10 +6975,10 @@ static yp_x_string_node_t *
7224
6975
  yp_xstring_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing) {
7225
6976
  yp_x_string_node_t *node = yp_xstring_node_create(parser, opening, content, closing);
7226
6977
 
7227
- ptrdiff_t length = content->end - content->start;
7228
- assert(length >= 0);
6978
+ assert((content->end - content->start) >= 0);
6979
+ yp_string_shared_init(&node->unescaped, content->start, content->end);
7229
6980
 
7230
- yp_unescape_manipulate_string(parser, content->start, (size_t) length, &node->unescaped, YP_UNESCAPE_ALL, &parser->error_list);
6981
+ yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL, &parser->error_list);
7231
6982
  return node;
7232
6983
  }
7233
6984
 
@@ -7705,7 +7456,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
7705
7456
  char *name = calloc(length + 2, sizeof(char));
7706
7457
  if (name == NULL) return NULL;
7707
7458
 
7708
- yp_snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
7459
+ snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
7709
7460
 
7710
7461
  // Now switch the name to the new string.
7711
7462
  yp_string_free(&call->name);
@@ -8032,7 +7783,7 @@ parse_assocs(yp_parser_t *parser, yp_node_t *node) {
8032
7783
 
8033
7784
  // Parse a list of arguments.
8034
7785
  static void
8035
- parse_arguments(yp_parser_t *parser, yp_arguments_node_t *arguments, bool accepts_forwarding, yp_token_type_t terminator) {
7786
+ parse_arguments(yp_parser_t *parser, yp_arguments_t *arguments, bool accepts_forwarding, yp_token_type_t terminator) {
8036
7787
  yp_binding_power_t binding_power = yp_binding_powers[parser->current.type].left;
8037
7788
 
8038
7789
  // First we need to check if the next token is one that could be the start of
@@ -8085,6 +7836,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_node_t *arguments, bool accept
8085
7836
 
8086
7837
  argument = (yp_node_t *)yp_block_argument_node_create(parser, &operator, expression);
8087
7838
  parsed_block_argument = true;
7839
+ arguments->implicit_block = true;
8088
7840
  break;
8089
7841
  }
8090
7842
  case YP_TOKEN_USTAR: {
@@ -8171,7 +7923,7 @@ parse_arguments(yp_parser_t *parser, yp_arguments_node_t *arguments, bool accept
8171
7923
  }
8172
7924
  }
8173
7925
 
8174
- yp_arguments_node_arguments_append(arguments, argument);
7926
+ yp_arguments_node_arguments_append(arguments->arguments, argument);
8175
7927
 
8176
7928
  // If parsing the argument failed, we need to stop parsing arguments.
8177
7929
  if (YP_NODE_TYPE_P(argument, YP_NODE_MISSING_NODE) || parser->recovering) break;
@@ -8308,6 +8060,10 @@ update_parameter_state(yp_parser_t *parser, yp_token_t *token, yp_parameters_ord
8308
8060
  return;
8309
8061
  }
8310
8062
 
8063
+ if (token->type == YP_TOKEN_USTAR && *current == YP_PARAMETERS_ORDER_AFTER_OPTIONAL) {
8064
+ yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter *");
8065
+ }
8066
+
8311
8067
  if (*current == YP_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
8312
8068
  // We know what transition we failed on, so we can provide a better error here.
8313
8069
  yp_diagnostic_list_append(&parser->error_list, token->start, token->end, "Unexpected parameter order");
@@ -8863,7 +8619,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
8863
8619
  arguments->arguments = yp_arguments_node_create(parser);
8864
8620
 
8865
8621
  yp_accepts_block_stack_push(parser, true);
8866
- parse_arguments(parser, arguments->arguments, true, YP_TOKEN_PARENTHESIS_RIGHT);
8622
+ parse_arguments(parser, arguments, true, YP_TOKEN_PARENTHESIS_RIGHT);
8867
8623
  expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected a ')' to close the argument list.");
8868
8624
  yp_accepts_block_stack_pop(parser);
8869
8625
 
@@ -8877,7 +8633,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
8877
8633
  // operator. In this case we assume the subsequent token is part of an
8878
8634
  // argument to this method call.
8879
8635
  arguments->arguments = yp_arguments_node_create(parser);
8880
- parse_arguments(parser, arguments->arguments, true, YP_TOKEN_EOF);
8636
+ parse_arguments(parser, arguments, true, YP_TOKEN_EOF);
8881
8637
 
8882
8638
  yp_accepts_block_stack_pop(parser);
8883
8639
  }
@@ -8895,6 +8651,7 @@ parse_arguments_list(yp_parser_t *parser, yp_arguments_t *arguments, bool accept
8895
8651
  }
8896
8652
  }
8897
8653
 
8654
+ yp_arguments_validate(parser, arguments);
8898
8655
  return found;
8899
8656
  }
8900
8657
 
@@ -8920,7 +8677,7 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) {
8920
8677
  }
8921
8678
 
8922
8679
  yp_token_t end_keyword = not_provided(parser);
8923
- yp_node_t *parent;
8680
+ yp_node_t *parent = NULL;
8924
8681
 
8925
8682
  switch (context) {
8926
8683
  case YP_CONTEXT_IF:
@@ -8930,7 +8687,6 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) {
8930
8687
  parent = (yp_node_t *) yp_unless_node_create(parser, &keyword, predicate, statements);
8931
8688
  break;
8932
8689
  default:
8933
- parent = NULL;
8934
8690
  assert(false && "unreachable");
8935
8691
  break;
8936
8692
  }
@@ -8976,50 +8732,49 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) {
8976
8732
  switch (context) {
8977
8733
  case YP_CONTEXT_IF:
8978
8734
  ((yp_if_node_t *) current)->consequent = (yp_node_t *) else_node;
8979
- // Recurse down if nodes setting the appropriate end location in
8980
- // all cases.
8981
- yp_node_t *recursing_node = parent;
8982
- bool recursing = true;
8983
-
8984
- while (recursing) {
8985
- switch (YP_NODE_TYPE(recursing_node)) {
8986
- case YP_NODE_IF_NODE:
8987
- yp_if_node_end_keyword_loc_set((yp_if_node_t *) recursing_node, &parser->previous);
8988
- recursing_node = ((yp_if_node_t *) recursing_node)->consequent;
8989
- break;
8990
- case YP_NODE_ELSE_NODE:
8991
- yp_else_node_end_keyword_loc_set((yp_else_node_t *) recursing_node, &parser->previous);
8992
- recursing = false;
8993
- break;
8994
- default: {
8995
- recursing = false;
8996
- break;
8997
- }
8998
- }
8999
- }
9000
8735
  break;
9001
8736
  case YP_CONTEXT_UNLESS:
9002
8737
  ((yp_unless_node_t *) parent)->consequent = else_node;
9003
- yp_unless_node_end_keyword_loc_set((yp_unless_node_t *) parent, &parser->previous);
9004
8738
  break;
9005
8739
  default:
9006
8740
  assert(false && "unreachable");
9007
8741
  break;
9008
8742
  }
9009
8743
  } else {
9010
- expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `if` statement.");
8744
+ expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close conditional statement.");
8745
+ }
9011
8746
 
9012
- switch (context) {
9013
- case YP_CONTEXT_IF:
9014
- yp_if_node_end_keyword_loc_set((yp_if_node_t *) parent, &parser->previous);
9015
- break;
9016
- case YP_CONTEXT_UNLESS:
9017
- yp_unless_node_end_keyword_loc_set((yp_unless_node_t *) parent, &parser->previous);
9018
- break;
9019
- default:
9020
- assert(false && "unreachable");
9021
- break;
8747
+ // Set the appropriate end location for all of the nodes in the subtree.
8748
+ switch (context) {
8749
+ case YP_CONTEXT_IF: {
8750
+ yp_node_t *current = parent;
8751
+ bool recursing = true;
8752
+
8753
+ while (recursing) {
8754
+ switch (YP_NODE_TYPE(current)) {
8755
+ case YP_NODE_IF_NODE:
8756
+ yp_if_node_end_keyword_loc_set((yp_if_node_t *) current, &parser->previous);
8757
+ current = ((yp_if_node_t *) current)->consequent;
8758
+ recursing = current != NULL;
8759
+ break;
8760
+ case YP_NODE_ELSE_NODE:
8761
+ yp_else_node_end_keyword_loc_set((yp_else_node_t *) current, &parser->previous);
8762
+ recursing = false;
8763
+ break;
8764
+ default: {
8765
+ recursing = false;
8766
+ break;
8767
+ }
8768
+ }
8769
+ }
8770
+ break;
9022
8771
  }
8772
+ case YP_CONTEXT_UNLESS:
8773
+ yp_unless_node_end_keyword_loc_set((yp_unless_node_t *) parent, &parser->previous);
8774
+ break;
8775
+ default:
8776
+ assert(false && "unreachable");
8777
+ break;
9023
8778
  }
9024
8779
 
9025
8780
  return parent;
@@ -9093,7 +8848,12 @@ parse_string_part(yp_parser_t *parser) {
9093
8848
  yp_unescape_type_t unescape_type = YP_UNESCAPE_ALL;
9094
8849
 
9095
8850
  if (parser->lex_modes.current->mode == YP_LEX_HEREDOC) {
9096
- if (parser->lex_modes.current->as.heredoc.quote == YP_HEREDOC_QUOTE_SINGLE) {
8851
+ if (parser->lex_modes.current->as.heredoc.indent == YP_HEREDOC_INDENT_TILDE) {
8852
+ // If we're in a tilde heredoc, we want to unescape it later
8853
+ // because we don't want unescaped newlines to disappear
8854
+ // before we handle them in the dedent.
8855
+ unescape_type = YP_UNESCAPE_NONE;
8856
+ } else if (parser->lex_modes.current->as.heredoc.quote == YP_HEREDOC_QUOTE_SINGLE) {
9097
8857
  unescape_type = YP_UNESCAPE_MINIMAL;
9098
8858
  }
9099
8859
  }
@@ -9359,7 +9119,7 @@ parse_alias_argument(yp_parser_t *parser, bool first) {
9359
9119
  // Parse an identifier into either a local variable read or a call.
9360
9120
  static yp_node_t *
9361
9121
  parse_variable_call(yp_parser_t *parser) {
9362
- uint32_t flags = 0;
9122
+ yp_node_flags_t flags = 0;
9363
9123
 
9364
9124
  if (!match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) {
9365
9125
  int depth;
@@ -9371,7 +9131,7 @@ parse_variable_call(yp_parser_t *parser) {
9371
9131
  }
9372
9132
 
9373
9133
  yp_call_node_t *node = yp_call_node_variable_call_create(parser, &parser->previous);
9374
- node->flags = flags;
9134
+ node->base.flags |= flags;
9375
9135
 
9376
9136
  return (yp_node_t *) node;
9377
9137
  }
@@ -9466,14 +9226,30 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
9466
9226
  int common_whitespace;
9467
9227
  if ((common_whitespace = parse_heredoc_common_whitespace(parser, nodes)) <= 0) return;
9468
9228
 
9469
- // Iterate over all nodes, and trim whitespace accordingly.
9470
- for (size_t index = 0; index < nodes->size; index++) {
9471
- yp_node_t *node = nodes->nodes[index];
9472
- if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE)) continue;
9229
+ // The next node should be dedented if it's the first node in the list or if
9230
+ // if follows a string node.
9231
+ bool dedent_next = true;
9232
+
9233
+ // Iterate over all nodes, and trim whitespace accordingly. We're going to
9234
+ // keep around two indices: a read and a write. If we end up trimming all of
9235
+ // the whitespace from a node, then we'll drop it from the list entirely.
9236
+ size_t write_index = 0;
9237
+
9238
+ for (size_t read_index = 0; read_index < nodes->size; read_index++) {
9239
+ yp_node_t *node = nodes->nodes[read_index];
9240
+
9241
+ // We're not manipulating child nodes that aren't strings. In this case
9242
+ // we'll skip past it and indicate that the subsequent node should not
9243
+ // be dedented.
9244
+ if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE)) {
9245
+ nodes->nodes[write_index++] = node;
9246
+ dedent_next = false;
9247
+ continue;
9248
+ }
9473
9249
 
9474
9250
  // Get a reference to the string struct that is being held by the string
9475
9251
  // node. This is the value we're going to actual manipulate.
9476
- yp_string_t *string = &((yp_string_node_t *) node)->unescaped;
9252
+ yp_string_t *string = &(((yp_string_node_t *) node)->unescaped);
9477
9253
  yp_string_ensure_owned(string);
9478
9254
 
9479
9255
  // Now get the bounds of the existing string. We'll use this as a
@@ -9489,7 +9265,6 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
9489
9265
  // whitespace, so we'll maintain a pointer to the current position in the
9490
9266
  // string that we're writing to.
9491
9267
  char *dest_cursor = source_start;
9492
- bool dedent_next = (index == 0) || YP_NODE_TYPE_P(nodes->nodes[index - 1], YP_NODE_STRING_NODE);
9493
9268
 
9494
9269
  while (source_cursor < source_end) {
9495
9270
  // If we need to dedent the next element within the heredoc or the next
@@ -9534,8 +9309,20 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
9534
9309
  dedent_next = true;
9535
9310
  }
9536
9311
 
9537
- string->length = dest_length;
9312
+ // We only want to write this node into the list if it has any content.
9313
+ if (dest_length == 0) {
9314
+ yp_node_destroy(parser, node);
9315
+ } else {
9316
+ string->length = dest_length;
9317
+ yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL, &parser->error_list);
9318
+ nodes->nodes[write_index++] = node;
9319
+ }
9320
+
9321
+ // We always dedent the next node if it follows a string node.
9322
+ dedent_next = true;
9538
9323
  }
9324
+
9325
+ nodes->size = write_index;
9539
9326
  }
9540
9327
 
9541
9328
  static yp_node_t *
@@ -10172,6 +9959,30 @@ parse_pattern(yp_parser_t *parser, bool top_pattern, const char *message) {
10172
9959
  return node;
10173
9960
  }
10174
9961
 
9962
+ // Incorporate a negative sign into a numeric node by subtracting 1 character
9963
+ // from its start bounds. If it's a compound node, then we will recursively
9964
+ // apply this function to its value.
9965
+ static inline void
9966
+ parse_negative_numeric(yp_node_t *node) {
9967
+ switch (YP_NODE_TYPE(node)) {
9968
+ case YP_NODE_INTEGER_NODE:
9969
+ case YP_NODE_FLOAT_NODE:
9970
+ node->location.start--;
9971
+ break;
9972
+ case YP_NODE_RATIONAL_NODE:
9973
+ node->location.start--;
9974
+ parse_negative_numeric(((yp_rational_node_t *) node)->numeric);
9975
+ break;
9976
+ case YP_NODE_IMAGINARY_NODE:
9977
+ node->location.start--;
9978
+ parse_negative_numeric(((yp_imaginary_node_t *) node)->numeric);
9979
+ break;
9980
+ default:
9981
+ assert(false && "unreachable");
9982
+ break;
9983
+ }
9984
+ }
9985
+
10175
9986
  // Parse an expression that begins with the previous node that we just lexed.
10176
9987
  static inline yp_node_t *
10177
9988
  parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
@@ -10260,6 +10071,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10260
10071
  }
10261
10072
  case YP_TOKEN_PARENTHESIS_LEFT:
10262
10073
  case YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
10074
+ yp_token_type_t current_token_type = parser->current.type;
10263
10075
  parser_lex(parser);
10264
10076
 
10265
10077
  yp_token_t opening = parser->previous;
@@ -10280,7 +10092,11 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10280
10092
 
10281
10093
  // If we hit a right parenthesis, then we're done parsing the parentheses
10282
10094
  // node, and we can check which kind of node we should return.
10283
- if (accept(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
10095
+ if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
10096
+ if (current_token_type == YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
10097
+ lex_state_set(parser, YP_LEX_STATE_ENDARG);
10098
+ }
10099
+ parser_lex(parser);
10284
10100
  yp_accepts_block_stack_pop(parser);
10285
10101
 
10286
10102
  // If we have a single statement and are ending on a right parenthesis,
@@ -10496,7 +10312,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10496
10312
  if (parse_arguments_list(parser, &arguments, true)) {
10497
10313
  // Since we found arguments, we need to turn off the
10498
10314
  // variable call bit in the flags.
10499
- call->flags &= (uint32_t) ~YP_CALL_NODE_FLAGS_VARIABLE_CALL;
10315
+ call->base.flags &= (yp_node_flags_t) ~YP_CALL_NODE_FLAGS_VARIABLE_CALL;
10500
10316
 
10501
10317
  call->opening_loc = arguments.opening_loc;
10502
10318
  call->arguments = arguments.arguments;
@@ -10565,12 +10381,15 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10565
10381
 
10566
10382
  lex_state_set(parser, YP_LEX_STATE_END);
10567
10383
  expect(parser, YP_TOKEN_HEREDOC_END, "Expected a closing delimiter for heredoc.");
10384
+
10568
10385
  if (quote == YP_HEREDOC_QUOTE_BACKTICK) {
10569
10386
  assert(YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_X_STRING_NODE));
10570
10387
  yp_interpolated_xstring_node_closing_set(((yp_interpolated_x_string_node_t *) node), &parser->previous);
10388
+ node->location = ((yp_interpolated_x_string_node_t *) node)->opening_loc;
10571
10389
  } else {
10572
10390
  assert(YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_STRING_NODE));
10573
10391
  yp_interpolated_string_node_closing_set((yp_interpolated_string_node_t *) node, &parser->previous);
10392
+ node->location = ((yp_interpolated_string_node_t *) node)->opening_loc;
10574
10393
  }
10575
10394
 
10576
10395
  // If this is a heredoc that is indented with a ~, then we need to dedent
@@ -10850,7 +10669,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10850
10669
  parser_lex(parser);
10851
10670
 
10852
10671
  yp_token_t keyword = parser->previous;
10853
- yp_arguments_node_t *arguments = NULL;
10672
+ yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
10854
10673
 
10855
10674
  if (
10856
10675
  token_begins_expression_p(parser->current.type) ||
@@ -10859,16 +10678,16 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10859
10678
  yp_binding_power_t binding_power = yp_binding_powers[parser->current.type].left;
10860
10679
 
10861
10680
  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);
10681
+ arguments.arguments = yp_arguments_node_create(parser);
10682
+ parse_arguments(parser, &arguments, false, YP_TOKEN_EOF);
10864
10683
  }
10865
10684
  }
10866
10685
 
10867
10686
  switch (keyword.type) {
10868
10687
  case YP_TOKEN_KEYWORD_BREAK:
10869
- return (yp_node_t *) yp_break_node_create(parser, &keyword, arguments);
10688
+ return (yp_node_t *) yp_break_node_create(parser, &keyword, arguments.arguments);
10870
10689
  case YP_TOKEN_KEYWORD_NEXT:
10871
- return (yp_node_t *) yp_next_node_create(parser, &keyword, arguments);
10690
+ return (yp_node_t *) yp_next_node_create(parser, &keyword, arguments.arguments);
10872
10691
  case YP_TOKEN_KEYWORD_RETURN: {
10873
10692
  if (
10874
10693
  (parser->current_context->context == YP_CONTEXT_CLASS) ||
@@ -10876,7 +10695,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
10876
10695
  ) {
10877
10696
  yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid return in class/module body");
10878
10697
  }
10879
- return (yp_node_t *) yp_return_node_create(parser, &keyword, arguments);
10698
+ return (yp_node_t *) yp_return_node_create(parser, &keyword, arguments.arguments);
10880
10699
  }
10881
10700
  default:
10882
10701
  assert(false && "unreachable");
@@ -11342,6 +11161,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
11342
11161
  arguments.closing_loc = ((yp_location_t) { .start = parser->previous.start, .end = parser->previous.end });
11343
11162
  } else {
11344
11163
  receiver = parse_expression(parser, YP_BINDING_POWER_COMPOSITION, "Expected expression after `not`.");
11164
+ yp_flip_flop(receiver);
11345
11165
 
11346
11166
  if (!parser->recovering) {
11347
11167
  accept(parser, YP_TOKEN_NEWLINE);
@@ -11351,6 +11171,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
11351
11171
  }
11352
11172
  } else {
11353
11173
  receiver = parse_expression(parser, YP_BINDING_POWER_DEFINED, "Expected expression after `not`.");
11174
+ yp_flip_flop(receiver);
11354
11175
  }
11355
11176
 
11356
11177
  return (yp_node_t *) yp_call_node_not_create(parser, receiver, &message, &arguments);
@@ -11928,6 +11749,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
11928
11749
  yp_node_t *receiver = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary !.");
11929
11750
  yp_call_node_t *node = yp_call_node_unary_create(parser, &operator, receiver, "!");
11930
11751
 
11752
+ yp_flip_flop(receiver);
11931
11753
  return (yp_node_t *) node;
11932
11754
  }
11933
11755
  case YP_TOKEN_TILDE: {
@@ -11939,8 +11761,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
11939
11761
 
11940
11762
  return (yp_node_t *) node;
11941
11763
  }
11942
- case YP_TOKEN_UMINUS:
11943
- case YP_TOKEN_UMINUS_NUM: {
11764
+ case YP_TOKEN_UMINUS: {
11944
11765
  parser_lex(parser);
11945
11766
 
11946
11767
  yp_token_t operator = parser->previous;
@@ -11949,6 +11770,26 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
11949
11770
 
11950
11771
  return (yp_node_t *) node;
11951
11772
  }
11773
+ case YP_TOKEN_UMINUS_NUM: {
11774
+ parser_lex(parser);
11775
+
11776
+ yp_token_t operator = parser->previous;
11777
+ yp_node_t *node = parse_expression(parser, yp_binding_powers[parser->previous.type].right, "Expected a receiver after unary -.");
11778
+
11779
+ switch (YP_NODE_TYPE(node)) {
11780
+ case YP_NODE_INTEGER_NODE:
11781
+ case YP_NODE_FLOAT_NODE:
11782
+ case YP_NODE_RATIONAL_NODE:
11783
+ case YP_NODE_IMAGINARY_NODE:
11784
+ parse_negative_numeric(node);
11785
+ break;
11786
+ default:
11787
+ node = (yp_node_t *) yp_call_node_unary_create(parser, &operator, node, "-@");
11788
+ break;
11789
+ }
11790
+
11791
+ return node;
11792
+ }
11952
11793
  case YP_TOKEN_MINUS_GREATER: {
11953
11794
  int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
11954
11795
  parser->lambda_enclosure_nesting = parser->enclosure_nesting;
@@ -12195,18 +12036,18 @@ static inline yp_node_t *
12195
12036
  parse_assignment_value(yp_parser_t *parser, yp_binding_power_t previous_binding_power, yp_binding_power_t binding_power, const char *message) {
12196
12037
  yp_node_t *value = parse_starred_expression(parser, binding_power, message);
12197
12038
 
12198
- if (previous_binding_power == YP_BINDING_POWER_STATEMENT && accept(parser, YP_TOKEN_COMMA)) {
12039
+ 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
12040
  yp_token_t opening = not_provided(parser);
12200
12041
  yp_array_node_t *array = yp_array_node_create(parser, &opening);
12201
12042
 
12202
12043
  yp_array_node_elements_append(array, value);
12203
12044
  value = (yp_node_t *) array;
12204
12045
 
12205
- do {
12046
+ while (accept(parser, YP_TOKEN_COMMA)) {
12206
12047
  yp_node_t *element = parse_starred_expression(parser, binding_power, "Expected an element for the array.");
12207
12048
  yp_array_node_elements_append(array, element);
12208
12049
  if (YP_NODE_TYPE_P(element, YP_NODE_MISSING_NODE)) break;
12209
- } while (accept(parser, YP_TOKEN_COMMA));
12050
+ }
12210
12051
  }
12211
12052
 
12212
12053
  return value;
@@ -12264,14 +12105,19 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12264
12105
  case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
12265
12106
  yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
12266
12107
  /* fallthrough */
12267
- case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
12108
+ case YP_NODE_CLASS_VARIABLE_READ_NODE:
12109
+ case YP_NODE_CONSTANT_PATH_NODE:
12110
+ case YP_NODE_CONSTANT_READ_NODE:
12111
+ case YP_NODE_GLOBAL_VARIABLE_READ_NODE:
12112
+ case YP_NODE_INSTANCE_VARIABLE_READ_NODE:
12113
+ case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
12268
12114
  parser_lex(parser);
12269
12115
 
12270
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12271
- yp_node_t *result = (yp_node_t *) yp_global_variable_operator_and_write_node_create(parser, node, &token, value);
12116
+ yp_token_t operator = not_provided(parser);
12117
+ node = parse_target(parser, node, &operator, NULL);
12272
12118
 
12273
- yp_node_destroy(parser, node);
12274
- return result;
12119
+ yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12120
+ return (yp_node_t *) yp_and_write_node_create(parser, node, &token, value);
12275
12121
  }
12276
12122
  case YP_NODE_CALL_NODE: {
12277
12123
  yp_call_node_t *call_node = (yp_call_node_t *) node;
@@ -12289,12 +12135,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12289
12135
 
12290
12136
  parser_lex(parser);
12291
12137
 
12292
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12293
- yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message_loc.start, message_loc.end);
12294
- yp_node_t *result = (yp_node_t *) yp_local_variable_operator_and_write_node_create(parser, node, &token, value, constant_id);
12138
+ yp_token_t operator = not_provided(parser);
12139
+ node = parse_target(parser, node, &operator, NULL);
12295
12140
 
12296
- yp_node_destroy(parser, node);
12297
- return result;
12141
+ yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12142
+ return (yp_node_t *) yp_and_write_node_create(parser, node, &token, value);
12298
12143
  }
12299
12144
 
12300
12145
  parser_lex(parser);
@@ -12305,49 +12150,6 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12305
12150
  yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12306
12151
  return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
12307
12152
  }
12308
- case YP_NODE_CLASS_VARIABLE_READ_NODE: {
12309
- parser_lex(parser);
12310
-
12311
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12312
- yp_node_t *result = (yp_node_t *) yp_class_variable_operator_and_write_node_create(parser, node, &token, value);
12313
-
12314
- yp_node_destroy(parser, node);
12315
- return result;
12316
- }
12317
- case YP_NODE_CONSTANT_PATH_NODE: {
12318
- parser_lex(parser);
12319
-
12320
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12321
- return (yp_node_t *) yp_constant_path_operator_and_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
12322
- }
12323
- case YP_NODE_CONSTANT_READ_NODE: {
12324
- parser_lex(parser);
12325
-
12326
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12327
- yp_node_t *result = (yp_node_t *) yp_constant_operator_and_write_node_create(parser, node, &token, value);
12328
-
12329
- yp_node_destroy(parser, node);
12330
- return result;
12331
- }
12332
- case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
12333
- parser_lex(parser);
12334
-
12335
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12336
- yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_and_write_node_create(parser, node, &token, value);
12337
-
12338
- yp_node_destroy(parser, node);
12339
- return result;
12340
- }
12341
- case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
12342
- parser_lex(parser);
12343
-
12344
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12345
- yp_constant_id_t constant_id = ((yp_local_variable_read_node_t *) node)->constant_id;
12346
- yp_node_t *result = (yp_node_t *) yp_local_variable_operator_and_write_node_create(parser, node, &token, value, constant_id);
12347
-
12348
- yp_node_destroy(parser, node);
12349
- return result;
12350
- }
12351
12153
  case YP_NODE_MULTI_WRITE_NODE: {
12352
12154
  parser_lex(parser);
12353
12155
  yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `&&=' on a multi-write.");
@@ -12369,14 +12171,19 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12369
12171
  case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
12370
12172
  yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
12371
12173
  /* fallthrough */
12372
- case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
12174
+ case YP_NODE_CLASS_VARIABLE_READ_NODE:
12175
+ case YP_NODE_CONSTANT_PATH_NODE:
12176
+ case YP_NODE_CONSTANT_READ_NODE:
12177
+ case YP_NODE_GLOBAL_VARIABLE_READ_NODE:
12178
+ case YP_NODE_INSTANCE_VARIABLE_READ_NODE:
12179
+ case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
12373
12180
  parser_lex(parser);
12374
12181
 
12375
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12376
- yp_node_t *result = (yp_node_t *) yp_global_variable_operator_or_write_node_create(parser, node, &token, value);
12182
+ yp_token_t operator = not_provided(parser);
12183
+ node = parse_target(parser, node, &operator, NULL);
12377
12184
 
12378
- yp_node_destroy(parser, node);
12379
- return result;
12185
+ yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12186
+ return (yp_node_t *) yp_or_write_node_create(parser, node, &token, value);
12380
12187
  }
12381
12188
  case YP_NODE_CALL_NODE: {
12382
12189
  yp_call_node_t *call_node = (yp_call_node_t *) node;
@@ -12394,12 +12201,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12394
12201
 
12395
12202
  parser_lex(parser);
12396
12203
 
12397
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12398
- yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message_loc.start, message_loc.end);
12399
- yp_node_t *result = (yp_node_t *) yp_local_variable_operator_or_write_node_create(parser, node, &token, value, constant_id);
12204
+ yp_token_t operator = not_provided(parser);
12205
+ node = parse_target(parser, node, &operator, NULL);
12400
12206
 
12401
- yp_node_destroy(parser, node);
12402
- return result;
12207
+ yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12208
+ return (yp_node_t *) yp_or_write_node_create(parser, node, &token, value);
12403
12209
  }
12404
12210
 
12405
12211
  parser_lex(parser);
@@ -12410,49 +12216,6 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12410
12216
  yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12411
12217
  return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
12412
12218
  }
12413
- case YP_NODE_CLASS_VARIABLE_READ_NODE: {
12414
- parser_lex(parser);
12415
-
12416
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12417
- yp_node_t *result = (yp_node_t *) yp_class_variable_operator_or_write_node_create(parser, node, &token, value);
12418
-
12419
- yp_node_destroy(parser, node);
12420
- return result;
12421
- }
12422
- case YP_NODE_CONSTANT_PATH_NODE: {
12423
- parser_lex(parser);
12424
-
12425
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12426
- return (yp_node_t *) yp_constant_path_operator_or_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
12427
- }
12428
- case YP_NODE_CONSTANT_READ_NODE: {
12429
- parser_lex(parser);
12430
-
12431
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12432
- yp_node_t *result = (yp_node_t *) yp_constant_operator_or_write_node_create(parser, node, &token, value);
12433
-
12434
- yp_node_destroy(parser, node);
12435
- return result;
12436
- }
12437
- case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
12438
- parser_lex(parser);
12439
-
12440
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12441
- yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_or_write_node_create(parser, node, &token, value);
12442
-
12443
- yp_node_destroy(parser, node);
12444
- return result;
12445
- }
12446
- case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
12447
- parser_lex(parser);
12448
-
12449
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
12450
- yp_constant_id_t constant_id = ((yp_local_variable_read_node_t *) node)->constant_id;
12451
- yp_node_t *result = (yp_node_t *) yp_local_variable_operator_or_write_node_create(parser, node, &token, value, constant_id);
12452
-
12453
- yp_node_destroy(parser, node);
12454
- return result;
12455
- }
12456
12219
  case YP_NODE_MULTI_WRITE_NODE: {
12457
12220
  parser_lex(parser);
12458
12221
  yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `||=' on a multi-write.");
@@ -12484,14 +12247,19 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12484
12247
  case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
12485
12248
  yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
12486
12249
  /* fallthrough */
12487
- case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
12250
+ case YP_NODE_CLASS_VARIABLE_READ_NODE:
12251
+ case YP_NODE_CONSTANT_PATH_NODE:
12252
+ case YP_NODE_CONSTANT_READ_NODE:
12253
+ case YP_NODE_GLOBAL_VARIABLE_READ_NODE:
12254
+ case YP_NODE_INSTANCE_VARIABLE_READ_NODE:
12255
+ case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
12488
12256
  parser_lex(parser);
12489
12257
 
12490
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator");
12491
- yp_node_t *result = (yp_node_t *) yp_global_variable_operator_write_node_create(parser, node, &token, value);
12258
+ yp_token_t operator = not_provided(parser);
12259
+ node = parse_target(parser, node, &operator, NULL);
12492
12260
 
12493
- yp_node_destroy(parser, node);
12494
- return result;
12261
+ yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator");
12262
+ return (yp_node_t *) yp_operator_write_node_create(parser, node, &token, value);
12495
12263
  }
12496
12264
  case YP_NODE_CALL_NODE: {
12497
12265
  yp_call_node_t *call_node = (yp_call_node_t *) node;
@@ -12509,12 +12277,11 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12509
12277
 
12510
12278
  parser_lex(parser);
12511
12279
 
12512
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12513
- yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message_loc.start, message_loc.end);
12514
- yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id);
12280
+ yp_token_t operator = not_provided(parser);
12281
+ node = parse_target(parser, node, &operator, NULL);
12515
12282
 
12516
- yp_node_destroy(parser, node);
12517
- return result;
12283
+ yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
12284
+ return (yp_node_t *) yp_operator_write_node_create(parser, node, &token, value);
12518
12285
  }
12519
12286
 
12520
12287
  yp_token_t operator = not_provided(parser);
@@ -12524,49 +12291,6 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12524
12291
  yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12525
12292
  return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
12526
12293
  }
12527
- case YP_NODE_CLASS_VARIABLE_READ_NODE: {
12528
- parser_lex(parser);
12529
-
12530
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12531
- yp_node_t *result = (yp_node_t *) yp_class_variable_operator_write_node_create(parser, node, &token, value);
12532
-
12533
- yp_node_destroy(parser, node);
12534
- return result;
12535
- }
12536
- case YP_NODE_CONSTANT_PATH_NODE: {
12537
- parser_lex(parser);
12538
-
12539
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12540
- return (yp_node_t *) yp_constant_path_operator_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
12541
- }
12542
- case YP_NODE_CONSTANT_READ_NODE: {
12543
- parser_lex(parser);
12544
-
12545
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12546
- yp_node_t *result = (yp_node_t *) yp_constant_operator_write_node_create(parser, node, &token, value);
12547
-
12548
- yp_node_destroy(parser, node);
12549
- return result;
12550
- }
12551
- case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
12552
- parser_lex(parser);
12553
-
12554
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12555
- yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_write_node_create(parser, node, &token, value);
12556
-
12557
- yp_node_destroy(parser, node);
12558
- return result;
12559
- }
12560
- case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
12561
- parser_lex(parser);
12562
-
12563
- yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
12564
- yp_constant_id_t constant_id = ((yp_local_variable_read_node_t *) node)->constant_id;
12565
- yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id);
12566
-
12567
- yp_node_destroy(parser, node);
12568
- return result;
12569
- }
12570
12294
  case YP_NODE_MULTI_WRITE_NODE: {
12571
12295
  parser_lex(parser);
12572
12296
  yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected operator.");
@@ -12808,12 +12532,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12808
12532
  case YP_CASE_KEYWORD:
12809
12533
  case YP_TOKEN_IDENTIFIER: {
12810
12534
  parser_lex(parser);
12535
+ yp_token_t message = parser->previous;
12811
12536
 
12812
12537
  // If we have an identifier following a '::' operator, then it is for
12813
12538
  // sure a method call.
12814
12539
  yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
12815
12540
  parse_arguments_list(parser, &arguments, true);
12816
- yp_call_node_t *call = yp_call_node_call_create(parser, node, &delimiter, &parser->previous, &arguments);
12541
+ yp_call_node_t *call = yp_call_node_call_create(parser, node, &delimiter, &message, &arguments);
12817
12542
 
12818
12543
  // If this is followed by a comma then it is a multiple assignment.
12819
12544
  if (previous_binding_power == YP_BINDING_POWER_STATEMENT && match_type_p(parser, YP_TOKEN_COMMA)) {
@@ -12854,7 +12579,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12854
12579
  yp_accepts_block_stack_push(parser, true);
12855
12580
  arguments.arguments = yp_arguments_node_create(parser);
12856
12581
 
12857
- parse_arguments(parser, arguments.arguments, false, YP_TOKEN_BRACKET_RIGHT);
12582
+ parse_arguments(parser, &arguments, false, YP_TOKEN_BRACKET_RIGHT);
12858
12583
  yp_accepts_block_stack_pop(parser);
12859
12584
 
12860
12585
  expect(parser, YP_TOKEN_BRACKET_RIGHT, "Expected ']' to close the bracket expression.");
@@ -12878,6 +12603,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
12878
12603
  arguments.block = parse_block(parser);
12879
12604
  }
12880
12605
 
12606
+ yp_arguments_validate(parser, &arguments);
12881
12607
  return (yp_node_t *) yp_call_node_aref_create(parser, node, &arguments);
12882
12608
  }
12883
12609
  case YP_TOKEN_KEYWORD_IN: {
@@ -13058,6 +12784,8 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
13058
12784
  .enclosure_nesting = 0,
13059
12785
  .lambda_enclosure_nesting = -1,
13060
12786
  .brace_nesting = 0,
12787
+ .do_loop_stack = YP_STATE_STACK_EMPTY,
12788
+ .accepts_block_stack = YP_STATE_STACK_EMPTY,
13061
12789
  .lex_modes = {
13062
12790
  .index = 0,
13063
12791
  .stack = {{ .mode = YP_LEX_DEFAULT }},
@@ -13069,6 +12797,9 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
13069
12797
  .current = { .type = YP_TOKEN_EOF, .start = source, .end = source },
13070
12798
  .next_start = NULL,
13071
12799
  .heredoc_end = NULL,
12800
+ .comment_list = YP_LIST_EMPTY,
12801
+ .warning_list = YP_LIST_EMPTY,
12802
+ .error_list = YP_LIST_EMPTY,
13072
12803
  .current_scope = NULL,
13073
12804
  .current_context = NULL,
13074
12805
  .recovering = false,
@@ -13081,16 +12812,12 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
13081
12812
  .pattern_matching_newlines = false,
13082
12813
  .in_keyword_arg = false,
13083
12814
  .filepath_string = filepath_string,
12815
+ .constant_pool = YP_CONSTANT_POOL_EMPTY,
12816
+ .newline_list = YP_NEWLINE_LIST_EMPTY
13084
12817
  };
13085
12818
 
13086
- yp_state_stack_init(&parser->do_loop_stack);
13087
- yp_state_stack_init(&parser->accepts_block_stack);
13088
12819
  yp_accepts_block_stack_push(parser, true);
13089
12820
 
13090
- yp_list_init(&parser->warning_list);
13091
- yp_list_init(&parser->error_list);
13092
- yp_list_init(&parser->comment_list);
13093
-
13094
12821
  // Initialize the constant pool. We're going to completely guess as to the
13095
12822
  // number of constants that we'll need based on the size of the input. The
13096
12823
  // ratio we chose here is actually less arbitrary than you might think.