yarp 0.8.0 → 0.9.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 +34 -1
- data/README.md +4 -3
- data/config.yml +332 -52
- data/docs/configuration.md +1 -0
- data/docs/ruby_api.md +2 -0
- data/docs/serialization.md +1 -1
- data/docs/testing.md +2 -2
- data/ext/yarp/api_node.c +703 -136
- data/ext/yarp/extension.c +73 -24
- data/ext/yarp/extension.h +2 -2
- data/include/yarp/ast.h +331 -137
- data/include/yarp/node.h +10 -0
- data/include/yarp/unescape.h +4 -2
- data/include/yarp/util/yp_newline_list.h +3 -0
- data/include/yarp/version.h +2 -2
- data/include/yarp.h +10 -0
- data/lib/yarp/desugar_visitor.rb +267 -0
- data/lib/yarp/ffi.rb +27 -1
- data/lib/yarp/lex_compat.rb +93 -25
- data/lib/yarp/mutation_visitor.rb +683 -0
- data/lib/yarp/node.rb +3042 -508
- data/lib/yarp/serialize.rb +198 -126
- data/lib/yarp.rb +48 -2
- data/src/node.c +421 -185
- data/src/prettyprint.c +262 -80
- data/src/serialize.c +410 -270
- data/src/token_type.c +2 -2
- data/src/unescape.c +69 -51
- data/src/util/yp_newline_list.c +10 -0
- data/src/yarp.c +1208 -458
- data/yarp.gemspec +3 -1
- metadata +4 -2
data/src/yarp.c
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#include "yarp.h"
|
2
|
-
#include "yarp/version.h"
|
3
2
|
|
4
3
|
// The YARP version and the serialization format.
|
5
4
|
const char *
|
@@ -362,7 +361,7 @@ lex_state_ignored_p(yp_parser_t *parser) {
|
|
362
361
|
|
363
362
|
if (ignored) {
|
364
363
|
return YP_IGNORED_NEWLINE_ALL;
|
365
|
-
} else if (parser->lex_state == (YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED)) {
|
364
|
+
} else if ((parser->lex_state & ~((unsigned int) YP_LEX_STATE_LABEL)) == (YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED)) {
|
366
365
|
return YP_IGNORED_NEWLINE_PATTERN;
|
367
366
|
} else {
|
368
367
|
return YP_IGNORED_NEWLINE_NONE;
|
@@ -536,6 +535,73 @@ yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) {
|
|
536
535
|
}
|
537
536
|
}
|
538
537
|
|
538
|
+
/******************************************************************************/
|
539
|
+
/* Scope node functions */
|
540
|
+
/******************************************************************************/
|
541
|
+
|
542
|
+
// Generate a scope node from the given node.
|
543
|
+
void
|
544
|
+
yp_scope_node_init(yp_node_t *node, yp_scope_node_t *scope) {
|
545
|
+
scope->base.type = YP_NODE_SCOPE_NODE;
|
546
|
+
scope->base.location.start = node->location.start;
|
547
|
+
scope->base.location.end = node->location.end;
|
548
|
+
|
549
|
+
scope->parameters = NULL;
|
550
|
+
scope->body = NULL;
|
551
|
+
yp_constant_id_list_init(&scope->locals);
|
552
|
+
|
553
|
+
switch (YP_NODE_TYPE(node)) {
|
554
|
+
case YP_NODE_BLOCK_NODE: {
|
555
|
+
yp_block_node_t *cast = (yp_block_node_t *) node;
|
556
|
+
if (cast->parameters) scope->parameters = cast->parameters->parameters;
|
557
|
+
scope->body = cast->body;
|
558
|
+
scope->locals = cast->locals;
|
559
|
+
break;
|
560
|
+
}
|
561
|
+
case YP_NODE_CLASS_NODE: {
|
562
|
+
yp_class_node_t *cast = (yp_class_node_t *) node;
|
563
|
+
scope->body = cast->body;
|
564
|
+
scope->locals = cast->locals;
|
565
|
+
break;
|
566
|
+
}
|
567
|
+
case YP_NODE_DEF_NODE: {
|
568
|
+
yp_def_node_t *cast = (yp_def_node_t *) node;
|
569
|
+
scope->parameters = cast->parameters;
|
570
|
+
scope->body = cast->body;
|
571
|
+
scope->locals = cast->locals;
|
572
|
+
break;
|
573
|
+
}
|
574
|
+
case YP_NODE_LAMBDA_NODE: {
|
575
|
+
yp_lambda_node_t *cast = (yp_lambda_node_t *) node;
|
576
|
+
if (cast->parameters) scope->parameters = cast->parameters->parameters;
|
577
|
+
scope->body = cast->body;
|
578
|
+
scope->locals = cast->locals;
|
579
|
+
break;
|
580
|
+
}
|
581
|
+
case YP_NODE_MODULE_NODE: {
|
582
|
+
yp_module_node_t *cast = (yp_module_node_t *) node;
|
583
|
+
scope->body = cast->body;
|
584
|
+
scope->locals = cast->locals;
|
585
|
+
break;
|
586
|
+
}
|
587
|
+
case YP_NODE_PROGRAM_NODE: {
|
588
|
+
yp_program_node_t *cast = (yp_program_node_t *) node;
|
589
|
+
scope->body = (yp_node_t *) cast->statements;
|
590
|
+
scope->locals = cast->locals;
|
591
|
+
break;
|
592
|
+
}
|
593
|
+
case YP_NODE_SINGLETON_CLASS_NODE: {
|
594
|
+
yp_singleton_class_node_t *cast = (yp_singleton_class_node_t *) node;
|
595
|
+
scope->body = cast->body;
|
596
|
+
scope->locals = cast->locals;
|
597
|
+
break;
|
598
|
+
}
|
599
|
+
default:
|
600
|
+
assert(false && "unreachable");
|
601
|
+
break;
|
602
|
+
}
|
603
|
+
}
|
604
|
+
|
539
605
|
/******************************************************************************/
|
540
606
|
/* Node creation functions */
|
541
607
|
/******************************************************************************/
|
@@ -658,27 +724,6 @@ yp_and_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *opera
|
|
658
724
|
return node;
|
659
725
|
}
|
660
726
|
|
661
|
-
// Allocate and initialize a new AndWriteNode.
|
662
|
-
static yp_and_write_node_t *
|
663
|
-
yp_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
664
|
-
yp_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_and_write_node_t);
|
665
|
-
|
666
|
-
*node = (yp_and_write_node_t) {
|
667
|
-
{
|
668
|
-
.type = YP_NODE_AND_WRITE_NODE,
|
669
|
-
.location = {
|
670
|
-
.start = target->location.start,
|
671
|
-
.end = value->location.end
|
672
|
-
},
|
673
|
-
},
|
674
|
-
.target = target,
|
675
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
676
|
-
.value = value
|
677
|
-
};
|
678
|
-
|
679
|
-
return node;
|
680
|
-
}
|
681
|
-
|
682
727
|
// Allocate an initialize a new arguments node.
|
683
728
|
static yp_arguments_node_t *
|
684
729
|
yp_arguments_node_create(yp_parser_t *parser) {
|
@@ -1151,7 +1196,7 @@ yp_call_node_create(yp_parser_t *parser) {
|
|
1151
1196
|
},
|
1152
1197
|
.receiver = NULL,
|
1153
1198
|
.operator_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1154
|
-
.message_loc =
|
1199
|
+
.message_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1155
1200
|
.opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1156
1201
|
.arguments = NULL,
|
1157
1202
|
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
@@ -1486,7 +1531,7 @@ yp_case_node_end_keyword_loc_set(yp_case_node_t *node, const yp_token_t *end_key
|
|
1486
1531
|
|
1487
1532
|
// Allocate a new ClassNode node.
|
1488
1533
|
static yp_class_node_t *
|
1489
|
-
yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, yp_node_t *constant_path, const yp_token_t *inheritance_operator, yp_node_t *superclass, yp_node_t *body, const yp_token_t *end_keyword) {
|
1534
|
+
yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, yp_node_t *constant_path, const yp_token_t *name, const yp_token_t *inheritance_operator, yp_node_t *superclass, yp_node_t *body, const yp_token_t *end_keyword) {
|
1490
1535
|
yp_class_node_t *node = YP_ALLOC_NODE(parser, yp_class_node_t);
|
1491
1536
|
|
1492
1537
|
*node = (yp_class_node_t) {
|
@@ -1500,7 +1545,77 @@ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y
|
|
1500
1545
|
.inheritance_operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
|
1501
1546
|
.superclass = superclass,
|
1502
1547
|
.body = body,
|
1503
|
-
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
1548
|
+
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword),
|
1549
|
+
.name = YP_EMPTY_STRING
|
1550
|
+
};
|
1551
|
+
|
1552
|
+
yp_string_shared_init(&node->name, name->start, name->end);
|
1553
|
+
return node;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
// Allocate and initialize a new ClassVariableAndWriteNode node.
|
1557
|
+
static yp_class_variable_and_write_node_t *
|
1558
|
+
yp_class_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1559
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_CLASS_VARIABLE_READ_NODE));
|
1560
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1561
|
+
yp_class_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_and_write_node_t);
|
1562
|
+
|
1563
|
+
*node = (yp_class_variable_and_write_node_t) {
|
1564
|
+
{
|
1565
|
+
.type = YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE,
|
1566
|
+
.location = {
|
1567
|
+
.start = target->location.start,
|
1568
|
+
.end = value->location.end
|
1569
|
+
}
|
1570
|
+
},
|
1571
|
+
.name_loc = target->location,
|
1572
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1573
|
+
.value = value
|
1574
|
+
};
|
1575
|
+
|
1576
|
+
return node;
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
// Allocate and initialize a new ClassVariableOperatorWriteNode node.
|
1580
|
+
static yp_class_variable_operator_write_node_t *
|
1581
|
+
yp_class_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1582
|
+
yp_class_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_operator_write_node_t);
|
1583
|
+
|
1584
|
+
*node = (yp_class_variable_operator_write_node_t) {
|
1585
|
+
{
|
1586
|
+
.type = YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
|
1587
|
+
.location = {
|
1588
|
+
.start = target->location.start,
|
1589
|
+
.end = value->location.end
|
1590
|
+
}
|
1591
|
+
},
|
1592
|
+
.name_loc = target->location,
|
1593
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1594
|
+
.value = value,
|
1595
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1596
|
+
};
|
1597
|
+
|
1598
|
+
return node;
|
1599
|
+
}
|
1600
|
+
|
1601
|
+
// Allocate and initialize a new ClassVariableOrWriteNode node.
|
1602
|
+
static yp_class_variable_or_write_node_t *
|
1603
|
+
yp_class_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1604
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_CLASS_VARIABLE_READ_NODE));
|
1605
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1606
|
+
yp_class_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_or_write_node_t);
|
1607
|
+
|
1608
|
+
*node = (yp_class_variable_or_write_node_t) {
|
1609
|
+
{
|
1610
|
+
.type = YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE,
|
1611
|
+
.location = {
|
1612
|
+
.start = target->location.start,
|
1613
|
+
.end = value->location.end
|
1614
|
+
}
|
1615
|
+
},
|
1616
|
+
.name_loc = target->location,
|
1617
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1618
|
+
.value = value
|
1504
1619
|
};
|
1505
1620
|
|
1506
1621
|
return node;
|
@@ -1525,10 +1640,10 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
|
|
1525
1640
|
.type = YP_NODE_CLASS_VARIABLE_WRITE_NODE,
|
1526
1641
|
.location = {
|
1527
1642
|
.start = read_node->base.location.start,
|
1528
|
-
.end = value
|
1643
|
+
.end = value->location.end
|
1529
1644
|
},
|
1530
1645
|
},
|
1531
|
-
.name_loc = YP_LOCATION_NODE_VALUE((yp_node_t *)read_node),
|
1646
|
+
.name_loc = YP_LOCATION_NODE_VALUE((yp_node_t *) read_node),
|
1532
1647
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
1533
1648
|
.value = value
|
1534
1649
|
};
|
@@ -1536,6 +1651,72 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
|
|
1536
1651
|
return node;
|
1537
1652
|
}
|
1538
1653
|
|
1654
|
+
// Allocate and initialize a new ConstantPathAndWriteNode node.
|
1655
|
+
static yp_constant_path_and_write_node_t *
|
1656
|
+
yp_constant_path_and_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1657
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1658
|
+
yp_constant_path_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_and_write_node_t);
|
1659
|
+
|
1660
|
+
*node = (yp_constant_path_and_write_node_t) {
|
1661
|
+
{
|
1662
|
+
.type = YP_NODE_CONSTANT_PATH_AND_WRITE_NODE,
|
1663
|
+
.location = {
|
1664
|
+
.start = target->base.location.start,
|
1665
|
+
.end = value->location.end
|
1666
|
+
}
|
1667
|
+
},
|
1668
|
+
.target = target,
|
1669
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1670
|
+
.value = value
|
1671
|
+
};
|
1672
|
+
|
1673
|
+
return node;
|
1674
|
+
}
|
1675
|
+
|
1676
|
+
// Allocate and initialize a new ConstantPathOperatorWriteNode node.
|
1677
|
+
static yp_constant_path_operator_write_node_t *
|
1678
|
+
yp_constant_path_operator_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1679
|
+
yp_constant_path_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_operator_write_node_t);
|
1680
|
+
|
1681
|
+
*node = (yp_constant_path_operator_write_node_t) {
|
1682
|
+
{
|
1683
|
+
.type = YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE,
|
1684
|
+
.location = {
|
1685
|
+
.start = target->base.location.start,
|
1686
|
+
.end = value->location.end
|
1687
|
+
}
|
1688
|
+
},
|
1689
|
+
.target = target,
|
1690
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1691
|
+
.value = value,
|
1692
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1693
|
+
};
|
1694
|
+
|
1695
|
+
return node;
|
1696
|
+
}
|
1697
|
+
|
1698
|
+
// Allocate and initialize a new ConstantPathOrWriteNode node.
|
1699
|
+
static yp_constant_path_or_write_node_t *
|
1700
|
+
yp_constant_path_or_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1701
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1702
|
+
yp_constant_path_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_or_write_node_t);
|
1703
|
+
|
1704
|
+
*node = (yp_constant_path_or_write_node_t) {
|
1705
|
+
{
|
1706
|
+
.type = YP_NODE_CONSTANT_PATH_OR_WRITE_NODE,
|
1707
|
+
.location = {
|
1708
|
+
.start = target->base.location.start,
|
1709
|
+
.end = value->location.end
|
1710
|
+
}
|
1711
|
+
},
|
1712
|
+
.target = target,
|
1713
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1714
|
+
.value = value
|
1715
|
+
};
|
1716
|
+
|
1717
|
+
return node;
|
1718
|
+
}
|
1719
|
+
|
1539
1720
|
// Allocate and initialize a new ConstantPathNode node.
|
1540
1721
|
static yp_constant_path_node_t *
|
1541
1722
|
yp_constant_path_node_create(yp_parser_t *parser, yp_node_t *parent, const yp_token_t *delimiter, yp_node_t *child) {
|
@@ -1567,7 +1748,7 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
|
|
1567
1748
|
.type = YP_NODE_CONSTANT_PATH_WRITE_NODE,
|
1568
1749
|
.location = {
|
1569
1750
|
.start = target->base.location.start,
|
1570
|
-
.end =
|
1751
|
+
.end = value->location.end
|
1571
1752
|
},
|
1572
1753
|
},
|
1573
1754
|
.target = target,
|
@@ -1578,6 +1759,74 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
|
|
1578
1759
|
return node;
|
1579
1760
|
}
|
1580
1761
|
|
1762
|
+
// Allocate and initialize a new ConstantAndWriteNode node.
|
1763
|
+
static yp_constant_and_write_node_t *
|
1764
|
+
yp_constant_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1765
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
|
1766
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1767
|
+
yp_constant_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_and_write_node_t);
|
1768
|
+
|
1769
|
+
*node = (yp_constant_and_write_node_t) {
|
1770
|
+
{
|
1771
|
+
.type = YP_NODE_CONSTANT_AND_WRITE_NODE,
|
1772
|
+
.location = {
|
1773
|
+
.start = target->location.start,
|
1774
|
+
.end = value->location.end
|
1775
|
+
}
|
1776
|
+
},
|
1777
|
+
.name_loc = target->location,
|
1778
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1779
|
+
.value = value
|
1780
|
+
};
|
1781
|
+
|
1782
|
+
return node;
|
1783
|
+
}
|
1784
|
+
|
1785
|
+
// Allocate and initialize a new ConstantOperatorWriteNode node.
|
1786
|
+
static yp_constant_operator_write_node_t *
|
1787
|
+
yp_constant_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1788
|
+
yp_constant_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_operator_write_node_t);
|
1789
|
+
|
1790
|
+
*node = (yp_constant_operator_write_node_t) {
|
1791
|
+
{
|
1792
|
+
.type = YP_NODE_CONSTANT_OPERATOR_WRITE_NODE,
|
1793
|
+
.location = {
|
1794
|
+
.start = target->location.start,
|
1795
|
+
.end = value->location.end
|
1796
|
+
}
|
1797
|
+
},
|
1798
|
+
.name_loc = target->location,
|
1799
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1800
|
+
.value = value,
|
1801
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1802
|
+
};
|
1803
|
+
|
1804
|
+
return node;
|
1805
|
+
}
|
1806
|
+
|
1807
|
+
// Allocate and initialize a new ConstantOrWriteNode node.
|
1808
|
+
static yp_constant_or_write_node_t *
|
1809
|
+
yp_constant_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1810
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
|
1811
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1812
|
+
yp_constant_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_or_write_node_t);
|
1813
|
+
|
1814
|
+
*node = (yp_constant_or_write_node_t) {
|
1815
|
+
{
|
1816
|
+
.type = YP_NODE_CONSTANT_OR_WRITE_NODE,
|
1817
|
+
.location = {
|
1818
|
+
.start = target->location.start,
|
1819
|
+
.end = value->location.end
|
1820
|
+
}
|
1821
|
+
},
|
1822
|
+
.name_loc = target->location,
|
1823
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1824
|
+
.value = value
|
1825
|
+
};
|
1826
|
+
|
1827
|
+
return node;
|
1828
|
+
}
|
1829
|
+
|
1581
1830
|
// Allocate and initialize a new ConstantReadNode node.
|
1582
1831
|
static yp_constant_read_node_t *
|
1583
1832
|
yp_constant_read_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
@@ -1598,7 +1847,7 @@ yp_constant_write_node_create(yp_parser_t *parser, yp_location_t *name_loc, cons
|
|
1598
1847
|
.type = YP_NODE_CONSTANT_WRITE_NODE,
|
1599
1848
|
.location = {
|
1600
1849
|
.start = name_loc->start,
|
1601
|
-
.end = value
|
1850
|
+
.end = value->location.end
|
1602
1851
|
},
|
1603
1852
|
},
|
1604
1853
|
.name_loc = *name_loc,
|
@@ -2012,6 +2261,74 @@ yp_hash_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *assoc
|
|
2012
2261
|
return node;
|
2013
2262
|
}
|
2014
2263
|
|
2264
|
+
// Allocate and initialize a new GlobalVariableAndWriteNode node.
|
2265
|
+
static yp_global_variable_and_write_node_t *
|
2266
|
+
yp_global_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2267
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE));
|
2268
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2269
|
+
yp_global_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_and_write_node_t);
|
2270
|
+
|
2271
|
+
*node = (yp_global_variable_and_write_node_t) {
|
2272
|
+
{
|
2273
|
+
.type = YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE,
|
2274
|
+
.location = {
|
2275
|
+
.start = target->location.start,
|
2276
|
+
.end = value->location.end
|
2277
|
+
}
|
2278
|
+
},
|
2279
|
+
.name_loc = target->location,
|
2280
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2281
|
+
.value = value
|
2282
|
+
};
|
2283
|
+
|
2284
|
+
return node;
|
2285
|
+
}
|
2286
|
+
|
2287
|
+
// Allocate and initialize a new GlobalVariableOperatorWriteNode node.
|
2288
|
+
static yp_global_variable_operator_write_node_t *
|
2289
|
+
yp_global_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2290
|
+
yp_global_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_operator_write_node_t);
|
2291
|
+
|
2292
|
+
*node = (yp_global_variable_operator_write_node_t) {
|
2293
|
+
{
|
2294
|
+
.type = YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
|
2295
|
+
.location = {
|
2296
|
+
.start = target->location.start,
|
2297
|
+
.end = value->location.end
|
2298
|
+
}
|
2299
|
+
},
|
2300
|
+
.name_loc = target->location,
|
2301
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2302
|
+
.value = value,
|
2303
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
2304
|
+
};
|
2305
|
+
|
2306
|
+
return node;
|
2307
|
+
}
|
2308
|
+
|
2309
|
+
// Allocate and initialize a new GlobalVariableOrWriteNode node.
|
2310
|
+
static yp_global_variable_or_write_node_t *
|
2311
|
+
yp_global_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2312
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE));
|
2313
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2314
|
+
yp_global_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_or_write_node_t);
|
2315
|
+
|
2316
|
+
*node = (yp_global_variable_or_write_node_t) {
|
2317
|
+
{
|
2318
|
+
.type = YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE,
|
2319
|
+
.location = {
|
2320
|
+
.start = target->location.start,
|
2321
|
+
.end = value->location.end
|
2322
|
+
}
|
2323
|
+
},
|
2324
|
+
.name_loc = target->location,
|
2325
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2326
|
+
.value = value
|
2327
|
+
};
|
2328
|
+
|
2329
|
+
return node;
|
2330
|
+
}
|
2331
|
+
|
2015
2332
|
// Allocate a new GlobalVariableReadNode node.
|
2016
2333
|
static yp_global_variable_read_node_t *
|
2017
2334
|
yp_global_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
@@ -2037,7 +2354,7 @@ yp_global_variable_write_node_create(yp_parser_t *parser, const yp_location_t *n
|
|
2037
2354
|
.type = YP_NODE_GLOBAL_VARIABLE_WRITE_NODE,
|
2038
2355
|
.location = {
|
2039
2356
|
.start = name_loc->start,
|
2040
|
-
.end =
|
2357
|
+
.end = value->location.end
|
2041
2358
|
},
|
2042
2359
|
},
|
2043
2360
|
.name_loc = *name_loc,
|
@@ -2302,6 +2619,74 @@ yp_in_node_create(yp_parser_t *parser, yp_node_t *pattern, yp_statements_node_t
|
|
2302
2619
|
return node;
|
2303
2620
|
}
|
2304
2621
|
|
2622
|
+
// Allocate and initialize a new InstanceVariableAndWriteNode node.
|
2623
|
+
static yp_instance_variable_and_write_node_t *
|
2624
|
+
yp_instance_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2625
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_INSTANCE_VARIABLE_READ_NODE));
|
2626
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2627
|
+
yp_instance_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_and_write_node_t);
|
2628
|
+
|
2629
|
+
*node = (yp_instance_variable_and_write_node_t) {
|
2630
|
+
{
|
2631
|
+
.type = YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE,
|
2632
|
+
.location = {
|
2633
|
+
.start = target->location.start,
|
2634
|
+
.end = value->location.end
|
2635
|
+
}
|
2636
|
+
},
|
2637
|
+
.name_loc = target->location,
|
2638
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2639
|
+
.value = value
|
2640
|
+
};
|
2641
|
+
|
2642
|
+
return node;
|
2643
|
+
}
|
2644
|
+
|
2645
|
+
// Allocate and initialize a new InstanceVariableOperatorWriteNode node.
|
2646
|
+
static yp_instance_variable_operator_write_node_t *
|
2647
|
+
yp_instance_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2648
|
+
yp_instance_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_operator_write_node_t);
|
2649
|
+
|
2650
|
+
*node = (yp_instance_variable_operator_write_node_t) {
|
2651
|
+
{
|
2652
|
+
.type = YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
|
2653
|
+
.location = {
|
2654
|
+
.start = target->location.start,
|
2655
|
+
.end = value->location.end
|
2656
|
+
}
|
2657
|
+
},
|
2658
|
+
.name_loc = target->location,
|
2659
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2660
|
+
.value = value,
|
2661
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
2662
|
+
};
|
2663
|
+
|
2664
|
+
return node;
|
2665
|
+
}
|
2666
|
+
|
2667
|
+
// Allocate and initialize a new InstanceVariableOrWriteNode node.
|
2668
|
+
static yp_instance_variable_or_write_node_t *
|
2669
|
+
yp_instance_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2670
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_INSTANCE_VARIABLE_READ_NODE));
|
2671
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2672
|
+
yp_instance_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_or_write_node_t);
|
2673
|
+
|
2674
|
+
*node = (yp_instance_variable_or_write_node_t) {
|
2675
|
+
{
|
2676
|
+
.type = YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE,
|
2677
|
+
.location = {
|
2678
|
+
.start = target->location.start,
|
2679
|
+
.end = value->location.end
|
2680
|
+
}
|
2681
|
+
},
|
2682
|
+
.name_loc = target->location,
|
2683
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2684
|
+
.value = value
|
2685
|
+
};
|
2686
|
+
|
2687
|
+
return node;
|
2688
|
+
}
|
2689
|
+
|
2305
2690
|
// Allocate and initialize a new InstanceVariableReadNode node.
|
2306
2691
|
static yp_instance_variable_read_node_t *
|
2307
2692
|
yp_instance_variable_read_node_create(yp_parser_t *parser, const yp_token_t *token) {
|
@@ -2324,7 +2709,7 @@ yp_instance_variable_write_node_create(yp_parser_t *parser, yp_instance_variable
|
|
2324
2709
|
.type = YP_NODE_INSTANCE_VARIABLE_WRITE_NODE,
|
2325
2710
|
.location = {
|
2326
2711
|
.start = read_node->base.location.start,
|
2327
|
-
.end = value
|
2712
|
+
.end = value->location.end
|
2328
2713
|
}
|
2329
2714
|
},
|
2330
2715
|
.name_loc = YP_LOCATION_NODE_BASE_VALUE(read_node),
|
@@ -2438,12 +2823,6 @@ yp_interpolated_symbol_node_append(yp_interpolated_symbol_node_t *node, yp_node_
|
|
2438
2823
|
node->base.location.end = part->location.end;
|
2439
2824
|
}
|
2440
2825
|
|
2441
|
-
static inline void
|
2442
|
-
yp_interpolated_symbol_node_closing_set(yp_interpolated_symbol_node_t *node, const yp_token_t *closing) {
|
2443
|
-
node->closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
|
2444
|
-
node->base.location.end = closing->end;
|
2445
|
-
}
|
2446
|
-
|
2447
2826
|
// Allocate a new InterpolatedXStringNode node.
|
2448
2827
|
static yp_interpolated_x_string_node_t *
|
2449
2828
|
yp_interpolated_xstring_node_create(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *closing) {
|
@@ -2551,25 +2930,102 @@ static yp_lambda_node_t *
|
|
2551
2930
|
yp_lambda_node_create(
|
2552
2931
|
yp_parser_t *parser,
|
2553
2932
|
yp_constant_id_list_t *locals,
|
2933
|
+
const yp_token_t *operator,
|
2554
2934
|
const yp_token_t *opening,
|
2935
|
+
const yp_token_t *closing,
|
2555
2936
|
yp_block_parameters_node_t *parameters,
|
2556
|
-
yp_node_t *body
|
2557
|
-
const yp_token_t *closing
|
2937
|
+
yp_node_t *body
|
2558
2938
|
) {
|
2559
2939
|
yp_lambda_node_t *node = YP_ALLOC_NODE(parser, yp_lambda_node_t);
|
2560
2940
|
|
2561
|
-
*node = (yp_lambda_node_t) {
|
2941
|
+
*node = (yp_lambda_node_t) {
|
2942
|
+
{
|
2943
|
+
.type = YP_NODE_LAMBDA_NODE,
|
2944
|
+
.location = {
|
2945
|
+
.start = operator->start,
|
2946
|
+
.end = closing->end
|
2947
|
+
},
|
2948
|
+
},
|
2949
|
+
.locals = *locals,
|
2950
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2951
|
+
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
2952
|
+
.closing_loc = YP_LOCATION_TOKEN_VALUE(closing),
|
2953
|
+
.parameters = parameters,
|
2954
|
+
.body = body
|
2955
|
+
};
|
2956
|
+
|
2957
|
+
return node;
|
2958
|
+
}
|
2959
|
+
|
2960
|
+
// Allocate and initialize a new LocalVariableAndWriteNode node.
|
2961
|
+
static yp_local_variable_and_write_node_t *
|
2962
|
+
yp_local_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t constant_id, uint32_t depth) {
|
2963
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
|
2964
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2965
|
+
yp_local_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_and_write_node_t);
|
2966
|
+
|
2967
|
+
*node = (yp_local_variable_and_write_node_t) {
|
2968
|
+
{
|
2969
|
+
.type = YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE,
|
2970
|
+
.location = {
|
2971
|
+
.start = target->location.start,
|
2972
|
+
.end = value->location.end
|
2973
|
+
}
|
2974
|
+
},
|
2975
|
+
.name_loc = target->location,
|
2976
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2977
|
+
.value = value,
|
2978
|
+
.constant_id = constant_id,
|
2979
|
+
.depth = depth
|
2980
|
+
};
|
2981
|
+
|
2982
|
+
return node;
|
2983
|
+
}
|
2984
|
+
|
2985
|
+
// Allocate and initialize a new LocalVariableOperatorWriteNode node.
|
2986
|
+
static yp_local_variable_operator_write_node_t *
|
2987
|
+
yp_local_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t constant_id, uint32_t depth) {
|
2988
|
+
yp_local_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_operator_write_node_t);
|
2989
|
+
|
2990
|
+
*node = (yp_local_variable_operator_write_node_t) {
|
2991
|
+
{
|
2992
|
+
.type = YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
|
2993
|
+
.location = {
|
2994
|
+
.start = target->location.start,
|
2995
|
+
.end = value->location.end
|
2996
|
+
}
|
2997
|
+
},
|
2998
|
+
.name_loc = target->location,
|
2999
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
3000
|
+
.value = value,
|
3001
|
+
.constant_id = constant_id,
|
3002
|
+
.operator_id = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
3003
|
+
.depth = depth
|
3004
|
+
};
|
3005
|
+
|
3006
|
+
return node;
|
3007
|
+
}
|
3008
|
+
|
3009
|
+
// Allocate and initialize a new LocalVariableOrWriteNode node.
|
3010
|
+
static yp_local_variable_or_write_node_t *
|
3011
|
+
yp_local_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t constant_id, uint32_t depth) {
|
3012
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
|
3013
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
3014
|
+
yp_local_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_or_write_node_t);
|
3015
|
+
|
3016
|
+
*node = (yp_local_variable_or_write_node_t) {
|
2562
3017
|
{
|
2563
|
-
.type =
|
3018
|
+
.type = YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE,
|
2564
3019
|
.location = {
|
2565
|
-
.start =
|
2566
|
-
.end =
|
2567
|
-
}
|
3020
|
+
.start = target->location.start,
|
3021
|
+
.end = value->location.end
|
3022
|
+
}
|
2568
3023
|
},
|
2569
|
-
.
|
2570
|
-
.
|
2571
|
-
.
|
2572
|
-
.
|
3024
|
+
.name_loc = target->location,
|
3025
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
3026
|
+
.value = value,
|
3027
|
+
.constant_id = constant_id,
|
3028
|
+
.depth = depth
|
2573
3029
|
};
|
2574
3030
|
|
2575
3031
|
return node;
|
@@ -2602,7 +3058,7 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t consta
|
|
2602
3058
|
.type = YP_NODE_LOCAL_VARIABLE_WRITE_NODE,
|
2603
3059
|
.location = {
|
2604
3060
|
.start = name_loc->start,
|
2605
|
-
.end = value
|
3061
|
+
.end = value->location.end
|
2606
3062
|
}
|
2607
3063
|
},
|
2608
3064
|
.constant_id = constant_id,
|
@@ -2615,21 +3071,18 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t consta
|
|
2615
3071
|
return node;
|
2616
3072
|
}
|
2617
3073
|
|
2618
|
-
// Allocate and initialize a new
|
2619
|
-
static
|
3074
|
+
// Allocate and initialize a new LocalVariableTargetNode node.
|
3075
|
+
static yp_local_variable_target_node_t *
|
2620
3076
|
yp_local_variable_target_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
2621
|
-
|
3077
|
+
yp_local_variable_target_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_target_node_t);
|
2622
3078
|
|
2623
|
-
*node = (
|
3079
|
+
*node = (yp_local_variable_target_node_t) {
|
2624
3080
|
{
|
2625
|
-
.type =
|
3081
|
+
.type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE,
|
2626
3082
|
.location = YP_LOCATION_TOKEN_VALUE(name)
|
2627
3083
|
},
|
2628
3084
|
.constant_id = yp_parser_constant_id_token(parser, name),
|
2629
|
-
.depth = 0
|
2630
|
-
.value = NULL,
|
2631
|
-
.name_loc = YP_LOCATION_TOKEN_VALUE(name),
|
2632
|
-
.operator_loc = { .start = NULL, .end = NULL }
|
3085
|
+
.depth = 0
|
2633
3086
|
};
|
2634
3087
|
|
2635
3088
|
return node;
|
@@ -2679,7 +3132,7 @@ yp_match_required_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t *
|
|
2679
3132
|
|
2680
3133
|
// Allocate a new ModuleNode node.
|
2681
3134
|
static yp_module_node_t *
|
2682
|
-
yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, yp_node_t *body, const yp_token_t *end_keyword) {
|
3135
|
+
yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, const yp_token_t *name, yp_node_t *body, const yp_token_t *end_keyword) {
|
2683
3136
|
yp_module_node_t *node = YP_ALLOC_NODE(parser, yp_module_node_t);
|
2684
3137
|
|
2685
3138
|
*node = (yp_module_node_t) {
|
@@ -2694,9 +3147,11 @@ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const
|
|
2694
3147
|
.module_keyword_loc = YP_LOCATION_TOKEN_VALUE(module_keyword),
|
2695
3148
|
.constant_path = constant_path,
|
2696
3149
|
.body = body,
|
2697
|
-
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
3150
|
+
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword),
|
3151
|
+
.name = YP_EMPTY_STRING
|
2698
3152
|
};
|
2699
3153
|
|
3154
|
+
yp_string_shared_init(&node->name, name->start, name->end);
|
2700
3155
|
return node;
|
2701
3156
|
}
|
2702
3157
|
|
@@ -2708,7 +3163,10 @@ yp_multi_write_node_create(yp_parser_t *parser, const yp_token_t *operator, yp_n
|
|
2708
3163
|
*node = (yp_multi_write_node_t) {
|
2709
3164
|
{
|
2710
3165
|
.type = YP_NODE_MULTI_WRITE_NODE,
|
2711
|
-
.location = {
|
3166
|
+
.location = {
|
3167
|
+
.start = lparen_loc->start,
|
3168
|
+
.end = value == NULL ? rparen_loc->end : value->location.end
|
3169
|
+
},
|
2712
3170
|
},
|
2713
3171
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
2714
3172
|
.value = value,
|
@@ -2808,28 +3266,6 @@ yp_numbered_reference_read_node_create(yp_parser_t *parser, const yp_token_t *na
|
|
2808
3266
|
return node;
|
2809
3267
|
}
|
2810
3268
|
|
2811
|
-
// Allocate and initialize a new OperatorWriteNode.
|
2812
|
-
static yp_operator_write_node_t *
|
2813
|
-
yp_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2814
|
-
yp_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_operator_write_node_t);
|
2815
|
-
|
2816
|
-
*node = (yp_operator_write_node_t) {
|
2817
|
-
{
|
2818
|
-
.type = YP_NODE_OPERATOR_WRITE_NODE,
|
2819
|
-
.location = {
|
2820
|
-
.start = target->location.start,
|
2821
|
-
.end = value->location.end
|
2822
|
-
},
|
2823
|
-
},
|
2824
|
-
.target = target,
|
2825
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2826
|
-
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
2827
|
-
.value = value
|
2828
|
-
};
|
2829
|
-
|
2830
|
-
return node;
|
2831
|
-
}
|
2832
|
-
|
2833
3269
|
// Allocate a new OptionalParameterNode node.
|
2834
3270
|
static yp_optional_parameter_node_t *
|
2835
3271
|
yp_optional_parameter_node_create(yp_parser_t *parser, const yp_token_t *name, const yp_token_t *operator, yp_node_t *value) {
|
@@ -2873,27 +3309,6 @@ yp_or_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *operat
|
|
2873
3309
|
return node;
|
2874
3310
|
}
|
2875
3311
|
|
2876
|
-
// Allocate and initialize a new OrWriteNode.
|
2877
|
-
static yp_or_write_node_t *
|
2878
|
-
yp_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2879
|
-
yp_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_or_write_node_t);
|
2880
|
-
|
2881
|
-
*node = (yp_or_write_node_t) {
|
2882
|
-
{
|
2883
|
-
.type = YP_NODE_OR_WRITE_NODE,
|
2884
|
-
.location = {
|
2885
|
-
.start = target->location.start,
|
2886
|
-
.end = value->location.end
|
2887
|
-
},
|
2888
|
-
},
|
2889
|
-
.target = target,
|
2890
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2891
|
-
.value = value
|
2892
|
-
};
|
2893
|
-
|
2894
|
-
return node;
|
2895
|
-
}
|
2896
|
-
|
2897
3312
|
// Allocate and initialize a new ParametersNode node.
|
2898
3313
|
static yp_parameters_node_t *
|
2899
3314
|
yp_parameters_node_create(yp_parser_t *parser) {
|
@@ -3600,7 +4015,7 @@ yp_symbol_node_label_create(yp_parser_t *parser, const yp_token_t *token) {
|
|
3600
4015
|
assert((label.end - label.start) >= 0);
|
3601
4016
|
yp_string_shared_init(&node->unescaped, label.start, label.end);
|
3602
4017
|
|
3603
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL
|
4018
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL);
|
3604
4019
|
break;
|
3605
4020
|
}
|
3606
4021
|
case YP_TOKEN_MISSING: {
|
@@ -3641,20 +4056,20 @@ yp_symbol_node_label_p(yp_node_t *node) {
|
|
3641
4056
|
|
3642
4057
|
// Convert the given StringNode node to a SymbolNode node.
|
3643
4058
|
static yp_symbol_node_t *
|
3644
|
-
yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node) {
|
4059
|
+
yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node, const yp_token_t *opening, const yp_token_t *closing) {
|
3645
4060
|
yp_symbol_node_t *new_node = YP_ALLOC_NODE(parser, yp_symbol_node_t);
|
3646
4061
|
|
3647
4062
|
*new_node = (yp_symbol_node_t) {
|
3648
4063
|
{
|
3649
4064
|
.type = YP_NODE_SYMBOL_NODE,
|
3650
4065
|
.location = {
|
3651
|
-
.start =
|
3652
|
-
.end =
|
4066
|
+
.start = opening->start,
|
4067
|
+
.end = closing->end
|
3653
4068
|
}
|
3654
4069
|
},
|
3655
|
-
.opening_loc =
|
4070
|
+
.opening_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
|
3656
4071
|
.value_loc = node->content_loc,
|
3657
|
-
.closing_loc =
|
4072
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
3658
4073
|
.unescaped = node->unescaped
|
3659
4074
|
};
|
3660
4075
|
|
@@ -3793,34 +4208,43 @@ yp_unless_node_end_keyword_loc_set(yp_unless_node_t *node, const yp_token_t *end
|
|
3793
4208
|
|
3794
4209
|
// Allocate a new UntilNode node.
|
3795
4210
|
static yp_until_node_t *
|
3796
|
-
yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4211
|
+
yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_token_t *closing, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
3797
4212
|
yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
|
3798
|
-
bool has_statements = (statements != NULL) && (statements->body.size != 0);
|
3799
4213
|
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
4214
|
+
*node = (yp_until_node_t) {
|
4215
|
+
{
|
4216
|
+
.type = YP_NODE_UNTIL_NODE,
|
4217
|
+
.flags = flags,
|
4218
|
+
.location = {
|
4219
|
+
.start = keyword->start,
|
4220
|
+
.end = closing->end,
|
4221
|
+
},
|
4222
|
+
},
|
4223
|
+
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4224
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
4225
|
+
.predicate = predicate,
|
4226
|
+
.statements = statements
|
4227
|
+
};
|
3806
4228
|
|
3807
|
-
|
3808
|
-
|
3809
|
-
|
3810
|
-
|
3811
|
-
|
3812
|
-
|
4229
|
+
return node;
|
4230
|
+
}
|
4231
|
+
|
4232
|
+
// Allocate a new UntilNode node.
|
4233
|
+
static yp_until_node_t *
|
4234
|
+
yp_until_node_modifier_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4235
|
+
yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
|
3813
4236
|
|
3814
4237
|
*node = (yp_until_node_t) {
|
3815
4238
|
{
|
3816
4239
|
.type = YP_NODE_UNTIL_NODE,
|
3817
4240
|
.flags = flags,
|
3818
4241
|
.location = {
|
3819
|
-
.start = start,
|
3820
|
-
.end = end,
|
4242
|
+
.start = statements->base.location.start,
|
4243
|
+
.end = predicate->location.end,
|
3821
4244
|
},
|
3822
4245
|
},
|
3823
4246
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4247
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
3824
4248
|
.predicate = predicate,
|
3825
4249
|
.statements = statements
|
3826
4250
|
};
|
@@ -3868,34 +4292,43 @@ yp_when_node_statements_set(yp_when_node_t *node, yp_statements_node_t *statemen
|
|
3868
4292
|
|
3869
4293
|
// Allocate a new WhileNode node.
|
3870
4294
|
static yp_while_node_t *
|
3871
|
-
yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4295
|
+
yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_token_t *closing, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
3872
4296
|
yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
|
3873
4297
|
|
3874
|
-
|
3875
|
-
|
3876
|
-
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
3880
|
-
|
4298
|
+
*node = (yp_while_node_t) {
|
4299
|
+
{
|
4300
|
+
.type = YP_NODE_WHILE_NODE,
|
4301
|
+
.flags = flags,
|
4302
|
+
.location = {
|
4303
|
+
.start = keyword->start,
|
4304
|
+
.end = closing->end
|
4305
|
+
},
|
4306
|
+
},
|
4307
|
+
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4308
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
4309
|
+
.predicate = predicate,
|
4310
|
+
.statements = statements
|
4311
|
+
};
|
3881
4312
|
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
3885
|
-
|
3886
|
-
|
3887
|
-
|
4313
|
+
return node;
|
4314
|
+
}
|
4315
|
+
|
4316
|
+
// Allocate a new WhileNode node.
|
4317
|
+
static yp_while_node_t *
|
4318
|
+
yp_while_node_modifier_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4319
|
+
yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
|
3888
4320
|
|
3889
4321
|
*node = (yp_while_node_t) {
|
3890
4322
|
{
|
3891
4323
|
.type = YP_NODE_WHILE_NODE,
|
3892
4324
|
.flags = flags,
|
3893
4325
|
.location = {
|
3894
|
-
.start = start,
|
3895
|
-
.end = end
|
4326
|
+
.start = statements->base.location.start,
|
4327
|
+
.end = predicate->location.end
|
3896
4328
|
},
|
3897
4329
|
},
|
3898
4330
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4331
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
3899
4332
|
.predicate = predicate,
|
3900
4333
|
.statements = statements
|
3901
4334
|
};
|
@@ -4003,13 +4436,15 @@ yp_parser_local_depth(yp_parser_t *parser, yp_token_t *token) {
|
|
4003
4436
|
}
|
4004
4437
|
|
4005
4438
|
// Add a local variable from a location to the current scope.
|
4006
|
-
static
|
4439
|
+
static yp_constant_id_t
|
4007
4440
|
yp_parser_local_add_location(yp_parser_t *parser, const char *start, const char *end) {
|
4008
4441
|
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, start, end);
|
4009
4442
|
|
4010
4443
|
if (!yp_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
|
4011
4444
|
yp_constant_id_list_append(&parser->current_scope->locals, constant_id);
|
4012
4445
|
}
|
4446
|
+
|
4447
|
+
return constant_id;
|
4013
4448
|
}
|
4014
4449
|
|
4015
4450
|
// Add a local variable from a token to the current scope.
|
@@ -4157,27 +4592,30 @@ yp_do_loop_stack_p(yp_parser_t *parser) {
|
|
4157
4592
|
/* Lexer check helpers */
|
4158
4593
|
/******************************************************************************/
|
4159
4594
|
|
4160
|
-
// Get the next character in the source starting from
|
4161
|
-
//
|
4162
|
-
// then return '\0'.
|
4595
|
+
// Get the next character in the source starting from +cursor+. If that position
|
4596
|
+
// is beyond the end of the source then return '\0'.
|
4163
4597
|
static inline char
|
4164
|
-
peek_at(yp_parser_t *parser,
|
4165
|
-
if (
|
4166
|
-
return
|
4598
|
+
peek_at(yp_parser_t *parser, const char *cursor) {
|
4599
|
+
if (cursor < parser->end) {
|
4600
|
+
return *cursor;
|
4167
4601
|
} else {
|
4168
4602
|
return '\0';
|
4169
4603
|
}
|
4170
4604
|
}
|
4171
4605
|
|
4606
|
+
// Get the next character in the source starting from parser->current.end and
|
4607
|
+
// adding the given offset. If that position is beyond the end of the source
|
4608
|
+
// then return '\0'.
|
4609
|
+
static inline char
|
4610
|
+
peek_offset(yp_parser_t *parser, ptrdiff_t offset) {
|
4611
|
+
return peek_at(parser, parser->current.end + offset);
|
4612
|
+
}
|
4613
|
+
|
4172
4614
|
// Get the next character in the source starting from parser->current.end. If
|
4173
4615
|
// that position is beyond the end of the source then return '\0'.
|
4174
4616
|
static inline char
|
4175
4617
|
peek(yp_parser_t *parser) {
|
4176
|
-
|
4177
|
-
return *parser->current.end;
|
4178
|
-
} else {
|
4179
|
-
return '\0';
|
4180
|
-
}
|
4618
|
+
return peek_at(parser, parser->current.end);
|
4181
4619
|
}
|
4182
4620
|
|
4183
4621
|
// Get the next string of length len in the source starting from parser->current.end.
|
@@ -4202,6 +4640,35 @@ match(yp_parser_t *parser, char value) {
|
|
4202
4640
|
return false;
|
4203
4641
|
}
|
4204
4642
|
|
4643
|
+
// Return the length of the line ending string starting at +cursor+, or 0 if it
|
4644
|
+
// is not a line ending. This function is intended to be CRLF/LF agnostic.
|
4645
|
+
static inline size_t
|
4646
|
+
match_eol_at(yp_parser_t *parser, const char *cursor) {
|
4647
|
+
if (peek_at(parser, cursor) == '\n') {
|
4648
|
+
return 1;
|
4649
|
+
}
|
4650
|
+
if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
|
4651
|
+
return 2;
|
4652
|
+
}
|
4653
|
+
return 0;
|
4654
|
+
}
|
4655
|
+
|
4656
|
+
// Return the length of the line ending string starting at
|
4657
|
+
// parser->current.end + offset, or 0 if it is not a line ending. This function
|
4658
|
+
// is intended to be CRLF/LF agnostic.
|
4659
|
+
static inline size_t
|
4660
|
+
match_eol_offset(yp_parser_t *parser, ptrdiff_t offset) {
|
4661
|
+
return match_eol_at(parser, parser->current.end + offset);
|
4662
|
+
}
|
4663
|
+
|
4664
|
+
// Return the length of the line ending string starting at parser->current.end,
|
4665
|
+
// or 0 if it is not a line ending. This function is intended to be CRLF/LF
|
4666
|
+
// agnostic.
|
4667
|
+
static inline size_t
|
4668
|
+
match_eol(yp_parser_t *parser) {
|
4669
|
+
return match_eol_at(parser, parser->current.end);
|
4670
|
+
}
|
4671
|
+
|
4205
4672
|
// Skip to the next newline character or NUL byte.
|
4206
4673
|
static inline const char *
|
4207
4674
|
next_newline(const char *cursor, ptrdiff_t length) {
|
@@ -4225,11 +4692,13 @@ parser_lex_encoding_comment_start(yp_parser_t *parser, const char *cursor, ptrdi
|
|
4225
4692
|
|
4226
4693
|
const char *cursor_limit = cursor + length - key_length + 1;
|
4227
4694
|
while ((cursor = yp_memchr(cursor, 'c', (size_t) (cursor_limit - cursor), parser->encoding_changed, &parser->encoding)) != NULL) {
|
4228
|
-
if (
|
4229
|
-
(
|
4230
|
-
|
4231
|
-
|
4232
|
-
|
4695
|
+
if (strncmp(cursor, "coding", key_length - 1) == 0) {
|
4696
|
+
size_t whitespace_after_coding = yp_strspn_inline_whitespace(cursor + key_length - 1, parser->end - (cursor + key_length - 1));
|
4697
|
+
size_t cur_pos = key_length + whitespace_after_coding;
|
4698
|
+
|
4699
|
+
if (cursor[cur_pos - 1] == ':' || cursor[cur_pos - 1] == '=') {
|
4700
|
+
return cursor + cur_pos;
|
4701
|
+
}
|
4233
4702
|
}
|
4234
4703
|
|
4235
4704
|
cursor++;
|
@@ -4485,7 +4954,7 @@ lex_optional_float_suffix(yp_parser_t *parser) {
|
|
4485
4954
|
// Here we're going to attempt to parse the optional decimal portion of a
|
4486
4955
|
// float. If it's not there, then it's okay and we'll just continue on.
|
4487
4956
|
if (peek(parser) == '.') {
|
4488
|
-
if (yp_char_is_decimal_digit(
|
4957
|
+
if (yp_char_is_decimal_digit(peek_offset(parser, 1))) {
|
4489
4958
|
parser->current.end += 2;
|
4490
4959
|
parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end);
|
4491
4960
|
type = YP_TOKEN_FLOAT;
|
@@ -4518,7 +4987,7 @@ static yp_token_type_t
|
|
4518
4987
|
lex_numeric_prefix(yp_parser_t *parser) {
|
4519
4988
|
yp_token_type_t type = YP_TOKEN_INTEGER;
|
4520
4989
|
|
4521
|
-
if (parser
|
4990
|
+
if (peek_offset(parser, -1) == '0') {
|
4522
4991
|
switch (*parser->current.end) {
|
4523
4992
|
// 0d1111 is a decimal number
|
4524
4993
|
case 'd':
|
@@ -4601,7 +5070,7 @@ lex_numeric_prefix(yp_parser_t *parser) {
|
|
4601
5070
|
|
4602
5071
|
// If the last character that we consumed was an underscore, then this is
|
4603
5072
|
// actually an invalid integer value, and we should return an invalid token.
|
4604
|
-
if (parser
|
5073
|
+
if (peek_offset(parser, -1) == '_') {
|
4605
5074
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Number literal cannot end with a `_`.");
|
4606
5075
|
}
|
4607
5076
|
|
@@ -4782,7 +5251,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
4782
5251
|
|
4783
5252
|
if (
|
4784
5253
|
((lex_state_p(parser, YP_LEX_STATE_LABEL | YP_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
|
4785
|
-
(peek(parser) == ':') && (
|
5254
|
+
(peek(parser) == ':') && (peek_offset(parser, 1) != ':')
|
4786
5255
|
) {
|
4787
5256
|
// If we're in a position where we can accept a : at the end of an
|
4788
5257
|
// identifier, then we'll optionally accept it.
|
@@ -4798,7 +5267,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
4798
5267
|
}
|
4799
5268
|
|
4800
5269
|
return YP_TOKEN_IDENTIFIER;
|
4801
|
-
} else if (lex_state_p(parser, YP_LEX_STATE_FNAME) &&
|
5270
|
+
} else if (lex_state_p(parser, YP_LEX_STATE_FNAME) && peek_offset(parser, 1) != '~' && peek_offset(parser, 1) != '>' && (peek_offset(parser, 1) != '=' || peek_offset(parser, 2) == '>') && match(parser, '=')) {
|
4802
5271
|
// If we're in a position where we can accept a = at the end of an
|
4803
5272
|
// identifier, then we'll optionally accept it.
|
4804
5273
|
return YP_TOKEN_IDENTIFIER;
|
@@ -4806,7 +5275,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
4806
5275
|
|
4807
5276
|
if (
|
4808
5277
|
((lex_state_p(parser, YP_LEX_STATE_LABEL | YP_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
|
4809
|
-
peek(parser) == ':' &&
|
5278
|
+
peek(parser) == ':' && peek_offset(parser, 1) != ':'
|
4810
5279
|
) {
|
4811
5280
|
// If we're in a position where we can accept a : at the end of an
|
4812
5281
|
// identifier, then we'll optionally accept it.
|
@@ -5074,7 +5543,7 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5074
5543
|
|
5075
5544
|
if (parser->current.start[1] == '\\') {
|
5076
5545
|
lex_state_set(parser, YP_LEX_STATE_END);
|
5077
|
-
parser->current.end += yp_unescape_calculate_difference(parser->current.start + 1,
|
5546
|
+
parser->current.end += yp_unescape_calculate_difference(parser, parser->current.start + 1, YP_UNESCAPE_ALL, true);
|
5078
5547
|
return YP_TOKEN_CHARACTER_LITERAL;
|
5079
5548
|
} else {
|
5080
5549
|
size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end);
|
@@ -5083,7 +5552,7 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5083
5552
|
// an underscore. We check for this case
|
5084
5553
|
if (
|
5085
5554
|
!(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
|
5086
|
-
|
5555
|
+
peek(parser) == '_') ||
|
5087
5556
|
(
|
5088
5557
|
(parser->current.end + encoding_width >= parser->end) ||
|
5089
5558
|
!char_is_identifier(parser, parser->current.end + encoding_width)
|
@@ -5299,30 +5768,22 @@ parser_lex(yp_parser_t *parser) {
|
|
5299
5768
|
space_seen = true;
|
5300
5769
|
break;
|
5301
5770
|
case '\r':
|
5302
|
-
if (
|
5771
|
+
if (match_eol_offset(parser, 1)) {
|
5303
5772
|
chomping = false;
|
5304
5773
|
} else {
|
5305
5774
|
parser->current.end++;
|
5306
5775
|
space_seen = true;
|
5307
5776
|
}
|
5308
5777
|
break;
|
5309
|
-
case '\\':
|
5310
|
-
|
5311
|
-
|
5312
|
-
parser->current.end = parser->heredoc_end;
|
5313
|
-
parser->heredoc_end = NULL;
|
5314
|
-
} else {
|
5315
|
-
yp_newline_list_append(&parser->newline_list, parser->current.end + 1);
|
5316
|
-
parser->current.end += 2;
|
5317
|
-
space_seen = true;
|
5318
|
-
}
|
5319
|
-
} else if (peek_at(parser, 1) == '\r' && peek_at(parser, 2) == '\n') {
|
5778
|
+
case '\\': {
|
5779
|
+
size_t eol_length = match_eol_offset(parser, 1);
|
5780
|
+
if (eol_length) {
|
5320
5781
|
if (parser->heredoc_end) {
|
5321
5782
|
parser->current.end = parser->heredoc_end;
|
5322
5783
|
parser->heredoc_end = NULL;
|
5323
5784
|
} else {
|
5324
|
-
|
5325
|
-
parser->current.end
|
5785
|
+
parser->current.end += eol_length + 1;
|
5786
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
5326
5787
|
space_seen = true;
|
5327
5788
|
}
|
5328
5789
|
} else if (yp_char_is_inline_whitespace(*parser->current.end)) {
|
@@ -5330,7 +5791,9 @@ parser_lex(yp_parser_t *parser) {
|
|
5330
5791
|
} else {
|
5331
5792
|
chomping = false;
|
5332
5793
|
}
|
5794
|
+
|
5333
5795
|
break;
|
5796
|
+
}
|
5334
5797
|
default:
|
5335
5798
|
chomping = false;
|
5336
5799
|
break;
|
@@ -5340,13 +5803,14 @@ parser_lex(yp_parser_t *parser) {
|
|
5340
5803
|
// Next, we'll set to start of this token to be the current end.
|
5341
5804
|
parser->current.start = parser->current.end;
|
5342
5805
|
|
5343
|
-
// We'll check if we're at the end of the file. If we are, then we
|
5344
|
-
// return the EOF token.
|
5806
|
+
// We'll check if we're at the end of the file. If we are, then we
|
5807
|
+
// need to return the EOF token.
|
5345
5808
|
if (parser->current.end >= parser->end) {
|
5346
5809
|
LEX(YP_TOKEN_EOF);
|
5347
5810
|
}
|
5348
5811
|
|
5349
|
-
// Finally, we'll check the current character to determine the next
|
5812
|
+
// Finally, we'll check the current character to determine the next
|
5813
|
+
// token.
|
5350
5814
|
switch (*parser->current.end++) {
|
5351
5815
|
case '\0': // NUL or end of script
|
5352
5816
|
case '\004': // ^D
|
@@ -5356,16 +5820,14 @@ parser_lex(yp_parser_t *parser) {
|
|
5356
5820
|
|
5357
5821
|
case '#': { // comments
|
5358
5822
|
const char *ending = next_newline(parser->current.end, parser->end - parser->current.end);
|
5359
|
-
while (ending && ending < parser->end && *ending != '\n') {
|
5360
|
-
ending = next_newline(ending + 1, parser->end - ending);
|
5361
|
-
}
|
5362
5823
|
|
5363
5824
|
parser->current.end = ending == NULL ? parser->end : ending + 1;
|
5364
5825
|
parser->current.type = YP_TOKEN_COMMENT;
|
5365
5826
|
parser_lex_callback(parser);
|
5366
5827
|
|
5367
|
-
// If we found a comment while lexing, then we're going to
|
5368
|
-
// list of comments in the file and keep
|
5828
|
+
// If we found a comment while lexing, then we're going to
|
5829
|
+
// add it to the list of comments in the file and keep
|
5830
|
+
// lexing.
|
5369
5831
|
yp_comment_t *comment = parser_comment(parser, YP_COMMENT_INLINE);
|
5370
5832
|
yp_list_append(&parser->comment_list, (yp_list_node_t *) comment);
|
5371
5833
|
|
@@ -5376,21 +5838,29 @@ parser_lex(yp_parser_t *parser) {
|
|
5376
5838
|
lexed_comment = true;
|
5377
5839
|
}
|
5378
5840
|
/* fallthrough */
|
5379
|
-
case '\r':
|
5380
|
-
// The only way you can have carriage returns in this particular loop
|
5381
|
-
// is if you have a carriage return followed by a newline. In that
|
5382
|
-
// case we'll just skip over the carriage return and continue lexing,
|
5383
|
-
// in order to make it so that the newline token encapsulates both the
|
5384
|
-
// carriage return and the newline. Note that we need to check that
|
5385
|
-
// we haven't already lexed a comment here because that falls through
|
5386
|
-
// into here as well.
|
5387
|
-
if (!lexed_comment) parser->current.end++;
|
5388
|
-
}
|
5389
|
-
/* fallthrough */
|
5841
|
+
case '\r':
|
5390
5842
|
case '\n': {
|
5391
|
-
|
5392
|
-
|
5393
|
-
|
5843
|
+
size_t eol_length = match_eol_at(parser, parser->current.end - 1);
|
5844
|
+
if (eol_length) {
|
5845
|
+
// The only way you can have carriage returns in this
|
5846
|
+
// particular loop is if you have a carriage return
|
5847
|
+
// followed by a newline. In that case we'll just skip
|
5848
|
+
// over the carriage return and continue lexing, in
|
5849
|
+
// order to make it so that the newline token
|
5850
|
+
// encapsulates both the carriage return and the
|
5851
|
+
// newline. Note that we need to check that we haven't
|
5852
|
+
// already lexed a comment here because that falls
|
5853
|
+
// through into here as well.
|
5854
|
+
if (!lexed_comment) {
|
5855
|
+
parser->current.end += eol_length - 1; // skip CR
|
5856
|
+
}
|
5857
|
+
|
5858
|
+
if (parser->heredoc_end == NULL) {
|
5859
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
5860
|
+
}
|
5861
|
+
}
|
5862
|
+
|
5863
|
+
if (parser->heredoc_end) {
|
5394
5864
|
parser_flush_heredoc_end(parser);
|
5395
5865
|
}
|
5396
5866
|
|
@@ -5446,7 +5916,13 @@ parser_lex(yp_parser_t *parser) {
|
|
5446
5916
|
|
5447
5917
|
// If the lex state was ignored, or we hit a '.' or a '&.',
|
5448
5918
|
// we will lex the ignored newline
|
5449
|
-
if (
|
5919
|
+
if (
|
5920
|
+
lex_state_ignored_p(parser) ||
|
5921
|
+
(following && (
|
5922
|
+
(peek_at(parser, following) == '.') ||
|
5923
|
+
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '.')
|
5924
|
+
))
|
5925
|
+
) {
|
5450
5926
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5451
5927
|
lexed_comment = false;
|
5452
5928
|
goto lex_next_token;
|
@@ -5459,7 +5935,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5459
5935
|
// To match ripper, we need to emit an ignored newline even though
|
5460
5936
|
// its a real newline in the case that we have a beginless range
|
5461
5937
|
// on a subsequent line.
|
5462
|
-
if ((next_content + 1
|
5938
|
+
if (peek_at(parser, next_content + 1) == '.') {
|
5463
5939
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5464
5940
|
lex_state_set(parser, YP_LEX_STATE_BEG);
|
5465
5941
|
parser->command_start = true;
|
@@ -5477,7 +5953,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5477
5953
|
|
5478
5954
|
// If we hit a &. after a newline, then we're in a call chain and
|
5479
5955
|
// we need to return the call operator.
|
5480
|
-
if (
|
5956
|
+
if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '.') {
|
5481
5957
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5482
5958
|
lex_state_set(parser, YP_LEX_STATE_DOT);
|
5483
5959
|
parser->current.start = next_content;
|
@@ -5674,7 +6150,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5674
6150
|
|
5675
6151
|
// = => =~ == === =begin
|
5676
6152
|
case '=':
|
5677
|
-
if (current_token_starts_line(parser) && strncmp(peek_string(parser, 5), "begin", 5) == 0 && yp_char_is_whitespace(
|
6153
|
+
if (current_token_starts_line(parser) && strncmp(peek_string(parser, 5), "begin", 5) == 0 && yp_char_is_whitespace(peek_offset(parser, 5))) {
|
5678
6154
|
yp_token_type_t type = lex_embdoc(parser);
|
5679
6155
|
|
5680
6156
|
if (type == YP_TOKEN_EOF) {
|
@@ -6098,13 +6574,13 @@ parser_lex(yp_parser_t *parser) {
|
|
6098
6574
|
LEX(YP_TOKEN_COLON_COLON);
|
6099
6575
|
}
|
6100
6576
|
|
6101
|
-
if (lex_state_end_p(parser) || yp_char_is_whitespace(*parser->current.end) || (
|
6577
|
+
if (lex_state_end_p(parser) || yp_char_is_whitespace(*parser->current.end) || peek(parser) == '#') {
|
6102
6578
|
lex_state_set(parser, YP_LEX_STATE_BEG);
|
6103
6579
|
LEX(YP_TOKEN_COLON);
|
6104
6580
|
}
|
6105
6581
|
|
6106
|
-
if ((
|
6107
|
-
lex_mode_push_string(parser,
|
6582
|
+
if (peek(parser) == '"' || peek(parser) == '\'') {
|
6583
|
+
lex_mode_push_string(parser, peek(parser) == '"', false, '\0', *parser->current.end);
|
6108
6584
|
parser->current.end++;
|
6109
6585
|
}
|
6110
6586
|
|
@@ -6173,25 +6649,26 @@ parser_lex(yp_parser_t *parser) {
|
|
6173
6649
|
}
|
6174
6650
|
else if(
|
6175
6651
|
lex_state_beg_p(parser) ||
|
6176
|
-
(lex_state_p(parser, YP_LEX_STATE_FITEM) && (
|
6652
|
+
(lex_state_p(parser, YP_LEX_STATE_FITEM) && (peek(parser) == 's')) ||
|
6177
6653
|
lex_state_spcarg_p(parser, space_seen)
|
6178
6654
|
) {
|
6179
6655
|
if (!parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end)) {
|
6180
6656
|
lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6181
6657
|
|
6182
|
-
|
6658
|
+
size_t eol_length = match_eol(parser);
|
6659
|
+
if (eol_length) {
|
6660
|
+
parser->current.end += eol_length;
|
6661
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
6662
|
+
} else {
|
6183
6663
|
parser->current.end++;
|
6184
6664
|
}
|
6185
6665
|
|
6186
|
-
if (
|
6187
|
-
|
6666
|
+
if (parser->current.end < parser->end) {
|
6667
|
+
LEX(YP_TOKEN_STRING_BEGIN);
|
6188
6668
|
}
|
6189
|
-
|
6190
|
-
parser->current.end++;
|
6191
|
-
LEX(YP_TOKEN_STRING_BEGIN);
|
6192
6669
|
}
|
6193
6670
|
|
6194
|
-
switch (
|
6671
|
+
switch (peek(parser)) {
|
6195
6672
|
case 'i': {
|
6196
6673
|
parser->current.end++;
|
6197
6674
|
|
@@ -6215,6 +6692,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6215
6692
|
|
6216
6693
|
if (parser->current.end < parser->end) {
|
6217
6694
|
lex_mode_push_regexp(parser, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6695
|
+
yp_newline_list_check_append(&parser->newline_list, parser->current.end);
|
6218
6696
|
parser->current.end++;
|
6219
6697
|
}
|
6220
6698
|
|
@@ -6225,6 +6703,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6225
6703
|
|
6226
6704
|
if (parser->current.end < parser->end) {
|
6227
6705
|
lex_mode_push_string(parser, false, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6706
|
+
yp_newline_list_check_append(&parser->newline_list, parser->current.end);
|
6228
6707
|
parser->current.end++;
|
6229
6708
|
}
|
6230
6709
|
|
@@ -6235,6 +6714,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6235
6714
|
|
6236
6715
|
if (parser->current.end < parser->end) {
|
6237
6716
|
lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6717
|
+
yp_newline_list_check_append(&parser->newline_list, parser->current.end);
|
6238
6718
|
parser->current.end++;
|
6239
6719
|
}
|
6240
6720
|
|
@@ -6284,7 +6764,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6284
6764
|
// unparseable. In this case we'll just drop it from the parser
|
6285
6765
|
// and skip past it and hope that the next token is something
|
6286
6766
|
// that we can parse.
|
6287
|
-
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "
|
6767
|
+
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid %% token");
|
6288
6768
|
goto lex_next_token;
|
6289
6769
|
}
|
6290
6770
|
}
|
@@ -6336,8 +6816,9 @@ parser_lex(yp_parser_t *parser) {
|
|
6336
6816
|
((parser->current.end - parser->current.start) == 7) &&
|
6337
6817
|
current_token_starts_line(parser) &&
|
6338
6818
|
(strncmp(parser->current.start, "__END__", 7) == 0) &&
|
6339
|
-
(parser->current.end == parser->end ||
|
6340
|
-
|
6819
|
+
(parser->current.end == parser->end || match_eol(parser))
|
6820
|
+
)
|
6821
|
+
{
|
6341
6822
|
parser->current.end = parser->end;
|
6342
6823
|
parser->current.type = YP_TOKEN___END__;
|
6343
6824
|
parser_lex_callback(parser);
|
@@ -6394,7 +6875,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6394
6875
|
|
6395
6876
|
if ((whitespace = yp_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list, should_stop)) > 0) {
|
6396
6877
|
parser->current.end += whitespace;
|
6397
|
-
if (parser
|
6878
|
+
if (peek_offset(parser, -1) == '\n') {
|
6398
6879
|
// mutates next_start
|
6399
6880
|
parser_flush_heredoc_end(parser);
|
6400
6881
|
}
|
@@ -6458,13 +6939,11 @@ parser_lex(yp_parser_t *parser) {
|
|
6458
6939
|
// and find the next breakpoint.
|
6459
6940
|
if (*breakpoint == '\\') {
|
6460
6941
|
yp_unescape_type_t unescape_type = lex_mode->as.list.interpolation ? YP_UNESCAPE_ALL : YP_UNESCAPE_MINIMAL;
|
6461
|
-
size_t difference = yp_unescape_calculate_difference(
|
6942
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
6462
6943
|
|
6463
6944
|
// If the result is an escaped newline, then we need to
|
6464
6945
|
// track that newline.
|
6465
|
-
|
6466
|
-
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
6467
|
-
}
|
6946
|
+
yp_newline_list_check_append(&parser->newline_list, breakpoint + difference - 1);
|
6468
6947
|
|
6469
6948
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
6470
6949
|
continue;
|
@@ -6499,7 +6978,13 @@ parser_lex(yp_parser_t *parser) {
|
|
6499
6978
|
|
6500
6979
|
case YP_LEX_REGEXP: {
|
6501
6980
|
// First, we'll set to start of this token to be the current end.
|
6502
|
-
parser->
|
6981
|
+
if (parser->next_start == NULL) {
|
6982
|
+
parser->current.start = parser->current.end;
|
6983
|
+
} else {
|
6984
|
+
parser->current.start = parser->next_start;
|
6985
|
+
parser->current.end = parser->next_start;
|
6986
|
+
parser->next_start = NULL;
|
6987
|
+
}
|
6503
6988
|
|
6504
6989
|
// We'll check if we're at the end of the file. If we are, then we need to
|
6505
6990
|
// return the EOF token.
|
@@ -6526,7 +7011,16 @@ parser_lex(yp_parser_t *parser) {
|
|
6526
7011
|
// If we've hit a newline, then we need to track that in the
|
6527
7012
|
// list of newlines.
|
6528
7013
|
if (*breakpoint == '\n') {
|
6529
|
-
|
7014
|
+
// For the special case of a newline-terminated regular expression, we will pass
|
7015
|
+
// through this branch twice -- once with YP_TOKEN_REGEXP_BEGIN and then again
|
7016
|
+
// with YP_TOKEN_STRING_CONTENT. Let's avoid tracking the newline twice, by
|
7017
|
+
// tracking it only in the REGEXP_BEGIN case.
|
7018
|
+
if (
|
7019
|
+
!(lex_mode->as.regexp.terminator == '\n' && parser->current.type != YP_TOKEN_REGEXP_BEGIN)
|
7020
|
+
&& parser->heredoc_end == NULL
|
7021
|
+
) {
|
7022
|
+
yp_newline_list_append(&parser->newline_list, breakpoint);
|
7023
|
+
}
|
6530
7024
|
|
6531
7025
|
if (lex_mode->as.regexp.terminator != '\n') {
|
6532
7026
|
// If the terminator is not a newline, then we can set
|
@@ -6567,12 +7061,20 @@ parser_lex(yp_parser_t *parser) {
|
|
6567
7061
|
// literally. In this case we'll skip past the next character
|
6568
7062
|
// and find the next breakpoint.
|
6569
7063
|
if (*breakpoint == '\\') {
|
6570
|
-
size_t difference = yp_unescape_calculate_difference(
|
6571
|
-
|
6572
|
-
// If the result is an escaped newline
|
6573
|
-
|
6574
|
-
|
6575
|
-
|
7064
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, YP_UNESCAPE_ALL, false);
|
7065
|
+
|
7066
|
+
// If the result is an escaped newline ...
|
7067
|
+
if (*(breakpoint + difference - 1) == '\n') {
|
7068
|
+
if (parser->heredoc_end) {
|
7069
|
+
// ... if we are on the same line as a heredoc, flush the heredoc and
|
7070
|
+
// continue parsing after heredoc_end.
|
7071
|
+
parser->current.end = breakpoint + difference;
|
7072
|
+
parser_flush_heredoc_end(parser);
|
7073
|
+
LEX(YP_TOKEN_STRING_CONTENT);
|
7074
|
+
} else {
|
7075
|
+
// ... else track the newline.
|
7076
|
+
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
7077
|
+
}
|
6576
7078
|
}
|
6577
7079
|
|
6578
7080
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -6660,21 +7162,18 @@ parser_lex(yp_parser_t *parser) {
|
|
6660
7162
|
|
6661
7163
|
// Otherwise we need to switch back to the parent lex mode and
|
6662
7164
|
// return the end of the string.
|
6663
|
-
|
6664
|
-
|
6665
|
-
|
7165
|
+
size_t eol_length = match_eol_at(parser, breakpoint);
|
7166
|
+
if (eol_length) {
|
7167
|
+
parser->current.end = breakpoint + eol_length;
|
7168
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
6666
7169
|
} else {
|
6667
|
-
if (*parser->current.end == '\n') {
|
6668
|
-
yp_newline_list_append(&parser->newline_list, parser->current.end);
|
6669
|
-
}
|
6670
|
-
|
6671
7170
|
parser->current.end = breakpoint + 1;
|
6672
7171
|
}
|
6673
7172
|
|
6674
7173
|
if (
|
6675
7174
|
parser->lex_modes.current->as.string.label_allowed &&
|
6676
7175
|
(peek(parser) == ':') &&
|
6677
|
-
(
|
7176
|
+
(peek_offset(parser, 1) != ':')
|
6678
7177
|
) {
|
6679
7178
|
parser->current.end++;
|
6680
7179
|
lex_state_set(parser, YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED);
|
@@ -6712,12 +7211,20 @@ parser_lex(yp_parser_t *parser) {
|
|
6712
7211
|
// literally. In this case we'll skip past the next character and
|
6713
7212
|
// find the next breakpoint.
|
6714
7213
|
yp_unescape_type_t unescape_type = parser->lex_modes.current->as.string.interpolation ? YP_UNESCAPE_ALL : YP_UNESCAPE_MINIMAL;
|
6715
|
-
size_t difference = yp_unescape_calculate_difference(
|
7214
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
6716
7215
|
|
6717
|
-
// If the result is an escaped newline
|
6718
|
-
|
6719
|
-
|
6720
|
-
|
7216
|
+
// If the result is an escaped newline ...
|
7217
|
+
if (*(breakpoint + difference - 1) == '\n') {
|
7218
|
+
if (parser->heredoc_end) {
|
7219
|
+
// ... if we are on the same line as a heredoc, flush the heredoc and
|
7220
|
+
// continue parsing after heredoc_end.
|
7221
|
+
parser->current.end = breakpoint + difference;
|
7222
|
+
parser_flush_heredoc_end(parser);
|
7223
|
+
LEX(YP_TOKEN_STRING_CONTENT);
|
7224
|
+
} else {
|
7225
|
+
// ... else track the newline.
|
7226
|
+
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
7227
|
+
}
|
6721
7228
|
}
|
6722
7229
|
|
6723
7230
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -6770,7 +7277,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6770
7277
|
|
6771
7278
|
// If we are immediately following a newline and we have hit the
|
6772
7279
|
// terminator, then we need to return the ending of the heredoc.
|
6773
|
-
if (parser
|
7280
|
+
if (current_token_starts_line(parser)) {
|
6774
7281
|
const char *start = parser->current.start;
|
6775
7282
|
if (parser->lex_modes.current->as.heredoc.indent != YP_HEREDOC_INDENT_NONE) {
|
6776
7283
|
start += yp_strspn_inline_whitespace(start, parser->end - start);
|
@@ -6780,12 +7287,10 @@ parser_lex(yp_parser_t *parser) {
|
|
6780
7287
|
bool matched = true;
|
6781
7288
|
bool at_end = false;
|
6782
7289
|
|
6783
|
-
|
6784
|
-
|
6785
|
-
|
6786
|
-
|
6787
|
-
parser->current.end = start + ident_length + 2;
|
6788
|
-
yp_newline_list_append(&parser->newline_list, start + ident_length + 1);
|
7290
|
+
size_t eol_length = match_eol_at(parser, start + ident_length);
|
7291
|
+
if (eol_length) {
|
7292
|
+
parser->current.end = start + ident_length + eol_length;
|
7293
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
6789
7294
|
} else if (parser->end == (start + ident_length)) {
|
6790
7295
|
parser->current.end = start + ident_length;
|
6791
7296
|
at_end = true;
|
@@ -6850,19 +7355,10 @@ parser_lex(yp_parser_t *parser) {
|
|
6850
7355
|
(start + ident_length <= parser->end) &&
|
6851
7356
|
(strncmp(start, ident_start, ident_length) == 0)
|
6852
7357
|
) {
|
6853
|
-
// Heredoc terminators must be followed by a newline or EOF to be valid.
|
6854
|
-
if (start + ident_length == parser->end || start[ident_length] == '\n') {
|
6855
|
-
parser->current.end = breakpoint + 1;
|
6856
|
-
LEX(YP_TOKEN_STRING_CONTENT);
|
6857
|
-
}
|
6858
|
-
|
6859
|
-
// They can also be followed by a carriage return and then a
|
6860
|
-
// newline. Be sure here that we don't accidentally read off the
|
6861
|
-
// end.
|
7358
|
+
// Heredoc terminators must be followed by a newline, CRLF, or EOF to be valid.
|
6862
7359
|
if (
|
6863
|
-
|
6864
|
-
(start
|
6865
|
-
(start[ident_length + 1] == '\n')
|
7360
|
+
start + ident_length == parser->end ||
|
7361
|
+
match_eol_at(parser, start + ident_length)
|
6866
7362
|
) {
|
6867
7363
|
parser->current.end = breakpoint + 1;
|
6868
7364
|
LEX(YP_TOKEN_STRING_CONTENT);
|
@@ -6881,17 +7377,14 @@ parser_lex(yp_parser_t *parser) {
|
|
6881
7377
|
// stop looping before the newline and not after the
|
6882
7378
|
// newline so that we can still potentially find the
|
6883
7379
|
// terminator of the heredoc.
|
6884
|
-
|
6885
|
-
|
6886
|
-
|
6887
|
-
breakpoint += 2;
|
7380
|
+
size_t eol_length = match_eol_at(parser, breakpoint + 1);
|
7381
|
+
if (eol_length) {
|
7382
|
+
breakpoint += eol_length;
|
6888
7383
|
} else {
|
6889
7384
|
yp_unescape_type_t unescape_type = (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL;
|
6890
|
-
size_t difference = yp_unescape_calculate_difference(
|
7385
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
6891
7386
|
|
6892
|
-
|
6893
|
-
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
6894
|
-
}
|
7387
|
+
yp_newline_list_check_append(&parser->newline_list, breakpoint + difference - 1);
|
6895
7388
|
|
6896
7389
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
6897
7390
|
}
|
@@ -6945,7 +7438,7 @@ yp_regular_expression_node_create_and_unescape(yp_parser_t *parser, const yp_tok
|
|
6945
7438
|
assert((content->end - content->start) >= 0);
|
6946
7439
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6947
7440
|
|
6948
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type
|
7441
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
6949
7442
|
return node;
|
6950
7443
|
}
|
6951
7444
|
|
@@ -6956,7 +7449,7 @@ yp_symbol_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openin
|
|
6956
7449
|
assert((content->end - content->start) >= 0);
|
6957
7450
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6958
7451
|
|
6959
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type
|
7452
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
6960
7453
|
return node;
|
6961
7454
|
}
|
6962
7455
|
|
@@ -6967,7 +7460,7 @@ yp_string_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openin
|
|
6967
7460
|
assert((content->end - content->start) >= 0);
|
6968
7461
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6969
7462
|
|
6970
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type
|
7463
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
6971
7464
|
return node;
|
6972
7465
|
}
|
6973
7466
|
|
@@ -6978,7 +7471,7 @@ yp_xstring_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openi
|
|
6978
7471
|
assert((content->end - content->start) >= 0);
|
6979
7472
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6980
7473
|
|
6981
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL
|
7474
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL);
|
6982
7475
|
return node;
|
6983
7476
|
}
|
6984
7477
|
|
@@ -7315,22 +7808,156 @@ token_begins_expression_p(yp_token_type_t type) {
|
|
7315
7808
|
}
|
7316
7809
|
}
|
7317
7810
|
|
7318
|
-
// Parse an expression with the given binding power that may be optionally
|
7319
|
-
// prefixed by the * operator.
|
7320
|
-
static yp_node_t *
|
7321
|
-
parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) {
|
7322
|
-
if (accept(parser, YP_TOKEN_USTAR)) {
|
7323
|
-
yp_token_t operator = parser->previous;
|
7324
|
-
yp_node_t *expression = parse_expression(parser, binding_power, "Expected expression after `*'.");
|
7325
|
-
return (yp_node_t *) yp_splat_node_create(parser, &operator, expression);
|
7326
|
-
}
|
7811
|
+
// Parse an expression with the given binding power that may be optionally
|
7812
|
+
// prefixed by the * operator.
|
7813
|
+
static yp_node_t *
|
7814
|
+
parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) {
|
7815
|
+
if (accept(parser, YP_TOKEN_USTAR)) {
|
7816
|
+
yp_token_t operator = parser->previous;
|
7817
|
+
yp_node_t *expression = parse_expression(parser, binding_power, "Expected expression after `*'.");
|
7818
|
+
return (yp_node_t *) yp_splat_node_create(parser, &operator, expression);
|
7819
|
+
}
|
7820
|
+
|
7821
|
+
return parse_expression(parser, binding_power, message);
|
7822
|
+
}
|
7823
|
+
|
7824
|
+
// Convert the given node into a valid target node.
|
7825
|
+
static yp_node_t *
|
7826
|
+
parse_target(yp_parser_t *parser, yp_node_t *target) {
|
7827
|
+
switch (YP_NODE_TYPE(target)) {
|
7828
|
+
case YP_NODE_MISSING_NODE:
|
7829
|
+
return target;
|
7830
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE:
|
7831
|
+
assert(sizeof(yp_class_variable_target_node_t) == sizeof(yp_class_variable_read_node_t));
|
7832
|
+
target->type = YP_NODE_CLASS_VARIABLE_TARGET_NODE;
|
7833
|
+
return target;
|
7834
|
+
case YP_NODE_CONSTANT_PATH_NODE:
|
7835
|
+
assert(sizeof(yp_constant_path_target_node_t) == sizeof(yp_constant_path_node_t));
|
7836
|
+
target->type = YP_NODE_CONSTANT_PATH_TARGET_NODE;
|
7837
|
+
return target;
|
7838
|
+
case YP_NODE_CONSTANT_READ_NODE:
|
7839
|
+
assert(sizeof(yp_constant_target_node_t) == sizeof(yp_constant_read_node_t));
|
7840
|
+
target->type = YP_NODE_CONSTANT_TARGET_NODE;
|
7841
|
+
return target;
|
7842
|
+
case YP_NODE_BACK_REFERENCE_READ_NODE:
|
7843
|
+
assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_back_reference_read_node_t));
|
7844
|
+
/* fallthrough */
|
7845
|
+
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
7846
|
+
assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_numbered_reference_read_node_t));
|
7847
|
+
yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable");
|
7848
|
+
/* fallthrough */
|
7849
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE:
|
7850
|
+
assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_global_variable_read_node_t));
|
7851
|
+
target->type = YP_NODE_GLOBAL_VARIABLE_TARGET_NODE;
|
7852
|
+
return target;
|
7853
|
+
case YP_NODE_LOCAL_VARIABLE_READ_NODE:
|
7854
|
+
assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t));
|
7855
|
+
target->type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE;
|
7856
|
+
return target;
|
7857
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE:
|
7858
|
+
assert(sizeof(yp_instance_variable_target_node_t) == sizeof(yp_instance_variable_read_node_t));
|
7859
|
+
target->type = YP_NODE_INSTANCE_VARIABLE_TARGET_NODE;
|
7860
|
+
return target;
|
7861
|
+
case YP_NODE_MULTI_WRITE_NODE:
|
7862
|
+
return target;
|
7863
|
+
case YP_NODE_SPLAT_NODE: {
|
7864
|
+
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
7865
|
+
|
7866
|
+
if (splat->expression != NULL) {
|
7867
|
+
splat->expression = parse_target(parser, splat->expression);
|
7868
|
+
}
|
7327
7869
|
|
7328
|
-
|
7870
|
+
yp_token_t operator = not_provided(parser);
|
7871
|
+
yp_location_t location = { .start = NULL, .end = NULL };
|
7872
|
+
|
7873
|
+
yp_multi_write_node_t *multi_write = yp_multi_write_node_create(parser, &operator, NULL, &location, &location);
|
7874
|
+
yp_multi_write_node_targets_append(multi_write, (yp_node_t *) splat);
|
7875
|
+
|
7876
|
+
return (yp_node_t *) multi_write;
|
7877
|
+
}
|
7878
|
+
case YP_NODE_CALL_NODE: {
|
7879
|
+
yp_call_node_t *call = (yp_call_node_t *) target;
|
7880
|
+
|
7881
|
+
// If we have no arguments to the call node and we need this to be a
|
7882
|
+
// target then this is either a method call or a local variable write.
|
7883
|
+
if (
|
7884
|
+
(call->opening_loc.start == NULL) &&
|
7885
|
+
(call->arguments == NULL) &&
|
7886
|
+
(call->block == NULL)
|
7887
|
+
) {
|
7888
|
+
if (call->receiver == NULL) {
|
7889
|
+
// When we get here, we have a local variable write, because it
|
7890
|
+
// was previously marked as a method call but now we have an =.
|
7891
|
+
// This looks like:
|
7892
|
+
//
|
7893
|
+
// foo = 1
|
7894
|
+
//
|
7895
|
+
// When it was parsed in the prefix position, foo was seen as a
|
7896
|
+
// method call with no receiver and no arguments. Now we have an
|
7897
|
+
// =, so we know it's a local variable write.
|
7898
|
+
const yp_location_t message = call->message_loc;
|
7899
|
+
|
7900
|
+
yp_parser_local_add_location(parser, message.start, message.end);
|
7901
|
+
yp_node_destroy(parser, target);
|
7902
|
+
|
7903
|
+
const yp_token_t name = { .type = YP_TOKEN_IDENTIFIER, .start = message.start, .end = message.end };
|
7904
|
+
target = (yp_node_t *) yp_local_variable_read_node_create(parser, &name, 0);
|
7905
|
+
|
7906
|
+
assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t));
|
7907
|
+
target->type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE;
|
7908
|
+
|
7909
|
+
if (token_is_numbered_parameter(message.start, message.end)) {
|
7910
|
+
yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter");
|
7911
|
+
}
|
7912
|
+
|
7913
|
+
return target;
|
7914
|
+
}
|
7915
|
+
|
7916
|
+
// The method name needs to change. If we previously had foo, we now
|
7917
|
+
// need foo=. In this case we'll allocate a new owned string, copy
|
7918
|
+
// the previous method name in, and append an =.
|
7919
|
+
size_t length = yp_string_length(&call->name);
|
7920
|
+
|
7921
|
+
char *name = calloc(length + 2, sizeof(char));
|
7922
|
+
if (name == NULL) return NULL;
|
7923
|
+
|
7924
|
+
snprintf(name, length + 2, "%.*s=", (int) length, yp_string_source(&call->name));
|
7925
|
+
|
7926
|
+
// Now switch the name to the new string.
|
7927
|
+
yp_string_free(&call->name);
|
7928
|
+
yp_string_owned_init(&call->name, name, length + 1);
|
7929
|
+
|
7930
|
+
return target;
|
7931
|
+
}
|
7932
|
+
|
7933
|
+
// If there is no call operator and the message is "[]" then this is
|
7934
|
+
// an aref expression, and we can transform it into an aset
|
7935
|
+
// expression.
|
7936
|
+
if (
|
7937
|
+
(call->operator_loc.start == NULL) &&
|
7938
|
+
(call->message_loc.start[0] == '[') &&
|
7939
|
+
(call->message_loc.end[-1] == ']') &&
|
7940
|
+
(call->block == NULL)
|
7941
|
+
) {
|
7942
|
+
// Free the previous name and replace it with "[]=".
|
7943
|
+
yp_string_free(&call->name);
|
7944
|
+
yp_string_constant_init(&call->name, "[]=", 3);
|
7945
|
+
return target;
|
7946
|
+
}
|
7947
|
+
}
|
7948
|
+
/* fallthrough */
|
7949
|
+
default:
|
7950
|
+
// In this case we have a node that we don't know how to convert
|
7951
|
+
// into a target. We need to treat it as an error. For now, we'll
|
7952
|
+
// mark it as an error and just skip right past it.
|
7953
|
+
yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Unexpected write target.");
|
7954
|
+
return target;
|
7955
|
+
}
|
7329
7956
|
}
|
7330
7957
|
|
7331
|
-
// Convert the given node into a valid
|
7958
|
+
// Convert the given node into a valid write node.
|
7332
7959
|
static yp_node_t *
|
7333
|
-
|
7960
|
+
parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
|
7334
7961
|
switch (YP_NODE_TYPE(target)) {
|
7335
7962
|
case YP_NODE_MISSING_NODE:
|
7336
7963
|
return target;
|
@@ -7377,18 +8004,15 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7377
8004
|
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
|
7378
8005
|
yp_multi_write_node_operator_loc_set(multi_write, operator);
|
7379
8006
|
|
7380
|
-
|
7381
|
-
|
7382
|
-
multi_write->base.location.end = value->location.end;
|
7383
|
-
}
|
7384
|
-
|
8007
|
+
multi_write->value = value;
|
8008
|
+
multi_write->base.location.end = value->location.end;
|
7385
8009
|
return (yp_node_t *) multi_write;
|
7386
8010
|
}
|
7387
8011
|
case YP_NODE_SPLAT_NODE: {
|
7388
8012
|
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
7389
8013
|
|
7390
8014
|
if (splat->expression != NULL) {
|
7391
|
-
splat->expression =
|
8015
|
+
splat->expression = parse_write(parser, splat->expression, operator, value);
|
7392
8016
|
}
|
7393
8017
|
|
7394
8018
|
yp_location_t location = { .start = NULL, .end = NULL };
|
@@ -7441,12 +8065,10 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7441
8065
|
// method call with no arguments. Now we have an =, so we know it's
|
7442
8066
|
// a method call with an argument. In this case we will create the
|
7443
8067
|
// arguments node, parse the argument, and add it to the list.
|
7444
|
-
|
7445
|
-
|
7446
|
-
|
7447
|
-
|
7448
|
-
target->location.end = arguments->base.location.end;
|
7449
|
-
}
|
8068
|
+
yp_arguments_node_t *arguments = yp_arguments_node_create(parser);
|
8069
|
+
call->arguments = arguments;
|
8070
|
+
yp_arguments_node_arguments_append(arguments, value);
|
8071
|
+
target->location.end = arguments->base.location.end;
|
7450
8072
|
|
7451
8073
|
// The method name needs to change. If we previously had foo, we now
|
7452
8074
|
// need foo=. In this case we'll allocate a new owned string, copy
|
@@ -7474,15 +8096,13 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7474
8096
|
(call->message_loc.end[-1] == ']') &&
|
7475
8097
|
(call->block == NULL)
|
7476
8098
|
) {
|
7477
|
-
if (
|
7478
|
-
|
7479
|
-
call->arguments = yp_arguments_node_create(parser);
|
7480
|
-
}
|
7481
|
-
|
7482
|
-
yp_arguments_node_arguments_append(call->arguments, value);
|
7483
|
-
target->location.end = value->location.end;
|
8099
|
+
if (call->arguments == NULL) {
|
8100
|
+
call->arguments = yp_arguments_node_create(parser);
|
7484
8101
|
}
|
7485
8102
|
|
8103
|
+
yp_arguments_node_arguments_append(call->arguments, value);
|
8104
|
+
target->location.end = value->location.end;
|
8105
|
+
|
7486
8106
|
// Free the previous name and replace it with "[]=".
|
7487
8107
|
yp_string_free(&call->name);
|
7488
8108
|
yp_string_constant_init(&call->name, "[]=", 3);
|
@@ -7494,9 +8114,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7494
8114
|
// syntax error. In this case we'll fall through to our default
|
7495
8115
|
// handling. We need to free the value that we parsed because there
|
7496
8116
|
// is no way for us to attach it to the tree at this point.
|
7497
|
-
|
7498
|
-
yp_node_destroy(parser, value);
|
7499
|
-
}
|
8117
|
+
yp_node_destroy(parser, value);
|
7500
8118
|
}
|
7501
8119
|
/* fallthrough */
|
7502
8120
|
default:
|
@@ -7524,7 +8142,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7524
8142
|
// location that we know requires a multi write, as in the case of a for loop.
|
7525
8143
|
// In this case we will set up the parsing loop slightly differently.
|
7526
8144
|
if (first_target != NULL) {
|
7527
|
-
first_target = parse_target(parser, first_target
|
8145
|
+
first_target = parse_target(parser, first_target);
|
7528
8146
|
|
7529
8147
|
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
|
7530
8148
|
return first_target;
|
@@ -7555,9 +8173,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7555
8173
|
yp_node_t *name = NULL;
|
7556
8174
|
|
7557
8175
|
if (token_begins_expression_p(parser->current.type)) {
|
7558
|
-
yp_token_t operator = not_provided(parser);
|
7559
8176
|
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
|
7560
|
-
name = parse_target(parser, name
|
8177
|
+
name = parse_target(parser, name);
|
7561
8178
|
}
|
7562
8179
|
|
7563
8180
|
yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name);
|
@@ -7587,6 +8204,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7587
8204
|
|
7588
8205
|
if (YP_NODE_TYPE_P(child_target, YP_NODE_MULTI_WRITE_NODE)) {
|
7589
8206
|
target = (yp_multi_write_node_t *) child_target;
|
8207
|
+
target->base.location.start = lparen.start;
|
8208
|
+
target->base.location.end = rparen.end;
|
7590
8209
|
target->lparen_loc = (yp_location_t) { .start = lparen.start, .end = lparen.end };
|
7591
8210
|
target->rparen_loc = (yp_location_t) { .start = rparen.start, .end = rparen.end };
|
7592
8211
|
} else {
|
@@ -7603,6 +8222,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7603
8222
|
yp_multi_write_node_targets_append(target, child_target);
|
7604
8223
|
}
|
7605
8224
|
|
8225
|
+
target->base.location.start = lparen.start;
|
7606
8226
|
target->base.location.end = rparen.end;
|
7607
8227
|
yp_multi_write_node_targets_append(result, (yp_node_t *) target);
|
7608
8228
|
}
|
@@ -7625,7 +8245,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7625
8245
|
}
|
7626
8246
|
|
7627
8247
|
yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','.");
|
7628
|
-
target = parse_target(parser, target
|
8248
|
+
target = parse_target(parser, target);
|
7629
8249
|
|
7630
8250
|
yp_multi_write_node_targets_append(result, target);
|
7631
8251
|
}
|
@@ -8085,7 +8705,6 @@ parse_parameters(
|
|
8085
8705
|
bool looping = true;
|
8086
8706
|
|
8087
8707
|
yp_do_loop_stack_push(parser, false);
|
8088
|
-
|
8089
8708
|
yp_parameters_order_t order = YP_PARAMETERS_ORDER_NONE;
|
8090
8709
|
|
8091
8710
|
do {
|
@@ -8377,8 +8996,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8377
8996
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
8378
8997
|
|
8379
8998
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
8380
|
-
|
8381
|
-
reference = parse_target(parser, reference, &operator, NULL);
|
8999
|
+
reference = parse_target(parser, reference);
|
8382
9000
|
|
8383
9001
|
yp_rescue_node_reference_set(rescue, reference);
|
8384
9002
|
break;
|
@@ -8408,8 +9026,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8408
9026
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
8409
9027
|
|
8410
9028
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
8411
|
-
|
8412
|
-
reference = parse_target(parser, reference, &operator, NULL);
|
9029
|
+
reference = parse_target(parser, reference);
|
8413
9030
|
|
8414
9031
|
yp_rescue_node_reference_set(rescue, reference);
|
8415
9032
|
break;
|
@@ -8961,14 +9578,10 @@ parse_string_part(yp_parser_t *parser) {
|
|
8961
9578
|
|
8962
9579
|
static yp_node_t *
|
8963
9580
|
parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_state) {
|
8964
|
-
bool lex_string = lex_mode->mode == YP_LEX_STRING;
|
8965
|
-
bool can_be_interpolated = lex_string && lex_mode->as.string.interpolation;
|
8966
9581
|
yp_token_t opening = parser->previous;
|
8967
9582
|
|
8968
|
-
if (
|
8969
|
-
if (next_state != YP_LEX_STATE_NONE)
|
8970
|
-
lex_state_set(parser, next_state);
|
8971
|
-
}
|
9583
|
+
if (lex_mode->mode != YP_LEX_STRING) {
|
9584
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
8972
9585
|
yp_token_t symbol;
|
8973
9586
|
|
8974
9587
|
switch (parser->current.type) {
|
@@ -8998,37 +9611,44 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s
|
|
8998
9611
|
return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &symbol, &closing, YP_UNESCAPE_ALL);
|
8999
9612
|
}
|
9000
9613
|
|
9001
|
-
if (
|
9002
|
-
//
|
9003
|
-
|
9614
|
+
if (lex_mode->as.string.interpolation) {
|
9615
|
+
// If we have the end of the symbol, then we can return an empty symbol.
|
9616
|
+
if (match_type_p(parser, YP_TOKEN_STRING_END)) {
|
9617
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9618
|
+
parser_lex(parser);
|
9619
|
+
|
9620
|
+
yp_token_t content = not_provided(parser);
|
9621
|
+
yp_token_t closing = parser->previous;
|
9622
|
+
return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &closing, YP_UNESCAPE_NONE);
|
9623
|
+
}
|
9624
|
+
|
9625
|
+
// Now we can parse the first part of the symbol.
|
9626
|
+
yp_node_t *part = parse_string_part(parser);
|
9627
|
+
|
9628
|
+
// If we got a string part, then it's possible that we could transform
|
9629
|
+
// what looks like an interpolated symbol into a regular symbol.
|
9630
|
+
if (part && YP_NODE_TYPE_P(part, YP_NODE_STRING_NODE) && match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
9631
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9632
|
+
parser_lex(parser);
|
9633
|
+
|
9634
|
+
return (yp_node_t *) yp_string_node_to_symbol_node(parser, (yp_string_node_t *) part, &opening, &parser->previous);
|
9635
|
+
}
|
9636
|
+
|
9637
|
+
// Create a node_list first. We'll use this to check if it should be an
|
9638
|
+
// InterpolatedSymbolNode or a SymbolNode.
|
9004
9639
|
yp_node_list_t node_list = YP_EMPTY_NODE_LIST;
|
9640
|
+
if (part) yp_node_list_append(&node_list, part);
|
9005
9641
|
|
9006
9642
|
while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
9007
|
-
|
9008
|
-
if (part != NULL) {
|
9643
|
+
if ((part = parse_string_part(parser)) != NULL) {
|
9009
9644
|
yp_node_list_append(&node_list, part);
|
9010
9645
|
}
|
9011
9646
|
}
|
9012
9647
|
|
9013
|
-
|
9014
|
-
// If the only element on the node_list is a StringNode, we know this is a SymbolNode
|
9015
|
-
// and not an InterpolatedSymbolNode
|
9016
|
-
if (node_list.size == 1 && YP_NODE_TYPE_P(node_list.nodes[0], YP_NODE_STRING_NODE)) {
|
9017
|
-
res = (yp_node_t *)yp_string_node_to_symbol_node(parser, (yp_string_node_t *)node_list.nodes[0]);
|
9018
|
-
free(node_list.nodes);
|
9019
|
-
}
|
9020
|
-
else {
|
9021
|
-
yp_interpolated_symbol_node_t *interpolated = yp_interpolated_symbol_node_create(parser, &opening, &node_list, &opening);
|
9022
|
-
yp_interpolated_symbol_node_closing_set(interpolated, &parser->current);
|
9023
|
-
res = (yp_node_t *) interpolated;
|
9024
|
-
}
|
9025
|
-
|
9026
|
-
if (next_state != YP_LEX_STATE_NONE) {
|
9027
|
-
lex_state_set(parser, next_state);
|
9028
|
-
}
|
9648
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9029
9649
|
expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated symbol.");
|
9030
9650
|
|
9031
|
-
return
|
9651
|
+
return (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &node_list, &parser->previous);
|
9032
9652
|
}
|
9033
9653
|
|
9034
9654
|
yp_token_t content;
|
@@ -9172,9 +9792,12 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) {
|
|
9172
9792
|
const char *cur_char = content_loc->start;
|
9173
9793
|
|
9174
9794
|
while (cur_char && cur_char < content_loc->end) {
|
9175
|
-
// Any empty newlines aren't included in the minimum whitespace
|
9176
|
-
|
9177
|
-
|
9795
|
+
// Any empty newlines aren't included in the minimum whitespace
|
9796
|
+
// calculation.
|
9797
|
+
size_t eol_length;
|
9798
|
+
while ((eol_length = match_eol_at(parser, cur_char))) {
|
9799
|
+
cur_char += eol_length;
|
9800
|
+
}
|
9178
9801
|
|
9179
9802
|
if (cur_char == content_loc->end) break;
|
9180
9803
|
|
@@ -9189,11 +9812,12 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) {
|
|
9189
9812
|
cur_char++;
|
9190
9813
|
}
|
9191
9814
|
|
9192
|
-
// If we hit a newline, then we have encountered a line that
|
9193
|
-
// only whitespace, and it shouldn't be considered in
|
9194
|
-
// common leading whitespace.
|
9195
|
-
|
9196
|
-
|
9815
|
+
// If we hit a newline, then we have encountered a line that
|
9816
|
+
// contains only whitespace, and it shouldn't be considered in
|
9817
|
+
// the calculation of common leading whitespace.
|
9818
|
+
eol_length = match_eol_at(parser, cur_char);
|
9819
|
+
if (eol_length) {
|
9820
|
+
cur_char += eol_length;
|
9197
9821
|
continue;
|
9198
9822
|
}
|
9199
9823
|
|
@@ -9314,7 +9938,7 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9314
9938
|
yp_node_destroy(parser, node);
|
9315
9939
|
} else {
|
9316
9940
|
string->length = dest_length;
|
9317
|
-
yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL
|
9941
|
+
yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL);
|
9318
9942
|
nodes->nodes[write_index++] = node;
|
9319
9943
|
}
|
9320
9944
|
|
@@ -10071,10 +10695,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10071
10695
|
}
|
10072
10696
|
case YP_TOKEN_PARENTHESIS_LEFT:
|
10073
10697
|
case YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
|
10074
|
-
|
10698
|
+
yp_token_t opening = parser->current;
|
10075
10699
|
parser_lex(parser);
|
10076
|
-
|
10077
|
-
yp_token_t opening = parser->previous;
|
10078
10700
|
while (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE));
|
10079
10701
|
|
10080
10702
|
// If this is the end of the file or we match a right parenthesis, then
|
@@ -10093,7 +10715,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10093
10715
|
// If we hit a right parenthesis, then we're done parsing the parentheses
|
10094
10716
|
// node, and we can check which kind of node we should return.
|
10095
10717
|
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
10096
|
-
if (
|
10718
|
+
if (opening.type == YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
|
10097
10719
|
lex_state_set(parser, YP_LEX_STATE_ENDARG);
|
10098
10720
|
}
|
10099
10721
|
parser_lex(parser);
|
@@ -10111,6 +10733,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10111
10733
|
|
10112
10734
|
if (multi_statement->lparen_loc.start == NULL) {
|
10113
10735
|
multi_write = (yp_multi_write_node_t *) statement;
|
10736
|
+
multi_write->base.location.start = lparen_loc.start;
|
10737
|
+
multi_write->base.location.end = rparen_loc.end;
|
10114
10738
|
multi_write->lparen_loc = lparen_loc;
|
10115
10739
|
multi_write->rparen_loc = rparen_loc;
|
10116
10740
|
} else {
|
@@ -10213,7 +10837,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10213
10837
|
// fact a method call, not a constant read.
|
10214
10838
|
if (
|
10215
10839
|
match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) ||
|
10216
|
-
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser,
|
10840
|
+
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) ||
|
10217
10841
|
(yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT))
|
10218
10842
|
) {
|
10219
10843
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
@@ -10336,7 +10960,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10336
10960
|
// can still be a method call if it is followed by arguments or
|
10337
10961
|
// a block, so we need to check for that here.
|
10338
10962
|
if (
|
10339
|
-
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser,
|
10963
|
+
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) ||
|
10340
10964
|
(yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT))
|
10341
10965
|
) {
|
10342
10966
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
@@ -10754,7 +11378,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10754
11378
|
return (yp_node_t *) yp_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
|
10755
11379
|
}
|
10756
11380
|
|
10757
|
-
yp_node_t *
|
11381
|
+
yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a class name after `class`.");
|
11382
|
+
yp_token_t name = parser->previous;
|
11383
|
+
if (name.type != YP_TOKEN_CONSTANT) {
|
11384
|
+
yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected a constant name after `class`.");
|
11385
|
+
}
|
11386
|
+
|
10758
11387
|
yp_token_t inheritance_operator;
|
10759
11388
|
yp_node_t *superclass;
|
10760
11389
|
|
@@ -10795,7 +11424,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10795
11424
|
yp_constant_id_list_t locals = parser->current_scope->locals;
|
10796
11425
|
yp_parser_scope_pop(parser);
|
10797
11426
|
yp_do_loop_stack_pop(parser);
|
10798
|
-
return (yp_node_t *) yp_class_node_create(parser, &locals, &class_keyword, name, &inheritance_operator, superclass, statements, &parser->previous);
|
11427
|
+
return (yp_node_t *) yp_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->previous);
|
10799
11428
|
}
|
10800
11429
|
case YP_TOKEN_KEYWORD_DEF: {
|
10801
11430
|
yp_token_t def_keyword = parser->current;
|
@@ -10954,6 +11583,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10954
11583
|
break;
|
10955
11584
|
}
|
10956
11585
|
case YP_CASE_PARAMETER: {
|
11586
|
+
// If we're about to lex a label, we need to add the label
|
11587
|
+
// state to make sure the next newline is ignored.
|
11588
|
+
if (parser->current.type == YP_TOKEN_LABEL) {
|
11589
|
+
lex_state_set(parser, parser->lex_state | YP_LEX_STATE_LABEL);
|
11590
|
+
}
|
11591
|
+
|
10957
11592
|
lparen = not_provided(parser);
|
10958
11593
|
rparen = not_provided(parser);
|
10959
11594
|
params = parse_parameters(parser, YP_BINDING_POWER_DEFINED, false, false, true);
|
@@ -11183,13 +11818,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11183
11818
|
parser_lex(parser);
|
11184
11819
|
|
11185
11820
|
yp_token_t module_keyword = parser->previous;
|
11186
|
-
yp_node_t *
|
11821
|
+
yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a module name after `module`.");
|
11822
|
+
yp_token_t name;
|
11187
11823
|
|
11188
|
-
// If we can recover from a syntax error that occurred while parsing
|
11189
|
-
// name of the module, then we'll handle that here.
|
11190
|
-
if (YP_NODE_TYPE_P(
|
11191
|
-
yp_token_t
|
11192
|
-
return (yp_node_t *) yp_module_node_create(parser, NULL, &module_keyword,
|
11824
|
+
// If we can recover from a syntax error that occurred while parsing
|
11825
|
+
// the name of the module, then we'll handle that here.
|
11826
|
+
if (YP_NODE_TYPE_P(constant_path, YP_NODE_MISSING_NODE)) {
|
11827
|
+
yp_token_t missing = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
|
11828
|
+
return (yp_node_t *) yp_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
|
11193
11829
|
}
|
11194
11830
|
|
11195
11831
|
while (accept(parser, YP_TOKEN_COLON_COLON)) {
|
@@ -11198,7 +11834,15 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11198
11834
|
expect(parser, YP_TOKEN_CONSTANT, "Expected to find a module name after `::`.");
|
11199
11835
|
yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous);
|
11200
11836
|
|
11201
|
-
|
11837
|
+
constant_path = (yp_node_t *) yp_constant_path_node_create(parser, constant_path, &double_colon, constant);
|
11838
|
+
}
|
11839
|
+
|
11840
|
+
// Here we retrieve the name of the module. If it wasn't a constant,
|
11841
|
+
// then it's possible that `module foo` was passed, which is a
|
11842
|
+
// syntax error. We handle that here as well.
|
11843
|
+
name = parser->previous;
|
11844
|
+
if (name.type != YP_TOKEN_CONSTANT) {
|
11845
|
+
yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected to find a module name after `module`.");
|
11202
11846
|
}
|
11203
11847
|
|
11204
11848
|
yp_parser_scope_push(parser, true);
|
@@ -11225,7 +11869,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11225
11869
|
yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, "Module definition in method body");
|
11226
11870
|
}
|
11227
11871
|
|
11228
|
-
return (yp_node_t *) yp_module_node_create(parser, &locals, &module_keyword, name, statements, &parser->previous);
|
11872
|
+
return (yp_node_t *) yp_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous);
|
11229
11873
|
}
|
11230
11874
|
case YP_TOKEN_KEYWORD_NIL:
|
11231
11875
|
parser_lex(parser);
|
@@ -11261,12 +11905,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11261
11905
|
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `until` statement.");
|
11262
11906
|
}
|
11263
11907
|
|
11264
|
-
|
11265
|
-
if (parser->previous.type == YP_TOKEN_KEYWORD_END) {
|
11266
|
-
until_node->base.location.end = parser->previous.end;
|
11267
|
-
}
|
11268
|
-
|
11269
|
-
return (yp_node_t *) until_node;
|
11908
|
+
return (yp_node_t *) yp_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
|
11270
11909
|
}
|
11271
11910
|
case YP_TOKEN_KEYWORD_WHILE: {
|
11272
11911
|
yp_do_loop_stack_push(parser, true);
|
@@ -11287,11 +11926,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11287
11926
|
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `while` statement.");
|
11288
11927
|
}
|
11289
11928
|
|
11290
|
-
|
11291
|
-
if (parser->previous.type == YP_TOKEN_KEYWORD_END) {
|
11292
|
-
while_node->base.location.end = parser->previous.end;
|
11293
|
-
}
|
11294
|
-
return (yp_node_t *) while_node;
|
11929
|
+
return (yp_node_t *) yp_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
|
11295
11930
|
}
|
11296
11931
|
case YP_TOKEN_PERCENT_LOWER_I: {
|
11297
11932
|
parser_lex(parser);
|
@@ -11797,30 +12432,32 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11797
12432
|
yp_accepts_block_stack_push(parser, true);
|
11798
12433
|
parser_lex(parser);
|
11799
12434
|
|
11800
|
-
yp_token_t
|
12435
|
+
yp_token_t operator = parser->previous;
|
11801
12436
|
yp_parser_scope_push(parser, false);
|
11802
12437
|
yp_block_parameters_node_t *params;
|
11803
12438
|
|
11804
12439
|
switch (parser->current.type) {
|
11805
12440
|
case YP_TOKEN_PARENTHESIS_LEFT: {
|
11806
|
-
yp_token_t
|
12441
|
+
yp_token_t opening = parser->current;
|
11807
12442
|
parser_lex(parser);
|
11808
12443
|
|
11809
12444
|
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
11810
|
-
params = yp_block_parameters_node_create(parser, NULL, &
|
12445
|
+
params = yp_block_parameters_node_create(parser, NULL, &opening);
|
11811
12446
|
} else {
|
11812
|
-
params = parse_block_parameters(parser, false, &
|
12447
|
+
params = parse_block_parameters(parser, false, &opening, true);
|
11813
12448
|
}
|
11814
12449
|
|
11815
12450
|
accept(parser, YP_TOKEN_NEWLINE);
|
11816
12451
|
expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis.");
|
11817
|
-
yp_block_parameters_node_closing_set(params, &parser->previous);
|
11818
12452
|
|
12453
|
+
yp_block_parameters_node_closing_set(params, &parser->previous);
|
11819
12454
|
break;
|
11820
12455
|
}
|
11821
12456
|
case YP_CASE_PARAMETER: {
|
12457
|
+
yp_accepts_block_stack_push(parser, false);
|
11822
12458
|
yp_token_t opening = not_provided(parser);
|
11823
12459
|
params = parse_block_parameters(parser, false, &opening, true);
|
12460
|
+
yp_accepts_block_stack_pop(parser);
|
11824
12461
|
break;
|
11825
12462
|
}
|
11826
12463
|
default: {
|
@@ -11829,16 +12466,20 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11829
12466
|
}
|
11830
12467
|
}
|
11831
12468
|
|
12469
|
+
yp_token_t opening;
|
11832
12470
|
yp_node_t *body = NULL;
|
11833
12471
|
parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
|
11834
12472
|
|
11835
12473
|
if (accept(parser, YP_TOKEN_LAMBDA_BEGIN)) {
|
12474
|
+
opening = parser->previous;
|
12475
|
+
|
11836
12476
|
if (!accept(parser, YP_TOKEN_BRACE_RIGHT)) {
|
11837
12477
|
body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_BRACES);
|
11838
12478
|
expect(parser, YP_TOKEN_BRACE_RIGHT, "Expecting '}' to close lambda block.");
|
11839
12479
|
}
|
11840
12480
|
} else {
|
11841
12481
|
expect(parser, YP_TOKEN_KEYWORD_DO, "Expected a 'do' keyword or a '{' to open lambda block.");
|
12482
|
+
opening = parser->previous;
|
11842
12483
|
|
11843
12484
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
11844
12485
|
body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_DO_END);
|
@@ -11855,7 +12496,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11855
12496
|
yp_constant_id_list_t locals = parser->current_scope->locals;
|
11856
12497
|
yp_parser_scope_pop(parser);
|
11857
12498
|
yp_accepts_block_stack_pop(parser);
|
11858
|
-
return (yp_node_t *) yp_lambda_node_create(parser, &locals, &
|
12499
|
+
return (yp_node_t *) yp_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, params, body);
|
11859
12500
|
}
|
11860
12501
|
case YP_TOKEN_UPLUS: {
|
11861
12502
|
parser_lex(parser);
|
@@ -12074,7 +12715,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12074
12715
|
case YP_CASE_WRITABLE: {
|
12075
12716
|
parser_lex(parser);
|
12076
12717
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
12077
|
-
return
|
12718
|
+
return parse_write(parser, node, &token, value);
|
12078
12719
|
}
|
12079
12720
|
case YP_NODE_SPLAT_NODE: {
|
12080
12721
|
yp_splat_node_t *splat_node = (yp_splat_node_t *) node;
|
@@ -12083,7 +12724,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12083
12724
|
case YP_CASE_WRITABLE:
|
12084
12725
|
parser_lex(parser);
|
12085
12726
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
12086
|
-
return
|
12727
|
+
return parse_write(parser, (yp_node_t *) splat_node, &token, value);
|
12087
12728
|
default:
|
12088
12729
|
break;
|
12089
12730
|
}
|
@@ -12105,19 +12746,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12105
12746
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
12106
12747
|
yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
|
12107
12748
|
/* fallthrough */
|
12108
|
-
case
|
12109
|
-
|
12110
|
-
|
12111
|
-
|
12112
|
-
|
12113
|
-
|
12749
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
12750
|
+
parser_lex(parser);
|
12751
|
+
|
12752
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12753
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_and_write_node_create(parser, node, &token, value);
|
12754
|
+
|
12755
|
+
yp_node_destroy(parser, node);
|
12756
|
+
return result;
|
12757
|
+
}
|
12758
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12759
|
+
parser_lex(parser);
|
12760
|
+
|
12761
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12762
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_and_write_node_create(parser, node, &token, value);
|
12763
|
+
|
12764
|
+
yp_node_destroy(parser, node);
|
12765
|
+
return result;
|
12766
|
+
}
|
12767
|
+
case YP_NODE_CONSTANT_PATH_NODE: {
|
12768
|
+
parser_lex(parser);
|
12769
|
+
|
12770
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12771
|
+
return (yp_node_t *) yp_constant_path_and_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
12772
|
+
}
|
12773
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
12774
|
+
parser_lex(parser);
|
12775
|
+
|
12776
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12777
|
+
yp_node_t *result = (yp_node_t *) yp_constant_and_write_node_create(parser, node, &token, value);
|
12778
|
+
|
12779
|
+
yp_node_destroy(parser, node);
|
12780
|
+
return result;
|
12781
|
+
}
|
12782
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
12114
12783
|
parser_lex(parser);
|
12115
12784
|
|
12116
|
-
|
12117
|
-
|
12785
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12786
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_and_write_node_create(parser, node, &token, value);
|
12787
|
+
|
12788
|
+
yp_node_destroy(parser, node);
|
12789
|
+
return result;
|
12790
|
+
}
|
12791
|
+
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
12792
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12793
|
+
parser_lex(parser);
|
12118
12794
|
|
12119
12795
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12120
|
-
|
12796
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, cast->constant_id, cast->depth);
|
12797
|
+
|
12798
|
+
yp_node_destroy(parser, node);
|
12799
|
+
return result;
|
12121
12800
|
}
|
12122
12801
|
case YP_NODE_CALL_NODE: {
|
12123
12802
|
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
@@ -12127,25 +12806,22 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12127
12806
|
// will transform it into a local variable write.
|
12128
12807
|
if (yp_call_node_variable_call_p(call_node)) {
|
12129
12808
|
yp_location_t message_loc = call_node->message_loc;
|
12130
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12809
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12131
12810
|
|
12132
12811
|
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12133
12812
|
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12134
12813
|
}
|
12135
12814
|
|
12136
12815
|
parser_lex(parser);
|
12137
|
-
|
12138
|
-
yp_token_t operator = not_provided(parser);
|
12139
|
-
node = parse_target(parser, node, &operator, NULL);
|
12140
|
-
|
12141
12816
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12142
|
-
|
12817
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, constant_id, 0);
|
12818
|
+
|
12819
|
+
yp_node_destroy(parser, node);
|
12820
|
+
return result;
|
12143
12821
|
}
|
12144
12822
|
|
12145
12823
|
parser_lex(parser);
|
12146
|
-
|
12147
|
-
yp_token_t operator = not_provided(parser);
|
12148
|
-
node = parse_target(parser, node, &operator, NULL);
|
12824
|
+
node = parse_target(parser, node);
|
12149
12825
|
|
12150
12826
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12151
12827
|
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
@@ -12171,19 +12847,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12171
12847
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
12172
12848
|
yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
|
12173
12849
|
/* fallthrough */
|
12174
|
-
case
|
12175
|
-
|
12176
|
-
|
12177
|
-
|
12178
|
-
|
12179
|
-
|
12850
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
12851
|
+
parser_lex(parser);
|
12852
|
+
|
12853
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12854
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_or_write_node_create(parser, node, &token, value);
|
12855
|
+
|
12856
|
+
yp_node_destroy(parser, node);
|
12857
|
+
return result;
|
12858
|
+
}
|
12859
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12860
|
+
parser_lex(parser);
|
12861
|
+
|
12862
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12863
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_or_write_node_create(parser, node, &token, value);
|
12864
|
+
|
12865
|
+
yp_node_destroy(parser, node);
|
12866
|
+
return result;
|
12867
|
+
}
|
12868
|
+
case YP_NODE_CONSTANT_PATH_NODE: {
|
12869
|
+
parser_lex(parser);
|
12870
|
+
|
12871
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12872
|
+
return (yp_node_t *) yp_constant_path_or_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
12873
|
+
}
|
12874
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
12875
|
+
parser_lex(parser);
|
12876
|
+
|
12877
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12878
|
+
yp_node_t *result = (yp_node_t *) yp_constant_or_write_node_create(parser, node, &token, value);
|
12879
|
+
|
12880
|
+
yp_node_destroy(parser, node);
|
12881
|
+
return result;
|
12882
|
+
}
|
12883
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
12180
12884
|
parser_lex(parser);
|
12181
12885
|
|
12182
|
-
|
12183
|
-
|
12886
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12887
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_or_write_node_create(parser, node, &token, value);
|
12888
|
+
|
12889
|
+
yp_node_destroy(parser, node);
|
12890
|
+
return result;
|
12891
|
+
}
|
12892
|
+
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
12893
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12894
|
+
parser_lex(parser);
|
12184
12895
|
|
12185
12896
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12186
|
-
|
12897
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, cast->constant_id, cast->depth);
|
12898
|
+
|
12899
|
+
yp_node_destroy(parser, node);
|
12900
|
+
return result;
|
12187
12901
|
}
|
12188
12902
|
case YP_NODE_CALL_NODE: {
|
12189
12903
|
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
@@ -12193,25 +12907,22 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12193
12907
|
// will transform it into a local variable write.
|
12194
12908
|
if (yp_call_node_variable_call_p(call_node)) {
|
12195
12909
|
yp_location_t message_loc = call_node->message_loc;
|
12196
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12910
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12197
12911
|
|
12198
12912
|
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12199
12913
|
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12200
12914
|
}
|
12201
12915
|
|
12202
12916
|
parser_lex(parser);
|
12203
|
-
|
12204
|
-
yp_token_t operator = not_provided(parser);
|
12205
|
-
node = parse_target(parser, node, &operator, NULL);
|
12206
|
-
|
12207
12917
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12208
|
-
|
12918
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, constant_id, 0);
|
12919
|
+
|
12920
|
+
yp_node_destroy(parser, node);
|
12921
|
+
return result;
|
12209
12922
|
}
|
12210
12923
|
|
12211
12924
|
parser_lex(parser);
|
12212
|
-
|
12213
|
-
yp_token_t operator = not_provided(parser);
|
12214
|
-
node = parse_target(parser, node, &operator, NULL);
|
12925
|
+
node = parse_target(parser, node);
|
12215
12926
|
|
12216
12927
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12217
12928
|
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
@@ -12247,19 +12958,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12247
12958
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
12248
12959
|
yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
|
12249
12960
|
/* fallthrough */
|
12250
|
-
case
|
12251
|
-
|
12252
|
-
|
12253
|
-
|
12254
|
-
|
12961
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
12962
|
+
parser_lex(parser);
|
12963
|
+
|
12964
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12965
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_operator_write_node_create(parser, node, &token, value);
|
12966
|
+
|
12967
|
+
yp_node_destroy(parser, node);
|
12968
|
+
return result;
|
12969
|
+
}
|
12970
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12971
|
+
parser_lex(parser);
|
12972
|
+
|
12973
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12974
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_operator_write_node_create(parser, node, &token, value);
|
12975
|
+
|
12976
|
+
yp_node_destroy(parser, node);
|
12977
|
+
return result;
|
12978
|
+
}
|
12979
|
+
case YP_NODE_CONSTANT_PATH_NODE: {
|
12980
|
+
parser_lex(parser);
|
12981
|
+
|
12982
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12983
|
+
return (yp_node_t *) yp_constant_path_operator_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
12984
|
+
}
|
12985
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
12986
|
+
parser_lex(parser);
|
12987
|
+
|
12988
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12989
|
+
yp_node_t *result = (yp_node_t *) yp_constant_operator_write_node_create(parser, node, &token, value);
|
12990
|
+
|
12991
|
+
yp_node_destroy(parser, node);
|
12992
|
+
return result;
|
12993
|
+
}
|
12994
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
12995
|
+
parser_lex(parser);
|
12996
|
+
|
12997
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12998
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_write_node_create(parser, node, &token, value);
|
12999
|
+
|
13000
|
+
yp_node_destroy(parser, node);
|
13001
|
+
return result;
|
13002
|
+
}
|
12255
13003
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
13004
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12256
13005
|
parser_lex(parser);
|
12257
13006
|
|
12258
|
-
|
12259
|
-
|
13007
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13008
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, cast->constant_id, cast->depth);
|
12260
13009
|
|
12261
|
-
|
12262
|
-
return
|
13010
|
+
yp_node_destroy(parser, node);
|
13011
|
+
return result;
|
12263
13012
|
}
|
12264
13013
|
case YP_NODE_CALL_NODE: {
|
12265
13014
|
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
@@ -12269,25 +13018,23 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12269
13018
|
// will transform it into a local variable write.
|
12270
13019
|
if (yp_call_node_variable_call_p(call_node)) {
|
12271
13020
|
yp_location_t message_loc = call_node->message_loc;
|
12272
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
13021
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12273
13022
|
|
12274
13023
|
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12275
13024
|
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12276
13025
|
}
|
12277
13026
|
|
12278
13027
|
parser_lex(parser);
|
13028
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13029
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id, 0);
|
12279
13030
|
|
12280
|
-
|
12281
|
-
|
12282
|
-
|
12283
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12284
|
-
return (yp_node_t *) yp_operator_write_node_create(parser, node, &token, value);
|
13031
|
+
yp_node_destroy(parser, node);
|
13032
|
+
return result;
|
12285
13033
|
}
|
12286
13034
|
|
12287
|
-
|
12288
|
-
node = parse_target(parser, node, &operator, NULL);
|
12289
|
-
|
13035
|
+
node = parse_target(parser, node);
|
12290
13036
|
parser_lex(parser);
|
13037
|
+
|
12291
13038
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12292
13039
|
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12293
13040
|
}
|
@@ -12456,7 +13203,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12456
13203
|
yp_statements_node_body_append(statements, node);
|
12457
13204
|
|
12458
13205
|
yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'until'");
|
12459
|
-
return (yp_node_t *)
|
13206
|
+
return (yp_node_t *) yp_until_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_NODE_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0);
|
12460
13207
|
}
|
12461
13208
|
case YP_TOKEN_KEYWORD_WHILE_MODIFIER: {
|
12462
13209
|
parser_lex(parser);
|
@@ -12464,7 +13211,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12464
13211
|
yp_statements_node_body_append(statements, node);
|
12465
13212
|
|
12466
13213
|
yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'while'");
|
12467
|
-
return (yp_node_t *)
|
13214
|
+
return (yp_node_t *) yp_while_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_NODE_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0);
|
12468
13215
|
}
|
12469
13216
|
case YP_TOKEN_QUESTION_MARK: {
|
12470
13217
|
parser_lex(parser);
|
@@ -12502,7 +13249,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12502
13249
|
|
12503
13250
|
if (
|
12504
13251
|
(parser->current.type == YP_TOKEN_PARENTHESIS_LEFT) ||
|
12505
|
-
(token_begins_expression_p(parser->current.type) || match_any_type_p(parser,
|
13252
|
+
(token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))
|
12506
13253
|
) {
|
12507
13254
|
// If we have a constant immediately following a '::' operator, then
|
12508
13255
|
// this can either be a constant path or a method call, depending on
|
@@ -12734,7 +13481,7 @@ yp_metadata_read_u32(const char *ptr) {
|
|
12734
13481
|
// ]*
|
12735
13482
|
// ]
|
12736
13483
|
// ```
|
12737
|
-
|
13484
|
+
void
|
12738
13485
|
yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
12739
13486
|
uint32_t filepath_size = yp_metadata_read_u32(metadata);
|
12740
13487
|
metadata += 4;
|
@@ -12773,6 +13520,8 @@ yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
|
12773
13520
|
// Initialize a parser with the given start and end pointers.
|
12774
13521
|
YP_EXPORTED_FUNCTION void
|
12775
13522
|
yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char *filepath) {
|
13523
|
+
assert(source != NULL);
|
13524
|
+
|
12776
13525
|
// Set filepath to the file that was passed
|
12777
13526
|
if (!filepath) filepath = "";
|
12778
13527
|
yp_string_t filepath_string;
|
@@ -12841,14 +13590,15 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
|
|
12841
13590
|
size_t newline_size = size / 22;
|
12842
13591
|
yp_newline_list_init(&parser->newline_list, source, newline_size < 4 ? 4 : newline_size);
|
12843
13592
|
|
12844
|
-
|
13593
|
+
// Skip past the UTF-8 BOM if it exists.
|
12845
13594
|
if (size >= 3 && (unsigned char) source[0] == 0xef && (unsigned char) source[1] == 0xbb && (unsigned char) source[2] == 0xbf) {
|
12846
|
-
// If the first three bytes of the source are the UTF-8 BOM, then we'll skip
|
12847
|
-
// over them.
|
12848
13595
|
parser->current.end += 3;
|
12849
|
-
|
12850
|
-
|
12851
|
-
|
13596
|
+
parser->encoding_comment_start += 3;
|
13597
|
+
}
|
13598
|
+
|
13599
|
+
// If the first two bytes of the source are a shebang, then we'll indicate
|
13600
|
+
// that the encoding comment is at the end of the shebang.
|
13601
|
+
if (peek(parser) == '#' && peek_offset(parser, 1) == '!') {
|
12852
13602
|
const char *encoding_comment_start = next_newline(source, (ptrdiff_t) size);
|
12853
13603
|
if (encoding_comment_start) {
|
12854
13604
|
parser->encoding_comment_start = encoding_comment_start + 1;
|