prism 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
data/src/prism.c CHANGED
@@ -496,18 +496,8 @@ pm_parser_constant_id_owned(pm_parser_t *parser, const uint8_t *start, size_t le
496
496
 
497
497
  // Retrieve the constant pool id for the given static literal C string.
498
498
  static inline pm_constant_id_t
499
- pm_parser_constant_id_static(pm_parser_t *parser, const char *start, size_t length) {
500
- uint8_t *owned_copy;
501
- if (length > 0) {
502
- owned_copy = malloc(length);
503
- memcpy(owned_copy, start, length);
504
- } else {
505
- owned_copy = malloc(1);
506
- owned_copy[0] = '\0';
507
- }
508
- return pm_constant_pool_insert_owned(&parser->constant_pool, owned_copy, length);
509
- // Does not work because the static literal cannot be serialized as an offset of source
510
- // return pm_constant_pool_insert_shared(&parser->constant_pool, start, length);
499
+ pm_parser_constant_id_constant(pm_parser_t *parser, const char *start, size_t length) {
500
+ return pm_constant_pool_insert_constant(&parser->constant_pool, (const uint8_t *) start, length);
511
501
  }
512
502
 
513
503
  // Retrieve the constant pool id for the given token.
@@ -664,14 +654,22 @@ pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_b
664
654
 
665
655
  // Generate a scope node from the given node.
666
656
  void
667
- pm_scope_node_init(pm_node_t *node, pm_scope_node_t *scope) {
657
+ pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous, pm_parser_t *parser) {
668
658
  scope->base.type = PM_SCOPE_NODE;
669
659
  scope->base.location.start = node->location.start;
670
660
  scope->base.location.end = node->location.end;
671
661
 
672
- scope->ast_node = node;
662
+ scope->previous = previous;
663
+ scope->parser = parser;
664
+ scope->ast_node = (pm_node_t *)node;
673
665
  scope->parameters = NULL;
674
666
  scope->body = NULL;
667
+ scope->constants = NULL;
668
+ if (previous) {
669
+ scope->constants = previous->constants;
670
+ }
671
+ scope->index_lookup_table = NULL;
672
+
675
673
  pm_constant_id_list_init(&scope->locals);
676
674
 
677
675
  switch (PM_NODE_TYPE(node)) {
@@ -771,6 +769,7 @@ parse_decimal_number(pm_parser_t *parser, const uint8_t *start, const uint8_t *e
771
769
  static inline pm_node_flags_t
772
770
  pm_regular_expression_flags_create(const pm_token_t *closing) {
773
771
  pm_node_flags_t flags = 0;
772
+ pm_node_flags_t mask = (uint16_t) 0xFF0F;
774
773
 
775
774
  if (closing->type == PM_TOKEN_REGEXP_END) {
776
775
  for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
@@ -778,11 +777,13 @@ pm_regular_expression_flags_create(const pm_token_t *closing) {
778
777
  case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
779
778
  case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
780
779
  case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
781
- case 'e': flags |= PM_REGULAR_EXPRESSION_FLAGS_EUC_JP; break;
782
- case 'n': flags |= PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT; break;
783
- case 's': flags |= PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J; break;
784
- case 'u': flags |= PM_REGULAR_EXPRESSION_FLAGS_UTF_8; break;
785
780
  case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
781
+
782
+ case 'e': flags &= mask; flags |= PM_REGULAR_EXPRESSION_FLAGS_EUC_JP; break;
783
+ case 'n': flags &= mask; flags |= PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT; break;
784
+ case 's': flags &= mask; flags |= PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J; break;
785
+ case 'u': flags &= mask; flags |= PM_REGULAR_EXPRESSION_FLAGS_UTF_8; break;
786
+
786
787
  default: assert(false && "unreachable");
787
788
  }
788
789
  }
@@ -1180,7 +1181,8 @@ pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name)
1180
1181
  {
1181
1182
  .type = PM_BACK_REFERENCE_READ_NODE,
1182
1183
  .location = PM_LOCATION_TOKEN_VALUE(name),
1183
- }
1184
+ },
1185
+ .name = pm_parser_constant_id_token(parser, name)
1184
1186
  };
1185
1187
 
1186
1188
  return node;
@@ -1446,7 +1448,7 @@ pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_
1446
1448
  node->closing_loc = arguments->closing_loc;
1447
1449
  node->block = arguments->block;
1448
1450
 
1449
- node->name = pm_parser_constant_id_static(parser, "[]", 2);
1451
+ node->name = pm_parser_constant_id_constant(parser, "[]", 2);
1450
1452
  return node;
1451
1453
  }
1452
1454
 
@@ -1546,7 +1548,7 @@ pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *me
1546
1548
  node->arguments = arguments->arguments;
1547
1549
  node->closing_loc = arguments->closing_loc;
1548
1550
 
1549
- node->name = pm_parser_constant_id_static(parser, "!", 1);
1551
+ node->name = pm_parser_constant_id_constant(parser, "!", 1);
1550
1552
  return node;
1551
1553
  }
1552
1554
 
@@ -1573,7 +1575,7 @@ pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token
1573
1575
  node->base.flags |= PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
1574
1576
  }
1575
1577
 
1576
- node->name = pm_parser_constant_id_static(parser, "call", 4);
1578
+ node->name = pm_parser_constant_id_constant(parser, "call", 4);
1577
1579
  return node;
1578
1580
  }
1579
1581
 
@@ -1588,7 +1590,7 @@ pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *
1588
1590
  node->receiver = receiver;
1589
1591
  node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
1590
1592
 
1591
- node->name = pm_parser_constant_id_static(parser, name, strlen(name));
1593
+ node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
1592
1594
  return node;
1593
1595
  }
1594
1596
 
@@ -1612,11 +1614,38 @@ pm_call_node_variable_call_p(pm_call_node_t *node) {
1612
1614
  return node->base.flags & PM_CALL_NODE_FLAGS_VARIABLE_CALL;
1613
1615
  }
1614
1616
 
1617
+ // Returns whether or not this call is to the [] method in the index form (as
1618
+ // opposed to `foo.[]`).
1619
+ static inline bool
1620
+ pm_call_node_index_p(pm_call_node_t *node) {
1621
+ return (
1622
+ (node->call_operator_loc.start == NULL) &&
1623
+ (node->message_loc.start != NULL) &&
1624
+ (node->message_loc.start[0] == '[') &&
1625
+ (node->message_loc.end[-1] == ']')
1626
+ );
1627
+ }
1628
+
1629
+ // Returns whether or not this call can be used on the left-hand side of an
1630
+ // operator assignment.
1631
+ static inline bool
1632
+ pm_call_node_writable_p(pm_call_node_t *node) {
1633
+ return (
1634
+ (node->message_loc.start != NULL) &&
1635
+ (node->message_loc.end[-1] != '!') &&
1636
+ (node->message_loc.end[-1] != '?') &&
1637
+ (node->opening_loc.start == NULL) &&
1638
+ (node->arguments == NULL) &&
1639
+ (node->block == NULL)
1640
+ );
1641
+ }
1642
+
1615
1643
  // Initialize the read name by reading the write name and chopping off the '='.
1616
1644
  static void
1617
1645
  pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
1618
1646
  pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
1619
- if (write_constant->length >= 1) {
1647
+
1648
+ if (write_constant->length > 0) {
1620
1649
  size_t length = write_constant->length - 1;
1621
1650
 
1622
1651
  void *memory = malloc(length);
@@ -1625,7 +1654,7 @@ pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, p
1625
1654
  *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
1626
1655
  } else {
1627
1656
  // We can get here if the message was missing because of a syntax error.
1628
- *read_name = pm_parser_constant_id_static(parser, "", 0);
1657
+ *read_name = pm_parser_constant_id_constant(parser, "", 0);
1629
1658
  }
1630
1659
  }
1631
1660
 
@@ -1648,9 +1677,6 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
1648
1677
  .receiver = target->receiver,
1649
1678
  .call_operator_loc = target->call_operator_loc,
1650
1679
  .message_loc = target->message_loc,
1651
- .opening_loc = target->opening_loc,
1652
- .arguments = target->arguments,
1653
- .closing_loc = target->closing_loc,
1654
1680
  .read_name = 0,
1655
1681
  .write_name = target->name,
1656
1682
  .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
@@ -1667,6 +1693,39 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
1667
1693
  return node;
1668
1694
  }
1669
1695
 
1696
+ // Allocate and initialize a new IndexAndWriteNode node.
1697
+ static pm_index_and_write_node_t *
1698
+ pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
1699
+ assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
1700
+ pm_index_and_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_and_write_node_t);
1701
+
1702
+ *node = (pm_index_and_write_node_t) {
1703
+ {
1704
+ .type = PM_INDEX_AND_WRITE_NODE,
1705
+ .flags = target->base.flags,
1706
+ .location = {
1707
+ .start = target->base.location.start,
1708
+ .end = value->location.end
1709
+ }
1710
+ },
1711
+ .receiver = target->receiver,
1712
+ .call_operator_loc = target->call_operator_loc,
1713
+ .opening_loc = target->opening_loc,
1714
+ .arguments = target->arguments,
1715
+ .closing_loc = target->closing_loc,
1716
+ .block = target->block,
1717
+ .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
1718
+ .value = value
1719
+ };
1720
+
1721
+ // Here we're going to free the target, since it is no longer necessary.
1722
+ // However, we don't want to call `pm_node_destroy` because we want to keep
1723
+ // around all of its children since we just reused them.
1724
+ free(target);
1725
+
1726
+ return node;
1727
+ }
1728
+
1670
1729
  // Allocate a new CallOperatorWriteNode node.
1671
1730
  static pm_call_operator_write_node_t *
1672
1731
  pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
@@ -1685,9 +1744,6 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
1685
1744
  .receiver = target->receiver,
1686
1745
  .call_operator_loc = target->call_operator_loc,
1687
1746
  .message_loc = target->message_loc,
1688
- .opening_loc = target->opening_loc,
1689
- .arguments = target->arguments,
1690
- .closing_loc = target->closing_loc,
1691
1747
  .read_name = 0,
1692
1748
  .write_name = target->name,
1693
1749
  .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
@@ -1705,7 +1761,40 @@ pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target,
1705
1761
  return node;
1706
1762
  }
1707
1763
 
1708
- // Allocate and initialize a new CallOperatorOrWriteNode node.
1764
+ // Allocate a new IndexOperatorWriteNode node.
1765
+ static pm_index_operator_write_node_t *
1766
+ pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
1767
+ pm_index_operator_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_operator_write_node_t);
1768
+
1769
+ *node = (pm_index_operator_write_node_t) {
1770
+ {
1771
+ .type = PM_INDEX_OPERATOR_WRITE_NODE,
1772
+ .flags = target->base.flags,
1773
+ .location = {
1774
+ .start = target->base.location.start,
1775
+ .end = value->location.end
1776
+ }
1777
+ },
1778
+ .receiver = target->receiver,
1779
+ .call_operator_loc = target->call_operator_loc,
1780
+ .opening_loc = target->opening_loc,
1781
+ .arguments = target->arguments,
1782
+ .closing_loc = target->closing_loc,
1783
+ .block = target->block,
1784
+ .operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
1785
+ .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
1786
+ .value = value
1787
+ };
1788
+
1789
+ // Here we're going to free the target, since it is no longer necessary.
1790
+ // However, we don't want to call `pm_node_destroy` because we want to keep
1791
+ // around all of its children since we just reused them.
1792
+ free(target);
1793
+
1794
+ return node;
1795
+ }
1796
+
1797
+ // Allocate and initialize a new CallOrWriteNode node.
1709
1798
  static pm_call_or_write_node_t *
1710
1799
  pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
1711
1800
  assert(target->block == NULL);
@@ -1724,9 +1813,6 @@ pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
1724
1813
  .receiver = target->receiver,
1725
1814
  .call_operator_loc = target->call_operator_loc,
1726
1815
  .message_loc = target->message_loc,
1727
- .opening_loc = target->opening_loc,
1728
- .arguments = target->arguments,
1729
- .closing_loc = target->closing_loc,
1730
1816
  .read_name = 0,
1731
1817
  .write_name = target->name,
1732
1818
  .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
@@ -1743,6 +1829,39 @@ pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
1743
1829
  return node;
1744
1830
  }
1745
1831
 
1832
+ // Allocate and initialize a new IndexOrWriteNode node.
1833
+ static pm_index_or_write_node_t *
1834
+ pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
1835
+ assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
1836
+ pm_index_or_write_node_t *node = PM_ALLOC_NODE(parser, pm_index_or_write_node_t);
1837
+
1838
+ *node = (pm_index_or_write_node_t) {
1839
+ {
1840
+ .type = PM_INDEX_OR_WRITE_NODE,
1841
+ .flags = target->base.flags,
1842
+ .location = {
1843
+ .start = target->base.location.start,
1844
+ .end = value->location.end
1845
+ }
1846
+ },
1847
+ .receiver = target->receiver,
1848
+ .call_operator_loc = target->call_operator_loc,
1849
+ .opening_loc = target->opening_loc,
1850
+ .arguments = target->arguments,
1851
+ .closing_loc = target->closing_loc,
1852
+ .block = target->block,
1853
+ .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
1854
+ .value = value
1855
+ };
1856
+
1857
+ // Here we're going to free the target, since it is no longer necessary.
1858
+ // However, we don't want to call `pm_node_destroy` because we want to keep
1859
+ // around all of its children since we just reused them.
1860
+ free(target);
1861
+
1862
+ return node;
1863
+ }
1864
+
1746
1865
  // Allocate and initialize a new CapturePatternNode node.
1747
1866
  static pm_capture_pattern_node_t *
1748
1867
  pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *target, const pm_token_t *operator) {
@@ -2584,16 +2703,20 @@ pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *assoc
2584
2703
 
2585
2704
  // Retrieve the name from a node that will become a global variable write node.
2586
2705
  static pm_constant_id_t
2587
- pm_global_variable_write_name(pm_parser_t *parser, pm_node_t *target) {
2588
- if (PM_NODE_TYPE_P(target, PM_GLOBAL_VARIABLE_READ_NODE)) {
2589
- return ((pm_global_variable_read_node_t *) target)->name;
2706
+ pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
2707
+ switch (PM_NODE_TYPE(target)) {
2708
+ case PM_GLOBAL_VARIABLE_READ_NODE:
2709
+ return ((pm_global_variable_read_node_t *) target)->name;
2710
+ case PM_BACK_REFERENCE_READ_NODE:
2711
+ return ((pm_back_reference_read_node_t *) target)->name;
2712
+ case PM_NUMBERED_REFERENCE_READ_NODE:
2713
+ // This will only ever happen in the event of a syntax error, but we
2714
+ // still need to provide something for the node.
2715
+ return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
2716
+ default:
2717
+ assert(false && "unreachable");
2718
+ return (pm_constant_id_t) -1;
2590
2719
  }
2591
-
2592
- assert(PM_NODE_TYPE_P(target, PM_BACK_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(target, PM_NUMBERED_REFERENCE_READ_NODE));
2593
-
2594
- // This will only ever happen in the event of a syntax error, but we
2595
- // still need to provide something for the node.
2596
- return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
2597
2720
  }
2598
2721
 
2599
2722
  // Allocate and initialize a new GlobalVariableAndWriteNode node.
@@ -4978,6 +5101,13 @@ pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id) {
4978
5101
  }
4979
5102
  }
4980
5103
 
5104
+ // Add a local variable from a constant string to the current scope.
5105
+ static inline void
5106
+ pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
5107
+ pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
5108
+ if (constant_id != 0) pm_parser_local_add(parser, constant_id);
5109
+ }
5110
+
4981
5111
  // Add a local variable from a location to the current scope.
4982
5112
  static pm_constant_id_t
4983
5113
  pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
@@ -4993,10 +5123,11 @@ pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token) {
4993
5123
  }
4994
5124
 
4995
5125
  // Add a local variable from an owned string to the current scope.
4996
- static inline void
5126
+ static pm_constant_id_t
4997
5127
  pm_parser_local_add_owned(pm_parser_t *parser, const uint8_t *start, size_t length) {
4998
5128
  pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
4999
5129
  if (constant_id != 0) pm_parser_local_add(parser, constant_id);
5130
+ return constant_id;
5000
5131
  }
5001
5132
 
5002
5133
  // Add a parameter name to the current scope and check whether the name of the
@@ -9506,7 +9637,7 @@ parse_target(pm_parser_t *parser, pm_node_t *target) {
9506
9637
  (call->block == NULL)
9507
9638
  ) {
9508
9639
  // Replace the name with "[]=".
9509
- call->name = pm_parser_constant_id_static(parser, "[]=", 3);
9640
+ call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
9510
9641
  return target;
9511
9642
  }
9512
9643
  }
@@ -9673,7 +9804,7 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod
9673
9804
  target->location.end = value->location.end;
9674
9805
 
9675
9806
  // Replace the name with "[]=".
9676
- call->name = pm_parser_constant_id_static(parser, "[]=", 3);
9807
+ call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
9677
9808
  return target;
9678
9809
  }
9679
9810
 
@@ -10294,11 +10425,17 @@ parse_parameters(
10294
10425
  if (!allows_forwarding_parameter) {
10295
10426
  pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
10296
10427
  }
10428
+
10297
10429
  if (order > PM_PARAMETERS_ORDER_NOTHING_AFTER) {
10298
10430
  update_parameter_state(parser, &parser->current, &order);
10299
10431
  parser_lex(parser);
10300
10432
 
10301
- pm_parser_local_add_token(parser, &parser->previous);
10433
+ if (allows_forwarding_parameter) {
10434
+ pm_parser_local_add_constant(parser, "*", 1);
10435
+ pm_parser_local_add_constant(parser, "&", 1);
10436
+ pm_parser_local_add_token(parser, &parser->previous);
10437
+ }
10438
+
10302
10439
  pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
10303
10440
  if (params->keyword_rest != NULL) {
10304
10441
  // If we already have a keyword rest parameter, then we replace it with the
@@ -10313,6 +10450,7 @@ parse_parameters(
10313
10450
  update_parameter_state(parser, &parser->current, &order);
10314
10451
  parser_lex(parser);
10315
10452
  }
10453
+
10316
10454
  break;
10317
10455
  }
10318
10456
  case PM_TOKEN_CLASS_VARIABLE:
@@ -13145,7 +13283,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
13145
13283
  pm_arguments_t arguments = PM_EMPTY_ARGUMENTS;
13146
13284
  parse_arguments_list(parser, &arguments, true);
13147
13285
 
13148
- if (arguments.opening_loc.start == NULL && arguments.arguments == NULL) {
13286
+ if (
13287
+ arguments.opening_loc.start == NULL &&
13288
+ arguments.arguments == NULL &&
13289
+ ((arguments.block == NULL) || PM_NODE_TYPE_P(arguments.block, PM_BLOCK_NODE))
13290
+ ) {
13149
13291
  return (pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
13150
13292
  }
13151
13293
 
@@ -14435,12 +14577,18 @@ parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_
14435
14577
  }
14436
14578
 
14437
14579
  // Ensures a call node that is about to become a call operator node does not
14438
- // have a block attached. If it does, then we'll need to add an error message
14439
- // and destroy the block. Ideally we would keep the node around so that
14440
- // consumers would still have access to it, but we don't have a great structure
14441
- // for that at the moment.
14580
+ // have arguments or a block attached. If it does, then we'll need to add an
14581
+ // error message and destroy the arguments/block. Ideally we would keep the node
14582
+ // around so that consumers would still have access to it, but we don't have a
14583
+ // great structure for that at the moment.
14442
14584
  static void
14443
- parse_call_operator_write_block(pm_parser_t *parser, pm_call_node_t *call_node, const pm_token_t *operator) {
14585
+ parse_call_operator_write(pm_parser_t *parser, pm_call_node_t *call_node, const pm_token_t *operator) {
14586
+ if (call_node->arguments != NULL) {
14587
+ pm_parser_err_token(parser, operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
14588
+ pm_node_destroy(parser, (pm_node_t *) call_node->arguments);
14589
+ call_node->arguments = NULL;
14590
+ }
14591
+
14444
14592
  if (call_node->block != NULL) {
14445
14593
  pm_parser_err_token(parser, operator, PM_ERR_OPERATOR_WRITE_BLOCK);
14446
14594
  pm_node_destroy(parser, (pm_node_t *) call_node->block);
@@ -14553,33 +14701,45 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
14553
14701
  return result;
14554
14702
  }
14555
14703
  case PM_CALL_NODE: {
14704
+ parser_lex(parser);
14705
+ pm_call_node_t *cast = (pm_call_node_t *) node;
14706
+
14556
14707
  // If we have a vcall (a method with no arguments and no
14557
14708
  // receiver that could have been a local variable) then we
14558
14709
  // will transform it into a local variable write.
14559
- if (pm_call_node_variable_call_p((pm_call_node_t *) node)) {
14560
- pm_location_t message_loc = ((pm_call_node_t *) node)->message_loc;
14710
+ if (pm_call_node_variable_call_p(cast)) {
14711
+ pm_location_t message_loc = cast->message_loc;
14561
14712
  pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc.start, message_loc.end);
14562
14713
 
14563
14714
  if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
14564
14715
  pm_parser_err_location(parser, &message_loc, PM_ERR_PARAMETER_NUMBERED_RESERVED);
14565
14716
  }
14566
14717
 
14567
- parser_lex(parser);
14568
14718
  pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
14569
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, constant_id, 0);
14719
+ pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
14570
14720
 
14571
- pm_node_destroy(parser, node);
14721
+ pm_node_destroy(parser, (pm_node_t *) cast);
14572
14722
  return result;
14573
14723
  }
14574
14724
 
14575
- parser_lex(parser);
14576
- node = parse_target(parser, node);
14725
+ // If there is no call operator and the message is "[]" then
14726
+ // this is an aref expression, and we can transform it into
14727
+ // an aset expression.
14728
+ if (pm_call_node_index_p(cast)) {
14729
+ pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
14730
+ return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
14731
+ }
14577
14732
 
14578
- assert(PM_NODE_TYPE_P(node, PM_CALL_NODE));
14579
- parse_call_operator_write_block(parser, (pm_call_node_t *) node, &token);
14733
+ // If this node cannot be writable, then we have an error.
14734
+ if (pm_call_node_writable_p(cast)) {
14735
+ parse_write_name(parser, &cast->name);
14736
+ } else {
14737
+ pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
14738
+ }
14580
14739
 
14740
+ parse_call_operator_write(parser, cast, &token);
14581
14741
  pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
14582
- return (pm_node_t *) pm_call_and_write_node_create(parser, (pm_call_node_t *) node, &token, value);
14742
+ return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
14583
14743
  }
14584
14744
  case PM_MULTI_WRITE_NODE: {
14585
14745
  parser_lex(parser);
@@ -14655,33 +14815,45 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
14655
14815
  return result;
14656
14816
  }
14657
14817
  case PM_CALL_NODE: {
14818
+ parser_lex(parser);
14819
+ pm_call_node_t *cast = (pm_call_node_t *) node;
14820
+
14658
14821
  // If we have a vcall (a method with no arguments and no
14659
14822
  // receiver that could have been a local variable) then we
14660
14823
  // will transform it into a local variable write.
14661
- if (pm_call_node_variable_call_p((pm_call_node_t *) node)) {
14662
- pm_location_t message_loc = ((pm_call_node_t *) node)->message_loc;
14824
+ if (pm_call_node_variable_call_p(cast)) {
14825
+ pm_location_t message_loc = cast->message_loc;
14663
14826
  pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc.start, message_loc.end);
14664
14827
 
14665
14828
  if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
14666
14829
  pm_parser_err_location(parser, &message_loc, PM_ERR_PARAMETER_NUMBERED_RESERVED);
14667
14830
  }
14668
14831
 
14669
- parser_lex(parser);
14670
14832
  pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
14671
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, constant_id, 0);
14833
+ pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
14672
14834
 
14673
- pm_node_destroy(parser, node);
14835
+ pm_node_destroy(parser, (pm_node_t *) cast);
14674
14836
  return result;
14675
14837
  }
14676
14838
 
14677
- parser_lex(parser);
14678
- node = parse_target(parser, node);
14839
+ // If there is no call operator and the message is "[]" then
14840
+ // this is an aref expression, and we can transform it into
14841
+ // an aset expression.
14842
+ if (pm_call_node_index_p(cast)) {
14843
+ pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
14844
+ return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
14845
+ }
14679
14846
 
14680
- assert(PM_NODE_TYPE_P(node, PM_CALL_NODE));
14681
- parse_call_operator_write_block(parser, (pm_call_node_t *) node, &token);
14847
+ // If this node cannot be writable, then we have an error.
14848
+ if (pm_call_node_writable_p(cast)) {
14849
+ parse_write_name(parser, &cast->name);
14850
+ } else {
14851
+ pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
14852
+ }
14682
14853
 
14854
+ parse_call_operator_write(parser, cast, &token);
14683
14855
  pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
14684
- return (pm_node_t *) pm_call_or_write_node_create(parser, (pm_call_node_t *) node, &token, value);
14856
+ return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
14685
14857
  }
14686
14858
  case PM_MULTI_WRITE_NODE: {
14687
14859
  parser_lex(parser);
@@ -14767,33 +14939,45 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
14767
14939
  return result;
14768
14940
  }
14769
14941
  case PM_CALL_NODE: {
14942
+ parser_lex(parser);
14943
+ pm_call_node_t *cast = (pm_call_node_t *) node;
14944
+
14770
14945
  // If we have a vcall (a method with no arguments and no
14771
14946
  // receiver that could have been a local variable) then we
14772
14947
  // will transform it into a local variable write.
14773
- if (pm_call_node_variable_call_p((pm_call_node_t *) node)) {
14774
- pm_location_t message_loc = ((pm_call_node_t *) node)->message_loc;
14948
+ if (pm_call_node_variable_call_p(cast)) {
14949
+ pm_location_t message_loc = cast->message_loc;
14775
14950
  pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc.start, message_loc.end);
14776
14951
 
14777
14952
  if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
14778
14953
  pm_parser_err_location(parser, &message_loc, PM_ERR_PARAMETER_NUMBERED_RESERVED);
14779
14954
  }
14780
14955
 
14781
- parser_lex(parser);
14782
14956
  pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
14783
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, constant_id, 0);
14957
+ pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
14784
14958
 
14785
- pm_node_destroy(parser, node);
14959
+ pm_node_destroy(parser, (pm_node_t *) cast);
14786
14960
  return result;
14787
14961
  }
14788
14962
 
14789
- parser_lex(parser);
14790
- node = parse_target(parser, node);
14963
+ // If there is no call operator and the message is "[]" then
14964
+ // this is an aref expression, and we can transform it into
14965
+ // an aset expression.
14966
+ if (pm_call_node_index_p(cast)) {
14967
+ pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
14968
+ return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
14969
+ }
14791
14970
 
14792
- assert(PM_NODE_TYPE_P(node, PM_CALL_NODE));
14793
- parse_call_operator_write_block(parser, (pm_call_node_t *) node, &token);
14971
+ // If this node cannot be writable, then we have an error.
14972
+ if (pm_call_node_writable_p(cast)) {
14973
+ parse_write_name(parser, &cast->name);
14974
+ } else {
14975
+ pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
14976
+ }
14794
14977
 
14978
+ parse_call_operator_write(parser, cast, &token);
14795
14979
  pm_node_t *value = parse_expression(parser, binding_power, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR);
14796
- return (pm_node_t *) pm_call_operator_write_node_create(parser, (pm_call_node_t *) node, &token, value);
14980
+ return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
14797
14981
  }
14798
14982
  case PM_MULTI_WRITE_NODE: {
14799
14983
  parser_lex(parser);
@@ -14846,15 +15030,31 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
14846
15030
  pm_string_list_t named_captures;
14847
15031
  pm_string_list_init(&named_captures);
14848
15032
 
14849
- const pm_location_t *content_loc = &((pm_regular_expression_node_t *) node)->content_loc;
14850
- if (pm_regexp_named_capture_group_names(content_loc->start, (size_t) (content_loc->end - content_loc->start), &named_captures, parser->encoding_changed, &parser->encoding) && (named_captures.length > 0)) {
15033
+ const pm_string_t *unescaped = &((pm_regular_expression_node_t *) node)->unescaped;
15034
+ if (pm_regexp_named_capture_group_names(pm_string_source(unescaped), pm_string_length(unescaped), &named_captures, parser->encoding_changed, &parser->encoding) && (named_captures.length > 0)) {
14851
15035
  pm_match_write_node_t *match = pm_match_write_node_create(parser, call);
14852
15036
 
14853
15037
  for (size_t index = 0; index < named_captures.length; index++) {
14854
15038
  pm_string_t *name = &named_captures.strings[index];
14855
- assert(name->type == PM_STRING_SHARED);
15039
+ pm_constant_id_t local;
15040
+
15041
+ if (unescaped->type == PM_STRING_SHARED) {
15042
+ // If the unescaped string is a slice of the source,
15043
+ // then we can copy the names directly. The pointers
15044
+ // will line up.
15045
+ local = pm_parser_local_add_location(parser, name->source, name->source + name->length);
15046
+ } else {
15047
+ // Otherwise, the name is a slice of the malloc-ed
15048
+ // owned string, in which case we need to copy it
15049
+ // out into a new string.
15050
+ size_t length = pm_string_length(name);
15051
+
15052
+ void *memory = malloc(length);
15053
+ memcpy(memory, pm_string_source(name), length);
15054
+
15055
+ local = pm_parser_local_add_owned(parser, (const uint8_t *) memory, length);
15056
+ }
14856
15057
 
14857
- pm_constant_id_t local = pm_parser_local_add_location(parser, name->source, name->source + name->length);
14858
15058
  pm_constant_id_list_append(&match->locals, local);
14859
15059
  }
14860
15060