prism 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|