prism 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -1
- data/config.yml +2 -1
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +1 -1
- data/include/prism/diagnostic.h +1 -0
- data/include/prism/parser.h +25 -12
- data/include/prism/version.h +2 -2
- data/lib/prism/node.rb +1 -1
- data/lib/prism/parse_result.rb +140 -3
- data/lib/prism/serialize.rb +13 -1
- data/lib/prism/translation/parser.rb +3 -3
- data/lib/prism/translation/ripper.rb +1 -5
- data/lib/prism/translation/ruby_parser.rb +2 -2
- data/prism.gemspec +1 -1
- data/rbi/prism/node.rbi +5777 -1701
- data/rbi/prism/parse_result.rbi +29 -0
- data/rbi/prism.rbi +34 -34
- data/sig/prism/node.rbs +1 -90
- data/sig/prism/parse_result.rbs +20 -0
- data/src/diagnostic.c +3 -1
- data/src/prism.c +223 -115
- metadata +2 -2
data/src/prism.c
CHANGED
@@ -544,10 +544,7 @@ pm_parser_warn_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id
|
|
544
544
|
* token.
|
545
545
|
*/
|
546
546
|
static void
|
547
|
-
pm_parser_err_heredoc_term(pm_parser_t *parser,
|
548
|
-
const uint8_t *ident_start = lex_mode->as.heredoc.ident_start;
|
549
|
-
size_t ident_length = lex_mode->as.heredoc.ident_length;
|
550
|
-
|
547
|
+
pm_parser_err_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ident_length) {
|
551
548
|
PM_PARSER_ERR_FORMAT(
|
552
549
|
parser,
|
553
550
|
ident_start,
|
@@ -964,7 +961,7 @@ pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals,
|
|
964
961
|
if (local->name != PM_CONSTANT_ID_UNSET) {
|
965
962
|
pm_constant_id_list_insert(list, (size_t) local->index, local->name);
|
966
963
|
|
967
|
-
if (warn_unused && local->reads == 0) {
|
964
|
+
if (warn_unused && local->reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->location.start, parser->start_line) >= 0))) {
|
968
965
|
pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
|
969
966
|
|
970
967
|
if (constant->length >= 1 && *constant->start != '_') {
|
@@ -2110,14 +2107,6 @@ pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
|
|
2110
2107
|
return node;
|
2111
2108
|
}
|
2112
2109
|
|
2113
|
-
/**
|
2114
|
-
* Return the size of the given array node.
|
2115
|
-
*/
|
2116
|
-
static inline size_t
|
2117
|
-
pm_array_node_size(pm_array_node_t *node) {
|
2118
|
-
return node->elements.size;
|
2119
|
-
}
|
2120
|
-
|
2121
2110
|
/**
|
2122
2111
|
* Append an argument to an array node.
|
2123
2112
|
*/
|
@@ -8573,6 +8562,7 @@ context_terminator(pm_context_t context, pm_token_t *token) {
|
|
8573
8562
|
case PM_CONTEXT_MAIN:
|
8574
8563
|
case PM_CONTEXT_DEF_PARAMS:
|
8575
8564
|
case PM_CONTEXT_DEFINED:
|
8565
|
+
case PM_CONTEXT_MULTI_TARGET:
|
8576
8566
|
case PM_CONTEXT_TERNARY:
|
8577
8567
|
case PM_CONTEXT_RESCUE_MODIFIER:
|
8578
8568
|
return token->type == PM_TOKEN_EOF;
|
@@ -8777,6 +8767,7 @@ context_human(pm_context_t context) {
|
|
8777
8767
|
case PM_CONTEXT_LOOP_PREDICATE: return "loop predicate";
|
8778
8768
|
case PM_CONTEXT_MAIN: return "top level context";
|
8779
8769
|
case PM_CONTEXT_MODULE: return "module definition";
|
8770
|
+
case PM_CONTEXT_MULTI_TARGET: return "multiple targets";
|
8780
8771
|
case PM_CONTEXT_PARENS: return "parentheses";
|
8781
8772
|
case PM_CONTEXT_POSTEXE: return "'END' block";
|
8782
8773
|
case PM_CONTEXT_PREDICATE: return "predicate";
|
@@ -9051,6 +9042,10 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9051
9042
|
return PM_TOKEN_GLOBAL_VARIABLE;
|
9052
9043
|
}
|
9053
9044
|
|
9045
|
+
// True if multiple characters are allowed after the declaration of the
|
9046
|
+
// global variable. Not true when it starts with "$-".
|
9047
|
+
bool allow_multiple = true;
|
9048
|
+
|
9054
9049
|
switch (*parser->current.end) {
|
9055
9050
|
case '~': // $~: match-data
|
9056
9051
|
case '*': // $*: argv
|
@@ -9109,6 +9104,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9109
9104
|
|
9110
9105
|
case '-':
|
9111
9106
|
parser->current.end++;
|
9107
|
+
allow_multiple = false;
|
9112
9108
|
/* fallthrough */
|
9113
9109
|
default: {
|
9114
9110
|
size_t width;
|
@@ -9116,7 +9112,7 @@ lex_global_variable(pm_parser_t *parser) {
|
|
9116
9112
|
if ((width = char_is_identifier(parser, parser->current.end)) > 0) {
|
9117
9113
|
do {
|
9118
9114
|
parser->current.end += width;
|
9119
|
-
} while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
|
9115
|
+
} while (allow_multiple && parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
|
9120
9116
|
} else if (pm_char_is_whitespace(peek(parser))) {
|
9121
9117
|
// If we get here, then we have a $ followed by whitespace,
|
9122
9118
|
// which is not allowed.
|
@@ -9881,6 +9877,10 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9881
9877
|
}
|
9882
9878
|
case 'c': {
|
9883
9879
|
parser->current.end++;
|
9880
|
+
if (flags & PM_ESCAPE_FLAG_CONTROL) {
|
9881
|
+
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
|
9882
|
+
}
|
9883
|
+
|
9884
9884
|
if (parser->current.end == parser->end) {
|
9885
9885
|
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
|
9886
9886
|
return;
|
@@ -9894,10 +9894,6 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9894
9894
|
return;
|
9895
9895
|
}
|
9896
9896
|
case '\\':
|
9897
|
-
if (flags & PM_ESCAPE_FLAG_CONTROL) {
|
9898
|
-
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
|
9899
|
-
return;
|
9900
|
-
}
|
9901
9897
|
parser->current.end++;
|
9902
9898
|
|
9903
9899
|
if (match(parser, 'u') || match(parser, 'U')) {
|
@@ -9931,6 +9927,10 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9931
9927
|
}
|
9932
9928
|
case 'C': {
|
9933
9929
|
parser->current.end++;
|
9930
|
+
if (flags & PM_ESCAPE_FLAG_CONTROL) {
|
9931
|
+
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
|
9932
|
+
}
|
9933
|
+
|
9934
9934
|
if (peek(parser) != '-') {
|
9935
9935
|
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
|
9936
9936
|
pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
|
@@ -9951,10 +9951,6 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9951
9951
|
return;
|
9952
9952
|
}
|
9953
9953
|
case '\\':
|
9954
|
-
if (flags & PM_ESCAPE_FLAG_CONTROL) {
|
9955
|
-
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
|
9956
|
-
return;
|
9957
|
-
}
|
9958
9954
|
parser->current.end++;
|
9959
9955
|
|
9960
9956
|
if (match(parser, 'u') || match(parser, 'U')) {
|
@@ -9989,6 +9985,10 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
9989
9985
|
}
|
9990
9986
|
case 'M': {
|
9991
9987
|
parser->current.end++;
|
9988
|
+
if (flags & PM_ESCAPE_FLAG_META) {
|
9989
|
+
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
|
9990
|
+
}
|
9991
|
+
|
9992
9992
|
if (peek(parser) != '-') {
|
9993
9993
|
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
|
9994
9994
|
pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
|
@@ -10004,10 +10004,6 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
10004
10004
|
uint8_t peeked = peek(parser);
|
10005
10005
|
switch (peeked) {
|
10006
10006
|
case '\\':
|
10007
|
-
if (flags & PM_ESCAPE_FLAG_META) {
|
10008
|
-
pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
|
10009
|
-
return;
|
10010
|
-
}
|
10011
10007
|
parser->current.end++;
|
10012
10008
|
|
10013
10009
|
if (match(parser, 'u') || match(parser, 'U')) {
|
@@ -10050,6 +10046,8 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
|
|
10050
10046
|
default: {
|
10051
10047
|
if (parser->current.end < parser->end) {
|
10052
10048
|
escape_write_escape_encoded(parser, buffer);
|
10049
|
+
} else {
|
10050
|
+
pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
|
10053
10051
|
}
|
10054
10052
|
return;
|
10055
10053
|
}
|
@@ -11153,12 +11151,14 @@ parser_lex(pm_parser_t *parser) {
|
|
11153
11151
|
lex_mode_push(parser, (pm_lex_mode_t) {
|
11154
11152
|
.mode = PM_LEX_HEREDOC,
|
11155
11153
|
.as.heredoc = {
|
11156
|
-
.
|
11157
|
-
|
11154
|
+
.base = {
|
11155
|
+
.ident_start = ident_start,
|
11156
|
+
.ident_length = ident_length,
|
11157
|
+
.quote = quote,
|
11158
|
+
.indent = indent
|
11159
|
+
},
|
11158
11160
|
.next_start = parser->current.end,
|
11159
|
-
.
|
11160
|
-
.indent = indent,
|
11161
|
-
.common_whitespace = (size_t) -1,
|
11161
|
+
.common_whitespace = NULL,
|
11162
11162
|
.line_continuation = false
|
11163
11163
|
}
|
11164
11164
|
});
|
@@ -11171,7 +11171,7 @@ parser_lex(pm_parser_t *parser) {
|
|
11171
11171
|
// this is not a valid heredoc declaration. In this case we
|
11172
11172
|
// will add an error, but we will still return a heredoc
|
11173
11173
|
// start.
|
11174
|
-
if (!ident_error) pm_parser_err_heredoc_term(parser,
|
11174
|
+
if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
|
11175
11175
|
body_start = parser->end;
|
11176
11176
|
} else {
|
11177
11177
|
// Otherwise, we want to indicate that the body of the
|
@@ -12514,6 +12514,7 @@ parser_lex(pm_parser_t *parser) {
|
|
12514
12514
|
// Now let's grab the information about the identifier off of the
|
12515
12515
|
// current lex mode.
|
12516
12516
|
pm_lex_mode_t *lex_mode = parser->lex_modes.current;
|
12517
|
+
pm_heredoc_lex_mode_t *heredoc_lex_mode = &lex_mode->as.heredoc.base;
|
12517
12518
|
|
12518
12519
|
bool line_continuation = lex_mode->as.heredoc.line_continuation;
|
12519
12520
|
lex_mode->as.heredoc.line_continuation = false;
|
@@ -12523,15 +12524,16 @@ parser_lex(pm_parser_t *parser) {
|
|
12523
12524
|
// terminator) but still continue parsing so that content after the
|
12524
12525
|
// declaration of the heredoc can be parsed.
|
12525
12526
|
if (parser->current.end >= parser->end) {
|
12526
|
-
pm_parser_err_heredoc_term(parser,
|
12527
|
+
pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
|
12527
12528
|
parser->next_start = lex_mode->as.heredoc.next_start;
|
12528
12529
|
parser->heredoc_end = parser->current.end;
|
12529
12530
|
lex_state_set(parser, PM_LEX_STATE_END);
|
12531
|
+
lex_mode_pop(parser);
|
12530
12532
|
LEX(PM_TOKEN_HEREDOC_END);
|
12531
12533
|
}
|
12532
12534
|
|
12533
|
-
const uint8_t *ident_start =
|
12534
|
-
size_t ident_length =
|
12535
|
+
const uint8_t *ident_start = heredoc_lex_mode->ident_start;
|
12536
|
+
size_t ident_length = heredoc_lex_mode->ident_length;
|
12535
12537
|
|
12536
12538
|
// If we are immediately following a newline and we have hit the
|
12537
12539
|
// terminator, then we need to return the ending of the heredoc.
|
@@ -12556,10 +12558,7 @@ parser_lex(pm_parser_t *parser) {
|
|
12556
12558
|
const uint8_t *terminator_start = ident_end - ident_length;
|
12557
12559
|
const uint8_t *cursor = start;
|
12558
12560
|
|
12559
|
-
if (
|
12560
|
-
lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_DASH ||
|
12561
|
-
lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE
|
12562
|
-
) {
|
12561
|
+
if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
|
12563
12562
|
while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
|
12564
12563
|
cursor++;
|
12565
12564
|
}
|
@@ -12582,17 +12581,19 @@ parser_lex(pm_parser_t *parser) {
|
|
12582
12581
|
}
|
12583
12582
|
|
12584
12583
|
lex_state_set(parser, PM_LEX_STATE_END);
|
12584
|
+
lex_mode_pop(parser);
|
12585
12585
|
LEX(PM_TOKEN_HEREDOC_END);
|
12586
12586
|
}
|
12587
12587
|
}
|
12588
12588
|
|
12589
|
-
size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start,
|
12589
|
+
size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
|
12590
12590
|
if (
|
12591
|
-
|
12592
|
-
|
12591
|
+
heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
|
12592
|
+
lex_mode->as.heredoc.common_whitespace != NULL &&
|
12593
|
+
(*lex_mode->as.heredoc.common_whitespace > whitespace) &&
|
12593
12594
|
peek_at(parser, start) != '\n'
|
12594
12595
|
) {
|
12595
|
-
lex_mode->as.heredoc.common_whitespace = whitespace;
|
12596
|
+
*lex_mode->as.heredoc.common_whitespace = whitespace;
|
12596
12597
|
}
|
12597
12598
|
}
|
12598
12599
|
|
@@ -12601,7 +12602,7 @@ parser_lex(pm_parser_t *parser) {
|
|
12601
12602
|
// strpbrk to find the first of these characters.
|
12602
12603
|
uint8_t breakpoints[] = "\r\n\\#";
|
12603
12604
|
|
12604
|
-
pm_heredoc_quote_t quote =
|
12605
|
+
pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
|
12605
12606
|
if (quote == PM_HEREDOC_QUOTE_SINGLE) {
|
12606
12607
|
breakpoints[3] = '\0';
|
12607
12608
|
}
|
@@ -12664,8 +12665,7 @@ parser_lex(pm_parser_t *parser) {
|
|
12664
12665
|
// leading whitespace if we have a - or ~ heredoc.
|
12665
12666
|
const uint8_t *cursor = start;
|
12666
12667
|
|
12667
|
-
if (
|
12668
|
-
lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE) {
|
12668
|
+
if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
|
12669
12669
|
while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
|
12670
12670
|
cursor++;
|
12671
12671
|
}
|
@@ -12681,16 +12681,16 @@ parser_lex(pm_parser_t *parser) {
|
|
12681
12681
|
}
|
12682
12682
|
}
|
12683
12683
|
|
12684
|
-
size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.indent);
|
12684
|
+
size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
|
12685
12685
|
|
12686
12686
|
// If we have hit a newline that is followed by a valid
|
12687
12687
|
// terminator, then we need to return the content of the
|
12688
12688
|
// heredoc here as string content. Then, the next time a
|
12689
12689
|
// token is lexed, it will match again and return the
|
12690
12690
|
// end of the heredoc.
|
12691
|
-
if (lex_mode->as.heredoc.indent == PM_HEREDOC_INDENT_TILDE) {
|
12692
|
-
if ((lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) != '\n') {
|
12693
|
-
lex_mode->as.heredoc.common_whitespace = whitespace;
|
12691
|
+
if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
|
12692
|
+
if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) != '\n') {
|
12693
|
+
*lex_mode->as.heredoc.common_whitespace = whitespace;
|
12694
12694
|
}
|
12695
12695
|
|
12696
12696
|
parser->current.end = breakpoint + 1;
|
@@ -12757,7 +12757,7 @@ parser_lex(pm_parser_t *parser) {
|
|
12757
12757
|
// If we are in a tilde here, we should
|
12758
12758
|
// break out of the loop and return the
|
12759
12759
|
// string content.
|
12760
|
-
if (
|
12760
|
+
if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
|
12761
12761
|
const uint8_t *end = parser->current.end;
|
12762
12762
|
pm_newline_list_append(&parser->newline_list, end);
|
12763
12763
|
|
@@ -12983,7 +12983,7 @@ pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
|
|
12983
12983
|
[PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
|
12984
12984
|
[PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
|
12985
12985
|
[PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
|
12986
|
-
[PM_TOKEN_USTAR] =
|
12986
|
+
[PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
|
12987
12987
|
|
12988
12988
|
// -@
|
12989
12989
|
[PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
|
@@ -13165,13 +13165,11 @@ expect3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_to
|
|
13165
13165
|
* lex mode accordingly.
|
13166
13166
|
*/
|
13167
13167
|
static void
|
13168
|
-
expect1_heredoc_term(pm_parser_t *parser,
|
13168
|
+
expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ident_length) {
|
13169
13169
|
if (match1(parser, PM_TOKEN_HEREDOC_END)) {
|
13170
|
-
lex_mode_pop(parser);
|
13171
13170
|
parser_lex(parser);
|
13172
13171
|
} else {
|
13173
|
-
pm_parser_err_heredoc_term(parser,
|
13174
|
-
lex_mode_pop(parser);
|
13172
|
+
pm_parser_err_heredoc_term(parser, ident_start, ident_length);
|
13175
13173
|
parser->previous.start = parser->previous.end;
|
13176
13174
|
parser->previous.type = PM_TOKEN_MISSING;
|
13177
13175
|
}
|
@@ -13797,6 +13795,13 @@ parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t b
|
|
13797
13795
|
pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
|
13798
13796
|
pm_multi_target_node_targets_append(parser, result, splat);
|
13799
13797
|
has_rest = true;
|
13798
|
+
} else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
|
13799
|
+
context_push(parser, PM_CONTEXT_MULTI_TARGET);
|
13800
|
+
pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
|
13801
|
+
target = parse_target(parser, target, true, false);
|
13802
|
+
|
13803
|
+
pm_multi_target_node_targets_append(parser, result, target);
|
13804
|
+
context_pop(parser);
|
13800
13805
|
} else if (token_begins_expression_p(parser->current.type)) {
|
13801
13806
|
pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
|
13802
13807
|
target = parse_target(parser, target, true, false);
|
@@ -14108,8 +14113,8 @@ static void
|
|
14108
14113
|
parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
|
14109
14114
|
pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
|
14110
14115
|
|
14111
|
-
// First we need to check if the next token is one that could be the start
|
14112
|
-
// an argument. If it's not, then we can just return.
|
14116
|
+
// First we need to check if the next token is one that could be the start
|
14117
|
+
// of an argument. If it's not, then we can just return.
|
14113
14118
|
if (
|
14114
14119
|
match2(parser, terminator, PM_TOKEN_EOF) ||
|
14115
14120
|
(binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
|
@@ -14297,23 +14302,32 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
|
|
14297
14302
|
// If parsing the argument failed, we need to stop parsing arguments.
|
14298
14303
|
if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->recovering) break;
|
14299
14304
|
|
14300
|
-
// If the terminator of these arguments is not EOF, then we have a
|
14301
|
-
// token we're looking for. In that case we can accept a
|
14302
|
-
// because it is not functioning as a statement terminator.
|
14303
|
-
|
14305
|
+
// If the terminator of these arguments is not EOF, then we have a
|
14306
|
+
// specific token we're looking for. In that case we can accept a
|
14307
|
+
// newline here because it is not functioning as a statement terminator.
|
14308
|
+
bool accepted_newline = false;
|
14309
|
+
if (terminator != PM_TOKEN_EOF) {
|
14310
|
+
accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
|
14311
|
+
}
|
14304
14312
|
|
14305
14313
|
if (parser->previous.type == PM_TOKEN_COMMA && parsed_bare_hash) {
|
14306
|
-
// If we previously were on a comma and we just parsed a bare hash,
|
14307
|
-
// we want to continue parsing arguments. This is because the
|
14308
|
-
// grabbed up by the hash parser.
|
14314
|
+
// If we previously were on a comma and we just parsed a bare hash,
|
14315
|
+
// then we want to continue parsing arguments. This is because the
|
14316
|
+
// comma was grabbed up by the hash parser.
|
14317
|
+
} else if (accept1(parser, PM_TOKEN_COMMA)) {
|
14318
|
+
// If there was a comma, then we need to check if we also accepted a
|
14319
|
+
// newline. If we did, then this is a syntax error.
|
14320
|
+
if (accepted_newline) {
|
14321
|
+
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
|
14322
|
+
}
|
14309
14323
|
} else {
|
14310
|
-
// If there is no comma at the end of the argument list then we're
|
14311
|
-
// parsing arguments and can break out of this loop.
|
14312
|
-
|
14324
|
+
// If there is no comma at the end of the argument list then we're
|
14325
|
+
// done parsing arguments and can break out of this loop.
|
14326
|
+
break;
|
14313
14327
|
}
|
14314
14328
|
|
14315
|
-
// If we hit the terminator, then that means we have a trailing comma so
|
14316
|
-
// can accept that output as well.
|
14329
|
+
// If we hit the terminator, then that means we have a trailing comma so
|
14330
|
+
// we can accept that output as well.
|
14317
14331
|
if (match1(parser, terminator)) break;
|
14318
14332
|
}
|
14319
14333
|
}
|
@@ -14470,13 +14484,14 @@ parse_parameters(
|
|
14470
14484
|
bool accepts_blocks_in_defaults,
|
14471
14485
|
uint16_t depth
|
14472
14486
|
) {
|
14473
|
-
pm_parameters_node_t *params = pm_parameters_node_create(parser);
|
14474
|
-
bool looping = true;
|
14475
|
-
|
14476
14487
|
pm_do_loop_stack_push(parser, false);
|
14488
|
+
|
14489
|
+
pm_parameters_node_t *params = pm_parameters_node_create(parser);
|
14477
14490
|
pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
|
14478
14491
|
|
14479
|
-
|
14492
|
+
while (true) {
|
14493
|
+
bool parsing = true;
|
14494
|
+
|
14480
14495
|
switch (parser->current.type) {
|
14481
14496
|
case PM_TOKEN_PARENTHESIS_LEFT: {
|
14482
14497
|
update_parameter_state(parser, &parser->current, &order);
|
@@ -14611,7 +14626,7 @@ parse_parameters(
|
|
14611
14626
|
// then we can put a missing node in its place and stop parsing the
|
14612
14627
|
// parameters entirely now.
|
14613
14628
|
if (parser->recovering) {
|
14614
|
-
|
14629
|
+
parsing = false;
|
14615
14630
|
break;
|
14616
14631
|
}
|
14617
14632
|
} else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
|
@@ -14669,7 +14684,7 @@ parse_parameters(
|
|
14669
14684
|
context_pop(parser);
|
14670
14685
|
|
14671
14686
|
if (uses_parentheses) {
|
14672
|
-
|
14687
|
+
parsing = false;
|
14673
14688
|
break;
|
14674
14689
|
}
|
14675
14690
|
|
@@ -14713,7 +14728,7 @@ parse_parameters(
|
|
14713
14728
|
// then we can put a missing node in its place and stop parsing the
|
14714
14729
|
// parameters entirely now.
|
14715
14730
|
if (parser->recovering) {
|
14716
|
-
|
14731
|
+
parsing = false;
|
14717
14732
|
break;
|
14718
14733
|
}
|
14719
14734
|
}
|
@@ -14815,14 +14830,31 @@ parse_parameters(
|
|
14815
14830
|
}
|
14816
14831
|
}
|
14817
14832
|
|
14818
|
-
|
14833
|
+
parsing = false;
|
14819
14834
|
break;
|
14820
14835
|
}
|
14821
14836
|
|
14822
|
-
|
14823
|
-
|
14837
|
+
// If we hit some kind of issue while parsing the parameter, this would
|
14838
|
+
// have been set to false. In that case, we need to break out of the
|
14839
|
+
// loop.
|
14840
|
+
if (!parsing) break;
|
14841
|
+
|
14842
|
+
bool accepted_newline = false;
|
14843
|
+
if (uses_parentheses) {
|
14844
|
+
accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
|
14824
14845
|
}
|
14825
|
-
|
14846
|
+
|
14847
|
+
if (accept1(parser, PM_TOKEN_COMMA)) {
|
14848
|
+
// If there was a comma, but we also accepted a newline, then this
|
14849
|
+
// is a syntax error.
|
14850
|
+
if (accepted_newline) {
|
14851
|
+
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
|
14852
|
+
}
|
14853
|
+
} else {
|
14854
|
+
// If there was no comma, then we're done parsing parameters.
|
14855
|
+
break;
|
14856
|
+
}
|
14857
|
+
}
|
14826
14858
|
|
14827
14859
|
pm_do_loop_stack_pop(parser);
|
14828
14860
|
|
@@ -15500,6 +15532,7 @@ parse_return(pm_parser_t *parser, pm_node_t *node) {
|
|
15500
15532
|
case PM_CONTEXT_IF:
|
15501
15533
|
case PM_CONTEXT_LOOP_PREDICATE:
|
15502
15534
|
case PM_CONTEXT_MAIN:
|
15535
|
+
case PM_CONTEXT_MULTI_TARGET:
|
15503
15536
|
case PM_CONTEXT_PARENS:
|
15504
15537
|
case PM_CONTEXT_POSTEXE:
|
15505
15538
|
case PM_CONTEXT_PREDICATE:
|
@@ -15628,6 +15661,7 @@ parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
|
|
15628
15661
|
case PM_CONTEXT_MODULE_ENSURE:
|
15629
15662
|
case PM_CONTEXT_MODULE_RESCUE:
|
15630
15663
|
case PM_CONTEXT_MODULE:
|
15664
|
+
case PM_CONTEXT_MULTI_TARGET:
|
15631
15665
|
case PM_CONTEXT_PARENS:
|
15632
15666
|
case PM_CONTEXT_PREDICATE:
|
15633
15667
|
case PM_CONTEXT_RESCUE_MODIFIER:
|
@@ -17045,7 +17079,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
|
|
17045
17079
|
parse_pattern_hash_key(parser, &keys, first_node);
|
17046
17080
|
pm_node_t *value;
|
17047
17081
|
|
17048
|
-
if (
|
17082
|
+
if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
|
17049
17083
|
// Otherwise, we will create an implicit local variable
|
17050
17084
|
// target for the value.
|
17051
17085
|
value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
|
@@ -17082,7 +17116,12 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node
|
|
17082
17116
|
// If there are any other assocs, then we'll parse them now.
|
17083
17117
|
while (accept1(parser, PM_TOKEN_COMMA)) {
|
17084
17118
|
// Here we need to break to support trailing commas.
|
17085
|
-
if (
|
17119
|
+
if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
|
17120
|
+
// Trailing commas are not allowed to follow a rest pattern.
|
17121
|
+
if (rest != NULL) {
|
17122
|
+
pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
|
17123
|
+
}
|
17124
|
+
|
17086
17125
|
break;
|
17087
17126
|
}
|
17088
17127
|
|
@@ -17575,9 +17614,10 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flag
|
|
17575
17614
|
// Gather up all of the patterns into the list.
|
17576
17615
|
while (accept1(parser, PM_TOKEN_COMMA)) {
|
17577
17616
|
// Break early here in case we have a trailing comma.
|
17578
|
-
if (
|
17617
|
+
if (match6(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
|
17579
17618
|
node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
|
17580
17619
|
pm_node_list_append(&nodes, node);
|
17620
|
+
trailing_rest = true;
|
17581
17621
|
break;
|
17582
17622
|
}
|
17583
17623
|
|
@@ -17779,6 +17819,7 @@ parse_retry(pm_parser_t *parser, const pm_node_t *node) {
|
|
17779
17819
|
case PM_CONTEXT_LAMBDA_BRACES:
|
17780
17820
|
case PM_CONTEXT_LAMBDA_DO_END:
|
17781
17821
|
case PM_CONTEXT_LOOP_PREDICATE:
|
17822
|
+
case PM_CONTEXT_MULTI_TARGET:
|
17782
17823
|
case PM_CONTEXT_PARENS:
|
17783
17824
|
case PM_CONTEXT_POSTEXE:
|
17784
17825
|
case PM_CONTEXT_PREDICATE:
|
@@ -17862,6 +17903,7 @@ parse_yield(pm_parser_t *parser, const pm_node_t *node) {
|
|
17862
17903
|
case PM_CONTEXT_LAMBDA_ENSURE:
|
17863
17904
|
case PM_CONTEXT_LAMBDA_RESCUE:
|
17864
17905
|
case PM_CONTEXT_LOOP_PREDICATE:
|
17906
|
+
case PM_CONTEXT_MULTI_TARGET:
|
17865
17907
|
case PM_CONTEXT_PARENS:
|
17866
17908
|
case PM_CONTEXT_POSTEXE:
|
17867
17909
|
case PM_CONTEXT_PREDICATE:
|
@@ -17951,19 +17993,31 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
17951
17993
|
bool parsed_bare_hash = false;
|
17952
17994
|
|
17953
17995
|
while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
|
17996
|
+
bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
|
17997
|
+
|
17954
17998
|
// Handle the case where we don't have a comma and we have a
|
17955
17999
|
// newline followed by a right bracket.
|
17956
|
-
if (
|
18000
|
+
if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
|
17957
18001
|
break;
|
17958
18002
|
}
|
17959
18003
|
|
17960
18004
|
// Ensure that we have a comma between elements in the array.
|
17961
|
-
if (
|
17962
|
-
|
17963
|
-
|
18005
|
+
if (array->elements.size > 0) {
|
18006
|
+
if (accept1(parser, PM_TOKEN_COMMA)) {
|
18007
|
+
// If there was a comma but we also accepts a newline,
|
18008
|
+
// then this is a syntax error.
|
18009
|
+
if (accepted_newline) {
|
18010
|
+
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
|
18011
|
+
}
|
18012
|
+
} else {
|
18013
|
+
// If there was no comma, then we need to add a syntax
|
18014
|
+
// error.
|
18015
|
+
const uint8_t *location = parser->previous.end;
|
18016
|
+
PM_PARSER_ERR_FORMAT(parser, location, location, PM_ERR_ARRAY_SEPARATOR, pm_token_type_human(parser->current.type));
|
17964
18017
|
|
17965
|
-
|
17966
|
-
|
18018
|
+
parser->previous.start = location;
|
18019
|
+
parser->previous.type = PM_TOKEN_MISSING;
|
18020
|
+
}
|
17967
18021
|
}
|
17968
18022
|
|
17969
18023
|
// If we have a right bracket immediately following a comma,
|
@@ -18119,14 +18173,32 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18119
18173
|
multi_target->base.location.start = lparen_loc.start;
|
18120
18174
|
multi_target->base.location.end = rparen_loc.end;
|
18121
18175
|
|
18122
|
-
|
18123
|
-
|
18124
|
-
|
18125
|
-
|
18126
|
-
|
18176
|
+
pm_node_t *result;
|
18177
|
+
if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
|
18178
|
+
result = parse_targets(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
|
18179
|
+
accept1(parser, PM_TOKEN_NEWLINE);
|
18180
|
+
} else {
|
18181
|
+
result = (pm_node_t *) multi_target;
|
18127
18182
|
}
|
18128
18183
|
|
18129
|
-
|
18184
|
+
if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
|
18185
|
+
// All set, this is explicitly allowed by the parent
|
18186
|
+
// context.
|
18187
|
+
} else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) {
|
18188
|
+
// All set, we're inside a for loop and we're parsing
|
18189
|
+
// multiple targets.
|
18190
|
+
} else if (binding_power != PM_BINDING_POWER_STATEMENT) {
|
18191
|
+
// Multi targets are not allowed when it's not a
|
18192
|
+
// statement level.
|
18193
|
+
pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
|
18194
|
+
} else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
|
18195
|
+
// Multi targets must be followed by an equal sign in
|
18196
|
+
// order to be valid (or a right parenthesis if they are
|
18197
|
+
// nested).
|
18198
|
+
pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
|
18199
|
+
}
|
18200
|
+
|
18201
|
+
return result;
|
18130
18202
|
}
|
18131
18203
|
|
18132
18204
|
// If we have a single statement and are ending on a right parenthesis
|
@@ -18187,6 +18259,33 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18187
18259
|
pm_accepts_block_stack_pop(parser);
|
18188
18260
|
expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
|
18189
18261
|
|
18262
|
+
// When we're parsing multi targets, we allow them to be followed by
|
18263
|
+
// a right parenthesis if they are at the statement level. This is
|
18264
|
+
// only possible if they are the final statement in a parentheses.
|
18265
|
+
// We need to explicitly reject that here.
|
18266
|
+
{
|
18267
|
+
pm_node_t *statement = statements->body.nodes[statements->body.size - 1];
|
18268
|
+
|
18269
|
+
if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
|
18270
|
+
pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
|
18271
|
+
pm_multi_target_node_targets_append(parser, multi_target, statement);
|
18272
|
+
|
18273
|
+
statement = (pm_node_t *) multi_target;
|
18274
|
+
statements->body.nodes[statements->body.size - 1] = statement;
|
18275
|
+
}
|
18276
|
+
|
18277
|
+
if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
|
18278
|
+
const uint8_t *offset = statement->location.end;
|
18279
|
+
pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
|
18280
|
+
pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, offset, offset);
|
18281
|
+
|
18282
|
+
statement = (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &operator, value);
|
18283
|
+
statements->body.nodes[statements->body.size - 1] = statement;
|
18284
|
+
|
18285
|
+
pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
|
18286
|
+
}
|
18287
|
+
}
|
18288
|
+
|
18190
18289
|
pop_block_exits(parser, previous_block_exits);
|
18191
18290
|
pm_node_list_free(¤t_block_exits);
|
18192
18291
|
|
@@ -18442,10 +18541,11 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18442
18541
|
case PM_TOKEN_HEREDOC_START: {
|
18443
18542
|
// Here we have found a heredoc. We'll parse it and add it to the
|
18444
18543
|
// list of strings.
|
18445
|
-
|
18446
|
-
|
18447
|
-
|
18448
|
-
|
18544
|
+
assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
|
18545
|
+
pm_heredoc_lex_mode_t lex_mode = parser->lex_modes.current->as.heredoc.base;
|
18546
|
+
|
18547
|
+
size_t common_whitespace = (size_t) -1;
|
18548
|
+
parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
|
18449
18549
|
|
18450
18550
|
parser_lex(parser);
|
18451
18551
|
pm_token_t opening = parser->previous;
|
@@ -18456,10 +18556,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18456
18556
|
if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
|
18457
18557
|
// If we get here, then we have an empty heredoc. We'll create
|
18458
18558
|
// an empty content token and return an empty string node.
|
18459
|
-
expect1_heredoc_term(parser, lex_mode);
|
18559
|
+
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
|
18460
18560
|
pm_token_t content = parse_strings_empty_content(parser->previous.start);
|
18461
18561
|
|
18462
|
-
if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18562
|
+
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18463
18563
|
node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
|
18464
18564
|
} else {
|
18465
18565
|
node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
|
@@ -18486,18 +18586,17 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18486
18586
|
cast->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->current);
|
18487
18587
|
cast->base.location = cast->opening_loc;
|
18488
18588
|
|
18489
|
-
if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18589
|
+
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18490
18590
|
assert(sizeof(pm_string_node_t) == sizeof(pm_x_string_node_t));
|
18491
18591
|
cast->base.type = PM_X_STRING_NODE;
|
18492
18592
|
}
|
18493
18593
|
|
18494
|
-
size_t common_whitespace
|
18495
|
-
if (indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
|
18594
|
+
if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
|
18496
18595
|
parse_heredoc_dedent_string(&cast->unescaped, common_whitespace);
|
18497
18596
|
}
|
18498
18597
|
|
18499
18598
|
node = (pm_node_t *) cast;
|
18500
|
-
expect1_heredoc_term(parser, lex_mode);
|
18599
|
+
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
|
18501
18600
|
} else {
|
18502
18601
|
// If we get here, then we have multiple parts in the heredoc,
|
18503
18602
|
// so we'll need to create an interpolated string node to hold
|
@@ -18511,15 +18610,13 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18511
18610
|
}
|
18512
18611
|
}
|
18513
18612
|
|
18514
|
-
size_t common_whitespace = lex_mode->as.heredoc.common_whitespace;
|
18515
|
-
|
18516
18613
|
// Now that we have all of the parts, create the correct type of
|
18517
18614
|
// interpolated node.
|
18518
|
-
if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18615
|
+
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18519
18616
|
pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
|
18520
18617
|
cast->parts = parts;
|
18521
18618
|
|
18522
|
-
expect1_heredoc_term(parser, lex_mode);
|
18619
|
+
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
|
18523
18620
|
pm_interpolated_xstring_node_closing_set(cast, &parser->previous);
|
18524
18621
|
|
18525
18622
|
cast->base.location = cast->opening_loc;
|
@@ -18528,7 +18625,7 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18528
18625
|
pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
|
18529
18626
|
pm_node_list_free(&parts);
|
18530
18627
|
|
18531
|
-
expect1_heredoc_term(parser, lex_mode);
|
18628
|
+
expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
|
18532
18629
|
pm_interpolated_string_node_closing_set(cast, &parser->previous);
|
18533
18630
|
|
18534
18631
|
cast->base.location = cast->opening_loc;
|
@@ -18537,9 +18634,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
18537
18634
|
|
18538
18635
|
// If this is a heredoc that is indented with a ~, then we need
|
18539
18636
|
// to dedent each line by the common leading whitespace.
|
18540
|
-
if (indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
|
18637
|
+
if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
|
18541
18638
|
pm_node_list_t *nodes;
|
18542
|
-
if (quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18639
|
+
if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
|
18543
18640
|
nodes = &((pm_interpolated_x_string_node_t *) node)->parts;
|
18544
18641
|
} else {
|
18545
18642
|
nodes = &((pm_interpolated_string_node_t *) node)->parts;
|
@@ -21684,8 +21781,11 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
|
21684
21781
|
// Otherwise we'll look and see if the next token can be parsed as an infix
|
21685
21782
|
// operator. If it can, then we'll parse it using parse_expression_infix.
|
21686
21783
|
pm_binding_powers_t current_binding_powers;
|
21784
|
+
pm_token_type_t current_token_type;
|
21785
|
+
|
21687
21786
|
while (
|
21688
|
-
|
21787
|
+
current_token_type = parser->current.type,
|
21788
|
+
current_binding_powers = pm_binding_powers[current_token_type],
|
21689
21789
|
binding_power <= current_binding_powers.left &&
|
21690
21790
|
current_binding_powers.binary
|
21691
21791
|
) {
|
@@ -21726,6 +21826,13 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
|
21726
21826
|
// If the operator is nonassoc and we should not be able to parse the
|
21727
21827
|
// upcoming infix operator, break.
|
21728
21828
|
if (current_binding_powers.nonassoc) {
|
21829
|
+
// If this is a non-assoc operator and we are about to parse the
|
21830
|
+
// exact same operator, then we need to add an error.
|
21831
|
+
if (match1(parser, current_token_type)) {
|
21832
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
|
21833
|
+
break;
|
21834
|
+
}
|
21835
|
+
|
21729
21836
|
// If this is an endless range, then we need to reject a couple of
|
21730
21837
|
// additional operators because it violates the normal operator
|
21731
21838
|
// precedence rules. Those patterns are:
|
@@ -21735,7 +21842,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
|
21735
21842
|
//
|
21736
21843
|
if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
|
21737
21844
|
if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
|
21738
|
-
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(
|
21845
|
+
PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(current_token_type));
|
21739
21846
|
break;
|
21740
21847
|
}
|
21741
21848
|
|
@@ -21857,6 +21964,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
|
|
21857
21964
|
));
|
21858
21965
|
|
21859
21966
|
pm_arguments_node_arguments_append(arguments, (pm_node_t *) keywords);
|
21967
|
+
pm_node_flag_set((pm_node_t *) arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
|
21860
21968
|
}
|
21861
21969
|
|
21862
21970
|
pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
|