yarp 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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;
|