yarp 0.7.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 +54 -2
- data/Makefile +2 -0
- data/README.md +9 -5
- data/config.yml +160 -93
- 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 +361 -238
- data/ext/yarp/extension.c +75 -26
- data/ext/yarp/extension.h +2 -2
- data/include/yarp/ast.h +226 -175
- data/include/yarp/defines.h +5 -0
- data/include/yarp/node.h +10 -0
- data/include/yarp/unescape.h +4 -2
- data/include/yarp/util/yp_buffer.h +9 -1
- data/include/yarp/util/yp_constant_pool.h +3 -0
- data/include/yarp/util/yp_list.h +7 -7
- data/include/yarp/util/yp_newline_list.h +7 -0
- data/include/yarp/util/yp_state_stack.h +1 -1
- 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 +89 -48
- data/lib/yarp/lex_compat.rb +93 -25
- data/lib/yarp/mutation_visitor.rb +683 -0
- data/lib/yarp/node.rb +2061 -422
- data/lib/yarp/serialize.rb +162 -120
- data/lib/yarp.rb +54 -8
- data/src/node.c +360 -304
- data/src/prettyprint.c +190 -152
- data/src/serialize.c +382 -340
- data/src/token_type.c +2 -2
- data/src/unescape.c +89 -77
- data/src/util/yp_buffer.c +18 -0
- data/src/util/yp_list.c +7 -16
- data/src/util/yp_newline_list.c +10 -0
- data/src/util/yp_state_stack.c +0 -6
- data/src/yarp.c +941 -596
- 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;
|
@@ -450,8 +449,8 @@ yp_flip_flop(yp_node_t *node) {
|
|
450
449
|
case YP_NODE_PARENTHESES_NODE: {
|
451
450
|
yp_parentheses_node_t *cast = (yp_parentheses_node_t *) node;
|
452
451
|
|
453
|
-
if ((cast->
|
454
|
-
yp_statements_node_t *statements = (yp_statements_node_t *) cast->
|
452
|
+
if ((cast->body != NULL) && YP_NODE_TYPE_P(cast->body, YP_NODE_STATEMENTS_NODE)) {
|
453
|
+
yp_statements_node_t *statements = (yp_statements_node_t *) cast->body;
|
455
454
|
if (statements->body.size == 1) yp_flip_flop(statements->body.nodes[0]);
|
456
455
|
}
|
457
456
|
|
@@ -459,8 +458,12 @@ yp_flip_flop(yp_node_t *node) {
|
|
459
458
|
}
|
460
459
|
case YP_NODE_RANGE_NODE: {
|
461
460
|
yp_range_node_t *cast = (yp_range_node_t *) node;
|
462
|
-
|
463
|
-
|
461
|
+
if (cast->left) {
|
462
|
+
yp_flip_flop(cast->left);
|
463
|
+
}
|
464
|
+
if (cast->right) {
|
465
|
+
yp_flip_flop(cast->right);
|
466
|
+
}
|
464
467
|
|
465
468
|
// Here we change the range node into a flip flop node. We can do
|
466
469
|
// this since the nodes are exactly the same except for the type.
|
@@ -532,6 +535,73 @@ yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) {
|
|
532
535
|
}
|
533
536
|
}
|
534
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
|
+
|
535
605
|
/******************************************************************************/
|
536
606
|
/* Node creation functions */
|
537
607
|
/******************************************************************************/
|
@@ -993,7 +1063,7 @@ yp_block_argument_node_create(yp_parser_t *parser, const yp_token_t *operator, y
|
|
993
1063
|
|
994
1064
|
// Allocate and initialize a new BlockNode node.
|
995
1065
|
static yp_block_node_t *
|
996
|
-
yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *opening, yp_block_parameters_node_t *parameters, yp_node_t *
|
1066
|
+
yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *opening, yp_block_parameters_node_t *parameters, yp_node_t *body, const yp_token_t *closing) {
|
997
1067
|
yp_block_node_t *node = YP_ALLOC_NODE(parser, yp_block_node_t);
|
998
1068
|
|
999
1069
|
*node = (yp_block_node_t) {
|
@@ -1003,7 +1073,7 @@ yp_block_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y
|
|
1003
1073
|
},
|
1004
1074
|
.locals = *locals,
|
1005
1075
|
.parameters = parameters,
|
1006
|
-
.
|
1076
|
+
.body = body,
|
1007
1077
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
1008
1078
|
.closing_loc = YP_LOCATION_TOKEN_VALUE(closing)
|
1009
1079
|
};
|
@@ -1126,7 +1196,7 @@ yp_call_node_create(yp_parser_t *parser) {
|
|
1126
1196
|
},
|
1127
1197
|
.receiver = NULL,
|
1128
1198
|
.operator_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1129
|
-
.message_loc =
|
1199
|
+
.message_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1130
1200
|
.opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1131
1201
|
.arguments = NULL,
|
1132
1202
|
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
@@ -1461,7 +1531,7 @@ yp_case_node_end_keyword_loc_set(yp_case_node_t *node, const yp_token_t *end_key
|
|
1461
1531
|
|
1462
1532
|
// Allocate a new ClassNode node.
|
1463
1533
|
static yp_class_node_t *
|
1464
|
-
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 *
|
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) {
|
1465
1535
|
yp_class_node_t *node = YP_ALLOC_NODE(parser, yp_class_node_t);
|
1466
1536
|
|
1467
1537
|
*node = (yp_class_node_t) {
|
@@ -1474,23 +1544,25 @@ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y
|
|
1474
1544
|
.constant_path = constant_path,
|
1475
1545
|
.inheritance_operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
|
1476
1546
|
.superclass = superclass,
|
1477
|
-
.
|
1478
|
-
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
1547
|
+
.body = body,
|
1548
|
+
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword),
|
1549
|
+
.name = YP_EMPTY_STRING
|
1479
1550
|
};
|
1480
1551
|
|
1552
|
+
yp_string_shared_init(&node->name, name->start, name->end);
|
1481
1553
|
return node;
|
1482
1554
|
}
|
1483
1555
|
|
1484
|
-
// Allocate and initialize a new
|
1485
|
-
static
|
1486
|
-
|
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) {
|
1487
1559
|
assert(YP_NODE_TYPE_P(target, YP_NODE_CLASS_VARIABLE_READ_NODE));
|
1488
1560
|
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1489
|
-
|
1561
|
+
yp_class_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_and_write_node_t);
|
1490
1562
|
|
1491
|
-
*node = (
|
1563
|
+
*node = (yp_class_variable_and_write_node_t) {
|
1492
1564
|
{
|
1493
|
-
.type =
|
1565
|
+
.type = YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE,
|
1494
1566
|
.location = {
|
1495
1567
|
.start = target->location.start,
|
1496
1568
|
.end = value->location.end
|
@@ -1526,16 +1598,16 @@ yp_class_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *tar
|
|
1526
1598
|
return node;
|
1527
1599
|
}
|
1528
1600
|
|
1529
|
-
// Allocate and initialize a new
|
1530
|
-
static
|
1531
|
-
|
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) {
|
1532
1604
|
assert(YP_NODE_TYPE_P(target, YP_NODE_CLASS_VARIABLE_READ_NODE));
|
1533
1605
|
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1534
|
-
|
1606
|
+
yp_class_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_or_write_node_t);
|
1535
1607
|
|
1536
|
-
*node = (
|
1608
|
+
*node = (yp_class_variable_or_write_node_t) {
|
1537
1609
|
{
|
1538
|
-
.type =
|
1610
|
+
.type = YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE,
|
1539
1611
|
.location = {
|
1540
1612
|
.start = target->location.start,
|
1541
1613
|
.end = value->location.end
|
@@ -1568,10 +1640,10 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
|
|
1568
1640
|
.type = YP_NODE_CLASS_VARIABLE_WRITE_NODE,
|
1569
1641
|
.location = {
|
1570
1642
|
.start = read_node->base.location.start,
|
1571
|
-
.end = value
|
1643
|
+
.end = value->location.end
|
1572
1644
|
},
|
1573
1645
|
},
|
1574
|
-
.name_loc = YP_LOCATION_NODE_VALUE((yp_node_t *)read_node),
|
1646
|
+
.name_loc = YP_LOCATION_NODE_VALUE((yp_node_t *) read_node),
|
1575
1647
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
1576
1648
|
.value = value
|
1577
1649
|
};
|
@@ -1579,15 +1651,15 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
|
|
1579
1651
|
return node;
|
1580
1652
|
}
|
1581
1653
|
|
1582
|
-
// Allocate and initialize a new
|
1583
|
-
static
|
1584
|
-
|
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) {
|
1585
1657
|
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1586
|
-
|
1658
|
+
yp_constant_path_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_and_write_node_t);
|
1587
1659
|
|
1588
|
-
*node = (
|
1660
|
+
*node = (yp_constant_path_and_write_node_t) {
|
1589
1661
|
{
|
1590
|
-
.type =
|
1662
|
+
.type = YP_NODE_CONSTANT_PATH_AND_WRITE_NODE,
|
1591
1663
|
.location = {
|
1592
1664
|
.start = target->base.location.start,
|
1593
1665
|
.end = value->location.end
|
@@ -1623,15 +1695,15 @@ yp_constant_path_operator_write_node_create(yp_parser_t *parser, yp_constant_pat
|
|
1623
1695
|
return node;
|
1624
1696
|
}
|
1625
1697
|
|
1626
|
-
// Allocate and initialize a new
|
1627
|
-
static
|
1628
|
-
|
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) {
|
1629
1701
|
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1630
|
-
|
1702
|
+
yp_constant_path_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_or_write_node_t);
|
1631
1703
|
|
1632
|
-
*node = (
|
1704
|
+
*node = (yp_constant_path_or_write_node_t) {
|
1633
1705
|
{
|
1634
|
-
.type =
|
1706
|
+
.type = YP_NODE_CONSTANT_PATH_OR_WRITE_NODE,
|
1635
1707
|
.location = {
|
1636
1708
|
.start = target->base.location.start,
|
1637
1709
|
.end = value->location.end
|
@@ -1676,7 +1748,7 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
|
|
1676
1748
|
.type = YP_NODE_CONSTANT_PATH_WRITE_NODE,
|
1677
1749
|
.location = {
|
1678
1750
|
.start = target->base.location.start,
|
1679
|
-
.end =
|
1751
|
+
.end = value->location.end
|
1680
1752
|
},
|
1681
1753
|
},
|
1682
1754
|
.target = target,
|
@@ -1687,16 +1759,16 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
|
|
1687
1759
|
return node;
|
1688
1760
|
}
|
1689
1761
|
|
1690
|
-
// Allocate and initialize a new
|
1691
|
-
static
|
1692
|
-
|
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) {
|
1693
1765
|
assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
|
1694
1766
|
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1695
|
-
|
1767
|
+
yp_constant_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_and_write_node_t);
|
1696
1768
|
|
1697
|
-
*node = (
|
1769
|
+
*node = (yp_constant_and_write_node_t) {
|
1698
1770
|
{
|
1699
|
-
.type =
|
1771
|
+
.type = YP_NODE_CONSTANT_AND_WRITE_NODE,
|
1700
1772
|
.location = {
|
1701
1773
|
.start = target->location.start,
|
1702
1774
|
.end = value->location.end
|
@@ -1732,16 +1804,16 @@ yp_constant_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, c
|
|
1732
1804
|
return node;
|
1733
1805
|
}
|
1734
1806
|
|
1735
|
-
// Allocate and initialize a new
|
1736
|
-
static
|
1737
|
-
|
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) {
|
1738
1810
|
assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
|
1739
1811
|
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1740
|
-
|
1812
|
+
yp_constant_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_or_write_node_t);
|
1741
1813
|
|
1742
|
-
*node = (
|
1814
|
+
*node = (yp_constant_or_write_node_t) {
|
1743
1815
|
{
|
1744
|
-
.type =
|
1816
|
+
.type = YP_NODE_CONSTANT_OR_WRITE_NODE,
|
1745
1817
|
.location = {
|
1746
1818
|
.start = target->location.start,
|
1747
1819
|
.end = value->location.end
|
@@ -1775,7 +1847,7 @@ yp_constant_write_node_create(yp_parser_t *parser, yp_location_t *name_loc, cons
|
|
1775
1847
|
.type = YP_NODE_CONSTANT_WRITE_NODE,
|
1776
1848
|
.location = {
|
1777
1849
|
.start = name_loc->start,
|
1778
|
-
.end = value
|
1850
|
+
.end = value->location.end
|
1779
1851
|
},
|
1780
1852
|
},
|
1781
1853
|
.name_loc = *name_loc,
|
@@ -1793,7 +1865,7 @@ yp_def_node_create(
|
|
1793
1865
|
const yp_token_t *name,
|
1794
1866
|
yp_node_t *receiver,
|
1795
1867
|
yp_parameters_node_t *parameters,
|
1796
|
-
yp_node_t *
|
1868
|
+
yp_node_t *body,
|
1797
1869
|
yp_constant_id_list_t *locals,
|
1798
1870
|
const yp_token_t *def_keyword,
|
1799
1871
|
const yp_token_t *operator,
|
@@ -1806,7 +1878,7 @@ yp_def_node_create(
|
|
1806
1878
|
const char *end;
|
1807
1879
|
|
1808
1880
|
if (end_keyword->type == YP_TOKEN_NOT_PROVIDED) {
|
1809
|
-
end =
|
1881
|
+
end = body->location.end;
|
1810
1882
|
} else {
|
1811
1883
|
end = end_keyword->end;
|
1812
1884
|
}
|
@@ -1819,7 +1891,7 @@ yp_def_node_create(
|
|
1819
1891
|
.name_loc = YP_LOCATION_TOKEN_VALUE(name),
|
1820
1892
|
.receiver = receiver,
|
1821
1893
|
.parameters = parameters,
|
1822
|
-
.
|
1894
|
+
.body = body,
|
1823
1895
|
.locals = *locals,
|
1824
1896
|
.def_keyword_loc = YP_LOCATION_TOKEN_VALUE(def_keyword),
|
1825
1897
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
@@ -2189,16 +2261,16 @@ yp_hash_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *assoc
|
|
2189
2261
|
return node;
|
2190
2262
|
}
|
2191
2263
|
|
2192
|
-
// Allocate and initialize a new
|
2193
|
-
static
|
2194
|
-
|
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) {
|
2195
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));
|
2196
2268
|
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2197
|
-
|
2269
|
+
yp_global_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_and_write_node_t);
|
2198
2270
|
|
2199
|
-
*node = (
|
2271
|
+
*node = (yp_global_variable_and_write_node_t) {
|
2200
2272
|
{
|
2201
|
-
.type =
|
2273
|
+
.type = YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE,
|
2202
2274
|
.location = {
|
2203
2275
|
.start = target->location.start,
|
2204
2276
|
.end = value->location.end
|
@@ -2234,16 +2306,16 @@ yp_global_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *ta
|
|
2234
2306
|
return node;
|
2235
2307
|
}
|
2236
2308
|
|
2237
|
-
// Allocate and initialize a new
|
2238
|
-
static
|
2239
|
-
|
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) {
|
2240
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));
|
2241
2313
|
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2242
|
-
|
2314
|
+
yp_global_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_or_write_node_t);
|
2243
2315
|
|
2244
|
-
*node = (
|
2316
|
+
*node = (yp_global_variable_or_write_node_t) {
|
2245
2317
|
{
|
2246
|
-
.type =
|
2318
|
+
.type = YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE,
|
2247
2319
|
.location = {
|
2248
2320
|
.start = target->location.start,
|
2249
2321
|
.end = value->location.end
|
@@ -2282,7 +2354,7 @@ yp_global_variable_write_node_create(yp_parser_t *parser, const yp_location_t *n
|
|
2282
2354
|
.type = YP_NODE_GLOBAL_VARIABLE_WRITE_NODE,
|
2283
2355
|
.location = {
|
2284
2356
|
.start = name_loc->start,
|
2285
|
-
.end =
|
2357
|
+
.end = value->location.end
|
2286
2358
|
},
|
2287
2359
|
},
|
2288
2360
|
.name_loc = *name_loc,
|
@@ -2547,16 +2619,16 @@ yp_in_node_create(yp_parser_t *parser, yp_node_t *pattern, yp_statements_node_t
|
|
2547
2619
|
return node;
|
2548
2620
|
}
|
2549
2621
|
|
2550
|
-
// Allocate and initialize a new
|
2551
|
-
static
|
2552
|
-
|
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) {
|
2553
2625
|
assert(YP_NODE_TYPE_P(target, YP_NODE_INSTANCE_VARIABLE_READ_NODE));
|
2554
2626
|
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2555
|
-
|
2627
|
+
yp_instance_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_and_write_node_t);
|
2556
2628
|
|
2557
|
-
*node = (
|
2629
|
+
*node = (yp_instance_variable_and_write_node_t) {
|
2558
2630
|
{
|
2559
|
-
.type =
|
2631
|
+
.type = YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE,
|
2560
2632
|
.location = {
|
2561
2633
|
.start = target->location.start,
|
2562
2634
|
.end = value->location.end
|
@@ -2592,16 +2664,16 @@ yp_instance_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *
|
|
2592
2664
|
return node;
|
2593
2665
|
}
|
2594
2666
|
|
2595
|
-
// Allocate and initialize a new
|
2596
|
-
static
|
2597
|
-
|
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) {
|
2598
2670
|
assert(YP_NODE_TYPE_P(target, YP_NODE_INSTANCE_VARIABLE_READ_NODE));
|
2599
2671
|
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2600
|
-
|
2672
|
+
yp_instance_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_or_write_node_t);
|
2601
2673
|
|
2602
|
-
*node = (
|
2674
|
+
*node = (yp_instance_variable_or_write_node_t) {
|
2603
2675
|
{
|
2604
|
-
.type =
|
2676
|
+
.type = YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE,
|
2605
2677
|
.location = {
|
2606
2678
|
.start = target->location.start,
|
2607
2679
|
.end = value->location.end
|
@@ -2637,7 +2709,7 @@ yp_instance_variable_write_node_create(yp_parser_t *parser, yp_instance_variable
|
|
2637
2709
|
.type = YP_NODE_INSTANCE_VARIABLE_WRITE_NODE,
|
2638
2710
|
.location = {
|
2639
2711
|
.start = read_node->base.location.start,
|
2640
|
-
.end = value
|
2712
|
+
.end = value->location.end
|
2641
2713
|
}
|
2642
2714
|
},
|
2643
2715
|
.name_loc = YP_LOCATION_NODE_BASE_VALUE(read_node),
|
@@ -2706,6 +2778,10 @@ yp_interpolated_string_node_create(yp_parser_t *parser, const yp_token_t *openin
|
|
2706
2778
|
// Append a part to an InterpolatedStringNode node.
|
2707
2779
|
static inline void
|
2708
2780
|
yp_interpolated_string_node_append(yp_interpolated_string_node_t *node, yp_node_t *part) {
|
2781
|
+
if (node->parts.size == 0 && node->opening_loc.start == NULL) {
|
2782
|
+
node->base.location.start = part->location.start;
|
2783
|
+
}
|
2784
|
+
|
2709
2785
|
yp_node_list_append(&node->parts, part);
|
2710
2786
|
node->base.location.end = part->location.end;
|
2711
2787
|
}
|
@@ -2747,12 +2823,6 @@ yp_interpolated_symbol_node_append(yp_interpolated_symbol_node_t *node, yp_node_
|
|
2747
2823
|
node->base.location.end = part->location.end;
|
2748
2824
|
}
|
2749
2825
|
|
2750
|
-
static inline void
|
2751
|
-
yp_interpolated_symbol_node_closing_set(yp_interpolated_symbol_node_t *node, const yp_token_t *closing) {
|
2752
|
-
node->closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
|
2753
|
-
node->base.location.end = closing->end;
|
2754
|
-
}
|
2755
|
-
|
2756
2826
|
// Allocate a new InterpolatedXStringNode node.
|
2757
2827
|
static yp_interpolated_x_string_node_t *
|
2758
2828
|
yp_interpolated_xstring_node_create(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *closing) {
|
@@ -2860,10 +2930,11 @@ static yp_lambda_node_t *
|
|
2860
2930
|
yp_lambda_node_create(
|
2861
2931
|
yp_parser_t *parser,
|
2862
2932
|
yp_constant_id_list_t *locals,
|
2933
|
+
const yp_token_t *operator,
|
2863
2934
|
const yp_token_t *opening,
|
2935
|
+
const yp_token_t *closing,
|
2864
2936
|
yp_block_parameters_node_t *parameters,
|
2865
|
-
yp_node_t *
|
2866
|
-
const yp_token_t *closing
|
2937
|
+
yp_node_t *body
|
2867
2938
|
) {
|
2868
2939
|
yp_lambda_node_t *node = YP_ALLOC_NODE(parser, yp_lambda_node_t);
|
2869
2940
|
|
@@ -2871,29 +2942,31 @@ yp_lambda_node_create(
|
|
2871
2942
|
{
|
2872
2943
|
.type = YP_NODE_LAMBDA_NODE,
|
2873
2944
|
.location = {
|
2874
|
-
.start =
|
2945
|
+
.start = operator->start,
|
2875
2946
|
.end = closing->end
|
2876
2947
|
},
|
2877
2948
|
},
|
2878
2949
|
.locals = *locals,
|
2950
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2879
2951
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
2952
|
+
.closing_loc = YP_LOCATION_TOKEN_VALUE(closing),
|
2880
2953
|
.parameters = parameters,
|
2881
|
-
.
|
2954
|
+
.body = body
|
2882
2955
|
};
|
2883
2956
|
|
2884
2957
|
return node;
|
2885
2958
|
}
|
2886
2959
|
|
2887
|
-
// Allocate and initialize a new
|
2888
|
-
static
|
2889
|
-
|
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) {
|
2890
2963
|
assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
|
2891
2964
|
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2892
|
-
|
2965
|
+
yp_local_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_and_write_node_t);
|
2893
2966
|
|
2894
|
-
*node = (
|
2967
|
+
*node = (yp_local_variable_and_write_node_t) {
|
2895
2968
|
{
|
2896
|
-
.type =
|
2969
|
+
.type = YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE,
|
2897
2970
|
.location = {
|
2898
2971
|
.start = target->location.start,
|
2899
2972
|
.end = value->location.end
|
@@ -2902,7 +2975,8 @@ yp_local_variable_operator_and_write_node_create(yp_parser_t *parser, yp_node_t
|
|
2902
2975
|
.name_loc = target->location,
|
2903
2976
|
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2904
2977
|
.value = value,
|
2905
|
-
.constant_id = constant_id
|
2978
|
+
.constant_id = constant_id,
|
2979
|
+
.depth = depth
|
2906
2980
|
};
|
2907
2981
|
|
2908
2982
|
return node;
|
@@ -2910,7 +2984,7 @@ yp_local_variable_operator_and_write_node_create(yp_parser_t *parser, yp_node_t
|
|
2910
2984
|
|
2911
2985
|
// Allocate and initialize a new LocalVariableOperatorWriteNode node.
|
2912
2986
|
static yp_local_variable_operator_write_node_t *
|
2913
|
-
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) {
|
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) {
|
2914
2988
|
yp_local_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_operator_write_node_t);
|
2915
2989
|
|
2916
2990
|
*node = (yp_local_variable_operator_write_node_t) {
|
@@ -2925,22 +2999,23 @@ yp_local_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *tar
|
|
2925
2999
|
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2926
3000
|
.value = value,
|
2927
3001
|
.constant_id = constant_id,
|
2928
|
-
.operator_id = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
3002
|
+
.operator_id = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
3003
|
+
.depth = depth
|
2929
3004
|
};
|
2930
3005
|
|
2931
3006
|
return node;
|
2932
3007
|
}
|
2933
3008
|
|
2934
|
-
// Allocate and initialize a new
|
2935
|
-
static
|
2936
|
-
|
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) {
|
2937
3012
|
assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
|
2938
3013
|
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2939
|
-
|
3014
|
+
yp_local_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_or_write_node_t);
|
2940
3015
|
|
2941
|
-
*node = (
|
3016
|
+
*node = (yp_local_variable_or_write_node_t) {
|
2942
3017
|
{
|
2943
|
-
.type =
|
3018
|
+
.type = YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE,
|
2944
3019
|
.location = {
|
2945
3020
|
.start = target->location.start,
|
2946
3021
|
.end = value->location.end
|
@@ -2949,7 +3024,8 @@ yp_local_variable_operator_or_write_node_create(yp_parser_t *parser, yp_node_t *
|
|
2949
3024
|
.name_loc = target->location,
|
2950
3025
|
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2951
3026
|
.value = value,
|
2952
|
-
.constant_id = constant_id
|
3027
|
+
.constant_id = constant_id,
|
3028
|
+
.depth = depth
|
2953
3029
|
};
|
2954
3030
|
|
2955
3031
|
return node;
|
@@ -2982,7 +3058,7 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t consta
|
|
2982
3058
|
.type = YP_NODE_LOCAL_VARIABLE_WRITE_NODE,
|
2983
3059
|
.location = {
|
2984
3060
|
.start = name_loc->start,
|
2985
|
-
.end = value
|
3061
|
+
.end = value->location.end
|
2986
3062
|
}
|
2987
3063
|
},
|
2988
3064
|
.constant_id = constant_id,
|
@@ -2995,21 +3071,18 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t consta
|
|
2995
3071
|
return node;
|
2996
3072
|
}
|
2997
3073
|
|
2998
|
-
// Allocate and initialize a new
|
2999
|
-
static
|
3074
|
+
// Allocate and initialize a new LocalVariableTargetNode node.
|
3075
|
+
static yp_local_variable_target_node_t *
|
3000
3076
|
yp_local_variable_target_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
3001
|
-
|
3077
|
+
yp_local_variable_target_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_target_node_t);
|
3002
3078
|
|
3003
|
-
*node = (
|
3079
|
+
*node = (yp_local_variable_target_node_t) {
|
3004
3080
|
{
|
3005
|
-
.type =
|
3081
|
+
.type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE,
|
3006
3082
|
.location = YP_LOCATION_TOKEN_VALUE(name)
|
3007
3083
|
},
|
3008
3084
|
.constant_id = yp_parser_constant_id_token(parser, name),
|
3009
|
-
.depth = 0
|
3010
|
-
.value = NULL,
|
3011
|
-
.name_loc = YP_LOCATION_TOKEN_VALUE(name),
|
3012
|
-
.operator_loc = { .start = NULL, .end = NULL }
|
3085
|
+
.depth = 0
|
3013
3086
|
};
|
3014
3087
|
|
3015
3088
|
return node;
|
@@ -3059,7 +3132,7 @@ yp_match_required_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t *
|
|
3059
3132
|
|
3060
3133
|
// Allocate a new ModuleNode node.
|
3061
3134
|
static yp_module_node_t *
|
3062
|
-
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 *
|
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) {
|
3063
3136
|
yp_module_node_t *node = YP_ALLOC_NODE(parser, yp_module_node_t);
|
3064
3137
|
|
3065
3138
|
*node = (yp_module_node_t) {
|
@@ -3073,10 +3146,12 @@ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const
|
|
3073
3146
|
.locals = (locals == NULL ? ((yp_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
|
3074
3147
|
.module_keyword_loc = YP_LOCATION_TOKEN_VALUE(module_keyword),
|
3075
3148
|
.constant_path = constant_path,
|
3076
|
-
.
|
3077
|
-
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
3149
|
+
.body = body,
|
3150
|
+
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword),
|
3151
|
+
.name = YP_EMPTY_STRING
|
3078
3152
|
};
|
3079
3153
|
|
3154
|
+
yp_string_shared_init(&node->name, name->start, name->end);
|
3080
3155
|
return node;
|
3081
3156
|
}
|
3082
3157
|
|
@@ -3088,7 +3163,10 @@ yp_multi_write_node_create(yp_parser_t *parser, const yp_token_t *operator, yp_n
|
|
3088
3163
|
*node = (yp_multi_write_node_t) {
|
3089
3164
|
{
|
3090
3165
|
.type = YP_NODE_MULTI_WRITE_NODE,
|
3091
|
-
.location = {
|
3166
|
+
.location = {
|
3167
|
+
.start = lparen_loc->start,
|
3168
|
+
.end = value == NULL ? rparen_loc->end : value->location.end
|
3169
|
+
},
|
3092
3170
|
},
|
3093
3171
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
3094
3172
|
.value = value,
|
@@ -3343,7 +3421,7 @@ yp_program_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, yp_st
|
|
3343
3421
|
|
3344
3422
|
// Allocate and initialize new ParenthesesNode node.
|
3345
3423
|
static yp_parentheses_node_t *
|
3346
|
-
yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_node_t *
|
3424
|
+
yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_node_t *body, const yp_token_t *closing) {
|
3347
3425
|
yp_parentheses_node_t *node = YP_ALLOC_NODE(parser, yp_parentheses_node_t);
|
3348
3426
|
|
3349
3427
|
*node = (yp_parentheses_node_t) {
|
@@ -3354,7 +3432,7 @@ yp_parentheses_node_create(yp_parser_t *parser, const yp_token_t *opening, yp_no
|
|
3354
3432
|
.end = closing->end
|
3355
3433
|
}
|
3356
3434
|
},
|
3357
|
-
.
|
3435
|
+
.body = body,
|
3358
3436
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
3359
3437
|
.closing_loc = YP_LOCATION_TOKEN_VALUE(closing)
|
3360
3438
|
};
|
@@ -3700,7 +3778,7 @@ yp_self_node_create(yp_parser_t *parser, const yp_token_t *token) {
|
|
3700
3778
|
|
3701
3779
|
// Allocate a new SingletonClassNode node.
|
3702
3780
|
static yp_singleton_class_node_t *
|
3703
|
-
yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, const yp_token_t *operator, yp_node_t *expression, yp_node_t *
|
3781
|
+
yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, const yp_token_t *operator, yp_node_t *expression, yp_node_t *body, const yp_token_t *end_keyword) {
|
3704
3782
|
yp_singleton_class_node_t *node = YP_ALLOC_NODE(parser, yp_singleton_class_node_t);
|
3705
3783
|
|
3706
3784
|
*node = (yp_singleton_class_node_t) {
|
@@ -3715,7 +3793,7 @@ yp_singleton_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *local
|
|
3715
3793
|
.class_keyword_loc = YP_LOCATION_TOKEN_VALUE(class_keyword),
|
3716
3794
|
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
3717
3795
|
.expression = expression,
|
3718
|
-
.
|
3796
|
+
.body = body,
|
3719
3797
|
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
3720
3798
|
};
|
3721
3799
|
|
@@ -3934,10 +4012,10 @@ yp_symbol_node_label_create(yp_parser_t *parser, const yp_token_t *token) {
|
|
3934
4012
|
yp_token_t label = { .type = YP_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
|
3935
4013
|
node = yp_symbol_node_create(parser, &opening, &label, &closing);
|
3936
4014
|
|
3937
|
-
|
3938
|
-
|
4015
|
+
assert((label.end - label.start) >= 0);
|
4016
|
+
yp_string_shared_init(&node->unescaped, label.start, label.end);
|
3939
4017
|
|
3940
|
-
yp_unescape_manipulate_string(parser,
|
4018
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL);
|
3941
4019
|
break;
|
3942
4020
|
}
|
3943
4021
|
case YP_TOKEN_MISSING: {
|
@@ -3978,20 +4056,20 @@ yp_symbol_node_label_p(yp_node_t *node) {
|
|
3978
4056
|
|
3979
4057
|
// Convert the given StringNode node to a SymbolNode node.
|
3980
4058
|
static yp_symbol_node_t *
|
3981
|
-
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) {
|
3982
4060
|
yp_symbol_node_t *new_node = YP_ALLOC_NODE(parser, yp_symbol_node_t);
|
3983
4061
|
|
3984
4062
|
*new_node = (yp_symbol_node_t) {
|
3985
4063
|
{
|
3986
4064
|
.type = YP_NODE_SYMBOL_NODE,
|
3987
4065
|
.location = {
|
3988
|
-
.start =
|
3989
|
-
.end =
|
4066
|
+
.start = opening->start,
|
4067
|
+
.end = closing->end
|
3990
4068
|
}
|
3991
4069
|
},
|
3992
|
-
.opening_loc =
|
4070
|
+
.opening_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
|
3993
4071
|
.value_loc = node->content_loc,
|
3994
|
-
.closing_loc =
|
4072
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
3995
4073
|
.unescaped = node->unescaped
|
3996
4074
|
};
|
3997
4075
|
|
@@ -4130,34 +4208,43 @@ yp_unless_node_end_keyword_loc_set(yp_unless_node_t *node, const yp_token_t *end
|
|
4130
4208
|
|
4131
4209
|
// Allocate a new UntilNode node.
|
4132
4210
|
static yp_until_node_t *
|
4133
|
-
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) {
|
4134
4212
|
yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
|
4135
|
-
bool has_statements = (statements != NULL) && (statements->body.size != 0);
|
4136
4213
|
|
4137
|
-
|
4138
|
-
|
4139
|
-
|
4140
|
-
|
4141
|
-
|
4142
|
-
|
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
|
+
};
|
4143
4228
|
|
4144
|
-
|
4145
|
-
|
4146
|
-
|
4147
|
-
|
4148
|
-
|
4149
|
-
|
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);
|
4150
4236
|
|
4151
4237
|
*node = (yp_until_node_t) {
|
4152
4238
|
{
|
4153
4239
|
.type = YP_NODE_UNTIL_NODE,
|
4154
4240
|
.flags = flags,
|
4155
4241
|
.location = {
|
4156
|
-
.start = start,
|
4157
|
-
.end = end,
|
4242
|
+
.start = statements->base.location.start,
|
4243
|
+
.end = predicate->location.end,
|
4158
4244
|
},
|
4159
4245
|
},
|
4160
4246
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4247
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
4161
4248
|
.predicate = predicate,
|
4162
4249
|
.statements = statements
|
4163
4250
|
};
|
@@ -4205,34 +4292,43 @@ yp_when_node_statements_set(yp_when_node_t *node, yp_statements_node_t *statemen
|
|
4205
4292
|
|
4206
4293
|
// Allocate a new WhileNode node.
|
4207
4294
|
static yp_while_node_t *
|
4208
|
-
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) {
|
4209
4296
|
yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
|
4210
4297
|
|
4211
|
-
|
4212
|
-
|
4213
|
-
|
4214
|
-
|
4215
|
-
|
4216
|
-
|
4217
|
-
|
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
|
+
};
|
4218
4312
|
|
4219
|
-
|
4220
|
-
|
4221
|
-
|
4222
|
-
|
4223
|
-
|
4224
|
-
|
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);
|
4225
4320
|
|
4226
4321
|
*node = (yp_while_node_t) {
|
4227
4322
|
{
|
4228
4323
|
.type = YP_NODE_WHILE_NODE,
|
4229
4324
|
.flags = flags,
|
4230
4325
|
.location = {
|
4231
|
-
.start = start,
|
4232
|
-
.end = end
|
4326
|
+
.start = statements->base.location.start,
|
4327
|
+
.end = predicate->location.end
|
4233
4328
|
},
|
4234
4329
|
},
|
4235
4330
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4331
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
4236
4332
|
.predicate = predicate,
|
4237
4333
|
.statements = statements
|
4238
4334
|
};
|
@@ -4340,13 +4436,15 @@ yp_parser_local_depth(yp_parser_t *parser, yp_token_t *token) {
|
|
4340
4436
|
}
|
4341
4437
|
|
4342
4438
|
// Add a local variable from a location to the current scope.
|
4343
|
-
static
|
4439
|
+
static yp_constant_id_t
|
4344
4440
|
yp_parser_local_add_location(yp_parser_t *parser, const char *start, const char *end) {
|
4345
4441
|
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, start, end);
|
4346
4442
|
|
4347
4443
|
if (!yp_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
|
4348
4444
|
yp_constant_id_list_append(&parser->current_scope->locals, constant_id);
|
4349
4445
|
}
|
4446
|
+
|
4447
|
+
return constant_id;
|
4350
4448
|
}
|
4351
4449
|
|
4352
4450
|
// Add a local variable from a token to the current scope.
|
@@ -4494,27 +4592,30 @@ yp_do_loop_stack_p(yp_parser_t *parser) {
|
|
4494
4592
|
/* Lexer check helpers */
|
4495
4593
|
/******************************************************************************/
|
4496
4594
|
|
4497
|
-
// Get the next character in the source starting from
|
4498
|
-
//
|
4499
|
-
// 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'.
|
4500
4597
|
static inline char
|
4501
|
-
peek_at(yp_parser_t *parser,
|
4502
|
-
if (
|
4503
|
-
return
|
4598
|
+
peek_at(yp_parser_t *parser, const char *cursor) {
|
4599
|
+
if (cursor < parser->end) {
|
4600
|
+
return *cursor;
|
4504
4601
|
} else {
|
4505
4602
|
return '\0';
|
4506
4603
|
}
|
4507
4604
|
}
|
4508
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
|
+
|
4509
4614
|
// Get the next character in the source starting from parser->current.end. If
|
4510
4615
|
// that position is beyond the end of the source then return '\0'.
|
4511
4616
|
static inline char
|
4512
4617
|
peek(yp_parser_t *parser) {
|
4513
|
-
|
4514
|
-
return *parser->current.end;
|
4515
|
-
} else {
|
4516
|
-
return '\0';
|
4517
|
-
}
|
4618
|
+
return peek_at(parser, parser->current.end);
|
4518
4619
|
}
|
4519
4620
|
|
4520
4621
|
// Get the next string of length len in the source starting from parser->current.end.
|
@@ -4539,6 +4640,35 @@ match(yp_parser_t *parser, char value) {
|
|
4539
4640
|
return false;
|
4540
4641
|
}
|
4541
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
|
+
|
4542
4672
|
// Skip to the next newline character or NUL byte.
|
4543
4673
|
static inline const char *
|
4544
4674
|
next_newline(const char *cursor, ptrdiff_t length) {
|
@@ -4562,11 +4692,13 @@ parser_lex_encoding_comment_start(yp_parser_t *parser, const char *cursor, ptrdi
|
|
4562
4692
|
|
4563
4693
|
const char *cursor_limit = cursor + length - key_length + 1;
|
4564
4694
|
while ((cursor = yp_memchr(cursor, 'c', (size_t) (cursor_limit - cursor), parser->encoding_changed, &parser->encoding)) != NULL) {
|
4565
|
-
if (
|
4566
|
-
(
|
4567
|
-
|
4568
|
-
|
4569
|
-
|
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
|
+
}
|
4570
4702
|
}
|
4571
4703
|
|
4572
4704
|
cursor++;
|
@@ -4822,7 +4954,7 @@ lex_optional_float_suffix(yp_parser_t *parser) {
|
|
4822
4954
|
// Here we're going to attempt to parse the optional decimal portion of a
|
4823
4955
|
// float. If it's not there, then it's okay and we'll just continue on.
|
4824
4956
|
if (peek(parser) == '.') {
|
4825
|
-
if (yp_char_is_decimal_digit(
|
4957
|
+
if (yp_char_is_decimal_digit(peek_offset(parser, 1))) {
|
4826
4958
|
parser->current.end += 2;
|
4827
4959
|
parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end);
|
4828
4960
|
type = YP_TOKEN_FLOAT;
|
@@ -4855,7 +4987,7 @@ static yp_token_type_t
|
|
4855
4987
|
lex_numeric_prefix(yp_parser_t *parser) {
|
4856
4988
|
yp_token_type_t type = YP_TOKEN_INTEGER;
|
4857
4989
|
|
4858
|
-
if (parser
|
4990
|
+
if (peek_offset(parser, -1) == '0') {
|
4859
4991
|
switch (*parser->current.end) {
|
4860
4992
|
// 0d1111 is a decimal number
|
4861
4993
|
case 'd':
|
@@ -4938,7 +5070,7 @@ lex_numeric_prefix(yp_parser_t *parser) {
|
|
4938
5070
|
|
4939
5071
|
// If the last character that we consumed was an underscore, then this is
|
4940
5072
|
// actually an invalid integer value, and we should return an invalid token.
|
4941
|
-
if (parser
|
5073
|
+
if (peek_offset(parser, -1) == '_') {
|
4942
5074
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Number literal cannot end with a `_`.");
|
4943
5075
|
}
|
4944
5076
|
|
@@ -5119,7 +5251,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
5119
5251
|
|
5120
5252
|
if (
|
5121
5253
|
((lex_state_p(parser, YP_LEX_STATE_LABEL | YP_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
|
5122
|
-
(peek(parser) == ':') && (
|
5254
|
+
(peek(parser) == ':') && (peek_offset(parser, 1) != ':')
|
5123
5255
|
) {
|
5124
5256
|
// If we're in a position where we can accept a : at the end of an
|
5125
5257
|
// identifier, then we'll optionally accept it.
|
@@ -5135,7 +5267,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
5135
5267
|
}
|
5136
5268
|
|
5137
5269
|
return YP_TOKEN_IDENTIFIER;
|
5138
|
-
} 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, '=')) {
|
5139
5271
|
// If we're in a position where we can accept a = at the end of an
|
5140
5272
|
// identifier, then we'll optionally accept it.
|
5141
5273
|
return YP_TOKEN_IDENTIFIER;
|
@@ -5143,7 +5275,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
5143
5275
|
|
5144
5276
|
if (
|
5145
5277
|
((lex_state_p(parser, YP_LEX_STATE_LABEL | YP_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
|
5146
|
-
peek(parser) == ':' &&
|
5278
|
+
peek(parser) == ':' && peek_offset(parser, 1) != ':'
|
5147
5279
|
) {
|
5148
5280
|
// If we're in a position where we can accept a : at the end of an
|
5149
5281
|
// identifier, then we'll optionally accept it.
|
@@ -5411,7 +5543,7 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5411
5543
|
|
5412
5544
|
if (parser->current.start[1] == '\\') {
|
5413
5545
|
lex_state_set(parser, YP_LEX_STATE_END);
|
5414
|
-
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);
|
5415
5547
|
return YP_TOKEN_CHARACTER_LITERAL;
|
5416
5548
|
} else {
|
5417
5549
|
size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end);
|
@@ -5420,7 +5552,7 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5420
5552
|
// an underscore. We check for this case
|
5421
5553
|
if (
|
5422
5554
|
!(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
|
5423
|
-
|
5555
|
+
peek(parser) == '_') ||
|
5424
5556
|
(
|
5425
5557
|
(parser->current.end + encoding_width >= parser->end) ||
|
5426
5558
|
!char_is_identifier(parser, parser->current.end + encoding_width)
|
@@ -5636,28 +5768,32 @@ parser_lex(yp_parser_t *parser) {
|
|
5636
5768
|
space_seen = true;
|
5637
5769
|
break;
|
5638
5770
|
case '\r':
|
5639
|
-
if (
|
5771
|
+
if (match_eol_offset(parser, 1)) {
|
5640
5772
|
chomping = false;
|
5641
5773
|
} else {
|
5642
5774
|
parser->current.end++;
|
5643
5775
|
space_seen = true;
|
5644
5776
|
}
|
5645
5777
|
break;
|
5646
|
-
case '\\':
|
5647
|
-
|
5648
|
-
|
5649
|
-
parser->
|
5650
|
-
|
5651
|
-
|
5652
|
-
|
5653
|
-
|
5654
|
-
|
5778
|
+
case '\\': {
|
5779
|
+
size_t eol_length = match_eol_offset(parser, 1);
|
5780
|
+
if (eol_length) {
|
5781
|
+
if (parser->heredoc_end) {
|
5782
|
+
parser->current.end = parser->heredoc_end;
|
5783
|
+
parser->heredoc_end = NULL;
|
5784
|
+
} else {
|
5785
|
+
parser->current.end += eol_length + 1;
|
5786
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
5787
|
+
space_seen = true;
|
5788
|
+
}
|
5655
5789
|
} else if (yp_char_is_inline_whitespace(*parser->current.end)) {
|
5656
5790
|
parser->current.end += 2;
|
5657
5791
|
} else {
|
5658
5792
|
chomping = false;
|
5659
5793
|
}
|
5794
|
+
|
5660
5795
|
break;
|
5796
|
+
}
|
5661
5797
|
default:
|
5662
5798
|
chomping = false;
|
5663
5799
|
break;
|
@@ -5667,13 +5803,14 @@ parser_lex(yp_parser_t *parser) {
|
|
5667
5803
|
// Next, we'll set to start of this token to be the current end.
|
5668
5804
|
parser->current.start = parser->current.end;
|
5669
5805
|
|
5670
|
-
// We'll check if we're at the end of the file. If we are, then we
|
5671
|
-
// 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.
|
5672
5808
|
if (parser->current.end >= parser->end) {
|
5673
5809
|
LEX(YP_TOKEN_EOF);
|
5674
5810
|
}
|
5675
5811
|
|
5676
|
-
// 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.
|
5677
5814
|
switch (*parser->current.end++) {
|
5678
5815
|
case '\0': // NUL or end of script
|
5679
5816
|
case '\004': // ^D
|
@@ -5683,16 +5820,14 @@ parser_lex(yp_parser_t *parser) {
|
|
5683
5820
|
|
5684
5821
|
case '#': { // comments
|
5685
5822
|
const char *ending = next_newline(parser->current.end, parser->end - parser->current.end);
|
5686
|
-
while (ending && ending < parser->end && *ending != '\n') {
|
5687
|
-
ending = next_newline(ending + 1, parser->end - ending);
|
5688
|
-
}
|
5689
5823
|
|
5690
5824
|
parser->current.end = ending == NULL ? parser->end : ending + 1;
|
5691
5825
|
parser->current.type = YP_TOKEN_COMMENT;
|
5692
5826
|
parser_lex_callback(parser);
|
5693
5827
|
|
5694
|
-
// If we found a comment while lexing, then we're going to
|
5695
|
-
// 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.
|
5696
5831
|
yp_comment_t *comment = parser_comment(parser, YP_COMMENT_INLINE);
|
5697
5832
|
yp_list_append(&parser->comment_list, (yp_list_node_t *) comment);
|
5698
5833
|
|
@@ -5703,21 +5838,29 @@ parser_lex(yp_parser_t *parser) {
|
|
5703
5838
|
lexed_comment = true;
|
5704
5839
|
}
|
5705
5840
|
/* fallthrough */
|
5706
|
-
case '\r':
|
5707
|
-
// The only way you can have carriage returns in this particular loop
|
5708
|
-
// is if you have a carriage return followed by a newline. In that
|
5709
|
-
// case we'll just skip over the carriage return and continue lexing,
|
5710
|
-
// in order to make it so that the newline token encapsulates both the
|
5711
|
-
// carriage return and the newline. Note that we need to check that
|
5712
|
-
// we haven't already lexed a comment here because that falls through
|
5713
|
-
// into here as well.
|
5714
|
-
if (!lexed_comment) parser->current.end++;
|
5715
|
-
}
|
5716
|
-
/* fallthrough */
|
5841
|
+
case '\r':
|
5717
5842
|
case '\n': {
|
5718
|
-
|
5719
|
-
|
5720
|
-
|
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) {
|
5721
5864
|
parser_flush_heredoc_end(parser);
|
5722
5865
|
}
|
5723
5866
|
|
@@ -5773,7 +5916,13 @@ parser_lex(yp_parser_t *parser) {
|
|
5773
5916
|
|
5774
5917
|
// If the lex state was ignored, or we hit a '.' or a '&.',
|
5775
5918
|
// we will lex the ignored newline
|
5776
|
-
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
|
+
) {
|
5777
5926
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5778
5927
|
lexed_comment = false;
|
5779
5928
|
goto lex_next_token;
|
@@ -5786,7 +5935,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5786
5935
|
// To match ripper, we need to emit an ignored newline even though
|
5787
5936
|
// its a real newline in the case that we have a beginless range
|
5788
5937
|
// on a subsequent line.
|
5789
|
-
if ((next_content + 1
|
5938
|
+
if (peek_at(parser, next_content + 1) == '.') {
|
5790
5939
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5791
5940
|
lex_state_set(parser, YP_LEX_STATE_BEG);
|
5792
5941
|
parser->command_start = true;
|
@@ -5804,7 +5953,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5804
5953
|
|
5805
5954
|
// If we hit a &. after a newline, then we're in a call chain and
|
5806
5955
|
// we need to return the call operator.
|
5807
|
-
if (
|
5956
|
+
if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '.') {
|
5808
5957
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5809
5958
|
lex_state_set(parser, YP_LEX_STATE_DOT);
|
5810
5959
|
parser->current.start = next_content;
|
@@ -6001,7 +6150,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6001
6150
|
|
6002
6151
|
// = => =~ == === =begin
|
6003
6152
|
case '=':
|
6004
|
-
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))) {
|
6005
6154
|
yp_token_type_t type = lex_embdoc(parser);
|
6006
6155
|
|
6007
6156
|
if (type == YP_TOKEN_EOF) {
|
@@ -6425,13 +6574,13 @@ parser_lex(yp_parser_t *parser) {
|
|
6425
6574
|
LEX(YP_TOKEN_COLON_COLON);
|
6426
6575
|
}
|
6427
6576
|
|
6428
|
-
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) == '#') {
|
6429
6578
|
lex_state_set(parser, YP_LEX_STATE_BEG);
|
6430
6579
|
LEX(YP_TOKEN_COLON);
|
6431
6580
|
}
|
6432
6581
|
|
6433
|
-
if ((
|
6434
|
-
lex_mode_push_string(parser,
|
6582
|
+
if (peek(parser) == '"' || peek(parser) == '\'') {
|
6583
|
+
lex_mode_push_string(parser, peek(parser) == '"', false, '\0', *parser->current.end);
|
6435
6584
|
parser->current.end++;
|
6436
6585
|
}
|
6437
6586
|
|
@@ -6486,13 +6635,11 @@ parser_lex(yp_parser_t *parser) {
|
|
6486
6635
|
|
6487
6636
|
// % %= %i %I %q %Q %w %W
|
6488
6637
|
case '%': {
|
6489
|
-
//
|
6490
|
-
//
|
6491
|
-
//
|
6492
|
-
|
6493
|
-
|
6494
|
-
if (lex_state_beg_p(parser) && (parser->current.end >= parser->end)) {
|
6495
|
-
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "unexpected end of input");
|
6638
|
+
// If there is no subsequent character then we have an invalid token. We're
|
6639
|
+
// going to say it's the percent operator because we don't want to move into the
|
6640
|
+
// string lex mode unnecessarily.
|
6641
|
+
if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
|
6642
|
+
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Unexpected end of input");
|
6496
6643
|
LEX(YP_TOKEN_PERCENT);
|
6497
6644
|
}
|
6498
6645
|
|
@@ -6502,25 +6649,26 @@ parser_lex(yp_parser_t *parser) {
|
|
6502
6649
|
}
|
6503
6650
|
else if(
|
6504
6651
|
lex_state_beg_p(parser) ||
|
6505
|
-
(lex_state_p(parser, YP_LEX_STATE_FITEM) && (
|
6652
|
+
(lex_state_p(parser, YP_LEX_STATE_FITEM) && (peek(parser) == 's')) ||
|
6506
6653
|
lex_state_spcarg_p(parser, space_seen)
|
6507
6654
|
) {
|
6508
6655
|
if (!parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end)) {
|
6509
6656
|
lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6510
6657
|
|
6511
|
-
|
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 {
|
6512
6663
|
parser->current.end++;
|
6513
6664
|
}
|
6514
6665
|
|
6515
|
-
if (
|
6516
|
-
|
6666
|
+
if (parser->current.end < parser->end) {
|
6667
|
+
LEX(YP_TOKEN_STRING_BEGIN);
|
6517
6668
|
}
|
6518
|
-
|
6519
|
-
parser->current.end++;
|
6520
|
-
LEX(YP_TOKEN_STRING_BEGIN);
|
6521
6669
|
}
|
6522
6670
|
|
6523
|
-
switch (
|
6671
|
+
switch (peek(parser)) {
|
6524
6672
|
case 'i': {
|
6525
6673
|
parser->current.end++;
|
6526
6674
|
|
@@ -6544,6 +6692,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6544
6692
|
|
6545
6693
|
if (parser->current.end < parser->end) {
|
6546
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);
|
6547
6696
|
parser->current.end++;
|
6548
6697
|
}
|
6549
6698
|
|
@@ -6554,6 +6703,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6554
6703
|
|
6555
6704
|
if (parser->current.end < parser->end) {
|
6556
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);
|
6557
6707
|
parser->current.end++;
|
6558
6708
|
}
|
6559
6709
|
|
@@ -6564,6 +6714,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6564
6714
|
|
6565
6715
|
if (parser->current.end < parser->end) {
|
6566
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);
|
6567
6718
|
parser->current.end++;
|
6568
6719
|
}
|
6569
6720
|
|
@@ -6613,7 +6764,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6613
6764
|
// unparseable. In this case we'll just drop it from the parser
|
6614
6765
|
// and skip past it and hope that the next token is something
|
6615
6766
|
// that we can parse.
|
6616
|
-
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");
|
6617
6768
|
goto lex_next_token;
|
6618
6769
|
}
|
6619
6770
|
}
|
@@ -6665,8 +6816,9 @@ parser_lex(yp_parser_t *parser) {
|
|
6665
6816
|
((parser->current.end - parser->current.start) == 7) &&
|
6666
6817
|
current_token_starts_line(parser) &&
|
6667
6818
|
(strncmp(parser->current.start, "__END__", 7) == 0) &&
|
6668
|
-
(
|
6669
|
-
|
6819
|
+
(parser->current.end == parser->end || match_eol(parser))
|
6820
|
+
)
|
6821
|
+
{
|
6670
6822
|
parser->current.end = parser->end;
|
6671
6823
|
parser->current.type = YP_TOKEN___END__;
|
6672
6824
|
parser_lex_callback(parser);
|
@@ -6723,7 +6875,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6723
6875
|
|
6724
6876
|
if ((whitespace = yp_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list, should_stop)) > 0) {
|
6725
6877
|
parser->current.end += whitespace;
|
6726
|
-
if (parser
|
6878
|
+
if (peek_offset(parser, -1) == '\n') {
|
6727
6879
|
// mutates next_start
|
6728
6880
|
parser_flush_heredoc_end(parser);
|
6729
6881
|
}
|
@@ -6787,13 +6939,11 @@ parser_lex(yp_parser_t *parser) {
|
|
6787
6939
|
// and find the next breakpoint.
|
6788
6940
|
if (*breakpoint == '\\') {
|
6789
6941
|
yp_unescape_type_t unescape_type = lex_mode->as.list.interpolation ? YP_UNESCAPE_ALL : YP_UNESCAPE_MINIMAL;
|
6790
|
-
size_t difference = yp_unescape_calculate_difference(
|
6942
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
6791
6943
|
|
6792
6944
|
// If the result is an escaped newline, then we need to
|
6793
6945
|
// track that newline.
|
6794
|
-
|
6795
|
-
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
6796
|
-
}
|
6946
|
+
yp_newline_list_check_append(&parser->newline_list, breakpoint + difference - 1);
|
6797
6947
|
|
6798
6948
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
6799
6949
|
continue;
|
@@ -6828,7 +6978,13 @@ parser_lex(yp_parser_t *parser) {
|
|
6828
6978
|
|
6829
6979
|
case YP_LEX_REGEXP: {
|
6830
6980
|
// First, we'll set to start of this token to be the current end.
|
6831
|
-
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
|
+
}
|
6832
6988
|
|
6833
6989
|
// We'll check if we're at the end of the file. If we are, then we need to
|
6834
6990
|
// return the EOF token.
|
@@ -6855,7 +7011,16 @@ parser_lex(yp_parser_t *parser) {
|
|
6855
7011
|
// If we've hit a newline, then we need to track that in the
|
6856
7012
|
// list of newlines.
|
6857
7013
|
if (*breakpoint == '\n') {
|
6858
|
-
|
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
|
+
}
|
6859
7024
|
|
6860
7025
|
if (lex_mode->as.regexp.terminator != '\n') {
|
6861
7026
|
// If the terminator is not a newline, then we can set
|
@@ -6896,12 +7061,20 @@ parser_lex(yp_parser_t *parser) {
|
|
6896
7061
|
// literally. In this case we'll skip past the next character
|
6897
7062
|
// and find the next breakpoint.
|
6898
7063
|
if (*breakpoint == '\\') {
|
6899
|
-
size_t difference = yp_unescape_calculate_difference(
|
6900
|
-
|
6901
|
-
// If the result is an escaped newline
|
6902
|
-
|
6903
|
-
|
6904
|
-
|
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
|
+
}
|
6905
7078
|
}
|
6906
7079
|
|
6907
7080
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -6989,21 +7162,18 @@ parser_lex(yp_parser_t *parser) {
|
|
6989
7162
|
|
6990
7163
|
// Otherwise we need to switch back to the parent lex mode and
|
6991
7164
|
// return the end of the string.
|
6992
|
-
|
6993
|
-
|
6994
|
-
|
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);
|
6995
7169
|
} else {
|
6996
|
-
if (*parser->current.end == '\n') {
|
6997
|
-
yp_newline_list_append(&parser->newline_list, parser->current.end);
|
6998
|
-
}
|
6999
|
-
|
7000
7170
|
parser->current.end = breakpoint + 1;
|
7001
7171
|
}
|
7002
7172
|
|
7003
7173
|
if (
|
7004
7174
|
parser->lex_modes.current->as.string.label_allowed &&
|
7005
7175
|
(peek(parser) == ':') &&
|
7006
|
-
(
|
7176
|
+
(peek_offset(parser, 1) != ':')
|
7007
7177
|
) {
|
7008
7178
|
parser->current.end++;
|
7009
7179
|
lex_state_set(parser, YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED);
|
@@ -7041,12 +7211,20 @@ parser_lex(yp_parser_t *parser) {
|
|
7041
7211
|
// literally. In this case we'll skip past the next character and
|
7042
7212
|
// find the next breakpoint.
|
7043
7213
|
yp_unescape_type_t unescape_type = parser->lex_modes.current->as.string.interpolation ? YP_UNESCAPE_ALL : YP_UNESCAPE_MINIMAL;
|
7044
|
-
size_t difference = yp_unescape_calculate_difference(
|
7045
|
-
|
7046
|
-
// If the result is an escaped newline
|
7047
|
-
|
7048
|
-
|
7049
|
-
|
7214
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
7215
|
+
|
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
|
+
}
|
7050
7228
|
}
|
7051
7229
|
|
7052
7230
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -7082,6 +7260,7 @@ parser_lex(yp_parser_t *parser) {
|
|
7082
7260
|
} else {
|
7083
7261
|
parser->current.start = parser->next_start;
|
7084
7262
|
parser->current.end = parser->next_start;
|
7263
|
+
parser->heredoc_end = NULL;
|
7085
7264
|
parser->next_start = NULL;
|
7086
7265
|
}
|
7087
7266
|
|
@@ -7098,7 +7277,7 @@ parser_lex(yp_parser_t *parser) {
|
|
7098
7277
|
|
7099
7278
|
// If we are immediately following a newline and we have hit the
|
7100
7279
|
// terminator, then we need to return the ending of the heredoc.
|
7101
|
-
if (parser
|
7280
|
+
if (current_token_starts_line(parser)) {
|
7102
7281
|
const char *start = parser->current.start;
|
7103
7282
|
if (parser->lex_modes.current->as.heredoc.indent != YP_HEREDOC_INDENT_NONE) {
|
7104
7283
|
start += yp_strspn_inline_whitespace(start, parser->end - start);
|
@@ -7108,12 +7287,10 @@ parser_lex(yp_parser_t *parser) {
|
|
7108
7287
|
bool matched = true;
|
7109
7288
|
bool at_end = false;
|
7110
7289
|
|
7111
|
-
|
7112
|
-
|
7113
|
-
|
7114
|
-
|
7115
|
-
parser->current.end = start + ident_length + 2;
|
7116
|
-
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);
|
7117
7294
|
} else if (parser->end == (start + ident_length)) {
|
7118
7295
|
parser->current.end = start + ident_length;
|
7119
7296
|
at_end = true;
|
@@ -7178,19 +7355,10 @@ parser_lex(yp_parser_t *parser) {
|
|
7178
7355
|
(start + ident_length <= parser->end) &&
|
7179
7356
|
(strncmp(start, ident_start, ident_length) == 0)
|
7180
7357
|
) {
|
7181
|
-
// Heredoc terminators must be followed by a newline or EOF to be valid.
|
7182
|
-
if (start + ident_length == parser->end || start[ident_length] == '\n') {
|
7183
|
-
parser->current.end = breakpoint + 1;
|
7184
|
-
LEX(YP_TOKEN_STRING_CONTENT);
|
7185
|
-
}
|
7186
|
-
|
7187
|
-
// They can also be followed by a carriage return and then a
|
7188
|
-
// newline. Be sure here that we don't accidentally read off the
|
7189
|
-
// end.
|
7358
|
+
// Heredoc terminators must be followed by a newline, CRLF, or EOF to be valid.
|
7190
7359
|
if (
|
7191
|
-
|
7192
|
-
(start
|
7193
|
-
(start[ident_length + 1] == '\n')
|
7360
|
+
start + ident_length == parser->end ||
|
7361
|
+
match_eol_at(parser, start + ident_length)
|
7194
7362
|
) {
|
7195
7363
|
parser->current.end = breakpoint + 1;
|
7196
7364
|
LEX(YP_TOKEN_STRING_CONTENT);
|
@@ -7203,21 +7371,24 @@ parser_lex(yp_parser_t *parser) {
|
|
7203
7371
|
break;
|
7204
7372
|
}
|
7205
7373
|
case '\\': {
|
7206
|
-
// If we hit
|
7207
|
-
//
|
7208
|
-
//
|
7209
|
-
|
7210
|
-
|
7374
|
+
// If we hit an escape, then we need to skip past
|
7375
|
+
// however many characters the escape takes up. However
|
7376
|
+
// it's important that if \n or \r\n are escaped that we
|
7377
|
+
// stop looping before the newline and not after the
|
7378
|
+
// newline so that we can still potentially find the
|
7379
|
+
// terminator of the heredoc.
|
7380
|
+
size_t eol_length = match_eol_at(parser, breakpoint + 1);
|
7381
|
+
if (eol_length) {
|
7382
|
+
breakpoint += eol_length;
|
7211
7383
|
} else {
|
7212
7384
|
yp_unescape_type_t unescape_type = (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL;
|
7213
|
-
size_t difference = yp_unescape_calculate_difference(
|
7385
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
7214
7386
|
|
7215
|
-
|
7216
|
-
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
7217
|
-
}
|
7387
|
+
yp_newline_list_check_append(&parser->newline_list, breakpoint + difference - 1);
|
7218
7388
|
|
7219
7389
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
7220
7390
|
}
|
7391
|
+
|
7221
7392
|
break;
|
7222
7393
|
}
|
7223
7394
|
case '#': {
|
@@ -7264,10 +7435,10 @@ static yp_regular_expression_node_t *
|
|
7264
7435
|
yp_regular_expression_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
|
7265
7436
|
yp_regular_expression_node_t *node = yp_regular_expression_node_create(parser, opening, content, closing);
|
7266
7437
|
|
7267
|
-
|
7268
|
-
|
7438
|
+
assert((content->end - content->start) >= 0);
|
7439
|
+
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
7269
7440
|
|
7270
|
-
yp_unescape_manipulate_string(parser,
|
7441
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
7271
7442
|
return node;
|
7272
7443
|
}
|
7273
7444
|
|
@@ -7275,10 +7446,10 @@ static yp_symbol_node_t *
|
|
7275
7446
|
yp_symbol_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
|
7276
7447
|
yp_symbol_node_t *node = yp_symbol_node_create(parser, opening, content, closing);
|
7277
7448
|
|
7278
|
-
|
7279
|
-
|
7449
|
+
assert((content->end - content->start) >= 0);
|
7450
|
+
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
7280
7451
|
|
7281
|
-
yp_unescape_manipulate_string(parser,
|
7452
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
7282
7453
|
return node;
|
7283
7454
|
}
|
7284
7455
|
|
@@ -7286,10 +7457,10 @@ static yp_string_node_t *
|
|
7286
7457
|
yp_string_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
|
7287
7458
|
yp_string_node_t *node = yp_string_node_create(parser, opening, content, closing);
|
7288
7459
|
|
7289
|
-
|
7290
|
-
|
7460
|
+
assert((content->end - content->start) >= 0);
|
7461
|
+
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
7291
7462
|
|
7292
|
-
yp_unescape_manipulate_string(parser,
|
7463
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
7293
7464
|
return node;
|
7294
7465
|
}
|
7295
7466
|
|
@@ -7297,10 +7468,10 @@ static yp_x_string_node_t *
|
|
7297
7468
|
yp_xstring_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing) {
|
7298
7469
|
yp_x_string_node_t *node = yp_xstring_node_create(parser, opening, content, closing);
|
7299
7470
|
|
7300
|
-
|
7301
|
-
|
7471
|
+
assert((content->end - content->start) >= 0);
|
7472
|
+
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
7302
7473
|
|
7303
|
-
yp_unescape_manipulate_string(parser,
|
7474
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL);
|
7304
7475
|
return node;
|
7305
7476
|
}
|
7306
7477
|
|
@@ -7652,19 +7823,153 @@ parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power,
|
|
7652
7823
|
|
7653
7824
|
// Convert the given node into a valid target node.
|
7654
7825
|
static yp_node_t *
|
7655
|
-
parse_target(yp_parser_t *parser, yp_node_t *target
|
7826
|
+
parse_target(yp_parser_t *parser, yp_node_t *target) {
|
7656
7827
|
switch (YP_NODE_TYPE(target)) {
|
7657
7828
|
case YP_NODE_MISSING_NODE:
|
7658
7829
|
return target;
|
7659
|
-
case YP_NODE_CLASS_VARIABLE_READ_NODE:
|
7660
|
-
|
7661
|
-
|
7662
|
-
return
|
7663
|
-
}
|
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;
|
7664
7834
|
case YP_NODE_CONSTANT_PATH_NODE:
|
7665
|
-
|
7666
|
-
|
7667
|
-
|
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
|
+
}
|
7869
|
+
|
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
|
+
}
|
7956
|
+
}
|
7957
|
+
|
7958
|
+
// Convert the given node into a valid write node.
|
7959
|
+
static yp_node_t *
|
7960
|
+
parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
|
7961
|
+
switch (YP_NODE_TYPE(target)) {
|
7962
|
+
case YP_NODE_MISSING_NODE:
|
7963
|
+
return target;
|
7964
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
7965
|
+
yp_class_variable_write_node_t *write_node = yp_class_variable_read_node_to_class_variable_write_node(parser, (yp_class_variable_read_node_t *) target, operator, value);
|
7966
|
+
yp_node_destroy(parser, target);
|
7967
|
+
return (yp_node_t *) write_node;
|
7968
|
+
}
|
7969
|
+
case YP_NODE_CONSTANT_PATH_NODE:
|
7970
|
+
return (yp_node_t *) yp_constant_path_write_node_create(parser, (yp_constant_path_node_t *) target, operator, value);
|
7971
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
7972
|
+
yp_constant_write_node_t *node = yp_constant_write_node_create(parser, &target->location, operator, value);
|
7668
7973
|
yp_node_destroy(parser, target);
|
7669
7974
|
|
7670
7975
|
return (yp_node_t *) node;
|
@@ -7699,18 +8004,15 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7699
8004
|
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
|
7700
8005
|
yp_multi_write_node_operator_loc_set(multi_write, operator);
|
7701
8006
|
|
7702
|
-
|
7703
|
-
|
7704
|
-
multi_write->base.location.end = value->location.end;
|
7705
|
-
}
|
7706
|
-
|
8007
|
+
multi_write->value = value;
|
8008
|
+
multi_write->base.location.end = value->location.end;
|
7707
8009
|
return (yp_node_t *) multi_write;
|
7708
8010
|
}
|
7709
8011
|
case YP_NODE_SPLAT_NODE: {
|
7710
8012
|
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
7711
8013
|
|
7712
8014
|
if (splat->expression != NULL) {
|
7713
|
-
splat->expression =
|
8015
|
+
splat->expression = parse_write(parser, splat->expression, operator, value);
|
7714
8016
|
}
|
7715
8017
|
|
7716
8018
|
yp_location_t location = { .start = NULL, .end = NULL };
|
@@ -7763,12 +8065,10 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7763
8065
|
// method call with no arguments. Now we have an =, so we know it's
|
7764
8066
|
// a method call with an argument. In this case we will create the
|
7765
8067
|
// arguments node, parse the argument, and add it to the list.
|
7766
|
-
|
7767
|
-
|
7768
|
-
|
7769
|
-
|
7770
|
-
target->location.end = arguments->base.location.end;
|
7771
|
-
}
|
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;
|
7772
8072
|
|
7773
8073
|
// The method name needs to change. If we previously had foo, we now
|
7774
8074
|
// need foo=. In this case we'll allocate a new owned string, copy
|
@@ -7796,15 +8096,13 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7796
8096
|
(call->message_loc.end[-1] == ']') &&
|
7797
8097
|
(call->block == NULL)
|
7798
8098
|
) {
|
7799
|
-
if (
|
7800
|
-
|
7801
|
-
call->arguments = yp_arguments_node_create(parser);
|
7802
|
-
}
|
7803
|
-
|
7804
|
-
yp_arguments_node_arguments_append(call->arguments, value);
|
7805
|
-
target->location.end = value->location.end;
|
8099
|
+
if (call->arguments == NULL) {
|
8100
|
+
call->arguments = yp_arguments_node_create(parser);
|
7806
8101
|
}
|
7807
8102
|
|
8103
|
+
yp_arguments_node_arguments_append(call->arguments, value);
|
8104
|
+
target->location.end = value->location.end;
|
8105
|
+
|
7808
8106
|
// Free the previous name and replace it with "[]=".
|
7809
8107
|
yp_string_free(&call->name);
|
7810
8108
|
yp_string_constant_init(&call->name, "[]=", 3);
|
@@ -7816,9 +8114,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7816
8114
|
// syntax error. In this case we'll fall through to our default
|
7817
8115
|
// handling. We need to free the value that we parsed because there
|
7818
8116
|
// is no way for us to attach it to the tree at this point.
|
7819
|
-
|
7820
|
-
yp_node_destroy(parser, value);
|
7821
|
-
}
|
8117
|
+
yp_node_destroy(parser, value);
|
7822
8118
|
}
|
7823
8119
|
/* fallthrough */
|
7824
8120
|
default:
|
@@ -7846,7 +8142,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7846
8142
|
// location that we know requires a multi write, as in the case of a for loop.
|
7847
8143
|
// In this case we will set up the parsing loop slightly differently.
|
7848
8144
|
if (first_target != NULL) {
|
7849
|
-
first_target = parse_target(parser, first_target
|
8145
|
+
first_target = parse_target(parser, first_target);
|
7850
8146
|
|
7851
8147
|
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
|
7852
8148
|
return first_target;
|
@@ -7877,9 +8173,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7877
8173
|
yp_node_t *name = NULL;
|
7878
8174
|
|
7879
8175
|
if (token_begins_expression_p(parser->current.type)) {
|
7880
|
-
yp_token_t operator = not_provided(parser);
|
7881
8176
|
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
|
7882
|
-
name = parse_target(parser, name
|
8177
|
+
name = parse_target(parser, name);
|
7883
8178
|
}
|
7884
8179
|
|
7885
8180
|
yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name);
|
@@ -7909,6 +8204,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7909
8204
|
|
7910
8205
|
if (YP_NODE_TYPE_P(child_target, YP_NODE_MULTI_WRITE_NODE)) {
|
7911
8206
|
target = (yp_multi_write_node_t *) child_target;
|
8207
|
+
target->base.location.start = lparen.start;
|
8208
|
+
target->base.location.end = rparen.end;
|
7912
8209
|
target->lparen_loc = (yp_location_t) { .start = lparen.start, .end = lparen.end };
|
7913
8210
|
target->rparen_loc = (yp_location_t) { .start = rparen.start, .end = rparen.end };
|
7914
8211
|
} else {
|
@@ -7925,6 +8222,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7925
8222
|
yp_multi_write_node_targets_append(target, child_target);
|
7926
8223
|
}
|
7927
8224
|
|
8225
|
+
target->base.location.start = lparen.start;
|
7928
8226
|
target->base.location.end = rparen.end;
|
7929
8227
|
yp_multi_write_node_targets_append(result, (yp_node_t *) target);
|
7930
8228
|
}
|
@@ -7947,7 +8245,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7947
8245
|
}
|
7948
8246
|
|
7949
8247
|
yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','.");
|
7950
|
-
target = parse_target(parser, target
|
8248
|
+
target = parse_target(parser, target);
|
7951
8249
|
|
7952
8250
|
yp_multi_write_node_targets_append(result, target);
|
7953
8251
|
}
|
@@ -8407,7 +8705,6 @@ parse_parameters(
|
|
8407
8705
|
bool looping = true;
|
8408
8706
|
|
8409
8707
|
yp_do_loop_stack_push(parser, false);
|
8410
|
-
|
8411
8708
|
yp_parameters_order_t order = YP_PARAMETERS_ORDER_NONE;
|
8412
8709
|
|
8413
8710
|
do {
|
@@ -8699,8 +8996,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8699
8996
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
8700
8997
|
|
8701
8998
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
8702
|
-
|
8703
|
-
reference = parse_target(parser, reference, &operator, NULL);
|
8999
|
+
reference = parse_target(parser, reference);
|
8704
9000
|
|
8705
9001
|
yp_rescue_node_reference_set(rescue, reference);
|
8706
9002
|
break;
|
@@ -8730,8 +9026,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8730
9026
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
8731
9027
|
|
8732
9028
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
8733
|
-
|
8734
|
-
reference = parse_target(parser, reference, &operator, NULL);
|
9029
|
+
reference = parse_target(parser, reference);
|
8735
9030
|
|
8736
9031
|
yp_rescue_node_reference_set(rescue, reference);
|
8737
9032
|
break;
|
@@ -8999,7 +9294,7 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) {
|
|
8999
9294
|
}
|
9000
9295
|
|
9001
9296
|
yp_token_t end_keyword = not_provided(parser);
|
9002
|
-
yp_node_t *parent;
|
9297
|
+
yp_node_t *parent = NULL;
|
9003
9298
|
|
9004
9299
|
switch (context) {
|
9005
9300
|
case YP_CONTEXT_IF:
|
@@ -9009,7 +9304,6 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) {
|
|
9009
9304
|
parent = (yp_node_t *) yp_unless_node_create(parser, &keyword, predicate, statements);
|
9010
9305
|
break;
|
9011
9306
|
default:
|
9012
|
-
parent = NULL;
|
9013
9307
|
assert(false && "unreachable");
|
9014
9308
|
break;
|
9015
9309
|
}
|
@@ -9055,50 +9349,49 @@ parse_conditional(yp_parser_t *parser, yp_context_t context) {
|
|
9055
9349
|
switch (context) {
|
9056
9350
|
case YP_CONTEXT_IF:
|
9057
9351
|
((yp_if_node_t *) current)->consequent = (yp_node_t *) else_node;
|
9058
|
-
// Recurse down if nodes setting the appropriate end location in
|
9059
|
-
// all cases.
|
9060
|
-
yp_node_t *recursing_node = parent;
|
9061
|
-
bool recursing = true;
|
9062
|
-
|
9063
|
-
while (recursing) {
|
9064
|
-
switch (YP_NODE_TYPE(recursing_node)) {
|
9065
|
-
case YP_NODE_IF_NODE:
|
9066
|
-
yp_if_node_end_keyword_loc_set((yp_if_node_t *) recursing_node, &parser->previous);
|
9067
|
-
recursing_node = ((yp_if_node_t *) recursing_node)->consequent;
|
9068
|
-
break;
|
9069
|
-
case YP_NODE_ELSE_NODE:
|
9070
|
-
yp_else_node_end_keyword_loc_set((yp_else_node_t *) recursing_node, &parser->previous);
|
9071
|
-
recursing = false;
|
9072
|
-
break;
|
9073
|
-
default: {
|
9074
|
-
recursing = false;
|
9075
|
-
break;
|
9076
|
-
}
|
9077
|
-
}
|
9078
|
-
}
|
9079
9352
|
break;
|
9080
9353
|
case YP_CONTEXT_UNLESS:
|
9081
9354
|
((yp_unless_node_t *) parent)->consequent = else_node;
|
9082
|
-
yp_unless_node_end_keyword_loc_set((yp_unless_node_t *) parent, &parser->previous);
|
9083
9355
|
break;
|
9084
9356
|
default:
|
9085
9357
|
assert(false && "unreachable");
|
9086
9358
|
break;
|
9087
9359
|
}
|
9088
9360
|
} else {
|
9089
|
-
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close
|
9361
|
+
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close conditional statement.");
|
9362
|
+
}
|
9090
9363
|
|
9091
|
-
|
9092
|
-
|
9093
|
-
|
9094
|
-
|
9095
|
-
|
9096
|
-
|
9097
|
-
|
9098
|
-
|
9099
|
-
|
9100
|
-
|
9364
|
+
// Set the appropriate end location for all of the nodes in the subtree.
|
9365
|
+
switch (context) {
|
9366
|
+
case YP_CONTEXT_IF: {
|
9367
|
+
yp_node_t *current = parent;
|
9368
|
+
bool recursing = true;
|
9369
|
+
|
9370
|
+
while (recursing) {
|
9371
|
+
switch (YP_NODE_TYPE(current)) {
|
9372
|
+
case YP_NODE_IF_NODE:
|
9373
|
+
yp_if_node_end_keyword_loc_set((yp_if_node_t *) current, &parser->previous);
|
9374
|
+
current = ((yp_if_node_t *) current)->consequent;
|
9375
|
+
recursing = current != NULL;
|
9376
|
+
break;
|
9377
|
+
case YP_NODE_ELSE_NODE:
|
9378
|
+
yp_else_node_end_keyword_loc_set((yp_else_node_t *) current, &parser->previous);
|
9379
|
+
recursing = false;
|
9380
|
+
break;
|
9381
|
+
default: {
|
9382
|
+
recursing = false;
|
9383
|
+
break;
|
9384
|
+
}
|
9385
|
+
}
|
9386
|
+
}
|
9387
|
+
break;
|
9101
9388
|
}
|
9389
|
+
case YP_CONTEXT_UNLESS:
|
9390
|
+
yp_unless_node_end_keyword_loc_set((yp_unless_node_t *) parent, &parser->previous);
|
9391
|
+
break;
|
9392
|
+
default:
|
9393
|
+
assert(false && "unreachable");
|
9394
|
+
break;
|
9102
9395
|
}
|
9103
9396
|
|
9104
9397
|
return parent;
|
@@ -9172,7 +9465,12 @@ parse_string_part(yp_parser_t *parser) {
|
|
9172
9465
|
yp_unescape_type_t unescape_type = YP_UNESCAPE_ALL;
|
9173
9466
|
|
9174
9467
|
if (parser->lex_modes.current->mode == YP_LEX_HEREDOC) {
|
9175
|
-
if (parser->lex_modes.current->as.heredoc.
|
9468
|
+
if (parser->lex_modes.current->as.heredoc.indent == YP_HEREDOC_INDENT_TILDE) {
|
9469
|
+
// If we're in a tilde heredoc, we want to unescape it later
|
9470
|
+
// because we don't want unescaped newlines to disappear
|
9471
|
+
// before we handle them in the dedent.
|
9472
|
+
unescape_type = YP_UNESCAPE_NONE;
|
9473
|
+
} else if (parser->lex_modes.current->as.heredoc.quote == YP_HEREDOC_QUOTE_SINGLE) {
|
9176
9474
|
unescape_type = YP_UNESCAPE_MINIMAL;
|
9177
9475
|
}
|
9178
9476
|
}
|
@@ -9280,14 +9578,10 @@ parse_string_part(yp_parser_t *parser) {
|
|
9280
9578
|
|
9281
9579
|
static yp_node_t *
|
9282
9580
|
parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_state) {
|
9283
|
-
bool lex_string = lex_mode->mode == YP_LEX_STRING;
|
9284
|
-
bool can_be_interpolated = lex_string && lex_mode->as.string.interpolation;
|
9285
9581
|
yp_token_t opening = parser->previous;
|
9286
9582
|
|
9287
|
-
if (
|
9288
|
-
if (next_state != YP_LEX_STATE_NONE)
|
9289
|
-
lex_state_set(parser, next_state);
|
9290
|
-
}
|
9583
|
+
if (lex_mode->mode != YP_LEX_STRING) {
|
9584
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9291
9585
|
yp_token_t symbol;
|
9292
9586
|
|
9293
9587
|
switch (parser->current.type) {
|
@@ -9317,37 +9611,44 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s
|
|
9317
9611
|
return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &symbol, &closing, YP_UNESCAPE_ALL);
|
9318
9612
|
}
|
9319
9613
|
|
9320
|
-
if (
|
9321
|
-
//
|
9322
|
-
|
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.
|
9323
9639
|
yp_node_list_t node_list = YP_EMPTY_NODE_LIST;
|
9640
|
+
if (part) yp_node_list_append(&node_list, part);
|
9324
9641
|
|
9325
9642
|
while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
9326
|
-
|
9327
|
-
if (part != NULL) {
|
9643
|
+
if ((part = parse_string_part(parser)) != NULL) {
|
9328
9644
|
yp_node_list_append(&node_list, part);
|
9329
9645
|
}
|
9330
9646
|
}
|
9331
9647
|
|
9332
|
-
|
9333
|
-
// If the only element on the node_list is a StringNode, we know this is a SymbolNode
|
9334
|
-
// and not an InterpolatedSymbolNode
|
9335
|
-
if (node_list.size == 1 && YP_NODE_TYPE_P(node_list.nodes[0], YP_NODE_STRING_NODE)) {
|
9336
|
-
res = (yp_node_t *)yp_string_node_to_symbol_node(parser, (yp_string_node_t *)node_list.nodes[0]);
|
9337
|
-
free(node_list.nodes);
|
9338
|
-
}
|
9339
|
-
else {
|
9340
|
-
yp_interpolated_symbol_node_t *interpolated = yp_interpolated_symbol_node_create(parser, &opening, &node_list, &opening);
|
9341
|
-
yp_interpolated_symbol_node_closing_set(interpolated, &parser->current);
|
9342
|
-
res = (yp_node_t *) interpolated;
|
9343
|
-
}
|
9344
|
-
|
9345
|
-
if (next_state != YP_LEX_STATE_NONE) {
|
9346
|
-
lex_state_set(parser, next_state);
|
9347
|
-
}
|
9648
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9348
9649
|
expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated symbol.");
|
9349
9650
|
|
9350
|
-
return
|
9651
|
+
return (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &node_list, &parser->previous);
|
9351
9652
|
}
|
9352
9653
|
|
9353
9654
|
yp_token_t content;
|
@@ -9491,9 +9792,12 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) {
|
|
9491
9792
|
const char *cur_char = content_loc->start;
|
9492
9793
|
|
9493
9794
|
while (cur_char && cur_char < content_loc->end) {
|
9494
|
-
// Any empty newlines aren't included in the minimum whitespace
|
9495
|
-
|
9496
|
-
|
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
|
+
}
|
9497
9801
|
|
9498
9802
|
if (cur_char == content_loc->end) break;
|
9499
9803
|
|
@@ -9508,11 +9812,12 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) {
|
|
9508
9812
|
cur_char++;
|
9509
9813
|
}
|
9510
9814
|
|
9511
|
-
// If we hit a newline, then we have encountered a line that
|
9512
|
-
// only whitespace, and it shouldn't be considered in
|
9513
|
-
// common leading whitespace.
|
9514
|
-
|
9515
|
-
|
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;
|
9516
9821
|
continue;
|
9517
9822
|
}
|
9518
9823
|
|
@@ -9545,14 +9850,30 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9545
9850
|
int common_whitespace;
|
9546
9851
|
if ((common_whitespace = parse_heredoc_common_whitespace(parser, nodes)) <= 0) return;
|
9547
9852
|
|
9548
|
-
//
|
9549
|
-
|
9550
|
-
|
9551
|
-
|
9853
|
+
// The next node should be dedented if it's the first node in the list or if
|
9854
|
+
// if follows a string node.
|
9855
|
+
bool dedent_next = true;
|
9856
|
+
|
9857
|
+
// Iterate over all nodes, and trim whitespace accordingly. We're going to
|
9858
|
+
// keep around two indices: a read and a write. If we end up trimming all of
|
9859
|
+
// the whitespace from a node, then we'll drop it from the list entirely.
|
9860
|
+
size_t write_index = 0;
|
9861
|
+
|
9862
|
+
for (size_t read_index = 0; read_index < nodes->size; read_index++) {
|
9863
|
+
yp_node_t *node = nodes->nodes[read_index];
|
9864
|
+
|
9865
|
+
// We're not manipulating child nodes that aren't strings. In this case
|
9866
|
+
// we'll skip past it and indicate that the subsequent node should not
|
9867
|
+
// be dedented.
|
9868
|
+
if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE)) {
|
9869
|
+
nodes->nodes[write_index++] = node;
|
9870
|
+
dedent_next = false;
|
9871
|
+
continue;
|
9872
|
+
}
|
9552
9873
|
|
9553
9874
|
// Get a reference to the string struct that is being held by the string
|
9554
9875
|
// node. This is the value we're going to actual manipulate.
|
9555
|
-
yp_string_t *string = &((yp_string_node_t *) node)->unescaped;
|
9876
|
+
yp_string_t *string = &(((yp_string_node_t *) node)->unescaped);
|
9556
9877
|
yp_string_ensure_owned(string);
|
9557
9878
|
|
9558
9879
|
// Now get the bounds of the existing string. We'll use this as a
|
@@ -9568,7 +9889,6 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9568
9889
|
// whitespace, so we'll maintain a pointer to the current position in the
|
9569
9890
|
// string that we're writing to.
|
9570
9891
|
char *dest_cursor = source_start;
|
9571
|
-
bool dedent_next = (index == 0) || YP_NODE_TYPE_P(nodes->nodes[index - 1], YP_NODE_STRING_NODE);
|
9572
9892
|
|
9573
9893
|
while (source_cursor < source_end) {
|
9574
9894
|
// If we need to dedent the next element within the heredoc or the next
|
@@ -9613,8 +9933,20 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9613
9933
|
dedent_next = true;
|
9614
9934
|
}
|
9615
9935
|
|
9616
|
-
|
9936
|
+
// We only want to write this node into the list if it has any content.
|
9937
|
+
if (dest_length == 0) {
|
9938
|
+
yp_node_destroy(parser, node);
|
9939
|
+
} else {
|
9940
|
+
string->length = dest_length;
|
9941
|
+
yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL);
|
9942
|
+
nodes->nodes[write_index++] = node;
|
9943
|
+
}
|
9944
|
+
|
9945
|
+
// We always dedent the next node if it follows a string node.
|
9946
|
+
dedent_next = true;
|
9617
9947
|
}
|
9948
|
+
|
9949
|
+
nodes->size = write_index;
|
9618
9950
|
}
|
9619
9951
|
|
9620
9952
|
static yp_node_t *
|
@@ -10363,10 +10695,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10363
10695
|
}
|
10364
10696
|
case YP_TOKEN_PARENTHESIS_LEFT:
|
10365
10697
|
case YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
|
10366
|
-
|
10698
|
+
yp_token_t opening = parser->current;
|
10367
10699
|
parser_lex(parser);
|
10368
|
-
|
10369
|
-
yp_token_t opening = parser->previous;
|
10370
10700
|
while (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE));
|
10371
10701
|
|
10372
10702
|
// If this is the end of the file or we match a right parenthesis, then
|
@@ -10385,7 +10715,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10385
10715
|
// If we hit a right parenthesis, then we're done parsing the parentheses
|
10386
10716
|
// node, and we can check which kind of node we should return.
|
10387
10717
|
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
10388
|
-
if (
|
10718
|
+
if (opening.type == YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
|
10389
10719
|
lex_state_set(parser, YP_LEX_STATE_ENDARG);
|
10390
10720
|
}
|
10391
10721
|
parser_lex(parser);
|
@@ -10403,6 +10733,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10403
10733
|
|
10404
10734
|
if (multi_statement->lparen_loc.start == NULL) {
|
10405
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;
|
10406
10738
|
multi_write->lparen_loc = lparen_loc;
|
10407
10739
|
multi_write->rparen_loc = rparen_loc;
|
10408
10740
|
} else {
|
@@ -10505,7 +10837,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10505
10837
|
// fact a method call, not a constant read.
|
10506
10838
|
if (
|
10507
10839
|
match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) ||
|
10508
|
-
(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))) ||
|
10509
10841
|
(yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT))
|
10510
10842
|
) {
|
10511
10843
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
@@ -10628,7 +10960,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10628
10960
|
// can still be a method call if it is followed by arguments or
|
10629
10961
|
// a block, so we need to check for that here.
|
10630
10962
|
if (
|
10631
|
-
(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))) ||
|
10632
10964
|
(yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT))
|
10633
10965
|
) {
|
10634
10966
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
@@ -10673,12 +11005,15 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10673
11005
|
|
10674
11006
|
lex_state_set(parser, YP_LEX_STATE_END);
|
10675
11007
|
expect(parser, YP_TOKEN_HEREDOC_END, "Expected a closing delimiter for heredoc.");
|
11008
|
+
|
10676
11009
|
if (quote == YP_HEREDOC_QUOTE_BACKTICK) {
|
10677
11010
|
assert(YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_X_STRING_NODE));
|
10678
11011
|
yp_interpolated_xstring_node_closing_set(((yp_interpolated_x_string_node_t *) node), &parser->previous);
|
11012
|
+
node->location = ((yp_interpolated_x_string_node_t *) node)->opening_loc;
|
10679
11013
|
} else {
|
10680
11014
|
assert(YP_NODE_TYPE_P(node, YP_NODE_INTERPOLATED_STRING_NODE));
|
10681
11015
|
yp_interpolated_string_node_closing_set((yp_interpolated_string_node_t *) node, &parser->previous);
|
11016
|
+
node->location = ((yp_interpolated_string_node_t *) node)->opening_loc;
|
10682
11017
|
}
|
10683
11018
|
|
10684
11019
|
// If this is a heredoc that is indented with a ~, then we need to dedent
|
@@ -11043,7 +11378,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11043
11378
|
return (yp_node_t *) yp_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
|
11044
11379
|
}
|
11045
11380
|
|
11046
|
-
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
|
+
|
11047
11387
|
yp_token_t inheritance_operator;
|
11048
11388
|
yp_node_t *superclass;
|
11049
11389
|
|
@@ -11084,7 +11424,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11084
11424
|
yp_constant_id_list_t locals = parser->current_scope->locals;
|
11085
11425
|
yp_parser_scope_pop(parser);
|
11086
11426
|
yp_do_loop_stack_pop(parser);
|
11087
|
-
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);
|
11088
11428
|
}
|
11089
11429
|
case YP_TOKEN_KEYWORD_DEF: {
|
11090
11430
|
yp_token_t def_keyword = parser->current;
|
@@ -11243,6 +11583,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11243
11583
|
break;
|
11244
11584
|
}
|
11245
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
|
+
|
11246
11592
|
lparen = not_provided(parser);
|
11247
11593
|
rparen = not_provided(parser);
|
11248
11594
|
params = parse_parameters(parser, YP_BINDING_POWER_DEFINED, false, false, true);
|
@@ -11472,13 +11818,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11472
11818
|
parser_lex(parser);
|
11473
11819
|
|
11474
11820
|
yp_token_t module_keyword = parser->previous;
|
11475
|
-
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;
|
11476
11823
|
|
11477
|
-
// If we can recover from a syntax error that occurred while parsing
|
11478
|
-
// name of the module, then we'll handle that here.
|
11479
|
-
if (YP_NODE_TYPE_P(
|
11480
|
-
yp_token_t
|
11481
|
-
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);
|
11482
11829
|
}
|
11483
11830
|
|
11484
11831
|
while (accept(parser, YP_TOKEN_COLON_COLON)) {
|
@@ -11487,7 +11834,15 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11487
11834
|
expect(parser, YP_TOKEN_CONSTANT, "Expected to find a module name after `::`.");
|
11488
11835
|
yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous);
|
11489
11836
|
|
11490
|
-
|
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`.");
|
11491
11846
|
}
|
11492
11847
|
|
11493
11848
|
yp_parser_scope_push(parser, true);
|
@@ -11514,7 +11869,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11514
11869
|
yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, "Module definition in method body");
|
11515
11870
|
}
|
11516
11871
|
|
11517
|
-
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);
|
11518
11873
|
}
|
11519
11874
|
case YP_TOKEN_KEYWORD_NIL:
|
11520
11875
|
parser_lex(parser);
|
@@ -11550,12 +11905,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11550
11905
|
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `until` statement.");
|
11551
11906
|
}
|
11552
11907
|
|
11553
|
-
|
11554
|
-
if (parser->previous.type == YP_TOKEN_KEYWORD_END) {
|
11555
|
-
until_node->base.location.end = parser->previous.end;
|
11556
|
-
}
|
11557
|
-
|
11558
|
-
return (yp_node_t *) until_node;
|
11908
|
+
return (yp_node_t *) yp_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
|
11559
11909
|
}
|
11560
11910
|
case YP_TOKEN_KEYWORD_WHILE: {
|
11561
11911
|
yp_do_loop_stack_push(parser, true);
|
@@ -11576,11 +11926,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11576
11926
|
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `while` statement.");
|
11577
11927
|
}
|
11578
11928
|
|
11579
|
-
|
11580
|
-
if (parser->previous.type == YP_TOKEN_KEYWORD_END) {
|
11581
|
-
while_node->base.location.end = parser->previous.end;
|
11582
|
-
}
|
11583
|
-
return (yp_node_t *) while_node;
|
11929
|
+
return (yp_node_t *) yp_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
|
11584
11930
|
}
|
11585
11931
|
case YP_TOKEN_PERCENT_LOWER_I: {
|
11586
11932
|
parser_lex(parser);
|
@@ -12086,30 +12432,32 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
12086
12432
|
yp_accepts_block_stack_push(parser, true);
|
12087
12433
|
parser_lex(parser);
|
12088
12434
|
|
12089
|
-
yp_token_t
|
12435
|
+
yp_token_t operator = parser->previous;
|
12090
12436
|
yp_parser_scope_push(parser, false);
|
12091
12437
|
yp_block_parameters_node_t *params;
|
12092
12438
|
|
12093
12439
|
switch (parser->current.type) {
|
12094
12440
|
case YP_TOKEN_PARENTHESIS_LEFT: {
|
12095
|
-
yp_token_t
|
12441
|
+
yp_token_t opening = parser->current;
|
12096
12442
|
parser_lex(parser);
|
12097
12443
|
|
12098
12444
|
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
12099
|
-
params = yp_block_parameters_node_create(parser, NULL, &
|
12445
|
+
params = yp_block_parameters_node_create(parser, NULL, &opening);
|
12100
12446
|
} else {
|
12101
|
-
params = parse_block_parameters(parser, false, &
|
12447
|
+
params = parse_block_parameters(parser, false, &opening, true);
|
12102
12448
|
}
|
12103
12449
|
|
12104
12450
|
accept(parser, YP_TOKEN_NEWLINE);
|
12105
12451
|
expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis.");
|
12106
|
-
yp_block_parameters_node_closing_set(params, &parser->previous);
|
12107
12452
|
|
12453
|
+
yp_block_parameters_node_closing_set(params, &parser->previous);
|
12108
12454
|
break;
|
12109
12455
|
}
|
12110
12456
|
case YP_CASE_PARAMETER: {
|
12457
|
+
yp_accepts_block_stack_push(parser, false);
|
12111
12458
|
yp_token_t opening = not_provided(parser);
|
12112
12459
|
params = parse_block_parameters(parser, false, &opening, true);
|
12460
|
+
yp_accepts_block_stack_pop(parser);
|
12113
12461
|
break;
|
12114
12462
|
}
|
12115
12463
|
default: {
|
@@ -12118,16 +12466,20 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
12118
12466
|
}
|
12119
12467
|
}
|
12120
12468
|
|
12469
|
+
yp_token_t opening;
|
12121
12470
|
yp_node_t *body = NULL;
|
12122
12471
|
parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
|
12123
12472
|
|
12124
12473
|
if (accept(parser, YP_TOKEN_LAMBDA_BEGIN)) {
|
12474
|
+
opening = parser->previous;
|
12475
|
+
|
12125
12476
|
if (!accept(parser, YP_TOKEN_BRACE_RIGHT)) {
|
12126
12477
|
body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_BRACES);
|
12127
12478
|
expect(parser, YP_TOKEN_BRACE_RIGHT, "Expecting '}' to close lambda block.");
|
12128
12479
|
}
|
12129
12480
|
} else {
|
12130
12481
|
expect(parser, YP_TOKEN_KEYWORD_DO, "Expected a 'do' keyword or a '{' to open lambda block.");
|
12482
|
+
opening = parser->previous;
|
12131
12483
|
|
12132
12484
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
12133
12485
|
body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_DO_END);
|
@@ -12144,7 +12496,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
12144
12496
|
yp_constant_id_list_t locals = parser->current_scope->locals;
|
12145
12497
|
yp_parser_scope_pop(parser);
|
12146
12498
|
yp_accepts_block_stack_pop(parser);
|
12147
|
-
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);
|
12148
12500
|
}
|
12149
12501
|
case YP_TOKEN_UPLUS: {
|
12150
12502
|
parser_lex(parser);
|
@@ -12363,7 +12715,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12363
12715
|
case YP_CASE_WRITABLE: {
|
12364
12716
|
parser_lex(parser);
|
12365
12717
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
12366
|
-
return
|
12718
|
+
return parse_write(parser, node, &token, value);
|
12367
12719
|
}
|
12368
12720
|
case YP_NODE_SPLAT_NODE: {
|
12369
12721
|
yp_splat_node_t *splat_node = (yp_splat_node_t *) node;
|
@@ -12372,7 +12724,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12372
12724
|
case YP_CASE_WRITABLE:
|
12373
12725
|
parser_lex(parser);
|
12374
12726
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
12375
|
-
return
|
12727
|
+
return parse_write(parser, (yp_node_t *) splat_node, &token, value);
|
12376
12728
|
default:
|
12377
12729
|
break;
|
12378
12730
|
}
|
@@ -12398,48 +12750,16 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12398
12750
|
parser_lex(parser);
|
12399
12751
|
|
12400
12752
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12401
|
-
yp_node_t *result = (yp_node_t *)
|
12753
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_and_write_node_create(parser, node, &token, value);
|
12402
12754
|
|
12403
12755
|
yp_node_destroy(parser, node);
|
12404
12756
|
return result;
|
12405
12757
|
}
|
12406
|
-
case YP_NODE_CALL_NODE: {
|
12407
|
-
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
12408
|
-
|
12409
|
-
// If we have a vcall (a method with no arguments and no
|
12410
|
-
// receiver that could have been a local variable) then we
|
12411
|
-
// will transform it into a local variable write.
|
12412
|
-
if (yp_call_node_variable_call_p(call_node)) {
|
12413
|
-
yp_location_t message_loc = call_node->message_loc;
|
12414
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12415
|
-
|
12416
|
-
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12417
|
-
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12418
|
-
}
|
12419
|
-
|
12420
|
-
parser_lex(parser);
|
12421
|
-
|
12422
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12423
|
-
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message_loc.start, message_loc.end);
|
12424
|
-
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_and_write_node_create(parser, node, &token, value, constant_id);
|
12425
|
-
|
12426
|
-
yp_node_destroy(parser, node);
|
12427
|
-
return result;
|
12428
|
-
}
|
12429
|
-
|
12430
|
-
parser_lex(parser);
|
12431
|
-
|
12432
|
-
yp_token_t operator = not_provided(parser);
|
12433
|
-
node = parse_target(parser, node, &operator, NULL);
|
12434
|
-
|
12435
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12436
|
-
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12437
|
-
}
|
12438
12758
|
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12439
12759
|
parser_lex(parser);
|
12440
12760
|
|
12441
12761
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12442
|
-
yp_node_t *result = (yp_node_t *)
|
12762
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_and_write_node_create(parser, node, &token, value);
|
12443
12763
|
|
12444
12764
|
yp_node_destroy(parser, node);
|
12445
12765
|
return result;
|
@@ -12448,13 +12768,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12448
12768
|
parser_lex(parser);
|
12449
12769
|
|
12450
12770
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12451
|
-
return (yp_node_t *)
|
12771
|
+
return (yp_node_t *) yp_constant_path_and_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
12452
12772
|
}
|
12453
12773
|
case YP_NODE_CONSTANT_READ_NODE: {
|
12454
12774
|
parser_lex(parser);
|
12455
12775
|
|
12456
12776
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12457
|
-
yp_node_t *result = (yp_node_t *)
|
12777
|
+
yp_node_t *result = (yp_node_t *) yp_constant_and_write_node_create(parser, node, &token, value);
|
12458
12778
|
|
12459
12779
|
yp_node_destroy(parser, node);
|
12460
12780
|
return result;
|
@@ -12463,21 +12783,49 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12463
12783
|
parser_lex(parser);
|
12464
12784
|
|
12465
12785
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12466
|
-
yp_node_t *result = (yp_node_t *)
|
12786
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_and_write_node_create(parser, node, &token, value);
|
12467
12787
|
|
12468
12788
|
yp_node_destroy(parser, node);
|
12469
12789
|
return result;
|
12470
12790
|
}
|
12471
12791
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
12792
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12472
12793
|
parser_lex(parser);
|
12473
12794
|
|
12474
12795
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12475
|
-
|
12476
|
-
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_and_write_node_create(parser, node, &token, value, constant_id);
|
12796
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, cast->constant_id, cast->depth);
|
12477
12797
|
|
12478
12798
|
yp_node_destroy(parser, node);
|
12479
12799
|
return result;
|
12480
12800
|
}
|
12801
|
+
case YP_NODE_CALL_NODE: {
|
12802
|
+
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
12803
|
+
|
12804
|
+
// If we have a vcall (a method with no arguments and no
|
12805
|
+
// receiver that could have been a local variable) then we
|
12806
|
+
// will transform it into a local variable write.
|
12807
|
+
if (yp_call_node_variable_call_p(call_node)) {
|
12808
|
+
yp_location_t message_loc = call_node->message_loc;
|
12809
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12810
|
+
|
12811
|
+
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12812
|
+
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12813
|
+
}
|
12814
|
+
|
12815
|
+
parser_lex(parser);
|
12816
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
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;
|
12821
|
+
}
|
12822
|
+
|
12823
|
+
parser_lex(parser);
|
12824
|
+
node = parse_target(parser, node);
|
12825
|
+
|
12826
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12827
|
+
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12828
|
+
}
|
12481
12829
|
case YP_NODE_MULTI_WRITE_NODE: {
|
12482
12830
|
parser_lex(parser);
|
12483
12831
|
yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `&&=' on a multi-write.");
|
@@ -12503,48 +12851,16 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12503
12851
|
parser_lex(parser);
|
12504
12852
|
|
12505
12853
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12506
|
-
yp_node_t *result = (yp_node_t *)
|
12854
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_or_write_node_create(parser, node, &token, value);
|
12507
12855
|
|
12508
12856
|
yp_node_destroy(parser, node);
|
12509
12857
|
return result;
|
12510
12858
|
}
|
12511
|
-
case YP_NODE_CALL_NODE: {
|
12512
|
-
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
12513
|
-
|
12514
|
-
// If we have a vcall (a method with no arguments and no
|
12515
|
-
// receiver that could have been a local variable) then we
|
12516
|
-
// will transform it into a local variable write.
|
12517
|
-
if (yp_call_node_variable_call_p(call_node)) {
|
12518
|
-
yp_location_t message_loc = call_node->message_loc;
|
12519
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12520
|
-
|
12521
|
-
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12522
|
-
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12523
|
-
}
|
12524
|
-
|
12525
|
-
parser_lex(parser);
|
12526
|
-
|
12527
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12528
|
-
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message_loc.start, message_loc.end);
|
12529
|
-
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_or_write_node_create(parser, node, &token, value, constant_id);
|
12530
|
-
|
12531
|
-
yp_node_destroy(parser, node);
|
12532
|
-
return result;
|
12533
|
-
}
|
12534
|
-
|
12535
|
-
parser_lex(parser);
|
12536
|
-
|
12537
|
-
yp_token_t operator = not_provided(parser);
|
12538
|
-
node = parse_target(parser, node, &operator, NULL);
|
12539
|
-
|
12540
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12541
|
-
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12542
|
-
}
|
12543
12859
|
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12544
12860
|
parser_lex(parser);
|
12545
12861
|
|
12546
12862
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12547
|
-
yp_node_t *result = (yp_node_t *)
|
12863
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_or_write_node_create(parser, node, &token, value);
|
12548
12864
|
|
12549
12865
|
yp_node_destroy(parser, node);
|
12550
12866
|
return result;
|
@@ -12553,13 +12869,13 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12553
12869
|
parser_lex(parser);
|
12554
12870
|
|
12555
12871
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12556
|
-
return (yp_node_t *)
|
12872
|
+
return (yp_node_t *) yp_constant_path_or_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
12557
12873
|
}
|
12558
12874
|
case YP_NODE_CONSTANT_READ_NODE: {
|
12559
12875
|
parser_lex(parser);
|
12560
12876
|
|
12561
12877
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12562
|
-
yp_node_t *result = (yp_node_t *)
|
12878
|
+
yp_node_t *result = (yp_node_t *) yp_constant_or_write_node_create(parser, node, &token, value);
|
12563
12879
|
|
12564
12880
|
yp_node_destroy(parser, node);
|
12565
12881
|
return result;
|
@@ -12568,21 +12884,49 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12568
12884
|
parser_lex(parser);
|
12569
12885
|
|
12570
12886
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12571
|
-
yp_node_t *result = (yp_node_t *)
|
12887
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_or_write_node_create(parser, node, &token, value);
|
12572
12888
|
|
12573
12889
|
yp_node_destroy(parser, node);
|
12574
12890
|
return result;
|
12575
12891
|
}
|
12576
12892
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
12893
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12577
12894
|
parser_lex(parser);
|
12578
12895
|
|
12579
12896
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12580
|
-
|
12581
|
-
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_or_write_node_create(parser, node, &token, value, constant_id);
|
12897
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, cast->constant_id, cast->depth);
|
12582
12898
|
|
12583
12899
|
yp_node_destroy(parser, node);
|
12584
12900
|
return result;
|
12585
12901
|
}
|
12902
|
+
case YP_NODE_CALL_NODE: {
|
12903
|
+
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
12904
|
+
|
12905
|
+
// If we have a vcall (a method with no arguments and no
|
12906
|
+
// receiver that could have been a local variable) then we
|
12907
|
+
// will transform it into a local variable write.
|
12908
|
+
if (yp_call_node_variable_call_p(call_node)) {
|
12909
|
+
yp_location_t message_loc = call_node->message_loc;
|
12910
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12911
|
+
|
12912
|
+
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12913
|
+
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12914
|
+
}
|
12915
|
+
|
12916
|
+
parser_lex(parser);
|
12917
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
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;
|
12922
|
+
}
|
12923
|
+
|
12924
|
+
parser_lex(parser);
|
12925
|
+
node = parse_target(parser, node);
|
12926
|
+
|
12927
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12928
|
+
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12929
|
+
}
|
12586
12930
|
case YP_NODE_MULTI_WRITE_NODE: {
|
12587
12931
|
parser_lex(parser);
|
12588
12932
|
yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Cannot use `||=' on a multi-write.");
|
@@ -12617,43 +12961,12 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12617
12961
|
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
12618
12962
|
parser_lex(parser);
|
12619
12963
|
|
12620
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator");
|
12964
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12621
12965
|
yp_node_t *result = (yp_node_t *) yp_global_variable_operator_write_node_create(parser, node, &token, value);
|
12622
12966
|
|
12623
12967
|
yp_node_destroy(parser, node);
|
12624
12968
|
return result;
|
12625
12969
|
}
|
12626
|
-
case YP_NODE_CALL_NODE: {
|
12627
|
-
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
12628
|
-
|
12629
|
-
// If we have a vcall (a method with no arguments and no
|
12630
|
-
// receiver that could have been a local variable) then we
|
12631
|
-
// will transform it into a local variable write.
|
12632
|
-
if (yp_call_node_variable_call_p(call_node)) {
|
12633
|
-
yp_location_t message_loc = call_node->message_loc;
|
12634
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12635
|
-
|
12636
|
-
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12637
|
-
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12638
|
-
}
|
12639
|
-
|
12640
|
-
parser_lex(parser);
|
12641
|
-
|
12642
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12643
|
-
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, message_loc.start, message_loc.end);
|
12644
|
-
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id);
|
12645
|
-
|
12646
|
-
yp_node_destroy(parser, node);
|
12647
|
-
return result;
|
12648
|
-
}
|
12649
|
-
|
12650
|
-
yp_token_t operator = not_provided(parser);
|
12651
|
-
node = parse_target(parser, node, &operator, NULL);
|
12652
|
-
|
12653
|
-
parser_lex(parser);
|
12654
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12655
|
-
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12656
|
-
}
|
12657
12970
|
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12658
12971
|
parser_lex(parser);
|
12659
12972
|
|
@@ -12688,15 +13001,43 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12688
13001
|
return result;
|
12689
13002
|
}
|
12690
13003
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
13004
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12691
13005
|
parser_lex(parser);
|
12692
13006
|
|
12693
13007
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12694
|
-
|
12695
|
-
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id);
|
13008
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, cast->constant_id, cast->depth);
|
12696
13009
|
|
12697
13010
|
yp_node_destroy(parser, node);
|
12698
13011
|
return result;
|
12699
13012
|
}
|
13013
|
+
case YP_NODE_CALL_NODE: {
|
13014
|
+
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
13015
|
+
|
13016
|
+
// If we have a vcall (a method with no arguments and no
|
13017
|
+
// receiver that could have been a local variable) then we
|
13018
|
+
// will transform it into a local variable write.
|
13019
|
+
if (yp_call_node_variable_call_p(call_node)) {
|
13020
|
+
yp_location_t message_loc = call_node->message_loc;
|
13021
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
13022
|
+
|
13023
|
+
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
13024
|
+
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
13025
|
+
}
|
13026
|
+
|
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);
|
13030
|
+
|
13031
|
+
yp_node_destroy(parser, node);
|
13032
|
+
return result;
|
13033
|
+
}
|
13034
|
+
|
13035
|
+
node = parse_target(parser, node);
|
13036
|
+
parser_lex(parser);
|
13037
|
+
|
13038
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13039
|
+
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
13040
|
+
}
|
12700
13041
|
case YP_NODE_MULTI_WRITE_NODE: {
|
12701
13042
|
parser_lex(parser);
|
12702
13043
|
yp_diagnostic_list_append(&parser->error_list, token.start, token.end, "Unexpected operator.");
|
@@ -12862,7 +13203,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12862
13203
|
yp_statements_node_body_append(statements, node);
|
12863
13204
|
|
12864
13205
|
yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'until'");
|
12865
|
-
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);
|
12866
13207
|
}
|
12867
13208
|
case YP_TOKEN_KEYWORD_WHILE_MODIFIER: {
|
12868
13209
|
parser_lex(parser);
|
@@ -12870,7 +13211,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12870
13211
|
yp_statements_node_body_append(statements, node);
|
12871
13212
|
|
12872
13213
|
yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'while'");
|
12873
|
-
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);
|
12874
13215
|
}
|
12875
13216
|
case YP_TOKEN_QUESTION_MARK: {
|
12876
13217
|
parser_lex(parser);
|
@@ -12908,7 +13249,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12908
13249
|
|
12909
13250
|
if (
|
12910
13251
|
(parser->current.type == YP_TOKEN_PARENTHESIS_LEFT) ||
|
12911
|
-
(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))
|
12912
13253
|
) {
|
12913
13254
|
// If we have a constant immediately following a '::' operator, then
|
12914
13255
|
// this can either be a constant path or a method call, depending on
|
@@ -13140,7 +13481,7 @@ yp_metadata_read_u32(const char *ptr) {
|
|
13140
13481
|
// ]*
|
13141
13482
|
// ]
|
13142
13483
|
// ```
|
13143
|
-
|
13484
|
+
void
|
13144
13485
|
yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
13145
13486
|
uint32_t filepath_size = yp_metadata_read_u32(metadata);
|
13146
13487
|
metadata += 4;
|
@@ -13179,6 +13520,8 @@ yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
|
13179
13520
|
// Initialize a parser with the given start and end pointers.
|
13180
13521
|
YP_EXPORTED_FUNCTION void
|
13181
13522
|
yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char *filepath) {
|
13523
|
+
assert(source != NULL);
|
13524
|
+
|
13182
13525
|
// Set filepath to the file that was passed
|
13183
13526
|
if (!filepath) filepath = "";
|
13184
13527
|
yp_string_t filepath_string;
|
@@ -13190,6 +13533,8 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
|
|
13190
13533
|
.enclosure_nesting = 0,
|
13191
13534
|
.lambda_enclosure_nesting = -1,
|
13192
13535
|
.brace_nesting = 0,
|
13536
|
+
.do_loop_stack = YP_STATE_STACK_EMPTY,
|
13537
|
+
.accepts_block_stack = YP_STATE_STACK_EMPTY,
|
13193
13538
|
.lex_modes = {
|
13194
13539
|
.index = 0,
|
13195
13540
|
.stack = {{ .mode = YP_LEX_DEFAULT }},
|
@@ -13201,6 +13546,9 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
|
|
13201
13546
|
.current = { .type = YP_TOKEN_EOF, .start = source, .end = source },
|
13202
13547
|
.next_start = NULL,
|
13203
13548
|
.heredoc_end = NULL,
|
13549
|
+
.comment_list = YP_LIST_EMPTY,
|
13550
|
+
.warning_list = YP_LIST_EMPTY,
|
13551
|
+
.error_list = YP_LIST_EMPTY,
|
13204
13552
|
.current_scope = NULL,
|
13205
13553
|
.current_context = NULL,
|
13206
13554
|
.recovering = false,
|
@@ -13213,16 +13561,12 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
|
|
13213
13561
|
.pattern_matching_newlines = false,
|
13214
13562
|
.in_keyword_arg = false,
|
13215
13563
|
.filepath_string = filepath_string,
|
13564
|
+
.constant_pool = YP_CONSTANT_POOL_EMPTY,
|
13565
|
+
.newline_list = YP_NEWLINE_LIST_EMPTY
|
13216
13566
|
};
|
13217
13567
|
|
13218
|
-
yp_state_stack_init(&parser->do_loop_stack);
|
13219
|
-
yp_state_stack_init(&parser->accepts_block_stack);
|
13220
13568
|
yp_accepts_block_stack_push(parser, true);
|
13221
13569
|
|
13222
|
-
yp_list_init(&parser->warning_list);
|
13223
|
-
yp_list_init(&parser->error_list);
|
13224
|
-
yp_list_init(&parser->comment_list);
|
13225
|
-
|
13226
13570
|
// Initialize the constant pool. We're going to completely guess as to the
|
13227
13571
|
// number of constants that we'll need based on the size of the input. The
|
13228
13572
|
// ratio we chose here is actually less arbitrary than you might think.
|
@@ -13246,14 +13590,15 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
|
|
13246
13590
|
size_t newline_size = size / 22;
|
13247
13591
|
yp_newline_list_init(&parser->newline_list, source, newline_size < 4 ? 4 : newline_size);
|
13248
13592
|
|
13249
|
-
|
13593
|
+
// Skip past the UTF-8 BOM if it exists.
|
13250
13594
|
if (size >= 3 && (unsigned char) source[0] == 0xef && (unsigned char) source[1] == 0xbb && (unsigned char) source[2] == 0xbf) {
|
13251
|
-
// If the first three bytes of the source are the UTF-8 BOM, then we'll skip
|
13252
|
-
// over them.
|
13253
13595
|
parser->current.end += 3;
|
13254
|
-
|
13255
|
-
|
13256
|
-
|
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) == '!') {
|
13257
13602
|
const char *encoding_comment_start = next_newline(source, (ptrdiff_t) size);
|
13258
13603
|
if (encoding_comment_start) {
|
13259
13604
|
parser->encoding_comment_start = encoding_comment_start + 1;
|