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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/README.md +1 -1
- data/config.yml +86 -21
- data/ext/prism/api_node.c +213 -67
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +133 -83
- data/include/prism/diagnostic.h +1 -0
- data/include/prism/node.h +7 -0
- data/include/prism/util/pm_constant_pool.h +20 -6
- data/include/prism/version.h +2 -2
- data/include/prism.h +1 -1
- data/lib/prism/compiler.rb +9 -0
- data/lib/prism/debug.rb +30 -26
- data/lib/prism/dispatcher.rb +42 -0
- data/lib/prism/dsl.rb +23 -8
- data/lib/prism/ffi.rb +2 -2
- data/lib/prism/lex_compat.rb +9 -9
- data/lib/prism/mutation_compiler.rb +18 -3
- data/lib/prism/node.rb +580 -120
- data/lib/prism/serialize.rb +83 -77
- data/lib/prism/visitor.rb +9 -0
- data/prism.gemspec +1 -1
- data/src/diagnostic.c +1 -0
- data/src/node.c +99 -18
- data/src/prettyprint.c +102 -45
- data/src/prism.c +288 -88
- data/src/serialize.c +95 -57
- data/src/util/pm_constant_pool.c +25 -11
- metadata +2 -2
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
|
-
|
500
|
-
uint8_t *
|
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->
|
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 =
|
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 =
|
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 =
|
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 =
|
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
|
-
|
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 =
|
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
|
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
|
-
|
2589
|
-
|
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
|
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 =
|
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 =
|
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
|
-
|
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 (
|
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
|
14439
|
-
// and destroy the block. Ideally we would keep the node
|
14440
|
-
// consumers would still have access to it, but we don't have a
|
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
|
-
|
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(
|
14560
|
-
pm_location_t 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,
|
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,
|
14721
|
+
pm_node_destroy(parser, (pm_node_t *) cast);
|
14572
14722
|
return result;
|
14573
14723
|
}
|
14574
14724
|
|
14575
|
-
|
14576
|
-
|
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
|
-
|
14579
|
-
|
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,
|
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(
|
14662
|
-
pm_location_t 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,
|
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,
|
14835
|
+
pm_node_destroy(parser, (pm_node_t *) cast);
|
14674
14836
|
return result;
|
14675
14837
|
}
|
14676
14838
|
|
14677
|
-
|
14678
|
-
|
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
|
-
|
14681
|
-
|
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,
|
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(
|
14774
|
-
pm_location_t 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,
|
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,
|
14959
|
+
pm_node_destroy(parser, (pm_node_t *) cast);
|
14786
14960
|
return result;
|
14787
14961
|
}
|
14788
14962
|
|
14789
|
-
|
14790
|
-
|
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
|
-
|
14793
|
-
|
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,
|
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
|
14850
|
-
if (pm_regexp_named_capture_group_names(
|
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
|
-
|
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
|
|