prism 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/src/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